extra translations

This commit is contained in:
2026-08-28 16:59:45 +02:00
parent e10f2cf7d7
commit c276088fe6
7 changed files with 278 additions and 16 deletions
+3 -2
View File
@@ -249,8 +249,9 @@ header. Command failures are returned as HTTP 400 JSON responses with an
- implements keyboard actions and playlist drag-and-drop in the browser. - implements keyboard actions and playlist drag-and-drop in the browser.
[`public/translate.js`](public/translate.js) follows the key-based translation [`public/translate.js`](public/translate.js) follows the key-based translation
model used by rktplayer. It supports Dutch, English, German, French and Spanish model used by rktplayer. It supports Dutch, English, German, French, Spanish,
with English fallback. Browser preferences select the initial language; a Italian, Swedish, Norwegian, Finnish and Icelandic with English fallback.
Browser preferences select the initial language; a
manual selection is stored server-side per username and therefore follows the manual selection is stored server-side per username and therefore follows the
user across browsers. The native agent uses the equivalent user across browsers. The native agent uses the equivalent
[`private/translate.rkt`](private/translate.rkt) module and the operating-system [`private/translate.rkt`](private/translate.rkt) module and the operating-system
+3 -2
View File
@@ -120,7 +120,8 @@ nieuwe gebruiker het over. Een oudere
`playlists-for-local`-verzameling blijft in de keystore staan, maar wordt niet `playlists-for-local`-verzameling blijft in de keystore staan, maar wordt niet
automatisch aan een gebruiker toegewezen. automatisch aan een gebruiker toegewezen.
De webinterface ondersteunt Nederlands, Engels, Duits, Frans en Spaans. Bij De webinterface ondersteunt Nederlands, Engels, Duits, Frans, Spaans,
Italiaans, Zweeds, Noors, Fins en IJslands. Bij
het eerste bezoek wordt de voorkeurstaal van de browser gebruikt. Een keuze in het eerste bezoek wordt de voorkeurstaal van de browser gebruikt. Een keuze in
de taalselector wordt daarna per gebruiker als `language-for-<username>` in de taalselector wordt daarna per gebruiker als `language-for-<username>` in
`data/playlists.keystore` opgeslagen en geldt daardoor ook op andere apparaten. `data/playlists.keystore` opgeslagen en geldt daardoor ook op andere apparaten.
@@ -173,7 +174,7 @@ toe wanneer zijn volledige applicatie-ID vooraf als key onder
HTTP 403 en wordt niet als uitvoerpunt aangemaakt. De agent toont in dat geval HTTP 403 en wordt niet als uitvoerpunt aangemaakt. De agent toont in dat geval
zijn ID en meldt dat de serverbeheerder deze eerst aan de INI moet toevoegen. zijn ID en meldt dat de serverbeheerder deze eerst aan de INI moet toevoegen.
De GUI en het systeemvak volgen automatisch de systeemtaal en ondersteunen De GUI en het systeemvak volgen automatisch de systeemtaal en ondersteunen
dezelfde vijf talen als de webinterface. dezelfde tien talen als de webinterface.
Onder **Afspelen** toont de agent het playlistnummer, de huidige track en Onder **Afspelen** toont de agent het playlistnummer, de huidige track en
bestandsnaam, afspeeltoestand, verstreken en totale tijd, bitdiepte, bestandsnaam, afspeeltoestand, verstreken en totale tijd, bitdiepte,
+6 -3
View File
@@ -24,7 +24,8 @@
(define (user-language-key username) (define (user-language-key username)
(format "language-for-~a" username)) (format "language-for-~a" username))
(define supported-language-names '("en" "nl" "de" "fr" "es")) (define supported-language-names
'("en" "nl" "de" "fr" "es" "it" "sv" "no" "fi" "is"))
(define (track->datum item) (define (track->datum item)
(hasheq 'file (path->string (track-file item)) (hasheq 'file (path->string (track-file item))
@@ -143,7 +144,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Persist one user's interface language. ; goal : Persist one user's interface language.
; pre : Store is #f or open, username is normalized, and language is one of ; pre : Store is #f or open, username is normalized, and language is one of
; en, nl, de, fr, or es. ; en, nl, de, fr, es, it, sv, no, fi, or is.
; post : The user's language key contains language when a store exists. ; post : The user's language key contains language when a store exists.
; result : Void. ; result : Void.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -151,7 +152,7 @@
(unless (member language supported-language-names) (unless (member language supported-language-names)
(raise-argument-error (raise-argument-error
'save-user-language! 'save-user-language!
"one of en, nl, de, fr, or es" "one of en, nl, de, fr, es, it, sv, no, fi, or is"
language)) language))
(when store (when store
(call-with-semaphore (call-with-semaphore
@@ -215,6 +216,8 @@
(check-false (load-user-language store "hans")) (check-false (load-user-language store "hans"))
(save-user-language! store "hans" "fr") (save-user-language! store "hans" "fr")
(check-equal? (load-user-language store "hans") "fr") (check-equal? (load-user-language store "hans") "fr")
(save-user-language! store "hans" "fi")
(check-equal? (load-user-language store "hans") "fi")
(check-exn exn:fail:contract? (check-exn exn:fail:contract?
(λ () (save-user-language! store "hans" "it"))) (λ () (save-user-language! store "hans" "it")))
+138 -3
View File
@@ -134,13 +134,141 @@
'channel "canal" 'channel "canal"
'channels "canales" 'channels "canales"
'tray-open "Abrir el agente de RKT Web Player" 'tray-open "Abrir el agente de RKT Web Player"
'quit "Salir"))) 'quit "Salir")
'it
(hasheq
'app-title "Agente RKT Web Player"
'server "Server RKT Web Player"
'name "Nome"
'application-id "ID applicazione"
'playback "Riproduzione"
'no-track "Nessuna riproduzione in corso"
'no-track-selected "Nessuna traccia selezionata"
'save-connect "Salva e connetti"
'reconnect "Riconnetti"
'connecting "Connessione…"
'connected "Connesso"
'denied-title "Agente di riproduzione non consentito"
'denied-message "Questo agente di riproduzione non è consentito dal server. Aggiungi il seguente ID applicazione a [playback-agents] nel file INI del server:\n\n~a"
'unauthorized-status "Non autorizzato — lID applicazione non è nel file INI del server"
'disconnected "Non connesso: ~a"
'playing "In riproduzione"
'paused "In pausa"
'loading "Caricamento"
'stopped "Arrestato"
'channel "canale"
'channels "canali"
'tray-open "Apri lagente RKT Web Player"
'quit "Esci")
'sv
(hasheq
'app-title "RKT Web Player-agent"
'server "RKT Web Player-server"
'name "Namn"
'application-id "Program-ID"
'playback "Uppspelning"
'no-track "Inget spelas upp"
'no-track-selected "Inget spår har valts"
'save-connect "Spara och anslut"
'reconnect "Anslut igen"
'connecting "Ansluter…"
'connected "Ansluten"
'denied-title "Uppspelningsagenten är inte tillåten"
'denied-message "Servern tillåter inte den här uppspelningsagenten. Lägg till följande program-ID under [playback-agents] i serverns INI-fil:\n\n~a"
'unauthorized-status "Inte behörig — program-ID saknas i serverns INI-fil"
'disconnected "Inte ansluten: ~a"
'playing "Spelar"
'paused "Pausad"
'loading "Läser in"
'stopped "Stoppad"
'channel "kanal"
'channels "kanaler"
'tray-open "Öppna RKT Web Player-agenten"
'quit "Avsluta")
'no
(hasheq
'app-title "RKT Web Player-agent"
'server "RKT Web Player-server"
'name "Navn"
'application-id "Applikasjons-ID"
'playback "Avspilling"
'no-track "Ingenting spilles av"
'no-track-selected "Ingen spor er valgt"
'save-connect "Lagre og koble til"
'reconnect "Koble til på nytt"
'connecting "Kobler til…"
'connected "Tilkoblet"
'denied-title "Avspillingsagenten er ikke tillatt"
'denied-message "Serveren tillater ikke denne avspillingsagenten. Legg til følgende applikasjons-ID under [playback-agents] i serverens INI-fil:\n\n~a"
'unauthorized-status "Ikke autorisert — applikasjons-ID mangler i serverens INI-fil"
'disconnected "Ikke tilkoblet: ~a"
'playing "Spiller"
'paused "På pause"
'loading "Laster"
'stopped "Stoppet"
'channel "kanal"
'channels "kanaler"
'tray-open "Åpne RKT Web Player-agenten"
'quit "Avslutt")
'fi
(hasheq
'app-title "RKT Web Player -agentti"
'server "RKT Web Player -palvelin"
'name "Nimi"
'application-id "Sovellustunnus"
'playback "Toisto"
'no-track "Mitään ei toisteta"
'no-track-selected "Kappaletta ei ole valittu"
'save-connect "Tallenna ja yhdistä"
'reconnect "Yhdistä uudelleen"
'connecting "Yhdistetään…"
'connected "Yhdistetty"
'denied-title "Toistoagenttia ei sallita"
'denied-message "Palvelin ei salli tätä toistoagenttia. Lisää seuraava sovellustunnus palvelimen INI-tiedoston [playback-agents]-osioon:\n\n~a"
'unauthorized-status "Ei valtuutettu — sovellustunnus puuttuu palvelimen INI-tiedostosta"
'disconnected "Ei yhteyttä: ~a"
'playing "Toistetaan"
'paused "Keskeytetty"
'loading "Ladataan"
'stopped "Pysäytetty"
'channel "kanava"
'channels "kanavaa"
'tray-open "Avaa RKT Web Player -agentti"
'quit "Lopeta")
'is
(hasheq
'app-title "RKT Web Player-spilari"
'server "RKT Web Player-þjónn"
'name "Nafn"
'application-id "Forritsauðkenni"
'playback "Spilun"
'no-track "Ekkert er í spilun"
'no-track-selected "Ekkert lag valið"
'save-connect "Vista og tengjast"
'reconnect "Tengjast aftur"
'connecting "Tengist…"
'connected "Tengt"
'denied-title "Spilarinn er ekki leyfður"
'denied-message "Þessi spilari er ekki leyfður af þjóninum. Bættu eftirfarandi forritsauðkenni við [playback-agents] í INI-skrá þjónsins:\n\n~a"
'unauthorized-status "Ekki heimilað — forritsauðkenni vantar í INI-skrá þjónsins"
'disconnected "Ekki tengt: ~a"
'playing "Spilar"
'paused "Í bið"
'loading "Hleður"
'stopped "Stöðvað"
'channel "rás"
'channels "rásir"
'tray-open "Opna RKT Web Player-spilarann"
'quit "Hætta")))
(define (system-language) (define (system-language)
(define language-name (define language-name
(string-downcase (format "~a" (system-language+country)))) (string-downcase (format "~a" (system-language+country))))
(define short-name (car (regexp-split #px"[-_]" language-name))) (define short-name (car (regexp-split #px"[-_]" language-name)))
(define candidate (string->symbol short-name)) (define candidate
(case (string->symbol short-name)
((nb nn) 'no)
(else (string->symbol short-name))))
(if (hash-has-key? translation-map candidate) candidate 'en)) (if (hash-has-key? translation-map candidate) candidate 'en))
(define language (system-language)) (define language (system-language))
@@ -156,7 +284,12 @@
(nl "Nederlands") (nl "Nederlands")
(de "Deutsch") (de "Deutsch")
(fr "Français") (fr "Français")
(es "Español"))) (es "Español")
(it "Italiano")
(sv "Svenska")
(no "Norsk")
(fi "Suomi")
(is "Íslenska")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Select the language used by tr and __. ; goal : Select the language used by tr and __.
@@ -212,6 +345,8 @@
(check-equal? (tr 'connected) "Verbonden") (check-equal? (tr 'connected) "Verbonden")
(set-lang! 'de) (set-lang! 'de)
(check-equal? (__ 'quit) "Beenden") (check-equal? (__ 'quit) "Beenden")
(set-lang! 'is)
(check-equal? (tr 'connected) "Tengt")
(check-equal? (tr 'unknown-translation) "unknown-translation") (check-equal? (tr 'unknown-translation) "unknown-translation")
(check-exn exn:fail:contract? (λ () (set-lang! 'xx)))) (check-exn exn:fail:contract? (λ () (set-lang! 'xx))))
(λ () (set-lang! original-language)))) (λ () (set-lang! original-language))))
+1 -1
View File
@@ -20,7 +20,7 @@
<select id="renderer"></select> <select id="renderer"></select>
<button id="discover" class="square-button" type="button" data-i18n-title="searchPlayers" title="Search for network players" aria-label="Search for network players"></button> <button id="discover" class="square-button" type="button" data-i18n-title="searchPlayers" title="Search for network players" aria-label="Search for network players"></button>
<select id="language" class="language-select" aria-label="Language"> <select id="language" class="language-select" aria-label="Language">
<option value="en">EN</option><option value="nl">NL</option><option value="de">DE</option><option value="fr">FR</option><option value="es">ES</option> <option value="en">EN</option><option value="nl">NL</option><option value="de">DE</option><option value="fr">FR</option><option value="es">ES</option><option value="it">IT</option><option value="sv">SV</option><option value="no">NO</option><option value="fi">FI</option><option value="is">IS</option>
</select> </select>
<button id="logout" class="text-button" type="button" data-i18n="logout" data-i18n-aria="logout" aria-label="Log out" hidden>LOG OUT</button> <button id="logout" class="text-button" type="button" data-i18n="logout" data-i18n-aria="logout" aria-label="Log out" hidden>LOG OUT</button>
</div> </div>
+122 -1
View File
@@ -122,12 +122,133 @@
authUnknown: "Estado de autenticación desconocido: {message}", noConnection: "Sin conexión: {message}", authUnknown: "Estado de autenticación desconocido: {message}", noConnection: "Sin conexión: {message}",
loggedOut: "Has cerrado la sesión.", volumePercent: "Ajustar volumen, {value} por ciento", loggedOut: "Has cerrado la sesión.", volumePercent: "Ajustar volumen, {value} por ciento",
}, },
it: {
output: "USCITA", searchPlayers: "Cerca lettori di rete", logout: "ESCI",
rendererLocal: "LOCALE", defaultPlaylist: "Predefinita",
playbackControls: "Controlli di riproduzione", previousTrack: "Traccia precedente",
playOrPause: "Riproduci o metti in pausa", play: "Riproduci", pause: "Pausa", stop: "Arresta",
nextTrack: "Traccia successiva", playbackPosition: "Posizione di riproduzione",
repeatMode: "Modalità ripetizione", setVolume: "Regola il volume", volume: "Volume",
musicLibrary: "LIBRERIA MUSICALE", upFolder: "Cartella superiore", currentFolder: "Cartella corrente",
noLibraryConfigured: "Nessuna libreria configurata.", folderContents: "Contenuto della cartella",
nowPlaying: "IN RIPRODUZIONE", nothingSelected: "Nessuna selezione",
addTrackHint: "Aggiungi una traccia dalla libreria", playlists: "Playlist",
newPlaylist: "Nuova playlist", playlist: "PLAYLIST", clearList: "SVUOTA ELENCO",
emptyPlaylist: "Questa playlist è vuota.", emptyPlaylistHint: "Usa accanto a una traccia o cartella.",
title: "TITOLO", album: "ALBUM", duration: "DURATA", actions: "Azioni",
connecting: "Connessione…", signIn: "Accedi", username: "Nome utente",
password: "Password", noLibrary: "Nessuna libreria", playNow: "Riproduci {name} ora",
addNamed: "Aggiungi {name}", loadingNamed: "Caricamento di {name}…", addingNamed: "Aggiunta di {name}…",
playlistName: "Nome della playlist", removePlaylist: "Rimuovi playlist",
removeNamed: "Rimuovi {name}", oneTrack: "traccia", manyTracks: "tracce",
repeatOff: "Ripetizione disattivata", repeatAll: "Ripeti tutto", repeatOne: "Ripeti una traccia",
channels: "canali", oneChannel: "canale", searchingPlayers: "Ricerca dei lettori di rete…",
authUnknown: "Stato di autenticazione sconosciuto: {message}", noConnection: "Nessuna connessione: {message}",
loggedOut: "Hai effettuato la disconnessione.", volumePercent: "Regola il volume, {value} percento",
},
sv: {
output: "UTGÅNG", searchPlayers: "Sök efter nätverksspelare", logout: "LOGGA UT",
rendererLocal: "LOKAL", defaultPlaylist: "Standard",
playbackControls: "Uppspelningskontroller", previousTrack: "Föregående spår",
playOrPause: "Spela eller pausa", play: "Spela", pause: "Pausa", stop: "Stoppa",
nextTrack: "Nästa spår", playbackPosition: "Uppspelningsposition",
repeatMode: "Upprepningsläge", setVolume: "Ställ in volym", volume: "Volym",
musicLibrary: "MUSIKBIBLIOTEK", upFolder: "En mapp upp", currentFolder: "Aktuell mapp",
noLibraryConfigured: "Inget bibliotek har konfigurerats.", folderContents: "Mappinnehåll",
nowPlaying: "SPELAR NU", nothingSelected: "Inget har valts",
addTrackHint: "Lägg till ett spår från biblioteket", playlists: "Spellistor",
newPlaylist: "Ny spellista", playlist: "SPELLISTA", clearList: "TÖM LISTAN",
emptyPlaylist: "Den här spellistan är tom.", emptyPlaylistHint: "Använd bredvid ett spår eller en mapp.",
title: "TITEL", album: "ALBUM", duration: "LÄNGD", actions: "Åtgärder",
connecting: "Ansluter…", signIn: "Logga in", username: "Användarnamn",
password: "Lösenord", noLibrary: "Inget bibliotek", playNow: "Spela {name} nu",
addNamed: "Lägg till {name}", loadingNamed: "Läser in {name}…", addingNamed: "Lägger till {name}…",
playlistName: "Spellistans namn", removePlaylist: "Ta bort spellista",
removeNamed: "Ta bort {name}", oneTrack: "spår", manyTracks: "spår",
repeatOff: "Upprepning av", repeatAll: "Upprepa alla", repeatOne: "Upprepa ett spår",
channels: "kanaler", oneChannel: "kanal", searchingPlayers: "Söker efter nätverksspelare…",
authUnknown: "Okänd autentiseringsstatus: {message}", noConnection: "Ingen anslutning: {message}",
loggedOut: "Du har loggats ut.", volumePercent: "Ställ in volymen på {value} procent",
},
no: {
output: "UTGANG", searchPlayers: "Søk etter nettverksspillere", logout: "LOGG UT",
rendererLocal: "LOKAL", defaultPlaylist: "Standard",
playbackControls: "Avspillingskontroller", previousTrack: "Forrige spor",
playOrPause: "Spill av eller sett på pause", play: "Spill av", pause: "Pause", stop: "Stopp",
nextTrack: "Neste spor", playbackPosition: "Avspillingsposisjon",
repeatMode: "Gjentakelsesmodus", setVolume: "Still inn volum", volume: "Volum",
musicLibrary: "MUSIKKBIBLIOTEK", upFolder: "Én mappe opp", currentFolder: "Gjeldende mappe",
noLibraryConfigured: "Ingen bibliotek er konfigurert.", folderContents: "Mappeinnhold",
nowPlaying: "SPILLER NÅ", nothingSelected: "Ingenting er valgt",
addTrackHint: "Legg til et spor fra biblioteket", playlists: "Spillelister",
newPlaylist: "Ny spilleliste", playlist: "SPILLELISTE", clearList: "TØM LISTEN",
emptyPlaylist: "Denne spillelisten er tom.", emptyPlaylistHint: "Bruk ved siden av et spor eller en mappe.",
title: "TITTEL", album: "ALBUM", duration: "VARIGHET", actions: "Handlinger",
connecting: "Kobler til…", signIn: "Logg inn", username: "Brukernavn",
password: "Passord", noLibrary: "Ingen bibliotek", playNow: "Spill av {name} nå",
addNamed: "Legg til {name}", loadingNamed: "Laster inn {name}…", addingNamed: "Legger til {name}…",
playlistName: "Navn på spilleliste", removePlaylist: "Fjern spilleliste",
removeNamed: "Fjern {name}", oneTrack: "spor", manyTracks: "spor",
repeatOff: "Gjentakelse av", repeatAll: "Gjenta alle", repeatOne: "Gjenta ett spor",
channels: "kanaler", oneChannel: "kanal", searchingPlayers: "Søker etter nettverksspillere…",
authUnknown: "Ukjent autentiseringsstatus: {message}", noConnection: "Ingen tilkobling: {message}",
loggedOut: "Du er logget ut.", volumePercent: "Still inn volumet på {value} prosent",
},
fi: {
output: "ULOSTULO", searchPlayers: "Etsi verkkosoittimia", logout: "KIRJAUDU ULOS",
rendererLocal: "PAIKALLINEN", defaultPlaylist: "Oletus",
playbackControls: "Toiston ohjaimet", previousTrack: "Edellinen kappale",
playOrPause: "Toista tai keskeytä", play: "Toista", pause: "Keskeytä", stop: "Pysäytä",
nextTrack: "Seuraava kappale", playbackPosition: "Toistokohta",
repeatMode: "Toistotila", setVolume: "Säädä äänenvoimakkuutta", volume: "Äänenvoimakkuus",
musicLibrary: "MUSIIKKIKIRJASTO", upFolder: "Yksi kansio ylöspäin", currentFolder: "Nykyinen kansio",
noLibraryConfigured: "Kirjastoa ei ole määritetty.", folderContents: "Kansion sisältö",
nowPlaying: "NYT TOISTETAAN", nothingSelected: "Mitään ei ole valittu",
addTrackHint: "Lisää kappale kirjastosta", playlists: "Soittolistat",
newPlaylist: "Uusi soittolista", playlist: "SOITTOLISTA", clearList: "TYHJENNÄ LISTA",
emptyPlaylist: "Tämä soittolista on tyhjä.", emptyPlaylistHint: "Käytä kappaleen tai kansion vieressä.",
title: "NIMI", album: "ALBUMI", duration: "KESTO", actions: "Toiminnot",
connecting: "Yhdistetään…", signIn: "Kirjaudu sisään", username: "Käyttäjänimi",
password: "Salasana", noLibrary: "Ei kirjastoa", playNow: "Toista {name} nyt",
addNamed: "Lisää {name}", loadingNamed: "Ladataan {name}…", addingNamed: "Lisätään {name}…",
playlistName: "Soittolistan nimi", removePlaylist: "Poista soittolista",
removeNamed: "Poista {name}", oneTrack: "kappale", manyTracks: "kappaletta",
repeatOff: "Toisto pois", repeatAll: "Toista kaikki", repeatOne: "Toista yksi kappale",
channels: "kanavaa", oneChannel: "kanava", searchingPlayers: "Etsitään verkkosoittimia…",
authUnknown: "Todennuksen tila ei ole tiedossa: {message}", noConnection: "Ei yhteyttä: {message}",
loggedOut: "Olet kirjautunut ulos.", volumePercent: "Säädä äänenvoimakkuudeksi {value} prosenttia",
},
is: {
output: "ÚTTAK", searchPlayers: "Leita að netspilurum", logout: "SKRÁ ÚT",
rendererLocal: "STAÐBUNDIÐ", defaultPlaylist: "Sjálfgefið",
playbackControls: "Stýringar spilunar", previousTrack: "Fyrra lag",
playOrPause: "Spila eða gera hlé", play: "Spila", pause: "Gera hlé", stop: "Stöðva",
nextTrack: "Næsta lag", playbackPosition: "Staða spilunar",
repeatMode: "Endurtekningarhamur", setVolume: "Stilla hljóðstyrk", volume: "Hljóðstyrkur",
musicLibrary: "TÓNLISTARSAFN", upFolder: "Eina möppu upp", currentFolder: "Núverandi mappa",
noLibraryConfigured: "Ekkert safn er skilgreint.", folderContents: "Innihald möppu",
nowPlaying: "Í SPILUN", nothingSelected: "Ekkert valið",
addTrackHint: "Bættu lagi við úr safninu", playlists: "Spilunarlistar",
newPlaylist: "Nýr spilunarlisti", playlist: "SPILUNARLISTI", clearList: "HREINSA LISTA",
emptyPlaylist: "Þessi spilunarlisti er tómur.", emptyPlaylistHint: "Notaðu við hlið lags eða möppu.",
title: "TITILL", album: "PLATA", duration: "LENGD", actions: "Aðgerðir",
connecting: "Tengist…", signIn: "Skrá inn", username: "Notandanafn",
password: "Lykilorð", noLibrary: "Ekkert safn", playNow: "Spila {name} núna",
addNamed: "Bæta {name} við", loadingNamed: "Hleður {name}…", addingNamed: "Bætir {name} við…",
playlistName: "Heiti spilunarlista", removePlaylist: "Fjarlægja spilunarlista",
removeNamed: "Fjarlægja {name}", oneTrack: "lag", manyTracks: "lög",
repeatOff: "Endurtekning óvirk", repeatAll: "Endurtaka allt", repeatOne: "Endurtaka eitt lag",
channels: "rásir", oneChannel: "rás", searchingPlayers: "Leita að netspilurum…",
authUnknown: "Staða auðkenningar óþekkt: {message}", noConnection: "Engin tenging: {message}",
loggedOut: "Þú hefur skráð þig út.", volumePercent: "Stilla hljóðstyrk á {value} prósent",
},
}; };
const supported = Object.keys(translations); const supported = Object.keys(translations);
const requested = [...(navigator.languages || [navigator.language])] const requested = [...(navigator.languages || [navigator.language])]
.filter(Boolean) .filter(Boolean)
.map((value) => value.toLowerCase().split("-")[0]); .map((value) => value.toLowerCase().split("-")[0])
.map((value) => ({ nb: "no", nn: "no" })[value] || value);
let language = requested.find((value) => supported.includes(value)) || "en"; let language = requested.find((value) => supported.includes(value)) || "en";
function t(key, values = {}) { function t(key, values = {}) {
+5 -4
View File
@@ -51,8 +51,9 @@ Each username owns an ordered GUID index and separate playlist values.
It also owns an independent playback pipeline and a durable interface-language It also owns an independent playback pipeline and a durable interface-language
preference. Different outputs can play concurrently. Selecting an output that preference. Different outputs can play concurrently. Selecting an output that
another user owns stops the previous backend and transfers that output. The web another user owns stops the previous backend and transfers that output. The web
interface supports Dutch, English, German, French and Spanish; browser language interface supports Dutch, English, German, French, Spanish, Italian, Swedish,
is the initial default and a manual choice is stored per username. Norwegian, Finnish and Icelandic; browser language is the initial default and a
manual choice is stored per username.
When @racket[users] is non-empty, every browser client must authenticate. When @racket[users] is non-empty, every browser client must authenticate.
Sessions have a sliding idle timeout; an active browser cookie is renewed once Sessions have a sliding idle timeout; an active browser cookie is renewed once
half of @racket[session-seconds] has elapsed. Playback-agent endpoints continue half of @racket[session-seconds] has elapsed. Playback-agent endpoints continue
@@ -86,8 +87,8 @@ configured RKT Web Player server, downloads assigned tracks over HTTP, and
plays them with @tt{racket-audio}. Its configured display name is authoritative plays them with @tt{racket-audio}. Its configured display name is authoritative
and is followed by the server. Importing the module does not start the GUI; the and is followed by the server. Importing the module does not start the GUI; the
function must be called explicitly. function must be called explicitly.
The GUI and optional tray use Dutch, English, German, French or Spanish based The GUI and optional tray support the same ten languages based on the
on the operating-system language, with English as fallback. operating-system language, with English as fallback.
} }
@defproc[(run-player-agent-cli [#:server-url server-url @defproc[(run-player-agent-cli [#:server-url server-url