multi player / per user playing and translation

This commit is contained in:
2026-08-28 16:53:05 +02:00
parent 2743dfb4c0
commit e10f2cf7d7
17 changed files with 1432 additions and 482 deletions
+162
View File
@@ -0,0 +1,162 @@
(() => {
"use strict";
const translations = {
en: {
output: "OUTPUT", searchPlayers: "Search for network players", logout: "LOG OUT",
rendererLocal: "LOCAL", defaultPlaylist: "Default",
playbackControls: "Playback controls", previousTrack: "Previous track",
playOrPause: "Play or pause", play: "Play", pause: "Pause", stop: "Stop",
nextTrack: "Next track", playbackPosition: "Playback position",
repeatMode: "Repeat mode", setVolume: "Set volume", volume: "Volume",
musicLibrary: "MUSIC LIBRARY", upFolder: "Up one folder", currentFolder: "Current folder",
noLibraryConfigured: "No library configured.", folderContents: "Folder contents",
nowPlaying: "NOW PLAYING", nothingSelected: "Nothing selected yet",
addTrackHint: "Add a track from the library", playlists: "Playlists",
newPlaylist: "New playlist", playlist: "PLAYLIST", clearList: "CLEAR LIST",
emptyPlaylist: "This playlist is empty.", emptyPlaylistHint: "Use next to a track or folder.",
title: "TITLE", album: "ALBUM", duration: "DURATION", actions: "Actions",
connecting: "Connecting…", signIn: "Sign in", username: "Username",
password: "Password", noLibrary: "No library", playNow: "Play {name} now",
addNamed: "Add {name}", loadingNamed: "Loading {name}…", addingNamed: "Adding {name}…",
playlistName: "Playlist name", removePlaylist: "Remove playlist",
removeNamed: "Remove {name}", oneTrack: "track", manyTracks: "tracks",
repeatOff: "Repeat off", repeatAll: "Repeat all", repeatOne: "Repeat one track",
channels: "channels", oneChannel: "channel", searchingPlayers: "Searching for network players…",
authUnknown: "Authentication status unknown: {message}", noConnection: "No connection: {message}",
loggedOut: "You have been logged out.", volumePercent: "Set volume, {value} percent",
},
nl: {
output: "UITVOER", searchPlayers: "Netwerkspelers zoeken", logout: "UITLOGGEN",
rendererLocal: "LOKAAL", defaultPlaylist: "Standaard",
playbackControls: "Afspeelbediening", previousTrack: "Vorige track",
playOrPause: "Afspelen of pauzeren", play: "Afspelen", pause: "Pauzeren", stop: "Stoppen",
nextTrack: "Volgende track", playbackPosition: "Afspeelpositie",
repeatMode: "Herhaalmodus", setVolume: "Volume instellen", volume: "Volume",
musicLibrary: "MUZIEKBIBLIOTHEEK", upFolder: "Eén map omhoog", currentFolder: "Huidige map",
noLibraryConfigured: "Geen bibliotheek geconfigureerd.", folderContents: "Mapinhoud",
nowPlaying: "NU AAN HET SPELEN", nothingSelected: "Nog niets gekozen",
addTrackHint: "Voeg een track toe vanuit de bibliotheek", playlists: "Afspeellijsten",
newPlaylist: "Nieuwe afspeellijst", playlist: "AFSPEELLIJST", clearList: "LIJST WISSEN",
emptyPlaylist: "Deze afspeellijst is leeg.", emptyPlaylistHint: "Gebruik bij een track of map.",
title: "TITEL", album: "ALBUM", duration: "DUUR", actions: "Acties",
connecting: "Verbinden…", signIn: "Aanmelden", username: "Gebruikersnaam",
password: "Wachtwoord", noLibrary: "Geen bibliotheek", playNow: "{name} nu afspelen",
addNamed: "{name} toevoegen", loadingNamed: "{name} laden…", addingNamed: "{name} toevoegen…",
playlistName: "Naam van de afspeellijst", removePlaylist: "Afspeellijst verwijderen",
removeNamed: "{name} verwijderen", oneTrack: "track", manyTracks: "tracks",
repeatOff: "Herhalen uit", repeatAll: "Alles herhalen", repeatOne: "Eén track herhalen",
channels: "kanalen", oneChannel: "kanaal", searchingPlayers: "Netwerkspelers zoeken…",
authUnknown: "Authenticatiestatus onbekend: {message}", noConnection: "Geen verbinding: {message}",
loggedOut: "Je bent uitgelogd.", volumePercent: "Volume instellen, {value} procent",
},
de: {
output: "AUSGABE", searchPlayers: "Netzwerkplayer suchen", logout: "ABMELDEN",
rendererLocal: "LOKAL", defaultPlaylist: "Standard",
playbackControls: "Wiedergabesteuerung", previousTrack: "Vorheriger Titel",
playOrPause: "Wiedergeben oder pausieren", play: "Wiedergeben", pause: "Pausieren", stop: "Stoppen",
nextTrack: "Nächster Titel", playbackPosition: "Wiedergabeposition",
repeatMode: "Wiederholungsmodus", setVolume: "Lautstärke einstellen", volume: "Lautstärke",
musicLibrary: "MUSIKBIBLIOTHEK", upFolder: "Einen Ordner nach oben", currentFolder: "Aktueller Ordner",
noLibraryConfigured: "Keine Bibliothek konfiguriert.", folderContents: "Ordnerinhalt",
nowPlaying: "AKTUELLE WIEDERGABE", nothingSelected: "Noch nichts ausgewählt",
addTrackHint: "Titel aus der Bibliothek hinzufügen", playlists: "Wiedergabelisten",
newPlaylist: "Neue Wiedergabeliste", playlist: "WIEDERGABELISTE", clearList: "LISTE LEEREN",
emptyPlaylist: "Diese Wiedergabeliste ist leer.", emptyPlaylistHint: "Verwenden Sie neben einem Titel oder Ordner.",
title: "TITEL", album: "ALBUM", duration: "DAUER", actions: "Aktionen",
connecting: "Verbinden…", signIn: "Anmelden", username: "Benutzername",
password: "Passwort", noLibrary: "Keine Bibliothek", playNow: "{name} jetzt wiedergeben",
addNamed: "{name} hinzufügen", loadingNamed: "{name} wird geladen…", addingNamed: "{name} wird hinzugefügt…",
playlistName: "Name der Wiedergabeliste", removePlaylist: "Wiedergabeliste entfernen",
removeNamed: "{name} entfernen", oneTrack: "Titel", manyTracks: "Titel",
repeatOff: "Wiederholung aus", repeatAll: "Alles wiederholen", repeatOne: "Einen Titel wiederholen",
channels: "Kanäle", oneChannel: "Kanal", searchingPlayers: "Netzwerkplayer werden gesucht…",
authUnknown: "Authentifizierungsstatus unbekannt: {message}", noConnection: "Keine Verbindung: {message}",
loggedOut: "Sie wurden abgemeldet.", volumePercent: "Lautstärke einstellen, {value} Prozent",
},
fr: {
output: "SORTIE", searchPlayers: "Rechercher les lecteurs réseau", logout: "DÉCONNEXION",
rendererLocal: "LOCAL", defaultPlaylist: "Par défaut",
playbackControls: "Commandes de lecture", previousTrack: "Piste précédente",
playOrPause: "Lire ou mettre en pause", play: "Lire", pause: "Pause", stop: "Arrêter",
nextTrack: "Piste suivante", playbackPosition: "Position de lecture",
repeatMode: "Mode répétition", setVolume: "Régler le volume", volume: "Volume",
musicLibrary: "BIBLIOTHÈQUE MUSICALE", upFolder: "Dossier parent", currentFolder: "Dossier actuel",
noLibraryConfigured: "Aucune bibliothèque configurée.", folderContents: "Contenu du dossier",
nowPlaying: "LECTURE EN COURS", nothingSelected: "Aucune sélection",
addTrackHint: "Ajoutez une piste depuis la bibliothèque", playlists: "Listes de lecture",
newPlaylist: "Nouvelle liste de lecture", playlist: "LISTE DE LECTURE", clearList: "VIDER LA LISTE",
emptyPlaylist: "Cette liste de lecture est vide.", emptyPlaylistHint: "Utilisez à côté dune piste ou dun dossier.",
title: "TITRE", album: "ALBUM", duration: "DURÉE", actions: "Actions",
connecting: "Connexion…", signIn: "Se connecter", username: "Nom dutilisateur",
password: "Mot de passe", noLibrary: "Aucune bibliothèque", playNow: "Lire {name} maintenant",
addNamed: "Ajouter {name}", loadingNamed: "Chargement de {name}…", addingNamed: "Ajout de {name}…",
playlistName: "Nom de la liste de lecture", removePlaylist: "Supprimer la liste de lecture",
removeNamed: "Supprimer {name}", oneTrack: "piste", manyTracks: "pistes",
repeatOff: "Répétition désactivée", repeatAll: "Tout répéter", repeatOne: "Répéter une piste",
channels: "canaux", oneChannel: "canal", searchingPlayers: "Recherche des lecteurs réseau…",
authUnknown: "État dauthentification inconnu : {message}", noConnection: "Aucune connexion : {message}",
loggedOut: "Vous avez été déconnecté.", volumePercent: "Régler le volume, {value} pour cent",
},
es: {
output: "SALIDA", searchPlayers: "Buscar reproductores de red", logout: "CERRAR SESIÓN",
rendererLocal: "LOCAL", defaultPlaylist: "Predeterminada",
playbackControls: "Controles de reproducción", previousTrack: "Pista anterior",
playOrPause: "Reproducir o pausar", play: "Reproducir", pause: "Pausar", stop: "Detener",
nextTrack: "Pista siguiente", playbackPosition: "Posición de reproducción",
repeatMode: "Modo de repetición", setVolume: "Ajustar volumen", volume: "Volumen",
musicLibrary: "BIBLIOTECA MUSICAL", upFolder: "Subir una carpeta", currentFolder: "Carpeta actual",
noLibraryConfigured: "No hay ninguna biblioteca configurada.", folderContents: "Contenido de la carpeta",
nowPlaying: "REPRODUCIENDO", nothingSelected: "Nada seleccionado",
addTrackHint: "Añade una pista desde la biblioteca", playlists: "Listas de reproducción",
newPlaylist: "Nueva lista de reproducción", playlist: "LISTA DE REPRODUCCIÓN", clearList: "VACIAR LISTA",
emptyPlaylist: "Esta lista de reproducción está vacía.", emptyPlaylistHint: "Usa junto a una pista o carpeta.",
title: "TÍTULO", album: "ÁLBUM", duration: "DURACIÓN", actions: "Acciones",
connecting: "Conectando…", signIn: "Iniciar sesión", username: "Nombre de usuario",
password: "Contraseña", noLibrary: "Sin biblioteca", playNow: "Reproducir {name} ahora",
addNamed: "Añadir {name}", loadingNamed: "Cargando {name}…", addingNamed: "Añadiendo {name}…",
playlistName: "Nombre de la lista de reproducción", removePlaylist: "Eliminar lista de reproducción",
removeNamed: "Eliminar {name}", oneTrack: "pista", manyTracks: "pistas",
repeatOff: "Repetición desactivada", repeatAll: "Repetir todo", repeatOne: "Repetir una pista",
channels: "canales", oneChannel: "canal", searchingPlayers: "Buscando reproductores de red…",
authUnknown: "Estado de autenticación desconocido: {message}", noConnection: "Sin conexión: {message}",
loggedOut: "Has cerrado la sesión.", volumePercent: "Ajustar volumen, {value} por ciento",
},
};
const supported = Object.keys(translations);
const requested = [...(navigator.languages || [navigator.language])]
.filter(Boolean)
.map((value) => value.toLowerCase().split("-")[0]);
let language = requested.find((value) => supported.includes(value)) || "en";
function t(key, values = {}) {
const template = translations[language][key] ?? translations.en[key] ?? key;
return template.replace(/\{(\w+)\}/g, (_match, name) => values[name] ?? `{${name}}`);
}
function apply(root = document) {
document.documentElement.lang = language;
root.querySelectorAll("[data-i18n]").forEach((element) => {
element.textContent = t(element.dataset.i18n);
});
root.querySelectorAll("[data-i18n-title]").forEach((element) => {
const value = t(element.dataset.i18nTitle);
element.title = value;
element.setAttribute("aria-label", value);
});
root.querySelectorAll("[data-i18n-aria]").forEach((element) => {
element.setAttribute("aria-label", t(element.dataset.i18nAria));
});
}
function setLanguage(value) {
if (!supported.includes(value)) return;
language = value;
apply();
window.dispatchEvent(new CustomEvent("rkt-language-change"));
}
window.RktTranslate = { apply, language: () => language, setLanguage, supported, t };
window.addEventListener("DOMContentLoaded", () => apply());
})();