From 6e9b78e5b506d5adc037ca735b1e844e18056e58 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Tue, 10 Feb 2026 21:37:27 +0100 Subject: [PATCH] fix: missing translations, simplify translations --- lib/i18n/de.i18n.json | 150 +- lib/i18n/en.i18n.json | 145 +- lib/i18n/es.i18n.json | 1398 +++++++++-------- lib/i18n/fr.i18n.json | 150 +- lib/i18n/it.i18n.json | 150 +- lib/i18n/ko.i18n.json | 150 +- lib/i18n/nl.i18n.json | 150 +- lib/i18n/strings.g.dart | 4 +- lib/i18n/strings_de.g.dart | 306 +++- lib/i18n/strings_en.g.dart | 555 ++++++- lib/i18n/strings_es.g.dart | 306 +++- lib/i18n/strings_fr.g.dart | 306 +++- lib/i18n/strings_it.g.dart | 306 +++- lib/i18n/strings_ko.g.dart | 306 +++- lib/i18n/strings_nl.g.dart | 306 +++- lib/i18n/strings_sv.g.dart | 306 +++- lib/i18n/strings_zh.g.dart | 306 +++- lib/i18n/sv.i18n.json | 150 +- lib/i18n/zh.i18n.json | 150 +- lib/main.dart | 2 +- lib/navigation/navigation_tabs.dart | 6 +- lib/screens/auth_screen.dart | 6 +- .../base_media_list_detail_screen.dart | 2 +- lib/screens/collection_detail_screen.dart | 2 +- .../mobile_remote_screen.dart | 85 +- .../companion_remote/pairing_screen.dart | 105 +- lib/screens/discover_screen.dart | 10 +- .../playlist/playlist_detail_screen.dart | 2 +- lib/screens/search_screen.dart | 2 +- lib/screens/settings/settings_screen.dart | 14 +- lib/screens/video_player_screen.dart | 2 +- lib/services/play_queue_launcher.dart | 2 +- lib/utils/formatters.dart | 37 + .../remote_session_dialog.dart | 51 +- lib/widgets/download_tree_view.dart | 16 +- lib/widgets/media_context_menu.dart | 2 +- lib/widgets/side_navigation_rail.dart | 6 +- .../desktop_video_controls.dart | 75 +- .../video_controls/sheets/chapter_sheet.dart | 7 +- .../sheets/video_settings_sheet.dart | 26 +- .../video_controls/video_controls.dart | 1 + .../widgets/video_controls_header.dart | 2 +- 42 files changed, 4800 insertions(+), 1263 deletions(-) diff --git a/lib/i18n/de.i18n.json b/lib/i18n/de.i18n.json index 199c02a2..0dfd1d5c 100644 --- a/lib/i18n/de.i18n.json +++ b/lib/i18n/de.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "Lädt..." - }, + "title": "Plezy" +}, "auth": { "signInWithPlex": "Mit Plex anmelden", "showQRCode": "QR-Code anzeigen", - "cancel": "Abbrechen", "authenticate": "Authentifizieren", - "retry": "Erneut versuchen", "debugEnterToken": "Debug: Plex-Token eingeben", "plexTokenLabel": "Plex-Auth-Token", "plexTokenHint": "Plex.tv-Token eingeben", @@ -34,14 +31,28 @@ "no": "Nein", "delete": "Löschen", "shuffle": "Zufall", - "addTo": "Hinzufügen zu..." + "addTo": "Hinzufügen zu...", + "remove": "Entfernen", + "paste": "Einfügen", + "connect": "Verbinden", + "disconnect": "Trennen", + "play": "Abspielen", + "pause": "Pause", + "resume": "Fortsetzen", + "error": "Fehler", + "search": "Suche", + "home": "Startseite", + "back": "Zurück", + "settings": "Einstellungen", + "mute": "Stumm", + "ok": "OK", + "loading": "Laden..." }, "screens": { "licenses": "Lizenzen", "switchProfile": "Profil wechseln", "subtitleStyling": "Untertitel-Stil", "mpvConfig": "MPV-Konfiguration", - "search": "Suche", "logs": "Protokolle" }, "update": { @@ -203,7 +214,8 @@ "speedReset": "Geschwindigkeit zurücksetzen", "subSeekNext": "Zum nächsten Untertitel springen", "subSeekPrev": "Zum vorherigen Untertitel springen", - "shaderToggle": "Shader umschalten" + "shaderToggle": "Shader umschalten", + "skipMarker": "Intro/Abspann überspringen" } }, "pinEntry": { @@ -307,7 +319,6 @@ "timelineSlider": "Video-Zeitleiste", "volumeSlider": "Lautstärkepegel", "endsAt": "Endet um ${time}", - "backButton": "Zurück", "pipFailed": "Bild-in-Bild konnte nicht gestartet werden", "pipErrors": { "androidVersion": "Erfordert Android 8.0 oder neuer", @@ -315,7 +326,9 @@ "notSupported": "Dieses Gerät unterstützt den Bild-in-Bild-Modus nicht", "failed": "Bild-in-Bild konnte nicht gestartet werden", "unknown": "Ein Fehler ist aufgetreten: ${error}" - } + }, + "chapters": "Kapitel", + "noChaptersAvailable": "Keine Kapitel verfügbar" }, "userStatus": { "admin": "Eigentümer", @@ -395,19 +408,15 @@ "entriesCount": "${count} Einträge" }, "dialog": { - "confirmAction": "Aktion bestätigen", - "cancel": "Abbrechen" + "confirmAction": "Aktion bestätigen" }, "discover": { "title": "Entdecken", "switchProfile": "Profil wechseln", - "logout": "Abmelden", "noContentAvailable": "Kein Inhalt verfügbar", "addMediaToLibraries": "Medien zur Mediathek hinzufügen", "continueWatching": "Weiterschauen", - "play": "Abspielen", "playEpisode": "S${season}E${episode}", - "pause": "Pause", "overview": "Übersicht", "cast": "Besetzung", "seasons": "Staffeln", @@ -517,10 +526,7 @@ "licensesCount": "${count} Lizenzen" }, "navigation": { - "home": "Start", - "search": "Suche", "libraries": "Mediatheken", - "settings": "Einstellungen", "downloads": "Downloads" }, "downloads": { @@ -537,7 +543,11 @@ "episodesQueued": "${count} Episoden zum Download hinzugefügt", "downloadDeleted": "Download gelöscht", "deleteConfirm": "Möchtest du \"${title}\" wirklich löschen? Die heruntergeladene Datei wird von deinem Gerät entfernt.", - "deletingWithProgress": "Lösche ${title}... (${current} von ${total})" + "deletingWithProgress": "Lösche ${title}... (${current} von ${total})", + "noDownloadsTree": "Keine Downloads", + "pauseAll": "Alle pausieren", + "resumeAll": "Alle fortsetzen", + "deleteAll": "Alle löschen" }, "playlists": { "title": "Wiedergabelisten", @@ -642,5 +652,107 @@ "qualityFast": "Schnell", "qualityHQ": "Hohe Qualität", "mode": "Modus" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "Mit Gerät verbinden", + "hostRemoteSession": "Fernsteuerungssitzung starten", + "controlThisDevice": "Dieses Gerät mit dem Handy steuern", + "remoteControl": "Fernsteuerung", + "controlDesktop": "Ein Desktop-Gerät steuern", + "connectedTo": "Verbunden mit ${name}", + "session": { + "creatingSession": "Fernsteuerungssitzung wird erstellt...", + "failedToCreate": "Fernsteuerungssitzung konnte nicht erstellt werden:", + "noSession": "Keine Sitzung verfügbar", + "scanQrCode": "QR-Code scannen", + "orEnterManually": "Oder manuell eingeben", + "hostAddress": "Host-Adresse", + "sessionId": "Sitzungs-ID", + "pin": "PIN", + "connected": "Verbunden", + "waitingForConnection": "Warte auf Verbindung...", + "usePhoneToControl": "Verwende dein Mobilgerät, um diese App zu steuern", + "copiedToClipboard": "${label} in Zwischenablage kopiert", + "copyToClipboard": "In Zwischenablage kopieren", + "newSession": "Neue Sitzung", + "minimize": "Minimieren" + }, + "pairing": { + "recent": "Zuletzt", + "scan": "Scannen", + "manual": "Manuell", + "recentConnections": "Letzte Verbindungen", + "quickReconnect": "Schnell mit zuvor gekoppelten Geräten verbinden", + "pairWithDesktop": "Mit Desktop koppeln", + "enterSessionDetails": "Gib die Sitzungsdetails ein, die auf deinem Desktop-Gerät angezeigt werden", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "8-stellige Sitzungs-ID eingeben", + "pinHint": "6-stellige PIN eingeben", + "connecting": "Verbinde...", + "tips": "Tipps", + "tipDesktop": "Öffne Plezy auf deinem Desktop und aktiviere Companion Remote in den Einstellungen oder im Menü", + "tipScan": "Verwende den Scannen-Tab, um dich schnell per QR-Code auf deinem Desktop zu koppeln", + "tipWifi": "Stelle sicher, dass beide Geräte im selben WiFi-Netzwerk sind", + "cameraPermissionRequired": "Kameraberechtigung wird zum Scannen von QR-Codes benötigt.\nBitte erteile den Kamerazugriff in den Geräteeinstellungen.", + "cameraError": "Kamera konnte nicht gestartet werden: ${error}", + "scanInstruction": "Richte deine Kamera auf den QR-Code auf deinem Desktop", + "noRecentConnections": "Keine letzten Verbindungen", + "connectUsingManual": "Verbinde dich über die manuelle Eingabe, um loszulegen", + "invalidQrCode": "Ungültiges QR-Code-Format", + "removeRecentConnection": "Letzte Verbindung entfernen", + "removeConfirm": "\"${name}\" aus den letzten Verbindungen entfernen?", + "validationHostRequired": "Bitte Host-Adresse eingeben", + "validationHostFormat": "Format muss IP:Port sein (z.B. 192.168.1.100:48632)", + "validationSessionIdRequired": "Bitte Sitzungs-ID eingeben", + "validationSessionIdLength": "Sitzungs-ID muss 8 Zeichen lang sein", + "validationPinRequired": "Bitte PIN eingeben", + "validationPinLength": "PIN muss 6 Ziffern haben", + "connectionTimedOut": "Zeitüberschreitung. Bitte Sitzungs-ID und PIN überprüfen.", + "sessionNotFound": "Sitzung nicht gefunden. Bitte Zugangsdaten überprüfen.", + "failedToConnect": "Verbindung fehlgeschlagen: ${error}", + "failedToLoadRecent": "Letzte Sitzungen konnten nicht geladen werden: ${error}" + }, + "remote": { + "disconnectConfirm": "Möchtest du die Verbindung zur Fernsteuerungssitzung trennen?", + "reconnecting": "Verbindung wird wiederhergestellt...", + "attemptOf": "Versuch ${current} von 5", + "retryNow": "Jetzt wiederholen", + "connectionError": "Verbindungsfehler", + "notConnected": "Nicht verbunden", + "tabRemote": "Fernbedienung", + "tabPlay": "Wiedergabe", + "tabMore": "Mehr", + "menu": "Menü", + "tabNavigation": "Tab-Navigation", + "tabDiscover": "Entdecken", + "tabLibraries": "Mediatheken", + "tabSearch": "Suche", + "tabDownloads": "Downloads", + "tabSettings": "Einstellungen", + "previous": "Zurück", + "playPause": "Wiedergabe/Pause", + "next": "Weiter", + "seekBack": "Zurückspulen", + "stop": "Stopp", + "seekForward": "Vorspulen", + "volume": "Lautstärke", + "volumeDown": "Leiser", + "volumeUp": "Lauter", + "fullscreen": "Vollbild", + "subtitles": "Untertitel", + "audio": "Audio", + "searchHint": "Auf Desktop suchen..." + } + }, + "videoSettings": { + "playbackSettings": "Wiedergabeeinstellungen", + "playbackSpeed": "Wiedergabegeschwindigkeit", + "sleepTimer": "Schlaftimer", + "audioSync": "Audio-Synchronisation", + "subtitleSync": "Untertitel-Synchronisation", + "hdr": "HDR", + "audioOutput": "Audioausgabe", + "performanceOverlay": "Leistungsanzeige" } } diff --git a/lib/i18n/en.i18n.json b/lib/i18n/en.i18n.json index 15909d09..81c35990 100644 --- a/lib/i18n/en.i18n.json +++ b/lib/i18n/en.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "Loading..." + "title": "Plezy" }, "auth": { "signInWithPlex": "Sign in with Plex", "showQRCode": "Show QR Code", - "cancel": "Cancel", "authenticate": "Authenticate", - "retry": "Retry", "debugEnterToken": "Debug: Enter Plex Token", "plexTokenLabel": "Plex Auth Token", "plexTokenHint": "Enter your Plex.tv token", @@ -34,14 +31,28 @@ "no": "No", "delete": "Delete", "shuffle": "Shuffle", - "addTo": "Add to..." + "addTo": "Add to...", + "remove": "Remove", + "paste": "Paste", + "connect": "Connect", + "disconnect": "Disconnect", + "play": "Play", + "pause": "Pause", + "resume": "Resume", + "error": "Error", + "search": "Search", + "home": "Home", + "back": "Back", + "settings": "Settings", + "mute": "Mute", + "ok": "OK", + "loading": "Loading..." }, "screens": { "licenses": "Licenses", "switchProfile": "Switch Profile", "subtitleStyling": "Subtitle Styling", "mpvConfig": "MPV Configuration", - "search": "Search", "logs": "Logs" }, "update": { @@ -308,7 +319,6 @@ "timelineSlider": "Video timeline", "volumeSlider": "Volume level", "endsAt": "Ends at ${time}", - "backButton": "Back", "pipFailed": "Picture-in-picture failed to start", "pipErrors": { "androidVersion": "Requires Android 8.0 or newer", @@ -316,7 +326,9 @@ "notSupported": "Device doesn't support picture-in-picture mode", "failed": "Picture-in-picture failed to start", "unknown": "An error occurred: ${error}" - } + }, + "chapters": "Chapters", + "noChaptersAvailable": "No chapters available" }, "userStatus": { "admin": "Admin", @@ -396,19 +408,15 @@ "entriesCount": "${count} entries" }, "dialog": { - "confirmAction": "Confirm Action", - "cancel": "Cancel" + "confirmAction": "Confirm Action" }, "discover": { "title": "Discover", "switchProfile": "Switch Profile", - "logout": "Logout", "noContentAvailable": "No content available", "addMediaToLibraries": "Add some media to your libraries", "continueWatching": "Continue Watching", - "play": "Play", "playEpisode": "S${season}E${episode}", - "pause": "Pause", "overview": "Overview", "cast": "Cast", "seasons": "Seasons", @@ -518,10 +526,7 @@ "licensesCount": "${count} licenses" }, "navigation": { - "home": "Home", - "search": "Search", "libraries": "Libraries", - "settings": "Settings", "downloads": "Downloads" }, "collections": { @@ -634,7 +639,11 @@ "episodesQueued": "${count} episodes queued for download", "downloadDeleted": "Download deleted", "deleteConfirm": "Are you sure you want to delete \"${title}\"? This will remove the downloaded file from your device.", - "deletingWithProgress": "Deleting ${title}... (${current} of ${total})" + "deletingWithProgress": "Deleting ${title}... (${current} of ${total})", + "noDownloadsTree": "No downloads", + "pauseAll": "Pause all", + "resumeAll": "Resume all", + "deleteAll": "Delete all" }, "shaders": { "title": "Shaders", @@ -643,5 +652,107 @@ "qualityFast": "Fast", "qualityHQ": "High Quality", "mode": "Mode" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "Connect to Device", + "hostRemoteSession": "Host Remote Session", + "controlThisDevice": "Control this device with your phone", + "remoteControl": "Remote Control", + "controlDesktop": "Control a desktop device", + "connectedTo": "Connected to ${name}", + "session": { + "creatingSession": "Creating remote session...", + "failedToCreate": "Failed to create remote session:", + "noSession": "No session available", + "scanQrCode": "Scan QR Code", + "orEnterManually": "Or enter manually", + "hostAddress": "Host Address", + "sessionId": "Session ID", + "pin": "PIN", + "connected": "Connected", + "waitingForConnection": "Waiting for connection...", + "usePhoneToControl": "Use your mobile device to control this app", + "copiedToClipboard": "${label} copied to clipboard", + "copyToClipboard": "Copy to clipboard", + "newSession": "New Session", + "minimize": "Minimize" + }, + "pairing": { + "recent": "Recent", + "scan": "Scan", + "manual": "Manual", + "recentConnections": "Recent Connections", + "quickReconnect": "Quickly reconnect to previously paired devices", + "pairWithDesktop": "Pair with Desktop", + "enterSessionDetails": "Enter the session details shown on your desktop device", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "Enter 8-character session ID", + "pinHint": "Enter 6-digit PIN", + "connecting": "Connecting...", + "tips": "Tips", + "tipDesktop": "Open Plezy on your desktop and enable Companion Remote from settings or menu", + "tipScan": "Use the Scan tab to quickly pair by scanning the QR code on your desktop", + "tipWifi": "Make sure both devices are on the same WiFi network", + "cameraPermissionRequired": "Camera permission is required to scan QR codes.\nPlease grant camera access in your device settings.", + "cameraError": "Could not start camera: ${error}", + "scanInstruction": "Point your camera at the QR code shown on your desktop", + "noRecentConnections": "No recent connections", + "connectUsingManual": "Connect to a device using Manual entry to get started", + "invalidQrCode": "Invalid QR code format", + "removeRecentConnection": "Remove Recent Connection", + "removeConfirm": "Remove \"${name}\" from recent connections?", + "validationHostRequired": "Please enter host address", + "validationHostFormat": "Format must be IP:port (e.g., 192.168.1.100:48632)", + "validationSessionIdRequired": "Please enter a session ID", + "validationSessionIdLength": "Session ID must be 8 characters", + "validationPinRequired": "Please enter a PIN", + "validationPinLength": "PIN must be 6 digits", + "connectionTimedOut": "Connection timed out. Please check the session ID and PIN.", + "sessionNotFound": "Could not find the session. Please check your credentials.", + "failedToConnect": "Failed to connect: ${error}", + "failedToLoadRecent": "Failed to load recent sessions: ${error}" + }, + "remote": { + "disconnectConfirm": "Do you want to disconnect from the remote session?", + "reconnecting": "Reconnecting...", + "attemptOf": "Attempt ${current} of 5", + "retryNow": "Retry Now", + "connectionError": "Connection error", + "notConnected": "Not connected", + "tabRemote": "Remote", + "tabPlay": "Play", + "tabMore": "More", + "menu": "Menu", + "tabNavigation": "Tab Navigation", + "tabDiscover": "Discover", + "tabLibraries": "Libraries", + "tabSearch": "Search", + "tabDownloads": "Downloads", + "tabSettings": "Settings", + "previous": "Previous", + "playPause": "Play/Pause", + "next": "Next", + "seekBack": "Seek Back", + "stop": "Stop", + "seekForward": "Seek Fwd", + "volume": "Volume", + "volumeDown": "Down", + "volumeUp": "Up", + "fullscreen": "Fullscreen", + "subtitles": "Subtitles", + "audio": "Audio", + "searchHint": "Search on desktop..." + } + }, + "videoSettings": { + "playbackSettings": "Playback Settings", + "playbackSpeed": "Playback Speed", + "sleepTimer": "Sleep Timer", + "audioSync": "Audio Sync", + "subtitleSync": "Subtitle Sync", + "hdr": "HDR", + "audioOutput": "Audio Output", + "performanceOverlay": "Performance Overlay" } } diff --git a/lib/i18n/es.i18n.json b/lib/i18n/es.i18n.json index 8ceeb82e..97cdf3bd 100644 --- a/lib/i18n/es.i18n.json +++ b/lib/i18n/es.i18n.json @@ -1,646 +1,758 @@ { - "app": { - "title": "Plezy", - "loading": "Cargando..." - }, - "auth": { - "signInWithPlex": "Inicia sesión con Plex", - "showQRCode": "Mostrar código QR", - "cancel": "Cancelar", - "authenticate": "Autenticar", - "retry": "Reintentar", - "debugEnterToken": "Debug: Ingresar Token de Plex", - "plexTokenLabel": "Token de Autenticación de Plex", - "plexTokenHint": "Ingresa tu token de Plex.tv", - "authenticationTimeout": "Tiempo de autenticación agotado. Por favor, intenta de nuevo.", - "scanQRToSignIn": "Escanea este código QR para iniciar sesión", - "waitingForAuth": "Esperando autenticación...\nPor favor completa el inicio de sesión en tu navegador.", - "useBrowser": "Usar navegador" - }, - "common": { - "cancel": "Cancelar", - "save": "Guardar", - "close": "Cerrar", - "clear": "Borrar", - "reset": "Reiniciar", - "later": "Más tarde", - "submit": "Enviar", - "confirm": "Confirmar", - "retry": "Reintentar", - "logout": "Cerrar sesión", - "unknown": "Desconocido", - "refresh": "Actualizar", - "yes": "Sí", - "no": "No", - "delete": "Eliminar", - "shuffle": "Aleatorio", - "addTo": "Añadir a..." - }, - "screens": { - "licenses": "Licencias", - "switchProfile": "Cambiar Perfil", - "subtitleStyling": "Estilo de Subtítulos", - "mpvConfig": "Configuración de MPV", - "search": "Buscar", - "logs": "Logs" - }, - "update": { - "available": "Actualización disponible", - "versionAvailable": "Versión ${version} disponible", - "currentVersion": "Actual: ${version}", - "skipVersion": "Saltar esta versión", - "viewRelease": "Ver versión", - "latestVersion": "Ya estás en la última versión", - "checkFailed": "Error al buscar actualizaciones" - }, - "settings": { - "title": "Configuración", - "language": "Idioma", - "theme": "Tema", - "appearance": "Apariencia", - "videoPlayback": "Reproducción de Video", - "advanced": "Avanzado", - "episodePosterMode": "Estilo de Póster de Episodio", - "seriesPoster": "Póster de Serie", - "seriesPosterDescription": "Mostrar el póster de la serie para todos los episodios", - "seasonPoster": "Póster de Temporada", - "seasonPosterDescription": "Mostrar el póster de la temporada para los episodios", - "episodeThumbnail": "Miniatura de Episodio", - "episodeThumbnailDescription": "Mostrar miniaturas de capturas de pantalla de episodios en 16:9", - "showHeroSectionDescription": "Mostrar carrusel de contenido destacado en la pantalla de inicio", - "secondsLabel": "Segundos", - "minutesLabel": "Minutos", - "secondsShort": "s", - "minutesShort": "m", - "durationHint": "Ingresa la duración (${min}-${max})", - "systemTheme": "Sistema", - "systemThemeDescription": "Sigue la configuración del sistema", - "lightTheme": "Claro", - "darkTheme": "Oscuro", - "oledTheme": "OLED", - "oledThemeDescription": "Negro puro para pantallas OLED", - "libraryDensity": "Densidad de Biblioteca", - "compact": "Compacto", - "compactDescription": "Tarjetas más pequeñas, más elementos visibles", - "normal": "Normal", - "normalDescription": "Tamaño predeterminado", - "comfortable": "Cómodo", - "comfortableDescription": "Tarjetas más grandes, menos elementos visibles", - "viewMode": "Modo de Vista", - "gridView": "Cuadrícula", - "gridViewDescription": "Mostrar elementos en un diseño de cuadrícula", - "listView": "Lista", - "listViewDescription": "Mostrar elementos en un diseño de lista", - "showHeroSection": "Mostrar Sección Destacada", - "useGlobalHubs": "Usar Diseño de Inicio de Plex", - "useGlobalHubsDescription": "Mostrar los hubs de la página de inicio como el cliente oficial de Plex. Cuando está desactivado, muestra recomendaciones por biblioteca en su lugar.", - "showServerNameOnHubs": "Mostrar Nombre del Servidor en los Hubs", - "showServerNameOnHubsDescription": "Mostrar siempre el nombre del servidor en los títulos de los hubs. Cuando está desactivado, solo se muestra para nombres de hubs duplicados.", - "alwaysKeepSidebarOpen": "Mantener siempre la barra lateral abierta", - "alwaysKeepSidebarOpenDescription": "La barra lateral permanece expandida y el área de contenido se ajusta para adaptarse", - "showUnwatchedCount": "Mostrar conteo de no vistos", - "showUnwatchedCountDescription": "Mostrar el conteo de episodios no vistos en series y temporadas", - "playerBackend": "Reproductor", - "exoPlayer": "ExoPlayer (Recomendado)", - "exoPlayerDescription": "Reproductor nativo de Android con mejor soporte de hardware", - "mpv": "MPV", - "mpvDescription": "Reproductor avanzado con más funciones y soporte de subtítulos ASS", - "hardwareDecoding": "Decodificación por Hardware", - "hardwareDecodingDescription": "Usar aceleración por hardware cuando esté disponible", - "bufferSize": "Tamaño del Buffer", - "bufferSizeMB": "${size}MB", - "subtitleStyling": "Estilo de Subtítulos", - "subtitleStylingDescription": "Personalizar la apariencia de los subtítulos", - "smallSkipDuration": "Salto pequeño", - "largeSkipDuration": "Salto grande", - "secondsUnit": "${seconds} segundos", - "defaultSleepTimer": "Temporizador de apagado", - "minutesUnit": "${minutes} minutos", - "rememberTrackSelections": "Recordar selección de pistas por serie/película", - "rememberTrackSelectionsDescription": "Guardar automáticamente las preferencias de idioma de audio y subtítulos al cambiarlas durante la reproducción", - "clickVideoTogglesPlayback": "Clic en el video para reproducir/pausar", - "clickVideoTogglesPlaybackDescription": "Si está habilitado, hacer clic en el reproductor de video reproducirá/pausará el video. De lo contrario, mostrará/ocultará los controles.", - "videoPlayerControls": "Controles del Reproductor de Video", - "keyboardShortcuts": "Atajos de Teclado", - "keyboardShortcutsDescription": "Personalizar los atajos de teclado", - "videoPlayerNavigation": "Navegación del Reproductor de Video", - "videoPlayerNavigationDescription": "Usar las teclas de flecha para navegar por los controles del reproductor", - "debugLogging": "Registro de Depuración", - "debugLoggingDescription": "Habilitar registros detallados para resolución de problemas", - "viewLogs": "Ver Logs", - "viewLogsDescription": "Ver los registros de la aplicación", - "clearCache": "Borrar Caché", - "clearCacheDescription": "Esto borrará todas las imágenes y datos en caché. La aplicación puede tardar más en cargar contenido después de borrar la caché.", - "clearCacheSuccess": "Caché borrada con éxito", - "resetSettings": "Restablecer Configuración", - "resetSettingsDescription": "Esto restablecerá todos los ajustes a sus valores predeterminados. Esta acción no se puede deshacer.", - "resetSettingsSuccess": "Configuración restablecida con éxito", - "shortcutsReset": "Atajos restablecidos a los valores predeterminados", - "about": "Acerca de", - "aboutDescription": "Información de la aplicación y licencias", - "updates": "Actualizaciones", - "updateAvailable": "Actualización disponible", - "checkForUpdates": "Buscar actualizaciones", - "validationErrorEnterNumber": "Por favor, introduce un número válido", - "validationErrorDuration": "La duración debe estar entre ${min} y ${max} ${unit}", - "shortcutAlreadyAssigned": "El atajo ya está asignado a ${action}", - "shortcutUpdated": "Atajo actualizado para ${action}", - "autoSkip": "Salto automático", - "autoSkipIntro": "Saltar Intro automáticamente", - "autoSkipIntroDescription": "Saltar automáticamente los marcadores de intro después de unos segundos", - "autoSkipCredits": "Saltar Créditos automáticamente", - "autoSkipCreditsDescription": "Saltar automáticamente los créditos y reproducir el siguiente episodio", - "autoSkipDelay": "Retraso de Salto automático", - "autoSkipDelayDescription": "Esperar ${seconds} segundos antes de saltar automáticamente", - "downloads": "Descargas", - "downloadLocationDescription": "Elegir dónde almacenar el contenido descargado", - "downloadLocationDefault": "Predeterminado (Almacenamiento de la App)", - "downloadLocationCustom": "Ubicación personalizada", - "selectFolder": "Seleccionar carpeta", - "resetToDefault": "Restablecer al predeterminado", - "currentPath": "Actual: ${path}", - "downloadLocationChanged": "Ubicación de descarga cambiada", - "downloadLocationReset": "Ubicación de descarga restablecida al predeterminado", - "downloadLocationInvalid": "La carpeta seleccionada no tiene permisos de escritura", - "downloadLocationSelectError": "Error al seleccionar la carpeta", - "downloadOnWifiOnly": "Descargar solo con WiFi", - "downloadOnWifiOnlyDescription": "Evitar descargas cuando se usan datos móviles", - "cellularDownloadBlocked": "Las descargas están desactivadas en datos móviles. Conéctate a una red WiFi o cambia la configuración.", - "maxVolume": "Volumen Máximo", - "maxVolumeDescription": "Permitir aumento de volumen por encima del 100% para medios con sonido bajo", - "maxVolumePercent": "${percent}%", - "discordRichPresence": "Presencia de Discord", - "discordRichPresenceDescription": "Mostrar lo que estás viendo en Discord", - "matchContentFrameRate": "Ajustar frecuencia de actualización", - "matchContentFrameRateDescription": "Ajustar la frecuencia de actualización de la pantalla para que coincida con el video, reduciendo tirones y ahorrando batería", - "requireProfileSelectionOnOpen": "Pedir perfil al abrir la app", - "requireProfileSelectionOnOpenDescription": "Mostrar selección de perfil cada vez que se abre la aplicación" - }, - "search": { - "hint": "Buscar películas, series, música...", - "tryDifferentTerm": "Prueba con un término de búsqueda diferente", - "searchYourMedia": "Busca en tu contenido", - "enterTitleActorOrKeyword": "Introduce un título, actor o palabra clave" - }, - "hotkeys": { - "setShortcutFor": "Establecer atajo para ${actionName}", - "clearShortcut": "Borrar atajo", - "actions": { - "playPause": "Reproducir/Pausar", - "volumeUp": "Subir Volumen", - "volumeDown": "Bajar Volumen", - "seekForward": "Avanzar (${seconds}s)", - "seekBackward": "Retroceder (${seconds}s)", - "fullscreenToggle": "Alternar Pantalla Completa", - "muteToggle": "Alternar Silencio", - "subtitleToggle": "Alternar Subtítulos", - "audioTrackNext": "Siguiente Pista de Audio", - "subtitleTrackNext": "Siguiente Pista de Subtítulos", - "chapterNext": "Siguiente Capítulo", - "chapterPrevious": "Anterior Capítulo", - "speedIncrease": "Aumentar Velocidad", - "speedDecrease": "Disminuir Velocidad", - "speedReset": "Restablecer Velocidad", - "subSeekNext": "Ir al Siguiente Subtítulo", - "subSeekPrev": "Ir al Anterior Subtítulo", - "shaderToggle": "Alternar Shaders" - } - }, - "pinEntry": { - "enterPin": "Introduce el PIN", - "showPin": "Mostrar PIN", - "hidePin": "Ocultar PIN" - }, - "fileInfo": { - "title": "Información del Archivo", - "video": "Video", - "audio": "Audio", - "file": "Archivo", - "advanced": "Avanzado", - "codec": "Códec", - "resolution": "Resolución", - "bitrate": "Bitrate", - "frameRate": "Frecuencia de fotogramas", - "aspectRatio": "Relación de aspecto", - "profile": "Perfil", - "bitDepth": "Profundidad de bits", - "colorSpace": "Espacio de color", - "colorRange": "Rango de color", - "colorPrimaries": "Primarias de color", - "chromaSubsampling": "Submuestreo de croma", - "channels": "Canales", - "path": "Ruta", - "size": "Tamaño", - "container": "Contenedor", - "duration": "Duración", - "optimizedForStreaming": "Optimizado para streaming", - "has64bitOffsets": "Offsets de 64 bits" - }, - "mediaMenu": { - "markAsWatched": "Marcar como Visto", - "markAsUnwatched": "Marcar como No Visto", - "removeFromContinueWatching": "Eliminar de Seguir Viendo", - "goToSeries": "Ir a la serie", - "goToSeason": "Ir a la temporada", - "shufflePlay": "Reproducción Aleatoria", - "fileInfo": "Información del Archivo", - "confirmDelete": "¿Estás seguro de que quieres eliminar este elemento de tu sistema de archivos?", - "deleteMultipleWarning": "Es posible que se eliminen varios elementos.", - "mediaDeletedSuccessfully": "Elemento multimedia eliminado con éxito", - "mediaFailedToDelete": "Error al eliminar el elemento multimedia" - }, - "accessibility": { - "mediaCardMovie": "${title}, película", - "mediaCardShow": "${title}, serie de TV", - "mediaCardEpisode": "${title}, ${episodeInfo}", - "mediaCardSeason": "${title}, ${seasonInfo}", - "mediaCardWatched": "visto", - "mediaCardPartiallyWatched": "${percent} por ciento visto", - "mediaCardUnwatched": "no visto", - "tapToPlay": "Toca para reproducir" - }, - "tooltips": { - "shufflePlay": "Reproducción aleatoria", - "markAsWatched": "Marcar como visto", - "markAsUnwatched": "Marcar como no visto" - }, - "videoControls": { - "audioLabel": "Audio", - "subtitlesLabel": "Subtítulos", - "resetToZero": "Restablecer a 0ms", - "addTime": "+${amount}${unit}", - "minusTime": "-${amount}${unit}", - "playsLater": "${label} se reproduce más tarde", - "playsEarlier": "${label} se reproduce antes", - "noOffset": "Sin desfase", - "letterbox": "Letterbox", - "fillScreen": "Llenar pantalla", - "stretch": "Estirar", - "lockRotation": "Bloquear rotación", - "unlockRotation": "Desbloquear rotación", - "timerActive": "Temporizador Activo", - "playbackWillPauseIn": "La reproducción se pausará en ${duration}", - "sleepTimerCompleted": "Temporizador completado - reproducción pausada", - "autoPlayNext": "Reproducir siguiente automáticamente", - "playNext": "Reproducir siguiente", - "playButton": "Reproducir", - "pauseButton": "Pausa", - "seekBackwardButton": "Retroceder ${seconds} segundos", - "seekForwardButton": "Avanzar ${seconds} segundos", - "previousButton": "Episodio anterior", - "nextButton": "Episodio siguiente", - "previousChapterButton": "Capítulo anterior", - "nextChapterButton": "Capítulo siguiente", - "muteButton": "Silenciar", - "unmuteButton": "Activar sonido", - "settingsButton": "Ajustes de video", - "audioTrackButton": "Pistas de audio", - "subtitlesButton": "Subtítulos", - "chaptersButton": "Capítulos", - "versionsButton": "Versiones de video", - "pipButton": "Modo PiP (Imagen en Imagen)", - "aspectRatioButton": "Relación de aspecto", - "fullscreenButton": "Entrar en pantalla completa", - "exitFullscreenButton": "Salir de pantalla completa", - "alwaysOnTopButton": "Siempre visible", - "rotationLockButton": "Bloqueo de rotación", - "timelineSlider": "Línea de tiempo del video", - "volumeSlider": "Nivel de volumen", - "endsAt": "Termina a las ${time}", - "backButton": "Atrás", - "pipFailed": "Error al iniciar Imagen en Imagen", - "pipErrors": { - "androidVersion": "Requiere Android 8.0 o más reciente", - "permissionDisabled": "El permiso de Imagen en Imagen está desactivado. Actívalo en Ajustes > Aplicaciones > Plezy > Imagen en Imagen", - "notSupported": "El dispositivo no soporta el modo Imagen en Imagen", - "failed": "Error al iniciar Imagen en Imagen", - "unknown": "Ocurrió un error: ${error}" - } - }, - "userStatus": { - "admin": "Administrador", - "restricted": "Restringido", - "protected": "Protegido", - "current": "ACTUAL" - }, - "messages": { - "markedAsWatched": "Marcado como visto", - "markedAsUnwatched": "Marcado como no visto", - "markedAsWatchedOffline": "Marcado como visto (se sincronizará al estar en línea)", - "markedAsUnwatchedOffline": "Marcado como no visto (se sincronizará al estar en línea)", - "removedFromContinueWatching": "Eliminado de Seguir Viendo", - "errorLoading": "Error: ${error}", - "fileInfoNotAvailable": "Información de archivo no disponible", - "errorLoadingFileInfo": "Error al cargar info de archivo: ${error}", - "errorLoadingSeries": "Error al cargar la serie", - "errorLoadingSeason": "Error al cargar la temporada", - "musicNotSupported": "La reproducción de música aún no está soportada", - "logsCleared": "Logs borrados", - "logsCopied": "Logs copiados al portapapeles", - "noLogsAvailable": "No hay logs disponibles", - "libraryScanning": "Escaneando \"${title}\"...", - "libraryScanStarted": "Escaneo de biblioteca iniciado para \"${title}\"", - "libraryScanFailed": "Error al escanear biblioteca: ${error}", - "metadataRefreshing": "Actualizando metadatos de \"${title}\"...", - "metadataRefreshStarted": "Actualización de metadatos iniciada para \"${title}\"", - "metadataRefreshFailed": "Error al actualizar metadatos: ${error}", - "logoutConfirm": "¿Estás seguro de que quieres cerrar sesión?", - "noSeasonsFound": "No se encontraron temporadas", - "noEpisodesFound": "No se encontraron episodios en la primera temporada", - "noEpisodesFoundGeneral": "No se encontraron episodios", - "noResultsFound": "No se encontraron resultados", - "sleepTimerSet": "Temporizador establecido en ${label}", - "noItemsAvailable": "No hay elementos disponibles", - "failedToCreatePlayQueueNoItems": "Error al crear la cola de reproducción - no hay elementos", - "failedPlayback": "Error al ${action}: ${error}", - "switchingToCompatiblePlayer": "Cambiando a reproductor compatible...", - "logsUploaded": "Logs uploaded", - "logsUploadFailed": "Failed to upload logs", - "logId": "Log ID" - }, - "subtitlingStyling": { - "stylingOptions": "Opciones de Estilo", - "fontSize": "Tamaño de Fuente", - "textColor": "Color de Texto", - "borderSize": "Tamaño de Borde", - "borderColor": "Color de Borde", - "backgroundOpacity": "Opacidad de Fondo", - "backgroundColor": "Color de Fondo", - "position": "Position" - }, - "mpvConfig": { - "title": "Configuración de MPV", - "description": "Ajustes avanzados del reproductor de video", - "properties": "Propiedades", - "presets": "Ajustes preestablecidos", - "noProperties": "No hay propiedades configuradas", - "noPresets": "No hay ajustes guardados", - "addProperty": "Añadir Propiedad", - "editProperty": "Editar Propiedad", - "deleteProperty": "Eliminar Propiedad", - "propertyKey": "Clave de la Propiedad", - "propertyKeyHint": "ej., hwdec, demuxer-max-bytes", - "propertyValue": "Valor de la Propiedad", - "propertyValueHint": "ej., auto, 256000000", - "saveAsPreset": "Guardar como Ajuste...", - "presetName": "Nombre del Ajuste", - "presetNameHint": "Introduce un nombre para este ajuste", - "loadPreset": "Cargar", - "deletePreset": "Eliminar", - "presetSaved": "Ajuste guardado", - "presetLoaded": "Ajuste cargado", - "presetDeleted": "Ajuste eliminado", - "confirmDeletePreset": "¿Estás seguro de que quieres eliminar este ajuste?", - "confirmDeleteProperty": "¿Estás seguro de que quieres eliminar esta propiedad?", - "entriesCount": "${count} entradas" - }, - "dialog": { - "confirmAction": "Confirmar Acción", - "cancel": "Cancelar" - }, - "discover": { - "title": "Descubrir", - "switchProfile": "Cambiar Perfil", - "logout": "Cerrar sesión", - "noContentAvailable": "No hay contenido disponible", - "addMediaToLibraries": "Añade contenido a tus bibliotecas", - "continueWatching": "Seguir Viendo", - "play": "Reproducir", - "playEpisode": "T${season}E${episode}", - "pause": "Pausa", - "overview": "Resumen", - "cast": "Reparto", - "seasons": "Temporadas", - "studio": "Estudio", - "rating": "Calificación", - "episodeCount": "${count} episodios", - "watchedProgress": "${watched}/${total} vistos", - "movie": "Película", - "tvShow": "Serie de TV", - "minutesLeft": "quedan ${minutes} min" - }, - "errors": { - "searchFailed": "Error en la búsqueda: ${error}", - "connectionTimeout": "Tiempo de conexión agotado al cargar ${context}", - "connectionFailed": "No se pudo conectar con el servidor Plex", - "failedToLoad": "Error al cargar ${context}: ${error}", - "noClientAvailable": "No hay cliente disponible", - "authenticationFailed": "Error de autenticación: ${error}", - "couldNotLaunchUrl": "No se pudo abrir la URL de autenticación", - "pleaseEnterToken": "Por favor, introduce un token", - "invalidToken": "Token no válido", - "failedToVerifyToken": "Error al verificar el token: ${error}", - "failedToSwitchProfile": "Error al cambiar al perfil ${displayName}" - }, - "libraries": { - "title": "Bibliotecas", - "scanLibraryFiles": "Escanear Archivos de la Biblioteca", - "scanLibrary": "Escanear Biblioteca", - "analyze": "Analizar", - "analyzeLibrary": "Analizar Biblioteca", - "refreshMetadata": "Actualizar Metadatos", - "emptyTrash": "Vaciar Papelera", - "emptyingTrash": "Vaciando papelera de \"${title}\"...", - "trashEmptied": "Papelera vaciada para \"${title}\"", - "failedToEmptyTrash": "Error al vaciar papelera: ${error}", - "analyzing": "Analizando \"${title}\"...", - "analysisStarted": "Análisis iniciado para \"${title}\"", - "failedToAnalyze": "Error al analizar la biblioteca: ${error}", - "noLibrariesFound": "No se encontraron bibliotecas", - "thisLibraryIsEmpty": "Esta biblioteca está vacía", - "all": "Todos", - "clearAll": "Borrar Todo", - "scanLibraryConfirm": "¿Estás seguro de que quieres escanear \"${title}\"?", - "analyzeLibraryConfirm": "¿Estás seguro de que quieres analizar \"${title}\"?", - "refreshMetadataConfirm": "¿Estás seguro de que quieres actualizar los metadatos de \"${title}\"?", - "emptyTrashConfirm": "¿Estás seguro de que quieres vaciar la papelera de \"${title}\"?", - "manageLibraries": "Gestionar Bibliotecas", - "sort": "Ordenar", - "sortBy": "Ordenar por", - "filters": "Filtros", - "confirmActionMessage": "¿Estás seguro de que quieres realizar esta acción?", - "showLibrary": "Mostrar biblioteca", - "hideLibrary": "Ocultar biblioteca", - "libraryOptions": "Opciones de biblioteca", - "content": "contenido de la biblioteca", - "selectLibrary": "Seleccionar biblioteca", - "filtersWithCount": "Filtros (${count})", - "noRecommendations": "No hay recomendaciones disponibles", - "noCollections": "No hay colecciones en esta biblioteca", - "noFoldersFound": "No se encontraron carpetas", - "folders": "carpetas", - "tabs": { - "recommended": "Recomendado", - "browse": "Explorar", - "collections": "Colecciones", - "playlists": "Listas" - }, - "groupings": { - "all": "Todo", - "movies": "Películas", - "shows": "Series", - "seasons": "Temporadas", - "episodes": "Episodios", - "folders": "Carpetas" - } - }, - "about": { - "title": "Acerca de", - "openSourceLicenses": "Licencias de Código Abierto", - "versionLabel": "Versión ${version}", - "appDescription": "Un cliente de Plex para Flutter", - "viewLicensesDescription": "Ver licencias de librerías de terceros" - }, - "serverSelection": { - "allServerConnectionsFailed": "No se pudo conectar con ningún servidor. Por favor, comprueba tu conexión e inténtalo de nuevo.", - "noServersFoundForAccount": "No se encontraron servidores para ${username} (${email})", - "failedToLoadServers": "Error al cargar servidores: ${error}" - }, - "hubDetail": { - "title": "Título", - "releaseYear": "Año de lanzamiento", - "dateAdded": "Añadido el", - "rating": "Calificación", - "noItemsFound": "No se encontraron elementos" - }, - "logs": { - "clearLogs": "Borrar Logs", - "copyLogs": "Copiar Logs", - "uploadLogs": "Upload Logs", - "error": "Error:", - "stackTrace": "Traza de la pila (Stack Trace):" - }, - "licenses": { - "relatedPackages": "Paquetes relacionados", - "license": "Licencia", - "licenseNumber": "Licencia ${number}", - "licensesCount": "${count} licencias" - }, - "navigation": { - "home": "Inicio", - "search": "Buscar", - "libraries": "Bibliotecas", - "settings": "Configuración", - "downloads": "Descargas" - }, - "collections": { - "title": "Colecciones", - "collection": "Colección", - "empty": "La colección está vacía", - "unknownLibrarySection": "No se puede eliminar: Sección de biblioteca desconocida", - "deleteCollection": "Eliminar Colección", - "deleteConfirm": "¿Estás seguro de que quieres eliminar \"${title}\"? Esta acción no se puede deshacer.", - "deleted": "Colección eliminada", - "deleteFailed": "Error al eliminar la colección", - "deleteFailedWithError": "Error al eliminar la colección: ${error}", - "failedToLoadItems": "Error al cargar los elementos de la colección: ${error}", - "selectCollection": "Seleccionar Colección", - "createNewCollection": "Crear Nueva Colección", - "collectionName": "Nombre de la Colección", - "enterCollectionName": "Introduce el nombre de la colección", - "addedToCollection": "Añadido a la colección", - "errorAddingToCollection": "Error al añadir a la colección", - "created": "Colección creada", - "removeFromCollection": "Eliminar de la colección", - "removeFromCollectionConfirm": "¿Eliminar \"${title}\" de esta colección?", - "removedFromCollection": "Eliminado de la colección", - "removeFromCollectionFailed": "Error al eliminar de la colección", - "removeFromCollectionError": "Error al eliminar de la colección: ${error}" - }, - "playlists": { - "title": "Listas de reproducción", - "playlist": "Lista de reproducción", - "noPlaylists": "No se encontraron listas de reproducción", - "create": "Crear Lista de Reproducción", - "playlistName": "Nombre de la Lista", - "enterPlaylistName": "Introduce el nombre de la lista", - "delete": "Eliminar Lista", - "removeItem": "Eliminar de la Lista", - "smartPlaylist": "Lista Inteligente", - "itemCount": "${count} elementos", - "oneItem": "1 elemento", - "emptyPlaylist": "Esta lista está vacía", - "deleteConfirm": "¿Eliminar Lista de Reproducción?", - "deleteMessage": "¿Estás seguro de que quieres eliminar \"${name}\"?", - "created": "Lista de reproducción creada", - "deleted": "Lista de reproducción eliminada", - "itemAdded": "Añadido a la lista", - "itemRemoved": "Eliminado de la lista", - "selectPlaylist": "Seleccionar Lista", - "createNewPlaylist": "Crear Nueva Lista", - "errorCreating": "Error al crear la lista", - "errorDeleting": "Error al eliminar la lista", - "errorLoading": "Error al cargar las listas", - "errorAdding": "Error al añadir a la lista", - "errorReordering": "Error al reordenar los elementos de la lista", - "errorRemoving": "Error al eliminar de la lista" - }, - "watchTogether": { - "title": "Ver Juntos", - "description": "Mira contenido en sincronía con amigos y familiares", - "createSession": "Crear Sesión", - "creating": "Creando...", - "joinSession": "Unirse a Sesión", - "joining": "Uniendo...", - "controlMode": "Modo de Control", - "controlModeQuestion": "¿Quién puede controlar la reproducción?", - "hostOnly": "Solo el Anfitrión", - "anyone": "Cualquiera", - "hostingSession": "Anfitrión de la Sesión", - "inSession": "En Sesión", - "sessionCode": "Código de Sesión", - "hostControlsPlayback": "El anfitrión controla la reproducción", - "anyoneCanControl": "Cualquiera puede controlar la reproducción", - "hostControls": "Control del anfitrión", - "anyoneControls": "Control de cualquiera", - "participants": "Participantes", - "host": "Anfitrión", - "hostBadge": "ANFITRIÓN", - "youAreHost": "Eres el anfitrión", - "watchingWithOthers": "Viendo con otros", - "endSession": "Finalizar Sesión", - "leaveSession": "Salir de la Sesión", - "endSessionQuestion": "¿Finalizar Sesión?", - "leaveSessionQuestion": "¿Salir de la Sesión?", - "endSessionConfirm": "Esto finalizará la sesión para todos los participantes.", - "leaveSessionConfirm": "Serás eliminado de la sesión.", - "endSessionConfirmOverlay": "Esto finalizará la sesión de visualización para todos los participantes.", - "leaveSessionConfirmOverlay": "Serás desconectado de la sesión de visualización.", - "end": "Finalizar", - "leave": "Salir", - "syncing": "Sincronizando...", - "joinWatchSession": "Unirse a Sesión de Visualización", - "enterCodeHint": "Introduce el código de 8 caracteres", - "pasteFromClipboard": "Pegar desde el portapapeles", - "pleaseEnterCode": "Por favor, introduce un código de sesión", - "codeMustBe8Chars": "El código de sesión debe tener 8 caracteres", - "joinInstructions": "Introduce el código de sesión compartido por el anfitrión para unirte a su sesión.", - "failedToCreate": "Error al crear la sesión", - "failedToJoin": "Error al unirse a la sesión", - "sessionCodeCopied": "Código de sesión copiado al portapapeles" - }, - "downloads": { - "title": "Descargas", - "manage": "Gestionar", - "tvShows": "Series de TV", - "movies": "Películas", - "noDownloads": "No hay descargas aún", - "noDownloadsDescription": "El contenido descargado aparecerá aquí para verlo sin conexión", - "downloadNow": "Descargar", - "deleteDownload": "Eliminar descarga", - "retryDownload": "Reintentar descarga", - "downloadQueued": "Descarga en cola", - "episodesQueued": "${count} episodios en cola para descargar", - "downloadDeleted": "Descarga eliminada", - "deleteConfirm": "¿Estás seguro de que quieres eliminar \"${title}\"? Esto borrará el archivo descargado de tu dispositivo.", - "deletingWithProgress": "Eliminando ${title}... (${current} de ${total})" - }, - "shaders": { - "title": "Shaders", - "noShaderDescription": "Sin mejora de video", - "nvscalerDescription": "Escalado de imagen NVIDIA para un video más nítido", - "qualityFast": "Rápido", - "qualityHQ": "Alta Calidad", - "mode": "Modo" + "app": { + "title": "Plezy" +}, + "auth": { + "signInWithPlex": "Inicia sesión con Plex", + "showQRCode": "Mostrar código QR", + "authenticate": "Autenticar", + "debugEnterToken": "Debug: Ingresar Token de Plex", + "plexTokenLabel": "Token de Autenticación de Plex", + "plexTokenHint": "Ingresa tu token de Plex.tv", + "authenticationTimeout": "Tiempo de autenticación agotado. Por favor, intenta de nuevo.", + "scanQRToSignIn": "Escanea este código QR para iniciar sesión", + "waitingForAuth": "Esperando autenticación...\nPor favor completa el inicio de sesión en tu navegador.", + "useBrowser": "Usar navegador" + }, + "common": { + "cancel": "Cancelar", + "save": "Guardar", + "close": "Cerrar", + "clear": "Borrar", + "reset": "Reiniciar", + "later": "Más tarde", + "submit": "Enviar", + "confirm": "Confirmar", + "retry": "Reintentar", + "logout": "Cerrar sesión", + "unknown": "Desconocido", + "refresh": "Actualizar", + "yes": "Sí", + "no": "No", + "delete": "Eliminar", + "shuffle": "Aleatorio", + "addTo": "Añadir a...", + "remove": "Eliminar", + "paste": "Pegar", + "connect": "Conectar", + "disconnect": "Desconectar", + "play": "Reproducir", + "pause": "Pausa", + "resume": "Reanudar", + "error": "Error", + "search": "Buscar", + "home": "Inicio", + "back": "Atrás", + "settings": "Ajustes", + "mute": "Silencio", + "ok": "OK", + "loading": "Cargando..." + }, + "screens": { + "licenses": "Licencias", + "switchProfile": "Cambiar Perfil", + "subtitleStyling": "Estilo de Subtítulos", + "mpvConfig": "Configuración de MPV", + "logs": "Logs" + }, + "update": { + "available": "Actualización disponible", + "versionAvailable": "Versión ${version} disponible", + "currentVersion": "Actual: ${version}", + "skipVersion": "Saltar esta versión", + "viewRelease": "Ver versión", + "latestVersion": "Ya estás en la última versión", + "checkFailed": "Error al buscar actualizaciones" + }, + "settings": { + "title": "Configuración", + "language": "Idioma", + "theme": "Tema", + "appearance": "Apariencia", + "videoPlayback": "Reproducción de Video", + "advanced": "Avanzado", + "episodePosterMode": "Estilo de Póster de Episodio", + "seriesPoster": "Póster de Serie", + "seriesPosterDescription": "Mostrar el póster de la serie para todos los episodios", + "seasonPoster": "Póster de Temporada", + "seasonPosterDescription": "Mostrar el póster de la temporada para los episodios", + "episodeThumbnail": "Miniatura de Episodio", + "episodeThumbnailDescription": "Mostrar miniaturas de capturas de pantalla de episodios en 16:9", + "showHeroSectionDescription": "Mostrar carrusel de contenido destacado en la pantalla de inicio", + "secondsLabel": "Segundos", + "minutesLabel": "Minutos", + "secondsShort": "s", + "minutesShort": "m", + "durationHint": "Ingresa la duración (${min}-${max})", + "systemTheme": "Sistema", + "systemThemeDescription": "Sigue la configuración del sistema", + "lightTheme": "Claro", + "darkTheme": "Oscuro", + "oledTheme": "OLED", + "oledThemeDescription": "Negro puro para pantallas OLED", + "libraryDensity": "Densidad de Biblioteca", + "compact": "Compacto", + "compactDescription": "Tarjetas más pequeñas, más elementos visibles", + "normal": "Normal", + "normalDescription": "Tamaño predeterminado", + "comfortable": "Cómodo", + "comfortableDescription": "Tarjetas más grandes, menos elementos visibles", + "viewMode": "Modo de Vista", + "gridView": "Cuadrícula", + "gridViewDescription": "Mostrar elementos en un diseño de cuadrícula", + "listView": "Lista", + "listViewDescription": "Mostrar elementos en un diseño de lista", + "showHeroSection": "Mostrar Sección Destacada", + "useGlobalHubs": "Usar Diseño de Inicio de Plex", + "useGlobalHubsDescription": "Mostrar los hubs de la página de inicio como el cliente oficial de Plex. Cuando está desactivado, muestra recomendaciones por biblioteca en su lugar.", + "showServerNameOnHubs": "Mostrar Nombre del Servidor en los Hubs", + "showServerNameOnHubsDescription": "Mostrar siempre el nombre del servidor en los títulos de los hubs. Cuando está desactivado, solo se muestra para nombres de hubs duplicados.", + "alwaysKeepSidebarOpen": "Mantener siempre la barra lateral abierta", + "alwaysKeepSidebarOpenDescription": "La barra lateral permanece expandida y el área de contenido se ajusta para adaptarse", + "showUnwatchedCount": "Mostrar conteo de no vistos", + "showUnwatchedCountDescription": "Mostrar el conteo de episodios no vistos en series y temporadas", + "playerBackend": "Reproductor", + "exoPlayer": "ExoPlayer (Recomendado)", + "exoPlayerDescription": "Reproductor nativo de Android con mejor soporte de hardware", + "mpv": "MPV", + "mpvDescription": "Reproductor avanzado con más funciones y soporte de subtítulos ASS", + "hardwareDecoding": "Decodificación por Hardware", + "hardwareDecodingDescription": "Usar aceleración por hardware cuando esté disponible", + "bufferSize": "Tamaño del Buffer", + "bufferSizeMB": "${size}MB", + "subtitleStyling": "Estilo de Subtítulos", + "subtitleStylingDescription": "Personalizar la apariencia de los subtítulos", + "smallSkipDuration": "Salto pequeño", + "largeSkipDuration": "Salto grande", + "secondsUnit": "${seconds} segundos", + "defaultSleepTimer": "Temporizador de apagado", + "minutesUnit": "${minutes} minutos", + "rememberTrackSelections": "Recordar selección de pistas por serie/película", + "rememberTrackSelectionsDescription": "Guardar automáticamente las preferencias de idioma de audio y subtítulos al cambiarlas durante la reproducción", + "clickVideoTogglesPlayback": "Clic en el video para reproducir/pausar", + "clickVideoTogglesPlaybackDescription": "Si está habilitado, hacer clic en el reproductor de video reproducirá/pausará el video. De lo contrario, mostrará/ocultará los controles.", + "videoPlayerControls": "Controles del Reproductor de Video", + "keyboardShortcuts": "Atajos de Teclado", + "keyboardShortcutsDescription": "Personalizar los atajos de teclado", + "videoPlayerNavigation": "Navegación del Reproductor de Video", + "videoPlayerNavigationDescription": "Usar las teclas de flecha para navegar por los controles del reproductor", + "debugLogging": "Registro de Depuración", + "debugLoggingDescription": "Habilitar registros detallados para resolución de problemas", + "viewLogs": "Ver Logs", + "viewLogsDescription": "Ver los registros de la aplicación", + "clearCache": "Borrar Caché", + "clearCacheDescription": "Esto borrará todas las imágenes y datos en caché. La aplicación puede tardar más en cargar contenido después de borrar la caché.", + "clearCacheSuccess": "Caché borrada con éxito", + "resetSettings": "Restablecer Configuración", + "resetSettingsDescription": "Esto restablecerá todos los ajustes a sus valores predeterminados. Esta acción no se puede deshacer.", + "resetSettingsSuccess": "Configuración restablecida con éxito", + "shortcutsReset": "Atajos restablecidos a los valores predeterminados", + "about": "Acerca de", + "aboutDescription": "Información de la aplicación y licencias", + "updates": "Actualizaciones", + "updateAvailable": "Actualización disponible", + "checkForUpdates": "Buscar actualizaciones", + "validationErrorEnterNumber": "Por favor, introduce un número válido", + "validationErrorDuration": "La duración debe estar entre ${min} y ${max} ${unit}", + "shortcutAlreadyAssigned": "El atajo ya está asignado a ${action}", + "shortcutUpdated": "Atajo actualizado para ${action}", + "autoSkip": "Salto automático", + "autoSkipIntro": "Saltar Intro automáticamente", + "autoSkipIntroDescription": "Saltar automáticamente los marcadores de intro después de unos segundos", + "autoSkipCredits": "Saltar Créditos automáticamente", + "autoSkipCreditsDescription": "Saltar automáticamente los créditos y reproducir el siguiente episodio", + "autoSkipDelay": "Retraso de Salto automático", + "autoSkipDelayDescription": "Esperar ${seconds} segundos antes de saltar automáticamente", + "downloads": "Descargas", + "downloadLocationDescription": "Elegir dónde almacenar el contenido descargado", + "downloadLocationDefault": "Predeterminado (Almacenamiento de la App)", + "downloadLocationCustom": "Ubicación personalizada", + "selectFolder": "Seleccionar carpeta", + "resetToDefault": "Restablecer al predeterminado", + "currentPath": "Actual: ${path}", + "downloadLocationChanged": "Ubicación de descarga cambiada", + "downloadLocationReset": "Ubicación de descarga restablecida al predeterminado", + "downloadLocationInvalid": "La carpeta seleccionada no tiene permisos de escritura", + "downloadLocationSelectError": "Error al seleccionar la carpeta", + "downloadOnWifiOnly": "Descargar solo con WiFi", + "downloadOnWifiOnlyDescription": "Evitar descargas cuando se usan datos móviles", + "cellularDownloadBlocked": "Las descargas están desactivadas en datos móviles. Conéctate a una red WiFi o cambia la configuración.", + "maxVolume": "Volumen Máximo", + "maxVolumeDescription": "Permitir aumento de volumen por encima del 100% para medios con sonido bajo", + "maxVolumePercent": "${percent}%", + "discordRichPresence": "Presencia de Discord", + "discordRichPresenceDescription": "Mostrar lo que estás viendo en Discord", + "matchContentFrameRate": "Ajustar frecuencia de actualización", + "matchContentFrameRateDescription": "Ajustar la frecuencia de actualización de la pantalla para que coincida con el video, reduciendo tirones y ahorrando batería", + "requireProfileSelectionOnOpen": "Pedir perfil al abrir la app", + "requireProfileSelectionOnOpenDescription": "Mostrar selección de perfil cada vez que se abre la aplicación" + }, + "search": { + "hint": "Buscar películas, series, música...", + "tryDifferentTerm": "Prueba con un término de búsqueda diferente", + "searchYourMedia": "Busca en tu contenido", + "enterTitleActorOrKeyword": "Introduce un título, actor o palabra clave" + }, + "hotkeys": { + "setShortcutFor": "Establecer atajo para ${actionName}", + "clearShortcut": "Borrar atajo", + "actions": { + "playPause": "Reproducir/Pausar", + "volumeUp": "Subir Volumen", + "volumeDown": "Bajar Volumen", + "seekForward": "Avanzar (${seconds}s)", + "seekBackward": "Retroceder (${seconds}s)", + "fullscreenToggle": "Alternar Pantalla Completa", + "muteToggle": "Alternar Silencio", + "subtitleToggle": "Alternar Subtítulos", + "audioTrackNext": "Siguiente Pista de Audio", + "subtitleTrackNext": "Siguiente Pista de Subtítulos", + "chapterNext": "Siguiente Capítulo", + "chapterPrevious": "Anterior Capítulo", + "speedIncrease": "Aumentar Velocidad", + "speedDecrease": "Disminuir Velocidad", + "speedReset": "Restablecer Velocidad", + "subSeekNext": "Ir al Siguiente Subtítulo", + "subSeekPrev": "Ir al Anterior Subtítulo", + "shaderToggle": "Alternar Shaders", + "skipMarker": "Saltar Intro/Créditos" } + }, + "pinEntry": { + "enterPin": "Introduce el PIN", + "showPin": "Mostrar PIN", + "hidePin": "Ocultar PIN" + }, + "fileInfo": { + "title": "Información del Archivo", + "video": "Video", + "audio": "Audio", + "file": "Archivo", + "advanced": "Avanzado", + "codec": "Códec", + "resolution": "Resolución", + "bitrate": "Bitrate", + "frameRate": "Frecuencia de fotogramas", + "aspectRatio": "Relación de aspecto", + "profile": "Perfil", + "bitDepth": "Profundidad de bits", + "colorSpace": "Espacio de color", + "colorRange": "Rango de color", + "colorPrimaries": "Primarias de color", + "chromaSubsampling": "Submuestreo de croma", + "channels": "Canales", + "path": "Ruta", + "size": "Tamaño", + "container": "Contenedor", + "duration": "Duración", + "optimizedForStreaming": "Optimizado para streaming", + "has64bitOffsets": "Offsets de 64 bits" + }, + "mediaMenu": { + "markAsWatched": "Marcar como Visto", + "markAsUnwatched": "Marcar como No Visto", + "removeFromContinueWatching": "Eliminar de Seguir Viendo", + "goToSeries": "Ir a la serie", + "goToSeason": "Ir a la temporada", + "shufflePlay": "Reproducción Aleatoria", + "fileInfo": "Información del Archivo", + "confirmDelete": "¿Estás seguro de que quieres eliminar este elemento de tu sistema de archivos?", + "deleteMultipleWarning": "Es posible que se eliminen varios elementos.", + "mediaDeletedSuccessfully": "Elemento multimedia eliminado con éxito", + "mediaFailedToDelete": "Error al eliminar el elemento multimedia" + }, + "accessibility": { + "mediaCardMovie": "${title}, película", + "mediaCardShow": "${title}, serie de TV", + "mediaCardEpisode": "${title}, ${episodeInfo}", + "mediaCardSeason": "${title}, ${seasonInfo}", + "mediaCardWatched": "visto", + "mediaCardPartiallyWatched": "${percent} por ciento visto", + "mediaCardUnwatched": "no visto", + "tapToPlay": "Toca para reproducir" + }, + "tooltips": { + "shufflePlay": "Reproducción aleatoria", + "markAsWatched": "Marcar como visto", + "markAsUnwatched": "Marcar como no visto" + }, + "videoControls": { + "audioLabel": "Audio", + "subtitlesLabel": "Subtítulos", + "resetToZero": "Restablecer a 0ms", + "addTime": "+${amount}${unit}", + "minusTime": "-${amount}${unit}", + "playsLater": "${label} se reproduce más tarde", + "playsEarlier": "${label} se reproduce antes", + "noOffset": "Sin desfase", + "letterbox": "Letterbox", + "fillScreen": "Llenar pantalla", + "stretch": "Estirar", + "lockRotation": "Bloquear rotación", + "unlockRotation": "Desbloquear rotación", + "timerActive": "Temporizador Activo", + "playbackWillPauseIn": "La reproducción se pausará en ${duration}", + "sleepTimerCompleted": "Temporizador completado - reproducción pausada", + "autoPlayNext": "Reproducir siguiente automáticamente", + "playNext": "Reproducir siguiente", + "playButton": "Reproducir", + "pauseButton": "Pausa", + "seekBackwardButton": "Retroceder ${seconds} segundos", + "seekForwardButton": "Avanzar ${seconds} segundos", + "previousButton": "Episodio anterior", + "nextButton": "Episodio siguiente", + "previousChapterButton": "Capítulo anterior", + "nextChapterButton": "Capítulo siguiente", + "muteButton": "Silenciar", + "unmuteButton": "Activar sonido", + "settingsButton": "Ajustes de video", + "audioTrackButton": "Pistas de audio", + "subtitlesButton": "Subtítulos", + "chaptersButton": "Capítulos", + "versionsButton": "Versiones de video", + "pipButton": "Modo PiP (Imagen en Imagen)", + "aspectRatioButton": "Relación de aspecto", + "fullscreenButton": "Entrar en pantalla completa", + "exitFullscreenButton": "Salir de pantalla completa", + "alwaysOnTopButton": "Siempre visible", + "rotationLockButton": "Bloqueo de rotación", + "timelineSlider": "Línea de tiempo del video", + "volumeSlider": "Nivel de volumen", + "endsAt": "Termina a las ${time}", + "pipFailed": "Error al iniciar Imagen en Imagen", + "pipErrors": { + "androidVersion": "Requiere Android 8.0 o más reciente", + "permissionDisabled": "El permiso de Imagen en Imagen está desactivado. Actívalo en Ajustes > Aplicaciones > Plezy > Imagen en Imagen", + "notSupported": "El dispositivo no soporta el modo Imagen en Imagen", + "failed": "Error al iniciar Imagen en Imagen", + "unknown": "Ocurrió un error: ${error}" + }, + "chapters": "Capítulos", + "noChaptersAvailable": "No hay capítulos disponibles" + }, + "userStatus": { + "admin": "Administrador", + "restricted": "Restringido", + "protected": "Protegido", + "current": "ACTUAL" + }, + "messages": { + "markedAsWatched": "Marcado como visto", + "markedAsUnwatched": "Marcado como no visto", + "markedAsWatchedOffline": "Marcado como visto (se sincronizará al estar en línea)", + "markedAsUnwatchedOffline": "Marcado como no visto (se sincronizará al estar en línea)", + "removedFromContinueWatching": "Eliminado de Seguir Viendo", + "errorLoading": "Error: ${error}", + "fileInfoNotAvailable": "Información de archivo no disponible", + "errorLoadingFileInfo": "Error al cargar info de archivo: ${error}", + "errorLoadingSeries": "Error al cargar la serie", + "errorLoadingSeason": "Error al cargar la temporada", + "musicNotSupported": "La reproducción de música aún no está soportada", + "logsCleared": "Logs borrados", + "logsCopied": "Logs copiados al portapapeles", + "noLogsAvailable": "No hay logs disponibles", + "libraryScanning": "Escaneando \"${title}\"...", + "libraryScanStarted": "Escaneo de biblioteca iniciado para \"${title}\"", + "libraryScanFailed": "Error al escanear biblioteca: ${error}", + "metadataRefreshing": "Actualizando metadatos de \"${title}\"...", + "metadataRefreshStarted": "Actualización de metadatos iniciada para \"${title}\"", + "metadataRefreshFailed": "Error al actualizar metadatos: ${error}", + "logoutConfirm": "¿Estás seguro de que quieres cerrar sesión?", + "noSeasonsFound": "No se encontraron temporadas", + "noEpisodesFound": "No se encontraron episodios en la primera temporada", + "noEpisodesFoundGeneral": "No se encontraron episodios", + "noResultsFound": "No se encontraron resultados", + "sleepTimerSet": "Temporizador establecido en ${label}", + "noItemsAvailable": "No hay elementos disponibles", + "failedToCreatePlayQueueNoItems": "Error al crear la cola de reproducción - no hay elementos", + "failedPlayback": "Error al ${action}: ${error}", + "switchingToCompatiblePlayer": "Cambiando a reproductor compatible...", + "logsUploaded": "Logs uploaded", + "logsUploadFailed": "Failed to upload logs", + "logId": "Log ID" + }, + "subtitlingStyling": { + "stylingOptions": "Opciones de Estilo", + "fontSize": "Tamaño de Fuente", + "textColor": "Color de Texto", + "borderSize": "Tamaño de Borde", + "borderColor": "Color de Borde", + "backgroundOpacity": "Opacidad de Fondo", + "backgroundColor": "Color de Fondo", + "position": "Position" + }, + "mpvConfig": { + "title": "Configuración de MPV", + "description": "Ajustes avanzados del reproductor de video", + "properties": "Propiedades", + "presets": "Ajustes preestablecidos", + "noProperties": "No hay propiedades configuradas", + "noPresets": "No hay ajustes guardados", + "addProperty": "Añadir Propiedad", + "editProperty": "Editar Propiedad", + "deleteProperty": "Eliminar Propiedad", + "propertyKey": "Clave de la Propiedad", + "propertyKeyHint": "ej., hwdec, demuxer-max-bytes", + "propertyValue": "Valor de la Propiedad", + "propertyValueHint": "ej., auto, 256000000", + "saveAsPreset": "Guardar como Ajuste...", + "presetName": "Nombre del Ajuste", + "presetNameHint": "Introduce un nombre para este ajuste", + "loadPreset": "Cargar", + "deletePreset": "Eliminar", + "presetSaved": "Ajuste guardado", + "presetLoaded": "Ajuste cargado", + "presetDeleted": "Ajuste eliminado", + "confirmDeletePreset": "¿Estás seguro de que quieres eliminar este ajuste?", + "confirmDeleteProperty": "¿Estás seguro de que quieres eliminar esta propiedad?", + "entriesCount": "${count} entradas" + }, + "dialog": { + "confirmAction": "Confirmar Acción" + }, + "discover": { + "title": "Descubrir", + "switchProfile": "Cambiar Perfil", + "noContentAvailable": "No hay contenido disponible", + "addMediaToLibraries": "Añade contenido a tus bibliotecas", + "continueWatching": "Seguir Viendo", + "playEpisode": "T${season}E${episode}", + "overview": "Resumen", + "cast": "Reparto", + "seasons": "Temporadas", + "studio": "Estudio", + "rating": "Calificación", + "episodeCount": "${count} episodios", + "watchedProgress": "${watched}/${total} vistos", + "movie": "Película", + "tvShow": "Serie de TV", + "minutesLeft": "quedan ${minutes} min" + }, + "errors": { + "searchFailed": "Error en la búsqueda: ${error}", + "connectionTimeout": "Tiempo de conexión agotado al cargar ${context}", + "connectionFailed": "No se pudo conectar con el servidor Plex", + "failedToLoad": "Error al cargar ${context}: ${error}", + "noClientAvailable": "No hay cliente disponible", + "authenticationFailed": "Error de autenticación: ${error}", + "couldNotLaunchUrl": "No se pudo abrir la URL de autenticación", + "pleaseEnterToken": "Por favor, introduce un token", + "invalidToken": "Token no válido", + "failedToVerifyToken": "Error al verificar el token: ${error}", + "failedToSwitchProfile": "Error al cambiar al perfil ${displayName}" + }, + "libraries": { + "title": "Bibliotecas", + "scanLibraryFiles": "Escanear Archivos de la Biblioteca", + "scanLibrary": "Escanear Biblioteca", + "analyze": "Analizar", + "analyzeLibrary": "Analizar Biblioteca", + "refreshMetadata": "Actualizar Metadatos", + "emptyTrash": "Vaciar Papelera", + "emptyingTrash": "Vaciando papelera de \"${title}\"...", + "trashEmptied": "Papelera vaciada para \"${title}\"", + "failedToEmptyTrash": "Error al vaciar papelera: ${error}", + "analyzing": "Analizando \"${title}\"...", + "analysisStarted": "Análisis iniciado para \"${title}\"", + "failedToAnalyze": "Error al analizar la biblioteca: ${error}", + "noLibrariesFound": "No se encontraron bibliotecas", + "thisLibraryIsEmpty": "Esta biblioteca está vacía", + "all": "Todos", + "clearAll": "Borrar Todo", + "scanLibraryConfirm": "¿Estás seguro de que quieres escanear \"${title}\"?", + "analyzeLibraryConfirm": "¿Estás seguro de que quieres analizar \"${title}\"?", + "refreshMetadataConfirm": "¿Estás seguro de que quieres actualizar los metadatos de \"${title}\"?", + "emptyTrashConfirm": "¿Estás seguro de que quieres vaciar la papelera de \"${title}\"?", + "manageLibraries": "Gestionar Bibliotecas", + "sort": "Ordenar", + "sortBy": "Ordenar por", + "filters": "Filtros", + "confirmActionMessage": "¿Estás seguro de que quieres realizar esta acción?", + "showLibrary": "Mostrar biblioteca", + "hideLibrary": "Ocultar biblioteca", + "libraryOptions": "Opciones de biblioteca", + "content": "contenido de la biblioteca", + "selectLibrary": "Seleccionar biblioteca", + "filtersWithCount": "Filtros (${count})", + "noRecommendations": "No hay recomendaciones disponibles", + "noCollections": "No hay colecciones en esta biblioteca", + "noFoldersFound": "No se encontraron carpetas", + "folders": "carpetas", + "tabs": { + "recommended": "Recomendado", + "browse": "Explorar", + "collections": "Colecciones", + "playlists": "Listas" + }, + "groupings": { + "all": "Todo", + "movies": "Películas", + "shows": "Series", + "seasons": "Temporadas", + "episodes": "Episodios", + "folders": "Carpetas" + } + }, + "about": { + "title": "Acerca de", + "openSourceLicenses": "Licencias de Código Abierto", + "versionLabel": "Versión ${version}", + "appDescription": "Un cliente de Plex para Flutter", + "viewLicensesDescription": "Ver licencias de librerías de terceros" + }, + "serverSelection": { + "allServerConnectionsFailed": "No se pudo conectar con ningún servidor. Por favor, comprueba tu conexión e inténtalo de nuevo.", + "noServersFoundForAccount": "No se encontraron servidores para ${username} (${email})", + "failedToLoadServers": "Error al cargar servidores: ${error}" + }, + "hubDetail": { + "title": "Título", + "releaseYear": "Año de lanzamiento", + "dateAdded": "Añadido el", + "rating": "Calificación", + "noItemsFound": "No se encontraron elementos" + }, + "logs": { + "clearLogs": "Borrar Logs", + "copyLogs": "Copiar Logs", + "uploadLogs": "Upload Logs", + "error": "Error:", + "stackTrace": "Traza de la pila (Stack Trace):" + }, + "licenses": { + "relatedPackages": "Paquetes relacionados", + "license": "Licencia", + "licenseNumber": "Licencia ${number}", + "licensesCount": "${count} licencias" + }, + "navigation": { + "libraries": "Bibliotecas", + "downloads": "Descargas" + }, + "collections": { + "title": "Colecciones", + "collection": "Colección", + "empty": "La colección está vacía", + "unknownLibrarySection": "No se puede eliminar: Sección de biblioteca desconocida", + "deleteCollection": "Eliminar Colección", + "deleteConfirm": "¿Estás seguro de que quieres eliminar \"${title}\"? Esta acción no se puede deshacer.", + "deleted": "Colección eliminada", + "deleteFailed": "Error al eliminar la colección", + "deleteFailedWithError": "Error al eliminar la colección: ${error}", + "failedToLoadItems": "Error al cargar los elementos de la colección: ${error}", + "selectCollection": "Seleccionar Colección", + "createNewCollection": "Crear Nueva Colección", + "collectionName": "Nombre de la Colección", + "enterCollectionName": "Introduce el nombre de la colección", + "addedToCollection": "Añadido a la colección", + "errorAddingToCollection": "Error al añadir a la colección", + "created": "Colección creada", + "removeFromCollection": "Eliminar de la colección", + "removeFromCollectionConfirm": "¿Eliminar \"${title}\" de esta colección?", + "removedFromCollection": "Eliminado de la colección", + "removeFromCollectionFailed": "Error al eliminar de la colección", + "removeFromCollectionError": "Error al eliminar de la colección: ${error}" + }, + "playlists": { + "title": "Listas de reproducción", + "playlist": "Lista de reproducción", + "noPlaylists": "No se encontraron listas de reproducción", + "create": "Crear Lista de Reproducción", + "playlistName": "Nombre de la Lista", + "enterPlaylistName": "Introduce el nombre de la lista", + "delete": "Eliminar Lista", + "removeItem": "Eliminar de la Lista", + "smartPlaylist": "Lista Inteligente", + "itemCount": "${count} elementos", + "oneItem": "1 elemento", + "emptyPlaylist": "Esta lista está vacía", + "deleteConfirm": "¿Eliminar Lista de Reproducción?", + "deleteMessage": "¿Estás seguro de que quieres eliminar \"${name}\"?", + "created": "Lista de reproducción creada", + "deleted": "Lista de reproducción eliminada", + "itemAdded": "Añadido a la lista", + "itemRemoved": "Eliminado de la lista", + "selectPlaylist": "Seleccionar Lista", + "createNewPlaylist": "Crear Nueva Lista", + "errorCreating": "Error al crear la lista", + "errorDeleting": "Error al eliminar la lista", + "errorLoading": "Error al cargar las listas", + "errorAdding": "Error al añadir a la lista", + "errorReordering": "Error al reordenar los elementos de la lista", + "errorRemoving": "Error al eliminar de la lista" + }, + "watchTogether": { + "title": "Ver Juntos", + "description": "Mira contenido en sincronía con amigos y familiares", + "createSession": "Crear Sesión", + "creating": "Creando...", + "joinSession": "Unirse a Sesión", + "joining": "Uniendo...", + "controlMode": "Modo de Control", + "controlModeQuestion": "¿Quién puede controlar la reproducción?", + "hostOnly": "Solo el Anfitrión", + "anyone": "Cualquiera", + "hostingSession": "Anfitrión de la Sesión", + "inSession": "En Sesión", + "sessionCode": "Código de Sesión", + "hostControlsPlayback": "El anfitrión controla la reproducción", + "anyoneCanControl": "Cualquiera puede controlar la reproducción", + "hostControls": "Control del anfitrión", + "anyoneControls": "Control de cualquiera", + "participants": "Participantes", + "host": "Anfitrión", + "hostBadge": "ANFITRIÓN", + "youAreHost": "Eres el anfitrión", + "watchingWithOthers": "Viendo con otros", + "endSession": "Finalizar Sesión", + "leaveSession": "Salir de la Sesión", + "endSessionQuestion": "¿Finalizar Sesión?", + "leaveSessionQuestion": "¿Salir de la Sesión?", + "endSessionConfirm": "Esto finalizará la sesión para todos los participantes.", + "leaveSessionConfirm": "Serás eliminado de la sesión.", + "endSessionConfirmOverlay": "Esto finalizará la sesión de visualización para todos los participantes.", + "leaveSessionConfirmOverlay": "Serás desconectado de la sesión de visualización.", + "end": "Finalizar", + "leave": "Salir", + "syncing": "Sincronizando...", + "joinWatchSession": "Unirse a Sesión de Visualización", + "enterCodeHint": "Introduce el código de 8 caracteres", + "pasteFromClipboard": "Pegar desde el portapapeles", + "pleaseEnterCode": "Por favor, introduce un código de sesión", + "codeMustBe8Chars": "El código de sesión debe tener 8 caracteres", + "joinInstructions": "Introduce el código de sesión compartido por el anfitrión para unirte a su sesión.", + "failedToCreate": "Error al crear la sesión", + "failedToJoin": "Error al unirse a la sesión", + "sessionCodeCopied": "Código de sesión copiado al portapapeles" + }, + "downloads": { + "title": "Descargas", + "manage": "Gestionar", + "tvShows": "Series de TV", + "movies": "Películas", + "noDownloads": "No hay descargas aún", + "noDownloadsDescription": "El contenido descargado aparecerá aquí para verlo sin conexión", + "downloadNow": "Descargar", + "deleteDownload": "Eliminar descarga", + "retryDownload": "Reintentar descarga", + "downloadQueued": "Descarga en cola", + "episodesQueued": "${count} episodios en cola para descargar", + "downloadDeleted": "Descarga eliminada", + "deleteConfirm": "¿Estás seguro de que quieres eliminar \"${title}\"? Esto borrará el archivo descargado de tu dispositivo.", + "deletingWithProgress": "Eliminando ${title}... (${current} de ${total})", + "noDownloadsTree": "Sin descargas", + "pauseAll": "Pausar todo", + "resumeAll": "Reanudar todo", + "deleteAll": "Eliminar todo" + }, + "shaders": { + "title": "Shaders", + "noShaderDescription": "Sin mejora de video", + "nvscalerDescription": "Escalado de imagen NVIDIA para un video más nítido", + "qualityFast": "Rápido", + "qualityHQ": "Alta Calidad", + "mode": "Modo" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "Conectar a dispositivo", + "hostRemoteSession": "Iniciar sesión remota", + "controlThisDevice": "Controla este dispositivo con tu teléfono", + "remoteControl": "Control remoto", + "controlDesktop": "Controlar un dispositivo de escritorio", + "connectedTo": "Conectado a ${name}", + "session": { + "creatingSession": "Creando sesión remota...", + "failedToCreate": "Error al crear la sesión remota:", + "noSession": "No hay sesión disponible", + "scanQrCode": "Escanear código QR", + "orEnterManually": "O introducir manualmente", + "hostAddress": "Dirección del host", + "sessionId": "ID de sesión", + "pin": "PIN", + "connected": "Conectado", + "waitingForConnection": "Esperando conexión...", + "usePhoneToControl": "Usa tu dispositivo móvil para controlar esta app", + "copiedToClipboard": "${label} copiado al portapapeles", + "copyToClipboard": "Copiar al portapapeles", + "newSession": "Nueva sesión", + "minimize": "Minimizar" + }, + "pairing": { + "recent": "Recientes", + "scan": "Escanear", + "manual": "Manual", + "recentConnections": "Conexiones recientes", + "quickReconnect": "Reconectar rápidamente con dispositivos emparejados anteriormente", + "pairWithDesktop": "Emparejar con escritorio", + "enterSessionDetails": "Introduce los datos de la sesión que aparecen en tu dispositivo de escritorio", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "Introduce ID de sesión de 8 caracteres", + "pinHint": "Introduce PIN de 6 dígitos", + "connecting": "Conectando...", + "tips": "Consejos", + "tipDesktop": "Abre Plezy en tu escritorio y activa Companion Remote desde los ajustes o el menú", + "tipScan": "Usa la pestaña Escanear para emparejar rápidamente escaneando el código QR de tu escritorio", + "tipWifi": "Asegúrate de que ambos dispositivos estén en la misma red WiFi", + "cameraPermissionRequired": "Se necesita permiso de cámara para escanear códigos QR.\nPor favor, concede acceso a la cámara en los ajustes de tu dispositivo.", + "cameraError": "No se pudo iniciar la cámara: ${error}", + "scanInstruction": "Apunta tu cámara al código QR que aparece en tu escritorio", + "noRecentConnections": "No hay conexiones recientes", + "connectUsingManual": "Conéctate a un dispositivo usando la entrada manual para empezar", + "invalidQrCode": "Formato de código QR no válido", + "removeRecentConnection": "Eliminar conexión reciente", + "removeConfirm": "¿Eliminar \"${name}\" de las conexiones recientes?", + "validationHostRequired": "Por favor, introduce la dirección del host", + "validationHostFormat": "El formato debe ser IP:puerto (ej., 192.168.1.100:48632)", + "validationSessionIdRequired": "Por favor, introduce un ID de sesión", + "validationSessionIdLength": "El ID de sesión debe tener 8 caracteres", + "validationPinRequired": "Por favor, introduce un PIN", + "validationPinLength": "El PIN debe tener 6 dígitos", + "connectionTimedOut": "Tiempo de conexión agotado. Verifica el ID de sesión y el PIN.", + "sessionNotFound": "No se encontró la sesión. Verifica tus credenciales.", + "failedToConnect": "Error al conectar: ${error}", + "failedToLoadRecent": "Error al cargar sesiones recientes: ${error}" + }, + "remote": { + "disconnectConfirm": "¿Quieres desconectarte de la sesión remota?", + "reconnecting": "Reconectando...", + "attemptOf": "Intento ${current} de 5", + "retryNow": "Reintentar ahora", + "connectionError": "Error de conexión", + "notConnected": "No conectado", + "tabRemote": "Remoto", + "tabPlay": "Reproducir", + "tabMore": "Más", + "menu": "Menú", + "tabNavigation": "Navegación por pestañas", + "tabDiscover": "Descubrir", + "tabLibraries": "Bibliotecas", + "tabSearch": "Buscar", + "tabDownloads": "Descargas", + "tabSettings": "Configuración", + "previous": "Anterior", + "playPause": "Reproducir/Pausar", + "next": "Siguiente", + "seekBack": "Retroceder", + "stop": "Detener", + "seekForward": "Avanzar", + "volume": "Volumen", + "volumeDown": "Bajar", + "volumeUp": "Subir", + "fullscreen": "Pantalla completa", + "subtitles": "Subtítulos", + "audio": "Audio", + "searchHint": "Buscar en escritorio..." + } + }, + "videoSettings": { + "playbackSettings": "Ajustes de reproducción", + "playbackSpeed": "Velocidad de reproducción", + "sleepTimer": "Temporizador de apagado", + "audioSync": "Sincronización de audio", + "subtitleSync": "Sincronización de subtítulos", + "hdr": "HDR", + "audioOutput": "Salida de audio", + "performanceOverlay": "Indicador de rendimiento" + } } diff --git a/lib/i18n/fr.i18n.json b/lib/i18n/fr.i18n.json index ea85b3c3..c7f1d866 100644 --- a/lib/i18n/fr.i18n.json +++ b/lib/i18n/fr.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "Chargement..." - }, + "title": "Plezy" +}, "auth": { "signInWithPlex": "S'inscrire avec Plex", "showQRCode": "Afficher le QR Code", - "cancel": "Annuler", "authenticate": "S'authentifier", - "retry": "Réessayer", "debugEnterToken": "Debug: Entrez votre token Plex", "plexTokenLabel": "Token d'authentification Plex", "plexTokenHint": "Entrez votre token Plex.tv", @@ -34,14 +31,28 @@ "no": "Non", "delete": "Supprimer", "shuffle": "Mélanger", - "addTo": "Ajouter à..." + "addTo": "Ajouter à...", + "remove": "Supprimer", + "paste": "Coller", + "connect": "Connecter", + "disconnect": "Déconnecter", + "play": "Lire", + "pause": "Pause", + "resume": "Reprendre", + "error": "Erreur", + "search": "Recherche", + "home": "Accueil", + "back": "Retour", + "settings": "Paramètres", + "mute": "Muet", + "ok": "OK", + "loading": "Chargement..." }, "screens": { "licenses": "Licenses", "switchProfile": "Changer de profil", "subtitleStyling": "Configuration des sous-titres", "mpvConfig": "Configuration MPV", - "search": "Recherche", "logs": "Logs" }, "update": { @@ -203,7 +214,8 @@ "speedReset": "Réinitialiser la vitesse", "subSeekNext": "Rechercher le sous-titre suivant", "subSeekPrev": "Rechercher le sous-titre précédent", - "shaderToggle": "Activer/désactiver les shaders" + "shaderToggle": "Activer/désactiver les shaders", + "skipMarker": "Passer l'intro/le générique" } }, "pinEntry": { @@ -307,7 +319,6 @@ "timelineSlider": "Timeline vidéo", "volumeSlider": "Niveau sonore", "endsAt": "Fin à ${time}", - "backButton": "Retour", "pipFailed": "Échec du démarrage du mode image dans l'image", "pipErrors": { "androidVersion": "Nécessite Android 8.0 ou plus récent", @@ -315,7 +326,9 @@ "notSupported": "Cet appareil ne prend pas en charge le mode image dans l'image", "failed": "Échec du démarrage du mode image dans l'image", "unknown": "Une erreur s'est produite : ${error}" - } + }, + "chapters": "Chapitres", + "noChaptersAvailable": "Aucun chapitre disponible" }, "userStatus": { "admin": "Admin", @@ -395,19 +408,15 @@ "entriesCount": "${count} entrées" }, "dialog": { - "confirmAction": "Confirmer l'action", - "cancel": "Annuler" + "confirmAction": "Confirmer l'action" }, "discover": { "title": "Découvrez", "switchProfile": "Changer de profil", - "logout": "Déconnexion", "noContentAvailable": "Aucun contenu disponible", "addMediaToLibraries": "Ajoutez des médias à votre bibliothèque", "continueWatching": "Continuer à regarder", - "play": "Lire", "playEpisode": "S${season}E${episode}", - "pause": "Pause", "overview": "Aperçu", "cast": "Cast", "seasons": "Saisons", @@ -517,10 +526,7 @@ "licensesCount": "${count} licences" }, "navigation": { - "home": "Accueil", - "search": "Rechercher", "libraries": "Bibliothèques", - "settings": "Paramètres", "downloads": "Téléchargements" }, "collections": { @@ -633,7 +639,11 @@ "episodesQueued": "${count} épisodes en attente de téléchargement", "downloadDeleted": "Télécharger supprimé", "deleteConfirm": "Êtes-vous sûr de vouloir supprimer \"${title}\" ? Cela supprimera le fichier téléchargé de votre appareil.", - "deletingWithProgress": "Suppression de ${title}... (${current} sur ${total})" + "deletingWithProgress": "Suppression de ${title}... (${current} sur ${total})", + "noDownloadsTree": "Aucun téléchargement", + "pauseAll": "Tout mettre en pause", + "resumeAll": "Tout reprendre", + "deleteAll": "Tout supprimer" }, "shaders": { "title": "Shaders", @@ -642,5 +652,107 @@ "qualityFast": "Rapide", "qualityHQ": "Haute qualité", "mode": "Mode" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "Se connecter à un appareil", + "hostRemoteSession": "Héberger une session distante", + "controlThisDevice": "Contrôlez cet appareil avec votre téléphone", + "remoteControl": "Télécommande", + "controlDesktop": "Contrôler un appareil de bureau", + "connectedTo": "Connecté à ${name}", + "session": { + "creatingSession": "Création de la session distante...", + "failedToCreate": "Échec de la création de la session distante :", + "noSession": "Aucune session disponible", + "scanQrCode": "Scanner le QR Code", + "orEnterManually": "Ou saisir manuellement", + "hostAddress": "Adresse de l'hôte", + "sessionId": "ID de session", + "pin": "PIN", + "connected": "Connecté", + "waitingForConnection": "En attente de connexion...", + "usePhoneToControl": "Utilisez votre appareil mobile pour contrôler cette application", + "copiedToClipboard": "${label} copié dans le presse-papiers", + "copyToClipboard": "Copier dans le presse-papiers", + "newSession": "Nouvelle session", + "minimize": "Réduire" + }, + "pairing": { + "recent": "Récents", + "scan": "Scanner", + "manual": "Manuel", + "recentConnections": "Connexions récentes", + "quickReconnect": "Reconnexion rapide aux appareils précédemment jumelés", + "pairWithDesktop": "Jumeler avec un bureau", + "enterSessionDetails": "Saisissez les détails de la session affichés sur votre appareil de bureau", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "Saisissez l'ID de session à 8 caractères", + "pinHint": "Saisissez le PIN à 6 chiffres", + "connecting": "Connexion...", + "tips": "Conseils", + "tipDesktop": "Ouvrez Plezy sur votre bureau et activez Companion Remote depuis les paramètres ou le menu", + "tipScan": "Utilisez l'onglet Scanner pour jumeler rapidement en scannant le QR code sur votre bureau", + "tipWifi": "Assurez-vous que les deux appareils sont sur le même réseau WiFi", + "cameraPermissionRequired": "L'autorisation de la caméra est requise pour scanner les QR codes.\nVeuillez accorder l'accès à la caméra dans les paramètres de votre appareil.", + "cameraError": "Impossible de démarrer la caméra : ${error}", + "scanInstruction": "Pointez votre caméra vers le QR code affiché sur votre bureau", + "noRecentConnections": "Aucune connexion récente", + "connectUsingManual": "Connectez-vous à un appareil via la saisie manuelle pour commencer", + "invalidQrCode": "Format de QR code invalide", + "removeRecentConnection": "Supprimer la connexion récente", + "removeConfirm": "Supprimer \"${name}\" des connexions récentes ?", + "validationHostRequired": "Veuillez saisir l'adresse de l'hôte", + "validationHostFormat": "Le format doit être IP:port (ex : 192.168.1.100:48632)", + "validationSessionIdRequired": "Veuillez saisir un ID de session", + "validationSessionIdLength": "L'ID de session doit contenir 8 caractères", + "validationPinRequired": "Veuillez saisir un PIN", + "validationPinLength": "Le PIN doit contenir 6 chiffres", + "connectionTimedOut": "Délai de connexion expiré. Veuillez vérifier l'ID de session et le PIN.", + "sessionNotFound": "Session introuvable. Veuillez vérifier vos identifiants.", + "failedToConnect": "Échec de la connexion : ${error}", + "failedToLoadRecent": "Échec du chargement des sessions récentes : ${error}" + }, + "remote": { + "disconnectConfirm": "Voulez-vous vous déconnecter de la session distante ?", + "reconnecting": "Reconnexion...", + "attemptOf": "Tentative ${current} sur 5", + "retryNow": "Réessayer maintenant", + "connectionError": "Erreur de connexion", + "notConnected": "Non connecté", + "tabRemote": "Télécommande", + "tabPlay": "Lecture", + "tabMore": "Plus", + "menu": "Menu", + "tabNavigation": "Navigation par onglets", + "tabDiscover": "Découvrir", + "tabLibraries": "Bibliothèques", + "tabSearch": "Rechercher", + "tabDownloads": "Téléchargements", + "tabSettings": "Paramètres", + "previous": "Précédent", + "playPause": "Lecture/Pause", + "next": "Suivant", + "seekBack": "Reculer", + "stop": "Arrêter", + "seekForward": "Avancer", + "volume": "Volume", + "volumeDown": "Baisser", + "volumeUp": "Augmenter", + "fullscreen": "Plein écran", + "subtitles": "Sous-titres", + "audio": "Audio", + "searchHint": "Rechercher sur le bureau..." + } + }, + "videoSettings": { + "playbackSettings": "Paramètres de lecture", + "playbackSpeed": "Vitesse de lecture", + "sleepTimer": "Minuterie de mise en veille", + "audioSync": "Synchronisation audio", + "subtitleSync": "Synchronisation des sous-titres", + "hdr": "HDR", + "audioOutput": "Sortie audio", + "performanceOverlay": "Superposition de performance" } } diff --git a/lib/i18n/it.i18n.json b/lib/i18n/it.i18n.json index 50acca45..1ec1f750 100644 --- a/lib/i18n/it.i18n.json +++ b/lib/i18n/it.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "Caricamento..." - }, + "title": "Plezy" +}, "auth": { "signInWithPlex": "Accedi con Plex", "showQRCode": "Mostra QR Code", - "cancel": "Cancella", "authenticate": "Autenticazione", - "retry": "Riprova", "debugEnterToken": "Debug: Inserisci Token Plex", "plexTokenLabel": "Token Auth Plex", "plexTokenHint": "Inserisci il tuo token di Plex.tv", @@ -34,14 +31,28 @@ "no": "No", "delete": "Elimina", "shuffle": "Casuale", - "addTo": "Aggiungi a..." + "addTo": "Aggiungi a...", + "remove": "Rimuovi", + "paste": "Incolla", + "connect": "Connetti", + "disconnect": "Disconnetti", + "play": "Riproduci", + "pause": "Pausa", + "resume": "Riprendi", + "error": "Errore", + "search": "Cerca", + "home": "Home", + "back": "Indietro", + "settings": "Impostazioni", + "mute": "Muto", + "ok": "OK", + "loading": "Caricamento..." }, "screens": { "licenses": "Licenze", "switchProfile": "Cambia profilo", "subtitleStyling": "Stile sottotitoli", "mpvConfig": "Configurazione MPV", - "search": "Cerca", "logs": "Registro" }, "update": { @@ -203,7 +214,8 @@ "speedReset": "Ripristina velocità", "subSeekNext": "Vai al sottotitolo successivo", "subSeekPrev": "Vai al sottotitolo precedente", - "shaderToggle": "Attiva/disattiva shader" + "shaderToggle": "Attiva/disattiva shader", + "skipMarker": "Salta intro/titoli di coda" } }, "pinEntry": { @@ -307,7 +319,6 @@ "timelineSlider": "Timeline video", "volumeSlider": "Livello volume", "endsAt": "Finisce alle ${time}", - "backButton": "Indietro", "pipFailed": "Impossibile avviare la modalità Picture-in-Picture", "pipErrors": { "androidVersion": "Richiede Android 8.0 o versioni successive", @@ -315,7 +326,9 @@ "notSupported": "Questo dispositivo non supporta la modalità Picture-in-Picture", "failed": "Impossibile avviare la modalità Picture-in-Picture", "unknown": "Si è verificato un errore: ${error}" - } + }, + "chapters": "Capitoli", + "noChaptersAvailable": "Nessun capitolo disponibile" }, "userStatus": { "admin": "Admin", @@ -395,19 +408,15 @@ "entriesCount": "${count} voci" }, "dialog": { - "confirmAction": "Conferma azione", - "cancel": "Cancella" + "confirmAction": "Conferma azione" }, "discover": { "title": "Esplora", "switchProfile": "Cambia profilo", - "logout": "Disconnetti", "noContentAvailable": "Nessun contenuto disponibile", "addMediaToLibraries": "Aggiungi alcuni file multimediali alle tue librerie", "continueWatching": "Continua a guardare", - "play": "Riproduci", "playEpisode": "S${season}E${episode}", - "pause": "Pausa", "overview": "Panoramica", "cast": "Attori", "seasons": "Stagioni", @@ -517,10 +526,7 @@ "licensesCount": "${count} licenze" }, "navigation": { - "home": "Home", - "search": "Cerca", "libraries": "Librerie", - "settings": "Impostazioni", "downloads": "Download" }, "downloads": { @@ -537,7 +543,11 @@ "episodesQueued": "${count} episodi in coda per il download", "downloadDeleted": "Download eliminato", "deleteConfirm": "Sei sicuro di voler eliminare \"${title}\"? Il file scaricato verrà rimosso dal tuo dispositivo.", - "deletingWithProgress": "Eliminazione di ${title}... (${current} di ${total})" + "deletingWithProgress": "Eliminazione di ${title}... (${current} di ${total})", + "noDownloadsTree": "Nessun download", + "pauseAll": "Metti tutto in pausa", + "resumeAll": "Riprendi tutto", + "deleteAll": "Elimina tutto" }, "playlists": { "title": "Playlist", @@ -642,5 +652,107 @@ "qualityFast": "Veloce", "qualityHQ": "Alta qualità", "mode": "Modalità" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "Connetti a un dispositivo", + "hostRemoteSession": "Ospita sessione remota", + "controlThisDevice": "Controlla questo dispositivo con il tuo telefono", + "remoteControl": "Telecomando", + "controlDesktop": "Controlla un dispositivo desktop", + "connectedTo": "Connesso a ${name}", + "session": { + "creatingSession": "Creazione sessione remota...", + "failedToCreate": "Impossibile creare la sessione remota:", + "noSession": "Nessuna sessione disponibile", + "scanQrCode": "Scansiona QR Code", + "orEnterManually": "Oppure inserisci manualmente", + "hostAddress": "Indirizzo host", + "sessionId": "ID sessione", + "pin": "PIN", + "connected": "Connesso", + "waitingForConnection": "In attesa di connessione...", + "usePhoneToControl": "Usa il tuo dispositivo mobile per controllare questa app", + "copiedToClipboard": "${label} copiato negli appunti", + "copyToClipboard": "Copia negli appunti", + "newSession": "Nuova sessione", + "minimize": "Riduci" + }, + "pairing": { + "recent": "Recenti", + "scan": "Scansiona", + "manual": "Manuale", + "recentConnections": "Connessioni recenti", + "quickReconnect": "Riconnettiti rapidamente ai dispositivi associati in precedenza", + "pairWithDesktop": "Associa con desktop", + "enterSessionDetails": "Inserisci i dettagli della sessione mostrati sul tuo dispositivo desktop", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "Inserisci ID sessione di 8 caratteri", + "pinHint": "Inserisci PIN di 6 cifre", + "connecting": "Connessione...", + "tips": "Suggerimenti", + "tipDesktop": "Apri Plezy sul tuo desktop e abilita Companion Remote dalle impostazioni o dal menu", + "tipScan": "Usa la scheda Scansiona per associare rapidamente scansionando il QR code sul tuo desktop", + "tipWifi": "Assicurati che entrambi i dispositivi siano sulla stessa rete WiFi", + "cameraPermissionRequired": "L'autorizzazione della fotocamera è necessaria per scansionare i QR code.\nConcedi l'accesso alla fotocamera nelle impostazioni del dispositivo.", + "cameraError": "Impossibile avviare la fotocamera: ${error}", + "scanInstruction": "Punta la fotocamera verso il QR code mostrato sul tuo desktop", + "noRecentConnections": "Nessuna connessione recente", + "connectUsingManual": "Connettiti a un dispositivo tramite inserimento manuale per iniziare", + "invalidQrCode": "Formato QR code non valido", + "removeRecentConnection": "Rimuovi connessione recente", + "removeConfirm": "Rimuovere \"${name}\" dalle connessioni recenti?", + "validationHostRequired": "Inserisci l'indirizzo host", + "validationHostFormat": "Il formato deve essere IP:porta (es. 192.168.1.100:48632)", + "validationSessionIdRequired": "Inserisci un ID sessione", + "validationSessionIdLength": "L'ID sessione deve essere di 8 caratteri", + "validationPinRequired": "Inserisci un PIN", + "validationPinLength": "Il PIN deve essere di 6 cifre", + "connectionTimedOut": "Connessione scaduta. Verifica l'ID sessione e il PIN.", + "sessionNotFound": "Sessione non trovata. Verifica le tue credenziali.", + "failedToConnect": "Connessione fallita: ${error}", + "failedToLoadRecent": "Impossibile caricare le sessioni recenti: ${error}" + }, + "remote": { + "disconnectConfirm": "Vuoi disconnetterti dalla sessione remota?", + "reconnecting": "Riconnessione...", + "attemptOf": "Tentativo ${current} di 5", + "retryNow": "Riprova ora", + "connectionError": "Errore di connessione", + "notConnected": "Non connesso", + "tabRemote": "Telecomando", + "tabPlay": "Riproduci", + "tabMore": "Altro", + "menu": "Menu", + "tabNavigation": "Navigazione schede", + "tabDiscover": "Esplora", + "tabLibraries": "Librerie", + "tabSearch": "Cerca", + "tabDownloads": "Download", + "tabSettings": "Impostazioni", + "previous": "Precedente", + "playPause": "Riproduci/Pausa", + "next": "Successivo", + "seekBack": "Riavvolgi", + "stop": "Ferma", + "seekForward": "Avanti", + "volume": "Volume", + "volumeDown": "Abbassa", + "volumeUp": "Alza", + "fullscreen": "Schermo intero", + "subtitles": "Sottotitoli", + "audio": "Audio", + "searchHint": "Cerca sul desktop..." + } + }, + "videoSettings": { + "playbackSettings": "Impostazioni di riproduzione", + "playbackSpeed": "Velocità di riproduzione", + "sleepTimer": "Timer di spegnimento", + "audioSync": "Sincronizzazione audio", + "subtitleSync": "Sincronizzazione sottotitoli", + "hdr": "HDR", + "audioOutput": "Uscita audio", + "performanceOverlay": "Overlay prestazioni" } } diff --git a/lib/i18n/ko.i18n.json b/lib/i18n/ko.i18n.json index e77259df..083b729b 100644 --- a/lib/i18n/ko.i18n.json +++ b/lib/i18n/ko.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "로딩 중..." - }, + "title": "Plezy" +}, "auth": { "signInWithPlex": "Plex 계정으로 로그인", "showQRCode": "QR 코드", - "cancel": "취소", "authenticate": "인증", - "retry": "재시도", "debugEnterToken": "디버깅을 위해 Plex 토큰을 입력하세요.", "plexTokenLabel": "Plex 인증 토큰", "plexTokenHint": "Plex.tv 토큰을 입력하세요", @@ -34,14 +31,28 @@ "no": "아니오", "delete": "삭제", "shuffle": "무작위 재생", - "addTo": "추가하기..." + "addTo": "추가하기...", + "remove": "삭제", + "paste": "붙여넣기", + "connect": "연결", + "disconnect": "연결 해제", + "play": "재생", + "pause": "일시정지", + "resume": "재개", + "error": "오류", + "search": "검색", + "home": "홈", + "back": "뒤로", + "settings": "설정", + "mute": "음소거", + "ok": "확인", + "loading": "로딩 중..." }, "screens": { "licenses": "라이선스", "switchProfile": "프로필 전환", "subtitleStyling": "자막 스타일 설정", "mpvConfig": "MPV 설정", - "search": "검색", "logs": "로그" }, "update": { @@ -203,7 +214,8 @@ "speedReset": "속도 초기화", "subSeekNext": "다음 자막으로 이동", "subSeekPrev": "이전 자막으로 이동", - "shaderToggle": "셰이더 전환" + "shaderToggle": "셰이더 전환", + "skipMarker": "인트로/크레딧 건너뛰기" } }, "pinEntry": { @@ -307,7 +319,6 @@ "timelineSlider": "타임라인", "volumeSlider": "볼륨 조절", "endsAt": "${time}에 종료", - "backButton": "뒤로 가기", "pipFailed": "화면 속 화면 모드를 시작할 수 없습니다", "pipErrors": { "androidVersion": "Android 8.0 이상이 필요합니다", @@ -315,7 +326,9 @@ "notSupported": "이 기기는 화면 속 화면 모드를 지원하지 않습니다", "failed": "화면 속 화면 모드를 시작할 수 없습니다", "unknown": "오류가 발생했습니다: ${error}" - } + }, + "chapters": "챕터", + "noChaptersAvailable": "사용 가능한 챕터가 없습니다" }, "userStatus": { "admin": "관리자", @@ -395,19 +408,15 @@ "entriesCount": "${count} 항목" }, "dialog": { - "confirmAction": "확인", - "cancel": "취소" + "confirmAction": "확인" }, "discover": { "title": "발견", "switchProfile": "사용자 전환", - "logout": "로그아웃", "noContentAvailable": "사용 가능한 콘텐츠가 없습니다", "addMediaToLibraries": "미디어 라이브러리에 미디어를 추가해 주세요", "continueWatching": "계속 시청", - "play": "재생", "playEpisode": "S${season}E${episode}", - "pause": "일시정지", "overview": "개요", "cast": "출연진", "seasons": "시즌 수", @@ -517,10 +526,7 @@ "licensesCount": "${count} 개의 라이선스" }, "navigation": { - "home": "홈", - "search": "검색", "libraries": "미디어 라이브러리", - "settings": "설정", "downloads": "다운로드" }, "collections": { @@ -633,7 +639,11 @@ "episodesQueued": "${count} 에피소드가 다운로드 대기열에 추가 되었습니다", "downloadDeleted": "다운로드 삭제됨", "deleteConfirm": "\"${title}\"를 삭제 하시겠습니까? 다운로드한 파일이 기기에서 삭제됩니다.", - "deletingWithProgress": "${title} 삭제 중... (${current}/${total})" + "deletingWithProgress": "${title} 삭제 중... (${current}/${total})", + "noDownloadsTree": "다운로드 없음", + "pauseAll": "모두 일시정지", + "resumeAll": "모두 재개", + "deleteAll": "모두 삭제" }, "shaders": { "title": "셰이더", @@ -642,5 +652,107 @@ "qualityFast": "빠름", "qualityHQ": "고품질", "mode": "모드" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "기기에 연결", + "hostRemoteSession": "원격 세션 호스트", + "controlThisDevice": "휴대폰으로 이 기기를 제어하세요", + "remoteControl": "원격 제어", + "controlDesktop": "데스크톱 기기 제어", + "connectedTo": "${name}에 연결됨", + "session": { + "creatingSession": "원격 세션 생성 중...", + "failedToCreate": "원격 세션 생성 실패:", + "noSession": "사용 가능한 세션이 없습니다", + "scanQrCode": "QR 코드 스캔", + "orEnterManually": "또는 수동으로 입력", + "hostAddress": "호스트 주소", + "sessionId": "세션 ID", + "pin": "PIN", + "connected": "연결됨", + "waitingForConnection": "연결 대기 중...", + "usePhoneToControl": "모바일 기기로 이 앱을 제어하세요", + "copiedToClipboard": "${label}이(가) 클립보드에 복사되었습니다", + "copyToClipboard": "클립보드에 복사", + "newSession": "새 세션", + "minimize": "최소화" + }, + "pairing": { + "recent": "최근", + "scan": "스캔", + "manual": "수동", + "recentConnections": "최근 연결", + "quickReconnect": "이전에 페어링한 기기에 빠르게 재연결", + "pairWithDesktop": "데스크톱과 페어링", + "enterSessionDetails": "데스크톱 기기에 표시된 세션 정보를 입력하세요", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "8자리 세션 ID 입력", + "pinHint": "6자리 PIN 입력", + "connecting": "연결 중...", + "tips": "팁", + "tipDesktop": "데스크톱에서 Plezy를 열고 설정 또는 메뉴에서 Companion Remote를 활성화하세요", + "tipScan": "스캔 탭을 사용하여 데스크톱의 QR 코드를 스캔하면 빠르게 페어링할 수 있습니다", + "tipWifi": "두 기기가 동일한 WiFi 네트워크에 연결되어 있는지 확인하세요", + "cameraPermissionRequired": "QR 코드를 스캔하려면 카메라 권한이 필요합니다.\n기기 설정에서 카메라 접근을 허용해 주세요.", + "cameraError": "카메라를 시작할 수 없습니다: ${error}", + "scanInstruction": "데스크톱에 표시된 QR 코드에 카메라를 향하세요", + "noRecentConnections": "최근 연결 없음", + "connectUsingManual": "수동 입력으로 기기에 연결하여 시작하세요", + "invalidQrCode": "유효하지 않은 QR 코드 형식", + "removeRecentConnection": "최근 연결 삭제", + "removeConfirm": "\"${name}\"을(를) 최근 연결에서 삭제하시겠습니까?", + "validationHostRequired": "호스트 주소를 입력하세요", + "validationHostFormat": "IP:포트 형식이어야 합니다 (예: 192.168.1.100:48632)", + "validationSessionIdRequired": "세션 ID를 입력하세요", + "validationSessionIdLength": "세션 ID는 8자리여야 합니다", + "validationPinRequired": "PIN을 입력하세요", + "validationPinLength": "PIN은 6자리여야 합니다", + "connectionTimedOut": "연결 시간이 초과되었습니다. 세션 ID와 PIN을 확인하세요.", + "sessionNotFound": "세션을 찾을 수 없습니다. 자격 증명을 확인하세요.", + "failedToConnect": "연결 실패: ${error}", + "failedToLoadRecent": "최근 세션 로드 실패: ${error}" + }, + "remote": { + "disconnectConfirm": "원격 세션 연결을 해제하시겠습니까?", + "reconnecting": "재연결 중...", + "attemptOf": "${current}/5 시도 중", + "retryNow": "지금 재시도", + "connectionError": "연결 오류", + "notConnected": "연결되지 않음", + "tabRemote": "리모컨", + "tabPlay": "재생", + "tabMore": "더 보기", + "menu": "메뉴", + "tabNavigation": "탭 탐색", + "tabDiscover": "발견", + "tabLibraries": "미디어 라이브러리", + "tabSearch": "검색", + "tabDownloads": "다운로드", + "tabSettings": "설정", + "previous": "이전", + "playPause": "재생/일시정지", + "next": "다음", + "seekBack": "되감기", + "stop": "정지", + "seekForward": "빨리감기", + "volume": "볼륨", + "volumeDown": "줄이기", + "volumeUp": "높이기", + "fullscreen": "전체 화면", + "subtitles": "자막", + "audio": "오디오", + "searchHint": "데스크톱에서 검색..." + } + }, + "videoSettings": { + "playbackSettings": "재생 설정", + "playbackSpeed": "재생 속도", + "sleepTimer": "취침 타이머", + "audioSync": "오디오 동기화", + "subtitleSync": "자막 동기화", + "hdr": "HDR", + "audioOutput": "오디오 출력", + "performanceOverlay": "성능 오버레이" } } diff --git a/lib/i18n/nl.i18n.json b/lib/i18n/nl.i18n.json index c4c74807..28e8d250 100644 --- a/lib/i18n/nl.i18n.json +++ b/lib/i18n/nl.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "Laden..." - }, + "title": "Plezy" +}, "auth": { "signInWithPlex": "Inloggen met Plex", "showQRCode": "Toon QR-code", - "cancel": "Annuleren", "authenticate": "Authenticeren", - "retry": "Opnieuw proberen", "debugEnterToken": "Debug: Voer Plex Token in", "plexTokenLabel": "Plex Authenticatietoken", "plexTokenHint": "Voer je Plex.tv token in", @@ -34,14 +31,28 @@ "no": "Nee", "delete": "Verwijderen", "shuffle": "Willekeurig", - "addTo": "Toevoegen aan..." + "addTo": "Toevoegen aan...", + "remove": "Verwijderen", + "paste": "Plakken", + "connect": "Verbinden", + "disconnect": "Verbinding verbreken", + "play": "Afspelen", + "pause": "Pauzeren", + "resume": "Hervatten", + "error": "Fout", + "search": "Zoeken", + "home": "Home", + "back": "Terug", + "settings": "Instellingen", + "mute": "Dempen", + "ok": "OK", + "loading": "Laden..." }, "screens": { "licenses": "Licenties", "switchProfile": "Wissel van profiel", "subtitleStyling": "Ondertitel opmaak", "mpvConfig": "MPV-configuratie", - "search": "Zoeken", "logs": "Logbestanden" }, "update": { @@ -203,7 +214,8 @@ "speedReset": "Snelheid resetten", "subSeekNext": "Naar volgende ondertitel", "subSeekPrev": "Naar vorige ondertitel", - "shaderToggle": "Shaders aan/uit" + "shaderToggle": "Shaders aan/uit", + "skipMarker": "Intro/aftiteling overslaan" } }, "pinEntry": { @@ -307,7 +319,6 @@ "timelineSlider": "Videotijdlijn", "volumeSlider": "Volumeniveau", "endsAt": "Eindigt om ${time}", - "backButton": "Terug", "pipFailed": "Beeld-in-beeld kon niet worden gestart", "pipErrors": { "androidVersion": "Vereist Android 8.0 of nieuwer", @@ -315,7 +326,9 @@ "notSupported": "Dit apparaat ondersteunt geen beeld-in-beeld modus", "failed": "Beeld-in-beeld kon niet worden gestart", "unknown": "Er is een fout opgetreden: ${error}" - } + }, + "chapters": "Hoofdstukken", + "noChaptersAvailable": "Geen hoofdstukken beschikbaar" }, "userStatus": { "admin": "Beheerder", @@ -395,19 +408,15 @@ "entriesCount": "${count} items" }, "dialog": { - "confirmAction": "Bevestig actie", - "cancel": "Annuleren" + "confirmAction": "Bevestig actie" }, "discover": { "title": "Ontdekken", "switchProfile": "Wissel van profiel", - "logout": "Uitloggen", "noContentAvailable": "Geen inhoud beschikbaar", "addMediaToLibraries": "Voeg wat media toe aan je bibliotheken", "continueWatching": "Verder kijken", - "play": "Afspelen", "playEpisode": "S${season}E${episode}", - "pause": "Pauzeren", "overview": "Overzicht", "cast": "Acteurs", "seasons": "Seizoenen", @@ -517,10 +526,7 @@ "licensesCount": "${count} licenties" }, "navigation": { - "home": "Thuis", - "search": "Zoeken", "libraries": "Bibliotheken", - "settings": "Instellingen", "downloads": "Downloads" }, "downloads": { @@ -537,7 +543,11 @@ "episodesQueued": "${count} afleveringen in wachtrij voor download", "downloadDeleted": "Download verwijderd", "deleteConfirm": "Weet je zeker dat je \"${title}\" wilt verwijderen? Het gedownloade bestand wordt van je apparaat verwijderd.", - "deletingWithProgress": "Verwijderen van ${title}... (${current} van ${total})" + "deletingWithProgress": "Verwijderen van ${title}... (${current} van ${total})", + "noDownloadsTree": "Geen downloads", + "pauseAll": "Alles pauzeren", + "resumeAll": "Alles hervatten", + "deleteAll": "Alles verwijderen" }, "playlists": { "title": "Afspeellijsten", @@ -642,5 +652,107 @@ "qualityFast": "Snel", "qualityHQ": "Hoge kwaliteit", "mode": "Modus" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "Verbinden met apparaat", + "hostRemoteSession": "Externe sessie hosten", + "controlThisDevice": "Bedien dit apparaat met je telefoon", + "remoteControl": "Afstandsbediening", + "controlDesktop": "Bedien een desktop-apparaat", + "connectedTo": "Verbonden met ${name}", + "session": { + "creatingSession": "Externe sessie aanmaken...", + "failedToCreate": "Kan externe sessie niet aanmaken:", + "noSession": "Geen sessie beschikbaar", + "scanQrCode": "Scan QR-code", + "orEnterManually": "Of voer handmatig in", + "hostAddress": "Hostadres", + "sessionId": "Sessie-ID", + "pin": "PIN", + "connected": "Verbonden", + "waitingForConnection": "Wachten op verbinding...", + "usePhoneToControl": "Gebruik je mobiele apparaat om deze app te bedienen", + "copiedToClipboard": "${label} gekopieerd naar klembord", + "copyToClipboard": "Kopieer naar klembord", + "newSession": "Nieuwe sessie", + "minimize": "Minimaliseren" + }, + "pairing": { + "recent": "Recent", + "scan": "Scannen", + "manual": "Handmatig", + "recentConnections": "Recente verbindingen", + "quickReconnect": "Snel opnieuw verbinden met eerder gekoppelde apparaten", + "pairWithDesktop": "Koppelen met desktop", + "enterSessionDetails": "Voer de sessiegegevens in die op je desktop-apparaat worden getoond", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "Voer 8-tekens sessie-ID in", + "pinHint": "Voer 6-cijferige PIN in", + "connecting": "Verbinden...", + "tips": "Tips", + "tipDesktop": "Open Plezy op je desktop en schakel Companion Remote in via instellingen of menu", + "tipScan": "Gebruik het tabblad Scannen om snel te koppelen door de QR-code op je desktop te scannen", + "tipWifi": "Zorg ervoor dat beide apparaten op hetzelfde WiFi-netwerk zitten", + "cameraPermissionRequired": "Cameratoestemming is vereist om QR-codes te scannen.\nGeef cameratoegang in je apparaatinstellingen.", + "cameraError": "Kan camera niet starten: ${error}", + "scanInstruction": "Richt je camera op de QR-code die op je desktop wordt getoond", + "noRecentConnections": "Geen recente verbindingen", + "connectUsingManual": "Verbind met een apparaat via Handmatige invoer om te beginnen", + "invalidQrCode": "Ongeldig QR-codeformaat", + "removeRecentConnection": "Recente verbinding verwijderen", + "removeConfirm": "\"${name}\" verwijderen uit recente verbindingen?", + "validationHostRequired": "Voer een hostadres in", + "validationHostFormat": "Formaat moet IP:poort zijn (bijv. 192.168.1.100:48632)", + "validationSessionIdRequired": "Voer een sessie-ID in", + "validationSessionIdLength": "Sessie-ID moet 8 tekens zijn", + "validationPinRequired": "Voer een PIN in", + "validationPinLength": "PIN moet 6 cijfers zijn", + "connectionTimedOut": "Verbinding verlopen. Controleer de sessie-ID en PIN.", + "sessionNotFound": "Kan de sessie niet vinden. Controleer je gegevens.", + "failedToConnect": "Verbinden mislukt: ${error}", + "failedToLoadRecent": "Kan recente sessies niet laden: ${error}" + }, + "remote": { + "disconnectConfirm": "Wil je de verbinding met de externe sessie verbreken?", + "reconnecting": "Opnieuw verbinden...", + "attemptOf": "Poging ${current} van 5", + "retryNow": "Nu opnieuw proberen", + "connectionError": "Verbindingsfout", + "notConnected": "Niet verbonden", + "tabRemote": "Afstandsbediening", + "tabPlay": "Afspelen", + "tabMore": "Meer", + "menu": "Menu", + "tabNavigation": "Tabnavigatie", + "tabDiscover": "Ontdekken", + "tabLibraries": "Bibliotheken", + "tabSearch": "Zoeken", + "tabDownloads": "Downloads", + "tabSettings": "Instellingen", + "previous": "Vorige", + "playPause": "Afspelen/Pauzeren", + "next": "Volgende", + "seekBack": "Terugspoelen", + "stop": "Stoppen", + "seekForward": "Vooruitspoelen", + "volume": "Volume", + "volumeDown": "Omlaag", + "volumeUp": "Omhoog", + "fullscreen": "Volledig scherm", + "subtitles": "Ondertitels", + "audio": "Audio", + "searchHint": "Zoeken op desktop..." + } + }, + "videoSettings": { + "playbackSettings": "Afspeelinstellingen", + "playbackSpeed": "Afspeelsnelheid", + "sleepTimer": "Slaaptimer", + "audioSync": "Audio synchronisatie", + "subtitleSync": "Ondertitel synchronisatie", + "hdr": "HDR", + "audioOutput": "Audio-uitvoer", + "performanceOverlay": "Prestatie-overlay" } } diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index a2e09834..87bdff29 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 9 -/// Strings: 5131 (570 per locale) +/// Strings: 6048 (672 per locale) /// -/// Built on 2026-02-10 at 15:52 UTC +/// Built on 2026-02-10 at 20:34 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/lib/i18n/strings_de.g.dart b/lib/i18n/strings_de.g.dart index fccb7592..8e4bf85f 100644 --- a/lib/i18n/strings_de.g.dart +++ b/lib/i18n/strings_de.g.dart @@ -70,6 +70,8 @@ class TranslationsDe with BaseTranslations implements T @override late final _TranslationsCollectionsDe collections = _TranslationsCollectionsDe._(_root); @override late final _TranslationsWatchTogetherDe watchTogether = _TranslationsWatchTogetherDe._(_root); @override late final _TranslationsShadersDe shaders = _TranslationsShadersDe._(_root); + @override late final _TranslationsCompanionRemoteDe companionRemote = _TranslationsCompanionRemoteDe._(_root); + @override late final _TranslationsVideoSettingsDe videoSettings = _TranslationsVideoSettingsDe._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppDe implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => 'Lädt...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthDe implements TranslationsAuthEn { // Translations @override String get signInWithPlex => 'Mit Plex anmelden'; @override String get showQRCode => 'QR-Code anzeigen'; - @override String get cancel => 'Abbrechen'; @override String get authenticate => 'Authentifizieren'; - @override String get retry => 'Erneut versuchen'; @override String get debugEnterToken => 'Debug: Plex-Token eingeben'; @override String get plexTokenLabel => 'Plex-Auth-Token'; @override String get plexTokenHint => 'Plex.tv-Token eingeben'; @@ -128,6 +127,21 @@ class _TranslationsCommonDe implements TranslationsCommonEn { @override String get delete => 'Löschen'; @override String get shuffle => 'Zufall'; @override String get addTo => 'Hinzufügen zu...'; + @override String get remove => 'Entfernen'; + @override String get paste => 'Einfügen'; + @override String get connect => 'Verbinden'; + @override String get disconnect => 'Trennen'; + @override String get play => 'Abspielen'; + @override String get pause => 'Pause'; + @override String get resume => 'Fortsetzen'; + @override String get error => 'Fehler'; + @override String get search => 'Suche'; + @override String get home => 'Startseite'; + @override String get back => 'Zurück'; + @override String get settings => 'Einstellungen'; + @override String get mute => 'Stumm'; + @override String get ok => 'OK'; + @override String get loading => 'Laden...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensDe implements TranslationsScreensEn { @override String get switchProfile => 'Profil wechseln'; @override String get subtitleStyling => 'Untertitel-Stil'; @override String get mpvConfig => 'MPV-Konfiguration'; - @override String get search => 'Suche'; @override String get logs => 'Protokolle'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsDe implements TranslationsVideoControlsEn { @override String get timelineSlider => 'Video-Zeitleiste'; @override String get volumeSlider => 'Lautstärkepegel'; @override String endsAt({required Object time}) => 'Endet um ${time}'; - @override String get backButton => 'Zurück'; @override String get pipFailed => 'Bild-in-Bild konnte nicht gestartet werden'; @override late final _TranslationsVideoControlsPipErrorsDe pipErrors = _TranslationsVideoControlsPipErrorsDe._(_root); + @override String get chapters => 'Kapitel'; + @override String get noChaptersAvailable => 'Keine Kapitel verfügbar'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogDe implements TranslationsDialogEn { // Translations @override String get confirmAction => 'Aktion bestätigen'; - @override String get cancel => 'Abbrechen'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverDe implements TranslationsDiscoverEn { // Translations @override String get title => 'Entdecken'; @override String get switchProfile => 'Profil wechseln'; - @override String get logout => 'Abmelden'; @override String get noContentAvailable => 'Kein Inhalt verfügbar'; @override String get addMediaToLibraries => 'Medien zur Mediathek hinzufügen'; @override String get continueWatching => 'Weiterschauen'; - @override String get play => 'Abspielen'; @override String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - @override String get pause => 'Pause'; @override String get overview => 'Übersicht'; @override String get cast => 'Besetzung'; @override String get seasons => 'Staffeln'; @@ -748,10 +758,7 @@ class _TranslationsNavigationDe implements TranslationsNavigationEn { final TranslationsDe _root; // ignore: unused_field // Translations - @override String get home => 'Start'; - @override String get search => 'Suche'; @override String get libraries => 'Mediatheken'; - @override String get settings => 'Einstellungen'; @override String get downloads => 'Downloads'; } @@ -776,6 +783,10 @@ class _TranslationsDownloadsDe implements TranslationsDownloadsEn { @override String get downloadDeleted => 'Download gelöscht'; @override String deleteConfirm({required Object title}) => 'Möchtest du "${title}" wirklich löschen? Die heruntergeladene Datei wird von deinem Gerät entfernt.'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => 'Lösche ${title}... (${current} von ${total})'; + @override String get noDownloadsTree => 'Keine Downloads'; + @override String get pauseAll => 'Alle pausieren'; + @override String get resumeAll => 'Alle fortsetzen'; + @override String get deleteAll => 'Alle löschen'; } // Path: playlists @@ -910,6 +921,42 @@ class _TranslationsShadersDe implements TranslationsShadersEn { @override String get mode => 'Modus'; } +// Path: companionRemote +class _TranslationsCompanionRemoteDe implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => 'Mit Gerät verbinden'; + @override String get hostRemoteSession => 'Fernsteuerungssitzung starten'; + @override String get controlThisDevice => 'Dieses Gerät mit dem Handy steuern'; + @override String get remoteControl => 'Fernsteuerung'; + @override String get controlDesktop => 'Ein Desktop-Gerät steuern'; + @override String connectedTo({required Object name}) => 'Verbunden mit ${name}'; + @override late final _TranslationsCompanionRemoteSessionDe session = _TranslationsCompanionRemoteSessionDe._(_root); + @override late final _TranslationsCompanionRemotePairingDe pairing = _TranslationsCompanionRemotePairingDe._(_root); + @override late final _TranslationsCompanionRemoteRemoteDe remote = _TranslationsCompanionRemoteRemoteDe._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsDe implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => 'Wiedergabeeinstellungen'; + @override String get playbackSpeed => 'Wiedergabegeschwindigkeit'; + @override String get sleepTimer => 'Schlaftimer'; + @override String get audioSync => 'Audio-Synchronisation'; + @override String get subtitleSync => 'Untertitel-Synchronisation'; + @override String get hdr => 'HDR'; + @override String get audioOutput => 'Audioausgabe'; + @override String get performanceOverlay => 'Leistungsanzeige'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsDe implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsDe._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsDe implements TranslationsHotkeysActionsEn { @override String get subSeekNext => 'Zum nächsten Untertitel springen'; @override String get subSeekPrev => 'Zum vorherigen Untertitel springen'; @override String get shaderToggle => 'Shader umschalten'; + @override String get skipMarker => 'Intro/Abspann überspringen'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsDe implements TranslationsLibrariesGrouping @override String get folders => 'Ordner'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionDe implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get creatingSession => 'Fernsteuerungssitzung wird erstellt...'; + @override String get failedToCreate => 'Fernsteuerungssitzung konnte nicht erstellt werden:'; + @override String get noSession => 'Keine Sitzung verfügbar'; + @override String get scanQrCode => 'QR-Code scannen'; + @override String get orEnterManually => 'Oder manuell eingeben'; + @override String get hostAddress => 'Host-Adresse'; + @override String get sessionId => 'Sitzungs-ID'; + @override String get pin => 'PIN'; + @override String get connected => 'Verbunden'; + @override String get waitingForConnection => 'Warte auf Verbindung...'; + @override String get usePhoneToControl => 'Verwende dein Mobilgerät, um diese App zu steuern'; + @override String copiedToClipboard({required Object label}) => '${label} in Zwischenablage kopiert'; + @override String get copyToClipboard => 'In Zwischenablage kopieren'; + @override String get newSession => 'Neue Sitzung'; + @override String get minimize => 'Minimieren'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingDe implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get recent => 'Zuletzt'; + @override String get scan => 'Scannen'; + @override String get manual => 'Manuell'; + @override String get recentConnections => 'Letzte Verbindungen'; + @override String get quickReconnect => 'Schnell mit zuvor gekoppelten Geräten verbinden'; + @override String get pairWithDesktop => 'Mit Desktop koppeln'; + @override String get enterSessionDetails => 'Gib die Sitzungsdetails ein, die auf deinem Desktop-Gerät angezeigt werden'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => '8-stellige Sitzungs-ID eingeben'; + @override String get pinHint => '6-stellige PIN eingeben'; + @override String get connecting => 'Verbinde...'; + @override String get tips => 'Tipps'; + @override String get tipDesktop => 'Öffne Plezy auf deinem Desktop und aktiviere Companion Remote in den Einstellungen oder im Menü'; + @override String get tipScan => 'Verwende den Scannen-Tab, um dich schnell per QR-Code auf deinem Desktop zu koppeln'; + @override String get tipWifi => 'Stelle sicher, dass beide Geräte im selben WiFi-Netzwerk sind'; + @override String get cameraPermissionRequired => 'Kameraberechtigung wird zum Scannen von QR-Codes benötigt.\nBitte erteile den Kamerazugriff in den Geräteeinstellungen.'; + @override String cameraError({required Object error}) => 'Kamera konnte nicht gestartet werden: ${error}'; + @override String get scanInstruction => 'Richte deine Kamera auf den QR-Code auf deinem Desktop'; + @override String get noRecentConnections => 'Keine letzten Verbindungen'; + @override String get connectUsingManual => 'Verbinde dich über die manuelle Eingabe, um loszulegen'; + @override String get invalidQrCode => 'Ungültiges QR-Code-Format'; + @override String get removeRecentConnection => 'Letzte Verbindung entfernen'; + @override String removeConfirm({required Object name}) => '"${name}" aus den letzten Verbindungen entfernen?'; + @override String get validationHostRequired => 'Bitte Host-Adresse eingeben'; + @override String get validationHostFormat => 'Format muss IP:Port sein (z.B. 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => 'Bitte Sitzungs-ID eingeben'; + @override String get validationSessionIdLength => 'Sitzungs-ID muss 8 Zeichen lang sein'; + @override String get validationPinRequired => 'Bitte PIN eingeben'; + @override String get validationPinLength => 'PIN muss 6 Ziffern haben'; + @override String get connectionTimedOut => 'Zeitüberschreitung. Bitte Sitzungs-ID und PIN überprüfen.'; + @override String get sessionNotFound => 'Sitzung nicht gefunden. Bitte Zugangsdaten überprüfen.'; + @override String failedToConnect({required Object error}) => 'Verbindung fehlgeschlagen: ${error}'; + @override String failedToLoadRecent({required Object error}) => 'Letzte Sitzungen konnten nicht geladen werden: ${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteDe implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteDe._(this._root); + + final TranslationsDe _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => 'Möchtest du die Verbindung zur Fernsteuerungssitzung trennen?'; + @override String get reconnecting => 'Verbindung wird wiederhergestellt...'; + @override String attemptOf({required Object current}) => 'Versuch ${current} von 5'; + @override String get retryNow => 'Jetzt wiederholen'; + @override String get connectionError => 'Verbindungsfehler'; + @override String get notConnected => 'Nicht verbunden'; + @override String get tabRemote => 'Fernbedienung'; + @override String get tabPlay => 'Wiedergabe'; + @override String get tabMore => 'Mehr'; + @override String get menu => 'Menü'; + @override String get tabNavigation => 'Tab-Navigation'; + @override String get tabDiscover => 'Entdecken'; + @override String get tabLibraries => 'Mediatheken'; + @override String get tabSearch => 'Suche'; + @override String get tabDownloads => 'Downloads'; + @override String get tabSettings => 'Einstellungen'; + @override String get previous => 'Zurück'; + @override String get playPause => 'Wiedergabe/Pause'; + @override String get next => 'Weiter'; + @override String get seekBack => 'Zurückspulen'; + @override String get stop => 'Stopp'; + @override String get seekForward => 'Vorspulen'; + @override String get volume => 'Lautstärke'; + @override String get volumeDown => 'Leiser'; + @override String get volumeUp => 'Lauter'; + @override String get fullscreen => 'Vollbild'; + @override String get subtitles => 'Untertitel'; + @override String get audio => 'Audio'; + @override String get searchHint => 'Auf Desktop suchen...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsDe { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => 'Lädt...', 'auth.signInWithPlex' => 'Mit Plex anmelden', 'auth.showQRCode' => 'QR-Code anzeigen', - 'auth.cancel' => 'Abbrechen', 'auth.authenticate' => 'Authentifizieren', - 'auth.retry' => 'Erneut versuchen', 'auth.debugEnterToken' => 'Debug: Plex-Token eingeben', 'auth.plexTokenLabel' => 'Plex-Auth-Token', 'auth.plexTokenHint' => 'Plex.tv-Token eingeben', @@ -1018,11 +1167,25 @@ extension on TranslationsDe { 'common.delete' => 'Löschen', 'common.shuffle' => 'Zufall', 'common.addTo' => 'Hinzufügen zu...', + 'common.remove' => 'Entfernen', + 'common.paste' => 'Einfügen', + 'common.connect' => 'Verbinden', + 'common.disconnect' => 'Trennen', + 'common.play' => 'Abspielen', + 'common.pause' => 'Pause', + 'common.resume' => 'Fortsetzen', + 'common.error' => 'Fehler', + 'common.search' => 'Suche', + 'common.home' => 'Startseite', + 'common.back' => 'Zurück', + 'common.settings' => 'Einstellungen', + 'common.mute' => 'Stumm', + 'common.ok' => 'OK', + 'common.loading' => 'Laden...', 'screens.licenses' => 'Lizenzen', 'screens.switchProfile' => 'Profil wechseln', 'screens.subtitleStyling' => 'Untertitel-Stil', 'screens.mpvConfig' => 'MPV-Konfiguration', - 'screens.search' => 'Suche', 'screens.logs' => 'Protokolle', 'update.available' => 'Update verfügbar', 'update.versionAvailable' => ({required Object version}) => 'Version ${version} ist verfügbar', @@ -1176,6 +1339,7 @@ extension on TranslationsDe { 'hotkeys.actions.subSeekNext' => 'Zum nächsten Untertitel springen', 'hotkeys.actions.subSeekPrev' => 'Zum vorherigen Untertitel springen', 'hotkeys.actions.shaderToggle' => 'Shader umschalten', + 'hotkeys.actions.skipMarker' => 'Intro/Abspann überspringen', 'pinEntry.enterPin' => 'PIN eingeben', 'pinEntry.showPin' => 'PIN anzeigen', 'pinEntry.hidePin' => 'PIN verbergen', @@ -1266,13 +1430,14 @@ extension on TranslationsDe { 'videoControls.timelineSlider' => 'Video-Zeitleiste', 'videoControls.volumeSlider' => 'Lautstärkepegel', 'videoControls.endsAt' => ({required Object time}) => 'Endet um ${time}', - 'videoControls.backButton' => 'Zurück', 'videoControls.pipFailed' => 'Bild-in-Bild konnte nicht gestartet werden', 'videoControls.pipErrors.androidVersion' => 'Erfordert Android 8.0 oder neuer', 'videoControls.pipErrors.permissionDisabled' => 'Bild-in-Bild-Berechtigung ist deaktiviert. Aktiviere sie unter Einstellungen > Apps > Plezy > Bild-in-Bild', 'videoControls.pipErrors.notSupported' => 'Dieses Gerät unterstützt den Bild-in-Bild-Modus nicht', 'videoControls.pipErrors.failed' => 'Bild-in-Bild konnte nicht gestartet werden', 'videoControls.pipErrors.unknown' => ({required Object error}) => 'Ein Fehler ist aufgetreten: ${error}', + 'videoControls.chapters' => 'Kapitel', + 'videoControls.noChaptersAvailable' => 'Keine Kapitel verfügbar', 'userStatus.admin' => 'Eigentümer', 'userStatus.restricted' => 'Eingeschränkt', 'userStatus.protected' => 'Geschützt', @@ -1343,16 +1508,12 @@ extension on TranslationsDe { 'mpvConfig.confirmDeleteProperty' => 'Möchten Sie diese Eigenschaft wirklich löschen?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} Einträge', 'dialog.confirmAction' => 'Aktion bestätigen', - 'dialog.cancel' => 'Abbrechen', 'discover.title' => 'Entdecken', 'discover.switchProfile' => 'Profil wechseln', - 'discover.logout' => 'Abmelden', 'discover.noContentAvailable' => 'Kein Inhalt verfügbar', 'discover.addMediaToLibraries' => 'Medien zur Mediathek hinzufügen', 'discover.continueWatching' => 'Weiterschauen', - 'discover.play' => 'Abspielen', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => 'Pause', 'discover.overview' => 'Übersicht', 'discover.cast' => 'Besetzung', 'discover.seasons' => 'Staffeln', @@ -1442,10 +1603,7 @@ extension on TranslationsDe { 'licenses.license' => 'Lizenz', 'licenses.licenseNumber' => ({required Object number}) => 'Lizenz ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} Lizenzen', - 'navigation.home' => 'Start', - 'navigation.search' => 'Suche', 'navigation.libraries' => 'Mediatheken', - 'navigation.settings' => 'Einstellungen', 'navigation.downloads' => 'Downloads', 'downloads.title' => 'Downloads', 'downloads.manage' => 'Verwalten', @@ -1461,6 +1619,10 @@ extension on TranslationsDe { 'downloads.downloadDeleted' => 'Download gelöscht', 'downloads.deleteConfirm' => ({required Object title}) => 'Möchtest du "${title}" wirklich löschen? Die heruntergeladene Datei wird von deinem Gerät entfernt.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => 'Lösche ${title}... (${current} von ${total})', + 'downloads.noDownloadsTree' => 'Keine Downloads', + 'downloads.pauseAll' => 'Alle pausieren', + 'downloads.resumeAll' => 'Alle fortsetzen', + 'downloads.deleteAll' => 'Alle löschen', 'playlists.title' => 'Wiedergabelisten', 'playlists.noPlaylists' => 'Keine Wiedergabelisten gefunden', 'playlists.create' => 'Wiedergabeliste erstellen', @@ -1489,6 +1651,8 @@ extension on TranslationsDe { 'playlists.playlist' => 'Wiedergabeliste', 'collections.title' => 'Sammlungen', 'collections.collection' => 'Sammlung', + _ => null, + } ?? switch (path) { 'collections.empty' => 'Sammlung ist leer', 'collections.unknownLibrarySection' => 'Löschen nicht möglich: Unbekannte Bibliothekssektion', 'collections.deleteCollection' => 'Sammlung löschen', @@ -1499,8 +1663,6 @@ extension on TranslationsDe { 'collections.failedToLoadItems' => ({required Object error}) => 'Sammlungselemente konnten nicht geladen werden: ${error}', 'collections.selectCollection' => 'Sammlung auswählen', 'collections.createNewCollection' => 'Neue Sammlung erstellen', - _ => null, - } ?? switch (path) { 'collections.collectionName' => 'Sammlungsname', 'collections.enterCollectionName' => 'Sammlungsnamen eingeben', 'collections.addedToCollection' => 'Zur Sammlung hinzugefügt', @@ -1559,6 +1721,98 @@ extension on TranslationsDe { 'shaders.qualityFast' => 'Schnell', 'shaders.qualityHQ' => 'Hohe Qualität', 'shaders.mode' => 'Modus', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => 'Mit Gerät verbinden', + 'companionRemote.hostRemoteSession' => 'Fernsteuerungssitzung starten', + 'companionRemote.controlThisDevice' => 'Dieses Gerät mit dem Handy steuern', + 'companionRemote.remoteControl' => 'Fernsteuerung', + 'companionRemote.controlDesktop' => 'Ein Desktop-Gerät steuern', + 'companionRemote.connectedTo' => ({required Object name}) => 'Verbunden mit ${name}', + 'companionRemote.session.creatingSession' => 'Fernsteuerungssitzung wird erstellt...', + 'companionRemote.session.failedToCreate' => 'Fernsteuerungssitzung konnte nicht erstellt werden:', + 'companionRemote.session.noSession' => 'Keine Sitzung verfügbar', + 'companionRemote.session.scanQrCode' => 'QR-Code scannen', + 'companionRemote.session.orEnterManually' => 'Oder manuell eingeben', + 'companionRemote.session.hostAddress' => 'Host-Adresse', + 'companionRemote.session.sessionId' => 'Sitzungs-ID', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => 'Verbunden', + 'companionRemote.session.waitingForConnection' => 'Warte auf Verbindung...', + 'companionRemote.session.usePhoneToControl' => 'Verwende dein Mobilgerät, um diese App zu steuern', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label} in Zwischenablage kopiert', + 'companionRemote.session.copyToClipboard' => 'In Zwischenablage kopieren', + 'companionRemote.session.newSession' => 'Neue Sitzung', + 'companionRemote.session.minimize' => 'Minimieren', + 'companionRemote.pairing.recent' => 'Zuletzt', + 'companionRemote.pairing.scan' => 'Scannen', + 'companionRemote.pairing.manual' => 'Manuell', + 'companionRemote.pairing.recentConnections' => 'Letzte Verbindungen', + 'companionRemote.pairing.quickReconnect' => 'Schnell mit zuvor gekoppelten Geräten verbinden', + 'companionRemote.pairing.pairWithDesktop' => 'Mit Desktop koppeln', + 'companionRemote.pairing.enterSessionDetails' => 'Gib die Sitzungsdetails ein, die auf deinem Desktop-Gerät angezeigt werden', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => '8-stellige Sitzungs-ID eingeben', + 'companionRemote.pairing.pinHint' => '6-stellige PIN eingeben', + 'companionRemote.pairing.connecting' => 'Verbinde...', + 'companionRemote.pairing.tips' => 'Tipps', + 'companionRemote.pairing.tipDesktop' => 'Öffne Plezy auf deinem Desktop und aktiviere Companion Remote in den Einstellungen oder im Menü', + 'companionRemote.pairing.tipScan' => 'Verwende den Scannen-Tab, um dich schnell per QR-Code auf deinem Desktop zu koppeln', + 'companionRemote.pairing.tipWifi' => 'Stelle sicher, dass beide Geräte im selben WiFi-Netzwerk sind', + 'companionRemote.pairing.cameraPermissionRequired' => 'Kameraberechtigung wird zum Scannen von QR-Codes benötigt.\nBitte erteile den Kamerazugriff in den Geräteeinstellungen.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => 'Kamera konnte nicht gestartet werden: ${error}', + 'companionRemote.pairing.scanInstruction' => 'Richte deine Kamera auf den QR-Code auf deinem Desktop', + 'companionRemote.pairing.noRecentConnections' => 'Keine letzten Verbindungen', + 'companionRemote.pairing.connectUsingManual' => 'Verbinde dich über die manuelle Eingabe, um loszulegen', + 'companionRemote.pairing.invalidQrCode' => 'Ungültiges QR-Code-Format', + 'companionRemote.pairing.removeRecentConnection' => 'Letzte Verbindung entfernen', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => '"${name}" aus den letzten Verbindungen entfernen?', + 'companionRemote.pairing.validationHostRequired' => 'Bitte Host-Adresse eingeben', + 'companionRemote.pairing.validationHostFormat' => 'Format muss IP:Port sein (z.B. 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => 'Bitte Sitzungs-ID eingeben', + 'companionRemote.pairing.validationSessionIdLength' => 'Sitzungs-ID muss 8 Zeichen lang sein', + 'companionRemote.pairing.validationPinRequired' => 'Bitte PIN eingeben', + 'companionRemote.pairing.validationPinLength' => 'PIN muss 6 Ziffern haben', + 'companionRemote.pairing.connectionTimedOut' => 'Zeitüberschreitung. Bitte Sitzungs-ID und PIN überprüfen.', + 'companionRemote.pairing.sessionNotFound' => 'Sitzung nicht gefunden. Bitte Zugangsdaten überprüfen.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => 'Verbindung fehlgeschlagen: ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => 'Letzte Sitzungen konnten nicht geladen werden: ${error}', + 'companionRemote.remote.disconnectConfirm' => 'Möchtest du die Verbindung zur Fernsteuerungssitzung trennen?', + 'companionRemote.remote.reconnecting' => 'Verbindung wird wiederhergestellt...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => 'Versuch ${current} von 5', + 'companionRemote.remote.retryNow' => 'Jetzt wiederholen', + 'companionRemote.remote.connectionError' => 'Verbindungsfehler', + 'companionRemote.remote.notConnected' => 'Nicht verbunden', + 'companionRemote.remote.tabRemote' => 'Fernbedienung', + 'companionRemote.remote.tabPlay' => 'Wiedergabe', + 'companionRemote.remote.tabMore' => 'Mehr', + 'companionRemote.remote.menu' => 'Menü', + 'companionRemote.remote.tabNavigation' => 'Tab-Navigation', + 'companionRemote.remote.tabDiscover' => 'Entdecken', + 'companionRemote.remote.tabLibraries' => 'Mediatheken', + 'companionRemote.remote.tabSearch' => 'Suche', + 'companionRemote.remote.tabDownloads' => 'Downloads', + 'companionRemote.remote.tabSettings' => 'Einstellungen', + 'companionRemote.remote.previous' => 'Zurück', + 'companionRemote.remote.playPause' => 'Wiedergabe/Pause', + 'companionRemote.remote.next' => 'Weiter', + 'companionRemote.remote.seekBack' => 'Zurückspulen', + 'companionRemote.remote.stop' => 'Stopp', + 'companionRemote.remote.seekForward' => 'Vorspulen', + 'companionRemote.remote.volume' => 'Lautstärke', + 'companionRemote.remote.volumeDown' => 'Leiser', + 'companionRemote.remote.volumeUp' => 'Lauter', + 'companionRemote.remote.fullscreen' => 'Vollbild', + 'companionRemote.remote.subtitles' => 'Untertitel', + 'companionRemote.remote.audio' => 'Audio', + 'companionRemote.remote.searchHint' => 'Auf Desktop suchen...', + 'videoSettings.playbackSettings' => 'Wiedergabeeinstellungen', + 'videoSettings.playbackSpeed' => 'Wiedergabegeschwindigkeit', + 'videoSettings.sleepTimer' => 'Schlaftimer', + 'videoSettings.audioSync' => 'Audio-Synchronisation', + 'videoSettings.subtitleSync' => 'Untertitel-Synchronisation', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => 'Audioausgabe', + 'videoSettings.performanceOverlay' => 'Leistungsanzeige', _ => null, }; } diff --git a/lib/i18n/strings_en.g.dart b/lib/i18n/strings_en.g.dart index d080b704..a516022e 100644 --- a/lib/i18n/strings_en.g.dart +++ b/lib/i18n/strings_en.g.dart @@ -73,6 +73,8 @@ class Translations with BaseTranslations { late final TranslationsWatchTogetherEn watchTogether = TranslationsWatchTogetherEn._(_root); late final TranslationsDownloadsEn downloads = TranslationsDownloadsEn._(_root); late final TranslationsShadersEn shaders = TranslationsShadersEn._(_root); + late final TranslationsCompanionRemoteEn companionRemote = TranslationsCompanionRemoteEn._(_root); + late final TranslationsVideoSettingsEn videoSettings = TranslationsVideoSettingsEn._(_root); } // Path: app @@ -85,9 +87,6 @@ class TranslationsAppEn { /// en: 'Plezy' String get title => 'Plezy'; - - /// en: 'Loading...' - String get loading => 'Loading...'; } // Path: auth @@ -104,15 +103,9 @@ class TranslationsAuthEn { /// en: 'Show QR Code' String get showQRCode => 'Show QR Code'; - /// en: 'Cancel' - String get cancel => 'Cancel'; - /// en: 'Authenticate' String get authenticate => 'Authenticate'; - /// en: 'Retry' - String get retry => 'Retry'; - /// en: 'Debug: Enter Plex Token' String get debugEnterToken => 'Debug: Enter Plex Token'; @@ -193,6 +186,51 @@ class TranslationsCommonEn { /// en: 'Add to...' String get addTo => 'Add to...'; + + /// en: 'Remove' + String get remove => 'Remove'; + + /// en: 'Paste' + String get paste => 'Paste'; + + /// en: 'Connect' + String get connect => 'Connect'; + + /// en: 'Disconnect' + String get disconnect => 'Disconnect'; + + /// en: 'Play' + String get play => 'Play'; + + /// en: 'Pause' + String get pause => 'Pause'; + + /// en: 'Resume' + String get resume => 'Resume'; + + /// en: 'Error' + String get error => 'Error'; + + /// en: 'Search' + String get search => 'Search'; + + /// en: 'Home' + String get home => 'Home'; + + /// en: 'Back' + String get back => 'Back'; + + /// en: 'Settings' + String get settings => 'Settings'; + + /// en: 'Mute' + String get mute => 'Mute'; + + /// en: 'OK' + String get ok => 'OK'; + + /// en: 'Loading...' + String get loading => 'Loading...'; } // Path: screens @@ -215,9 +253,6 @@ class TranslationsScreensEn { /// en: 'MPV Configuration' String get mpvConfig => 'MPV Configuration'; - /// en: 'Search' - String get search => 'Search'; - /// en: 'Logs' String get logs => 'Logs'; } @@ -985,13 +1020,16 @@ class TranslationsVideoControlsEn { /// en: 'Ends at ${time}' String endsAt({required Object time}) => 'Ends at ${time}'; - /// en: 'Back' - String get backButton => 'Back'; - /// en: 'Picture-in-picture failed to start' String get pipFailed => 'Picture-in-picture failed to start'; late final TranslationsVideoControlsPipErrorsEn pipErrors = TranslationsVideoControlsPipErrorsEn._(_root); + + /// en: 'Chapters' + String get chapters => 'Chapters'; + + /// en: 'No chapters available' + String get noChaptersAvailable => 'No chapters available'; } // Path: userStatus @@ -1247,9 +1285,6 @@ class TranslationsDialogEn { /// en: 'Confirm Action' String get confirmAction => 'Confirm Action'; - - /// en: 'Cancel' - String get cancel => 'Cancel'; } // Path: discover @@ -1266,9 +1301,6 @@ class TranslationsDiscoverEn { /// en: 'Switch Profile' String get switchProfile => 'Switch Profile'; - /// en: 'Logout' - String get logout => 'Logout'; - /// en: 'No content available' String get noContentAvailable => 'No content available'; @@ -1278,15 +1310,9 @@ class TranslationsDiscoverEn { /// en: 'Continue Watching' String get continueWatching => 'Continue Watching'; - /// en: 'Play' - String get play => 'Play'; - /// en: 'S${season}E${episode}' String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - /// en: 'Pause' - String get pause => 'Pause'; - /// en: 'Overview' String get overview => 'Overview'; @@ -1599,18 +1625,9 @@ class TranslationsNavigationEn { // Translations - /// en: 'Home' - String get home => 'Home'; - - /// en: 'Search' - String get search => 'Search'; - /// en: 'Libraries' String get libraries => 'Libraries'; - /// en: 'Settings' - String get settings => 'Settings'; - /// en: 'Downloads' String get downloads => 'Downloads'; } @@ -1961,6 +1978,18 @@ class TranslationsDownloadsEn { /// en: 'Deleting ${title}... (${current} of ${total})' String deletingWithProgress({required Object title, required Object current, required Object total}) => 'Deleting ${title}... (${current} of ${total})'; + + /// en: 'No downloads' + String get noDownloadsTree => 'No downloads'; + + /// en: 'Pause all' + String get pauseAll => 'Pause all'; + + /// en: 'Resume all' + String get resumeAll => 'Resume all'; + + /// en: 'Delete all' + String get deleteAll => 'Delete all'; } // Path: shaders @@ -1990,6 +2019,73 @@ class TranslationsShadersEn { String get mode => 'Mode'; } +// Path: companionRemote +class TranslationsCompanionRemoteEn { + TranslationsCompanionRemoteEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Companion Remote' + String get title => 'Companion Remote'; + + /// en: 'Connect to Device' + String get connectToDevice => 'Connect to Device'; + + /// en: 'Host Remote Session' + String get hostRemoteSession => 'Host Remote Session'; + + /// en: 'Control this device with your phone' + String get controlThisDevice => 'Control this device with your phone'; + + /// en: 'Remote Control' + String get remoteControl => 'Remote Control'; + + /// en: 'Control a desktop device' + String get controlDesktop => 'Control a desktop device'; + + /// en: 'Connected to ${name}' + String connectedTo({required Object name}) => 'Connected to ${name}'; + + late final TranslationsCompanionRemoteSessionEn session = TranslationsCompanionRemoteSessionEn._(_root); + late final TranslationsCompanionRemotePairingEn pairing = TranslationsCompanionRemotePairingEn._(_root); + late final TranslationsCompanionRemoteRemoteEn remote = TranslationsCompanionRemoteRemoteEn._(_root); +} + +// Path: videoSettings +class TranslationsVideoSettingsEn { + TranslationsVideoSettingsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Playback Settings' + String get playbackSettings => 'Playback Settings'; + + /// en: 'Playback Speed' + String get playbackSpeed => 'Playback Speed'; + + /// en: 'Sleep Timer' + String get sleepTimer => 'Sleep Timer'; + + /// en: 'Audio Sync' + String get audioSync => 'Audio Sync'; + + /// en: 'Subtitle Sync' + String get subtitleSync => 'Subtitle Sync'; + + /// en: 'HDR' + String get hdr => 'HDR'; + + /// en: 'Audio Output' + String get audioOutput => 'Audio Output'; + + /// en: 'Performance Overlay' + String get performanceOverlay => 'Performance Overlay'; +} + // Path: hotkeys.actions class TranslationsHotkeysActionsEn { TranslationsHotkeysActionsEn._(this._root); @@ -2128,6 +2224,264 @@ class TranslationsLibrariesGroupingsEn { String get folders => 'Folders'; } +// Path: companionRemote.session +class TranslationsCompanionRemoteSessionEn { + TranslationsCompanionRemoteSessionEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Creating remote session...' + String get creatingSession => 'Creating remote session...'; + + /// en: 'Failed to create remote session:' + String get failedToCreate => 'Failed to create remote session:'; + + /// en: 'No session available' + String get noSession => 'No session available'; + + /// en: 'Scan QR Code' + String get scanQrCode => 'Scan QR Code'; + + /// en: 'Or enter manually' + String get orEnterManually => 'Or enter manually'; + + /// en: 'Host Address' + String get hostAddress => 'Host Address'; + + /// en: 'Session ID' + String get sessionId => 'Session ID'; + + /// en: 'PIN' + String get pin => 'PIN'; + + /// en: 'Connected' + String get connected => 'Connected'; + + /// en: 'Waiting for connection...' + String get waitingForConnection => 'Waiting for connection...'; + + /// en: 'Use your mobile device to control this app' + String get usePhoneToControl => 'Use your mobile device to control this app'; + + /// en: '${label} copied to clipboard' + String copiedToClipboard({required Object label}) => '${label} copied to clipboard'; + + /// en: 'Copy to clipboard' + String get copyToClipboard => 'Copy to clipboard'; + + /// en: 'New Session' + String get newSession => 'New Session'; + + /// en: 'Minimize' + String get minimize => 'Minimize'; +} + +// Path: companionRemote.pairing +class TranslationsCompanionRemotePairingEn { + TranslationsCompanionRemotePairingEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Recent' + String get recent => 'Recent'; + + /// en: 'Scan' + String get scan => 'Scan'; + + /// en: 'Manual' + String get manual => 'Manual'; + + /// en: 'Recent Connections' + String get recentConnections => 'Recent Connections'; + + /// en: 'Quickly reconnect to previously paired devices' + String get quickReconnect => 'Quickly reconnect to previously paired devices'; + + /// en: 'Pair with Desktop' + String get pairWithDesktop => 'Pair with Desktop'; + + /// en: 'Enter the session details shown on your desktop device' + String get enterSessionDetails => 'Enter the session details shown on your desktop device'; + + /// en: '192.168.1.100:48632' + String get hostAddressHint => '192.168.1.100:48632'; + + /// en: 'Enter 8-character session ID' + String get sessionIdHint => 'Enter 8-character session ID'; + + /// en: 'Enter 6-digit PIN' + String get pinHint => 'Enter 6-digit PIN'; + + /// en: 'Connecting...' + String get connecting => 'Connecting...'; + + /// en: 'Tips' + String get tips => 'Tips'; + + /// en: 'Open Plezy on your desktop and enable Companion Remote from settings or menu' + String get tipDesktop => 'Open Plezy on your desktop and enable Companion Remote from settings or menu'; + + /// en: 'Use the Scan tab to quickly pair by scanning the QR code on your desktop' + String get tipScan => 'Use the Scan tab to quickly pair by scanning the QR code on your desktop'; + + /// en: 'Make sure both devices are on the same WiFi network' + String get tipWifi => 'Make sure both devices are on the same WiFi network'; + + /// en: 'Camera permission is required to scan QR codes. Please grant camera access in your device settings.' + String get cameraPermissionRequired => 'Camera permission is required to scan QR codes.\nPlease grant camera access in your device settings.'; + + /// en: 'Could not start camera: ${error}' + String cameraError({required Object error}) => 'Could not start camera: ${error}'; + + /// en: 'Point your camera at the QR code shown on your desktop' + String get scanInstruction => 'Point your camera at the QR code shown on your desktop'; + + /// en: 'No recent connections' + String get noRecentConnections => 'No recent connections'; + + /// en: 'Connect to a device using Manual entry to get started' + String get connectUsingManual => 'Connect to a device using Manual entry to get started'; + + /// en: 'Invalid QR code format' + String get invalidQrCode => 'Invalid QR code format'; + + /// en: 'Remove Recent Connection' + String get removeRecentConnection => 'Remove Recent Connection'; + + /// en: 'Remove "${name}" from recent connections?' + String removeConfirm({required Object name}) => 'Remove "${name}" from recent connections?'; + + /// en: 'Please enter host address' + String get validationHostRequired => 'Please enter host address'; + + /// en: 'Format must be IP:port (e.g., 192.168.1.100:48632)' + String get validationHostFormat => 'Format must be IP:port (e.g., 192.168.1.100:48632)'; + + /// en: 'Please enter a session ID' + String get validationSessionIdRequired => 'Please enter a session ID'; + + /// en: 'Session ID must be 8 characters' + String get validationSessionIdLength => 'Session ID must be 8 characters'; + + /// en: 'Please enter a PIN' + String get validationPinRequired => 'Please enter a PIN'; + + /// en: 'PIN must be 6 digits' + String get validationPinLength => 'PIN must be 6 digits'; + + /// en: 'Connection timed out. Please check the session ID and PIN.' + String get connectionTimedOut => 'Connection timed out. Please check the session ID and PIN.'; + + /// en: 'Could not find the session. Please check your credentials.' + String get sessionNotFound => 'Could not find the session. Please check your credentials.'; + + /// en: 'Failed to connect: ${error}' + String failedToConnect({required Object error}) => 'Failed to connect: ${error}'; + + /// en: 'Failed to load recent sessions: ${error}' + String failedToLoadRecent({required Object error}) => 'Failed to load recent sessions: ${error}'; +} + +// Path: companionRemote.remote +class TranslationsCompanionRemoteRemoteEn { + TranslationsCompanionRemoteRemoteEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Do you want to disconnect from the remote session?' + String get disconnectConfirm => 'Do you want to disconnect from the remote session?'; + + /// en: 'Reconnecting...' + String get reconnecting => 'Reconnecting...'; + + /// en: 'Attempt ${current} of 5' + String attemptOf({required Object current}) => 'Attempt ${current} of 5'; + + /// en: 'Retry Now' + String get retryNow => 'Retry Now'; + + /// en: 'Connection error' + String get connectionError => 'Connection error'; + + /// en: 'Not connected' + String get notConnected => 'Not connected'; + + /// en: 'Remote' + String get tabRemote => 'Remote'; + + /// en: 'Play' + String get tabPlay => 'Play'; + + /// en: 'More' + String get tabMore => 'More'; + + /// en: 'Menu' + String get menu => 'Menu'; + + /// en: 'Tab Navigation' + String get tabNavigation => 'Tab Navigation'; + + /// en: 'Discover' + String get tabDiscover => 'Discover'; + + /// en: 'Libraries' + String get tabLibraries => 'Libraries'; + + /// en: 'Search' + String get tabSearch => 'Search'; + + /// en: 'Downloads' + String get tabDownloads => 'Downloads'; + + /// en: 'Settings' + String get tabSettings => 'Settings'; + + /// en: 'Previous' + String get previous => 'Previous'; + + /// en: 'Play/Pause' + String get playPause => 'Play/Pause'; + + /// en: 'Next' + String get next => 'Next'; + + /// en: 'Seek Back' + String get seekBack => 'Seek Back'; + + /// en: 'Stop' + String get stop => 'Stop'; + + /// en: 'Seek Fwd' + String get seekForward => 'Seek Fwd'; + + /// en: 'Volume' + String get volume => 'Volume'; + + /// en: 'Down' + String get volumeDown => 'Down'; + + /// en: 'Up' + String get volumeUp => 'Up'; + + /// en: 'Fullscreen' + String get fullscreen => 'Fullscreen'; + + /// en: 'Subtitles' + String get subtitles => 'Subtitles'; + + /// en: 'Audio' + String get audio => 'Audio'; + + /// en: 'Search on desktop...' + String get searchHint => 'Search on desktop...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -2137,12 +2491,9 @@ extension on Translations { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => 'Loading...', 'auth.signInWithPlex' => 'Sign in with Plex', 'auth.showQRCode' => 'Show QR Code', - 'auth.cancel' => 'Cancel', 'auth.authenticate' => 'Authenticate', - 'auth.retry' => 'Retry', 'auth.debugEnterToken' => 'Debug: Enter Plex Token', 'auth.plexTokenLabel' => 'Plex Auth Token', 'auth.plexTokenHint' => 'Enter your Plex.tv token', @@ -2167,11 +2518,25 @@ extension on Translations { 'common.delete' => 'Delete', 'common.shuffle' => 'Shuffle', 'common.addTo' => 'Add to...', + 'common.remove' => 'Remove', + 'common.paste' => 'Paste', + 'common.connect' => 'Connect', + 'common.disconnect' => 'Disconnect', + 'common.play' => 'Play', + 'common.pause' => 'Pause', + 'common.resume' => 'Resume', + 'common.error' => 'Error', + 'common.search' => 'Search', + 'common.home' => 'Home', + 'common.back' => 'Back', + 'common.settings' => 'Settings', + 'common.mute' => 'Mute', + 'common.ok' => 'OK', + 'common.loading' => 'Loading...', 'screens.licenses' => 'Licenses', 'screens.switchProfile' => 'Switch Profile', 'screens.subtitleStyling' => 'Subtitle Styling', 'screens.mpvConfig' => 'MPV Configuration', - 'screens.search' => 'Search', 'screens.logs' => 'Logs', 'update.available' => 'Update Available', 'update.versionAvailable' => ({required Object version}) => 'Version ${version} is available', @@ -2416,13 +2781,14 @@ extension on Translations { 'videoControls.timelineSlider' => 'Video timeline', 'videoControls.volumeSlider' => 'Volume level', 'videoControls.endsAt' => ({required Object time}) => 'Ends at ${time}', - 'videoControls.backButton' => 'Back', 'videoControls.pipFailed' => 'Picture-in-picture failed to start', 'videoControls.pipErrors.androidVersion' => 'Requires Android 8.0 or newer', 'videoControls.pipErrors.permissionDisabled' => 'Picture-in-picture permission is disabled. Enable it in Settings > Apps > Plezy > Picture-in-picture', 'videoControls.pipErrors.notSupported' => 'Device doesn\'t support picture-in-picture mode', 'videoControls.pipErrors.failed' => 'Picture-in-picture failed to start', 'videoControls.pipErrors.unknown' => ({required Object error}) => 'An error occurred: ${error}', + 'videoControls.chapters' => 'Chapters', + 'videoControls.noChaptersAvailable' => 'No chapters available', 'userStatus.admin' => 'Admin', 'userStatus.restricted' => 'Restricted', 'userStatus.protected' => 'Protected', @@ -2493,16 +2859,12 @@ extension on Translations { 'mpvConfig.confirmDeleteProperty' => 'Are you sure you want to delete this property?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} entries', 'dialog.confirmAction' => 'Confirm Action', - 'dialog.cancel' => 'Cancel', 'discover.title' => 'Discover', 'discover.switchProfile' => 'Switch Profile', - 'discover.logout' => 'Logout', 'discover.noContentAvailable' => 'No content available', 'discover.addMediaToLibraries' => 'Add some media to your libraries', 'discover.continueWatching' => 'Continue Watching', - 'discover.play' => 'Play', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => 'Pause', 'discover.overview' => 'Overview', 'discover.cast' => 'Cast', 'discover.seasons' => 'Seasons', @@ -2592,10 +2954,7 @@ extension on Translations { 'licenses.license' => 'License', 'licenses.licenseNumber' => ({required Object number}) => 'License ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} licenses', - 'navigation.home' => 'Home', - 'navigation.search' => 'Search', 'navigation.libraries' => 'Libraries', - 'navigation.settings' => 'Settings', 'navigation.downloads' => 'Downloads', 'collections.title' => 'Collections', 'collections.collection' => 'Collection', @@ -2643,13 +3002,13 @@ extension on Translations { 'playlists.errorDeleting' => 'Failed to delete playlist', 'playlists.errorLoading' => 'Failed to load playlists', 'playlists.errorAdding' => 'Failed to add to playlist', + _ => null, + } ?? switch (path) { 'playlists.errorReordering' => 'Failed to reorder playlist item', 'playlists.errorRemoving' => 'Failed to remove from playlist', 'watchTogether.title' => 'Watch Together', 'watchTogether.description' => 'Watch content in sync with friends and family', 'watchTogether.createSession' => 'Create Session', - _ => null, - } ?? switch (path) { 'watchTogether.creating' => 'Creating...', 'watchTogether.joinSession' => 'Join Session', 'watchTogether.joining' => 'Joining...', @@ -2703,12 +3062,108 @@ extension on Translations { 'downloads.downloadDeleted' => 'Download deleted', 'downloads.deleteConfirm' => ({required Object title}) => 'Are you sure you want to delete "${title}"? This will remove the downloaded file from your device.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => 'Deleting ${title}... (${current} of ${total})', + 'downloads.noDownloadsTree' => 'No downloads', + 'downloads.pauseAll' => 'Pause all', + 'downloads.resumeAll' => 'Resume all', + 'downloads.deleteAll' => 'Delete all', 'shaders.title' => 'Shaders', 'shaders.noShaderDescription' => 'No video enhancement', 'shaders.nvscalerDescription' => 'NVIDIA image scaling for sharper video', 'shaders.qualityFast' => 'Fast', 'shaders.qualityHQ' => 'High Quality', 'shaders.mode' => 'Mode', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => 'Connect to Device', + 'companionRemote.hostRemoteSession' => 'Host Remote Session', + 'companionRemote.controlThisDevice' => 'Control this device with your phone', + 'companionRemote.remoteControl' => 'Remote Control', + 'companionRemote.controlDesktop' => 'Control a desktop device', + 'companionRemote.connectedTo' => ({required Object name}) => 'Connected to ${name}', + 'companionRemote.session.creatingSession' => 'Creating remote session...', + 'companionRemote.session.failedToCreate' => 'Failed to create remote session:', + 'companionRemote.session.noSession' => 'No session available', + 'companionRemote.session.scanQrCode' => 'Scan QR Code', + 'companionRemote.session.orEnterManually' => 'Or enter manually', + 'companionRemote.session.hostAddress' => 'Host Address', + 'companionRemote.session.sessionId' => 'Session ID', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => 'Connected', + 'companionRemote.session.waitingForConnection' => 'Waiting for connection...', + 'companionRemote.session.usePhoneToControl' => 'Use your mobile device to control this app', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label} copied to clipboard', + 'companionRemote.session.copyToClipboard' => 'Copy to clipboard', + 'companionRemote.session.newSession' => 'New Session', + 'companionRemote.session.minimize' => 'Minimize', + 'companionRemote.pairing.recent' => 'Recent', + 'companionRemote.pairing.scan' => 'Scan', + 'companionRemote.pairing.manual' => 'Manual', + 'companionRemote.pairing.recentConnections' => 'Recent Connections', + 'companionRemote.pairing.quickReconnect' => 'Quickly reconnect to previously paired devices', + 'companionRemote.pairing.pairWithDesktop' => 'Pair with Desktop', + 'companionRemote.pairing.enterSessionDetails' => 'Enter the session details shown on your desktop device', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => 'Enter 8-character session ID', + 'companionRemote.pairing.pinHint' => 'Enter 6-digit PIN', + 'companionRemote.pairing.connecting' => 'Connecting...', + 'companionRemote.pairing.tips' => 'Tips', + 'companionRemote.pairing.tipDesktop' => 'Open Plezy on your desktop and enable Companion Remote from settings or menu', + 'companionRemote.pairing.tipScan' => 'Use the Scan tab to quickly pair by scanning the QR code on your desktop', + 'companionRemote.pairing.tipWifi' => 'Make sure both devices are on the same WiFi network', + 'companionRemote.pairing.cameraPermissionRequired' => 'Camera permission is required to scan QR codes.\nPlease grant camera access in your device settings.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => 'Could not start camera: ${error}', + 'companionRemote.pairing.scanInstruction' => 'Point your camera at the QR code shown on your desktop', + 'companionRemote.pairing.noRecentConnections' => 'No recent connections', + 'companionRemote.pairing.connectUsingManual' => 'Connect to a device using Manual entry to get started', + 'companionRemote.pairing.invalidQrCode' => 'Invalid QR code format', + 'companionRemote.pairing.removeRecentConnection' => 'Remove Recent Connection', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => 'Remove "${name}" from recent connections?', + 'companionRemote.pairing.validationHostRequired' => 'Please enter host address', + 'companionRemote.pairing.validationHostFormat' => 'Format must be IP:port (e.g., 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => 'Please enter a session ID', + 'companionRemote.pairing.validationSessionIdLength' => 'Session ID must be 8 characters', + 'companionRemote.pairing.validationPinRequired' => 'Please enter a PIN', + 'companionRemote.pairing.validationPinLength' => 'PIN must be 6 digits', + 'companionRemote.pairing.connectionTimedOut' => 'Connection timed out. Please check the session ID and PIN.', + 'companionRemote.pairing.sessionNotFound' => 'Could not find the session. Please check your credentials.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => 'Failed to connect: ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => 'Failed to load recent sessions: ${error}', + 'companionRemote.remote.disconnectConfirm' => 'Do you want to disconnect from the remote session?', + 'companionRemote.remote.reconnecting' => 'Reconnecting...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => 'Attempt ${current} of 5', + 'companionRemote.remote.retryNow' => 'Retry Now', + 'companionRemote.remote.connectionError' => 'Connection error', + 'companionRemote.remote.notConnected' => 'Not connected', + 'companionRemote.remote.tabRemote' => 'Remote', + 'companionRemote.remote.tabPlay' => 'Play', + 'companionRemote.remote.tabMore' => 'More', + 'companionRemote.remote.menu' => 'Menu', + 'companionRemote.remote.tabNavigation' => 'Tab Navigation', + 'companionRemote.remote.tabDiscover' => 'Discover', + 'companionRemote.remote.tabLibraries' => 'Libraries', + 'companionRemote.remote.tabSearch' => 'Search', + 'companionRemote.remote.tabDownloads' => 'Downloads', + 'companionRemote.remote.tabSettings' => 'Settings', + 'companionRemote.remote.previous' => 'Previous', + 'companionRemote.remote.playPause' => 'Play/Pause', + 'companionRemote.remote.next' => 'Next', + 'companionRemote.remote.seekBack' => 'Seek Back', + 'companionRemote.remote.stop' => 'Stop', + 'companionRemote.remote.seekForward' => 'Seek Fwd', + 'companionRemote.remote.volume' => 'Volume', + 'companionRemote.remote.volumeDown' => 'Down', + 'companionRemote.remote.volumeUp' => 'Up', + 'companionRemote.remote.fullscreen' => 'Fullscreen', + 'companionRemote.remote.subtitles' => 'Subtitles', + 'companionRemote.remote.audio' => 'Audio', + 'companionRemote.remote.searchHint' => 'Search on desktop...', + 'videoSettings.playbackSettings' => 'Playback Settings', + 'videoSettings.playbackSpeed' => 'Playback Speed', + 'videoSettings.sleepTimer' => 'Sleep Timer', + 'videoSettings.audioSync' => 'Audio Sync', + 'videoSettings.subtitleSync' => 'Subtitle Sync', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => 'Audio Output', + 'videoSettings.performanceOverlay' => 'Performance Overlay', _ => null, }; } diff --git a/lib/i18n/strings_es.g.dart b/lib/i18n/strings_es.g.dart index b3f93d63..9d4ab06f 100644 --- a/lib/i18n/strings_es.g.dart +++ b/lib/i18n/strings_es.g.dart @@ -70,6 +70,8 @@ class TranslationsEs with BaseTranslations implements T @override late final _TranslationsWatchTogetherEs watchTogether = _TranslationsWatchTogetherEs._(_root); @override late final _TranslationsDownloadsEs downloads = _TranslationsDownloadsEs._(_root); @override late final _TranslationsShadersEs shaders = _TranslationsShadersEs._(_root); + @override late final _TranslationsCompanionRemoteEs companionRemote = _TranslationsCompanionRemoteEs._(_root); + @override late final _TranslationsVideoSettingsEs videoSettings = _TranslationsVideoSettingsEs._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppEs implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => 'Cargando...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthEs implements TranslationsAuthEn { // Translations @override String get signInWithPlex => 'Inicia sesión con Plex'; @override String get showQRCode => 'Mostrar código QR'; - @override String get cancel => 'Cancelar'; @override String get authenticate => 'Autenticar'; - @override String get retry => 'Reintentar'; @override String get debugEnterToken => 'Debug: Ingresar Token de Plex'; @override String get plexTokenLabel => 'Token de Autenticación de Plex'; @override String get plexTokenHint => 'Ingresa tu token de Plex.tv'; @@ -128,6 +127,21 @@ class _TranslationsCommonEs implements TranslationsCommonEn { @override String get delete => 'Eliminar'; @override String get shuffle => 'Aleatorio'; @override String get addTo => 'Añadir a...'; + @override String get remove => 'Eliminar'; + @override String get paste => 'Pegar'; + @override String get connect => 'Conectar'; + @override String get disconnect => 'Desconectar'; + @override String get play => 'Reproducir'; + @override String get pause => 'Pausa'; + @override String get resume => 'Reanudar'; + @override String get error => 'Error'; + @override String get search => 'Buscar'; + @override String get home => 'Inicio'; + @override String get back => 'Atrás'; + @override String get settings => 'Ajustes'; + @override String get mute => 'Silencio'; + @override String get ok => 'OK'; + @override String get loading => 'Cargando...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensEs implements TranslationsScreensEn { @override String get switchProfile => 'Cambiar Perfil'; @override String get subtitleStyling => 'Estilo de Subtítulos'; @override String get mpvConfig => 'Configuración de MPV'; - @override String get search => 'Buscar'; @override String get logs => 'Logs'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsEs implements TranslationsVideoControlsEn { @override String get timelineSlider => 'Línea de tiempo del video'; @override String get volumeSlider => 'Nivel de volumen'; @override String endsAt({required Object time}) => 'Termina a las ${time}'; - @override String get backButton => 'Atrás'; @override String get pipFailed => 'Error al iniciar Imagen en Imagen'; @override late final _TranslationsVideoControlsPipErrorsEs pipErrors = _TranslationsVideoControlsPipErrorsEs._(_root); + @override String get chapters => 'Capítulos'; + @override String get noChaptersAvailable => 'No hay capítulos disponibles'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogEs implements TranslationsDialogEn { // Translations @override String get confirmAction => 'Confirmar Acción'; - @override String get cancel => 'Cancelar'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverEs implements TranslationsDiscoverEn { // Translations @override String get title => 'Descubrir'; @override String get switchProfile => 'Cambiar Perfil'; - @override String get logout => 'Cerrar sesión'; @override String get noContentAvailable => 'No hay contenido disponible'; @override String get addMediaToLibraries => 'Añade contenido a tus bibliotecas'; @override String get continueWatching => 'Seguir Viendo'; - @override String get play => 'Reproducir'; @override String playEpisode({required Object season, required Object episode}) => 'T${season}E${episode}'; - @override String get pause => 'Pausa'; @override String get overview => 'Resumen'; @override String get cast => 'Reparto'; @override String get seasons => 'Temporadas'; @@ -748,10 +758,7 @@ class _TranslationsNavigationEs implements TranslationsNavigationEn { final TranslationsEs _root; // ignore: unused_field // Translations - @override String get home => 'Inicio'; - @override String get search => 'Buscar'; @override String get libraries => 'Bibliotecas'; - @override String get settings => 'Configuración'; @override String get downloads => 'Descargas'; } @@ -893,6 +900,10 @@ class _TranslationsDownloadsEs implements TranslationsDownloadsEn { @override String get downloadDeleted => 'Descarga eliminada'; @override String deleteConfirm({required Object title}) => '¿Estás seguro de que quieres eliminar "${title}"? Esto borrará el archivo descargado de tu dispositivo.'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => 'Eliminando ${title}... (${current} de ${total})'; + @override String get noDownloadsTree => 'Sin descargas'; + @override String get pauseAll => 'Pausar todo'; + @override String get resumeAll => 'Reanudar todo'; + @override String get deleteAll => 'Eliminar todo'; } // Path: shaders @@ -910,6 +921,42 @@ class _TranslationsShadersEs implements TranslationsShadersEn { @override String get mode => 'Modo'; } +// Path: companionRemote +class _TranslationsCompanionRemoteEs implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => 'Conectar a dispositivo'; + @override String get hostRemoteSession => 'Iniciar sesión remota'; + @override String get controlThisDevice => 'Controla este dispositivo con tu teléfono'; + @override String get remoteControl => 'Control remoto'; + @override String get controlDesktop => 'Controlar un dispositivo de escritorio'; + @override String connectedTo({required Object name}) => 'Conectado a ${name}'; + @override late final _TranslationsCompanionRemoteSessionEs session = _TranslationsCompanionRemoteSessionEs._(_root); + @override late final _TranslationsCompanionRemotePairingEs pairing = _TranslationsCompanionRemotePairingEs._(_root); + @override late final _TranslationsCompanionRemoteRemoteEs remote = _TranslationsCompanionRemoteRemoteEs._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsEs implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => 'Ajustes de reproducción'; + @override String get playbackSpeed => 'Velocidad de reproducción'; + @override String get sleepTimer => 'Temporizador de apagado'; + @override String get audioSync => 'Sincronización de audio'; + @override String get subtitleSync => 'Sincronización de subtítulos'; + @override String get hdr => 'HDR'; + @override String get audioOutput => 'Salida de audio'; + @override String get performanceOverlay => 'Indicador de rendimiento'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsEs implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsEs._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsEs implements TranslationsHotkeysActionsEn { @override String get subSeekNext => 'Ir al Siguiente Subtítulo'; @override String get subSeekPrev => 'Ir al Anterior Subtítulo'; @override String get shaderToggle => 'Alternar Shaders'; + @override String get skipMarker => 'Saltar Intro/Créditos'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsEs implements TranslationsLibrariesGrouping @override String get folders => 'Carpetas'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionEs implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get creatingSession => 'Creando sesión remota...'; + @override String get failedToCreate => 'Error al crear la sesión remota:'; + @override String get noSession => 'No hay sesión disponible'; + @override String get scanQrCode => 'Escanear código QR'; + @override String get orEnterManually => 'O introducir manualmente'; + @override String get hostAddress => 'Dirección del host'; + @override String get sessionId => 'ID de sesión'; + @override String get pin => 'PIN'; + @override String get connected => 'Conectado'; + @override String get waitingForConnection => 'Esperando conexión...'; + @override String get usePhoneToControl => 'Usa tu dispositivo móvil para controlar esta app'; + @override String copiedToClipboard({required Object label}) => '${label} copiado al portapapeles'; + @override String get copyToClipboard => 'Copiar al portapapeles'; + @override String get newSession => 'Nueva sesión'; + @override String get minimize => 'Minimizar'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingEs implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get recent => 'Recientes'; + @override String get scan => 'Escanear'; + @override String get manual => 'Manual'; + @override String get recentConnections => 'Conexiones recientes'; + @override String get quickReconnect => 'Reconectar rápidamente con dispositivos emparejados anteriormente'; + @override String get pairWithDesktop => 'Emparejar con escritorio'; + @override String get enterSessionDetails => 'Introduce los datos de la sesión que aparecen en tu dispositivo de escritorio'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => 'Introduce ID de sesión de 8 caracteres'; + @override String get pinHint => 'Introduce PIN de 6 dígitos'; + @override String get connecting => 'Conectando...'; + @override String get tips => 'Consejos'; + @override String get tipDesktop => 'Abre Plezy en tu escritorio y activa Companion Remote desde los ajustes o el menú'; + @override String get tipScan => 'Usa la pestaña Escanear para emparejar rápidamente escaneando el código QR de tu escritorio'; + @override String get tipWifi => 'Asegúrate de que ambos dispositivos estén en la misma red WiFi'; + @override String get cameraPermissionRequired => 'Se necesita permiso de cámara para escanear códigos QR.\nPor favor, concede acceso a la cámara en los ajustes de tu dispositivo.'; + @override String cameraError({required Object error}) => 'No se pudo iniciar la cámara: ${error}'; + @override String get scanInstruction => 'Apunta tu cámara al código QR que aparece en tu escritorio'; + @override String get noRecentConnections => 'No hay conexiones recientes'; + @override String get connectUsingManual => 'Conéctate a un dispositivo usando la entrada manual para empezar'; + @override String get invalidQrCode => 'Formato de código QR no válido'; + @override String get removeRecentConnection => 'Eliminar conexión reciente'; + @override String removeConfirm({required Object name}) => '¿Eliminar "${name}" de las conexiones recientes?'; + @override String get validationHostRequired => 'Por favor, introduce la dirección del host'; + @override String get validationHostFormat => 'El formato debe ser IP:puerto (ej., 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => 'Por favor, introduce un ID de sesión'; + @override String get validationSessionIdLength => 'El ID de sesión debe tener 8 caracteres'; + @override String get validationPinRequired => 'Por favor, introduce un PIN'; + @override String get validationPinLength => 'El PIN debe tener 6 dígitos'; + @override String get connectionTimedOut => 'Tiempo de conexión agotado. Verifica el ID de sesión y el PIN.'; + @override String get sessionNotFound => 'No se encontró la sesión. Verifica tus credenciales.'; + @override String failedToConnect({required Object error}) => 'Error al conectar: ${error}'; + @override String failedToLoadRecent({required Object error}) => 'Error al cargar sesiones recientes: ${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteEs implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => '¿Quieres desconectarte de la sesión remota?'; + @override String get reconnecting => 'Reconectando...'; + @override String attemptOf({required Object current}) => 'Intento ${current} de 5'; + @override String get retryNow => 'Reintentar ahora'; + @override String get connectionError => 'Error de conexión'; + @override String get notConnected => 'No conectado'; + @override String get tabRemote => 'Remoto'; + @override String get tabPlay => 'Reproducir'; + @override String get tabMore => 'Más'; + @override String get menu => 'Menú'; + @override String get tabNavigation => 'Navegación por pestañas'; + @override String get tabDiscover => 'Descubrir'; + @override String get tabLibraries => 'Bibliotecas'; + @override String get tabSearch => 'Buscar'; + @override String get tabDownloads => 'Descargas'; + @override String get tabSettings => 'Configuración'; + @override String get previous => 'Anterior'; + @override String get playPause => 'Reproducir/Pausar'; + @override String get next => 'Siguiente'; + @override String get seekBack => 'Retroceder'; + @override String get stop => 'Detener'; + @override String get seekForward => 'Avanzar'; + @override String get volume => 'Volumen'; + @override String get volumeDown => 'Bajar'; + @override String get volumeUp => 'Subir'; + @override String get fullscreen => 'Pantalla completa'; + @override String get subtitles => 'Subtítulos'; + @override String get audio => 'Audio'; + @override String get searchHint => 'Buscar en escritorio...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsEs { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => 'Cargando...', 'auth.signInWithPlex' => 'Inicia sesión con Plex', 'auth.showQRCode' => 'Mostrar código QR', - 'auth.cancel' => 'Cancelar', 'auth.authenticate' => 'Autenticar', - 'auth.retry' => 'Reintentar', 'auth.debugEnterToken' => 'Debug: Ingresar Token de Plex', 'auth.plexTokenLabel' => 'Token de Autenticación de Plex', 'auth.plexTokenHint' => 'Ingresa tu token de Plex.tv', @@ -1018,11 +1167,25 @@ extension on TranslationsEs { 'common.delete' => 'Eliminar', 'common.shuffle' => 'Aleatorio', 'common.addTo' => 'Añadir a...', + 'common.remove' => 'Eliminar', + 'common.paste' => 'Pegar', + 'common.connect' => 'Conectar', + 'common.disconnect' => 'Desconectar', + 'common.play' => 'Reproducir', + 'common.pause' => 'Pausa', + 'common.resume' => 'Reanudar', + 'common.error' => 'Error', + 'common.search' => 'Buscar', + 'common.home' => 'Inicio', + 'common.back' => 'Atrás', + 'common.settings' => 'Ajustes', + 'common.mute' => 'Silencio', + 'common.ok' => 'OK', + 'common.loading' => 'Cargando...', 'screens.licenses' => 'Licencias', 'screens.switchProfile' => 'Cambiar Perfil', 'screens.subtitleStyling' => 'Estilo de Subtítulos', 'screens.mpvConfig' => 'Configuración de MPV', - 'screens.search' => 'Buscar', 'screens.logs' => 'Logs', 'update.available' => 'Actualización disponible', 'update.versionAvailable' => ({required Object version}) => 'Versión ${version} disponible', @@ -1176,6 +1339,7 @@ extension on TranslationsEs { 'hotkeys.actions.subSeekNext' => 'Ir al Siguiente Subtítulo', 'hotkeys.actions.subSeekPrev' => 'Ir al Anterior Subtítulo', 'hotkeys.actions.shaderToggle' => 'Alternar Shaders', + 'hotkeys.actions.skipMarker' => 'Saltar Intro/Créditos', 'pinEntry.enterPin' => 'Introduce el PIN', 'pinEntry.showPin' => 'Mostrar PIN', 'pinEntry.hidePin' => 'Ocultar PIN', @@ -1266,13 +1430,14 @@ extension on TranslationsEs { 'videoControls.timelineSlider' => 'Línea de tiempo del video', 'videoControls.volumeSlider' => 'Nivel de volumen', 'videoControls.endsAt' => ({required Object time}) => 'Termina a las ${time}', - 'videoControls.backButton' => 'Atrás', 'videoControls.pipFailed' => 'Error al iniciar Imagen en Imagen', 'videoControls.pipErrors.androidVersion' => 'Requiere Android 8.0 o más reciente', 'videoControls.pipErrors.permissionDisabled' => 'El permiso de Imagen en Imagen está desactivado. Actívalo en Ajustes > Aplicaciones > Plezy > Imagen en Imagen', 'videoControls.pipErrors.notSupported' => 'El dispositivo no soporta el modo Imagen en Imagen', 'videoControls.pipErrors.failed' => 'Error al iniciar Imagen en Imagen', 'videoControls.pipErrors.unknown' => ({required Object error}) => 'Ocurrió un error: ${error}', + 'videoControls.chapters' => 'Capítulos', + 'videoControls.noChaptersAvailable' => 'No hay capítulos disponibles', 'userStatus.admin' => 'Administrador', 'userStatus.restricted' => 'Restringido', 'userStatus.protected' => 'Protegido', @@ -1343,16 +1508,12 @@ extension on TranslationsEs { 'mpvConfig.confirmDeleteProperty' => '¿Estás seguro de que quieres eliminar esta propiedad?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} entradas', 'dialog.confirmAction' => 'Confirmar Acción', - 'dialog.cancel' => 'Cancelar', 'discover.title' => 'Descubrir', 'discover.switchProfile' => 'Cambiar Perfil', - 'discover.logout' => 'Cerrar sesión', 'discover.noContentAvailable' => 'No hay contenido disponible', 'discover.addMediaToLibraries' => 'Añade contenido a tus bibliotecas', 'discover.continueWatching' => 'Seguir Viendo', - 'discover.play' => 'Reproducir', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'T${season}E${episode}', - 'discover.pause' => 'Pausa', 'discover.overview' => 'Resumen', 'discover.cast' => 'Reparto', 'discover.seasons' => 'Temporadas', @@ -1442,10 +1603,7 @@ extension on TranslationsEs { 'licenses.license' => 'Licencia', 'licenses.licenseNumber' => ({required Object number}) => 'Licencia ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} licencias', - 'navigation.home' => 'Inicio', - 'navigation.search' => 'Buscar', 'navigation.libraries' => 'Bibliotecas', - 'navigation.settings' => 'Configuración', 'navigation.downloads' => 'Descargas', 'collections.title' => 'Colecciones', 'collections.collection' => 'Colección', @@ -1493,14 +1651,14 @@ extension on TranslationsEs { 'playlists.errorDeleting' => 'Error al eliminar la lista', 'playlists.errorLoading' => 'Error al cargar las listas', 'playlists.errorAdding' => 'Error al añadir a la lista', + _ => null, + } ?? switch (path) { 'playlists.errorReordering' => 'Error al reordenar los elementos de la lista', 'playlists.errorRemoving' => 'Error al eliminar de la lista', 'watchTogether.title' => 'Ver Juntos', 'watchTogether.description' => 'Mira contenido en sincronía con amigos y familiares', 'watchTogether.createSession' => 'Crear Sesión', 'watchTogether.creating' => 'Creando...', - _ => null, - } ?? switch (path) { 'watchTogether.joinSession' => 'Unirse a Sesión', 'watchTogether.joining' => 'Uniendo...', 'watchTogether.controlMode' => 'Modo de Control', @@ -1553,12 +1711,108 @@ extension on TranslationsEs { 'downloads.downloadDeleted' => 'Descarga eliminada', 'downloads.deleteConfirm' => ({required Object title}) => '¿Estás seguro de que quieres eliminar "${title}"? Esto borrará el archivo descargado de tu dispositivo.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => 'Eliminando ${title}... (${current} de ${total})', + 'downloads.noDownloadsTree' => 'Sin descargas', + 'downloads.pauseAll' => 'Pausar todo', + 'downloads.resumeAll' => 'Reanudar todo', + 'downloads.deleteAll' => 'Eliminar todo', 'shaders.title' => 'Shaders', 'shaders.noShaderDescription' => 'Sin mejora de video', 'shaders.nvscalerDescription' => 'Escalado de imagen NVIDIA para un video más nítido', 'shaders.qualityFast' => 'Rápido', 'shaders.qualityHQ' => 'Alta Calidad', 'shaders.mode' => 'Modo', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => 'Conectar a dispositivo', + 'companionRemote.hostRemoteSession' => 'Iniciar sesión remota', + 'companionRemote.controlThisDevice' => 'Controla este dispositivo con tu teléfono', + 'companionRemote.remoteControl' => 'Control remoto', + 'companionRemote.controlDesktop' => 'Controlar un dispositivo de escritorio', + 'companionRemote.connectedTo' => ({required Object name}) => 'Conectado a ${name}', + 'companionRemote.session.creatingSession' => 'Creando sesión remota...', + 'companionRemote.session.failedToCreate' => 'Error al crear la sesión remota:', + 'companionRemote.session.noSession' => 'No hay sesión disponible', + 'companionRemote.session.scanQrCode' => 'Escanear código QR', + 'companionRemote.session.orEnterManually' => 'O introducir manualmente', + 'companionRemote.session.hostAddress' => 'Dirección del host', + 'companionRemote.session.sessionId' => 'ID de sesión', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => 'Conectado', + 'companionRemote.session.waitingForConnection' => 'Esperando conexión...', + 'companionRemote.session.usePhoneToControl' => 'Usa tu dispositivo móvil para controlar esta app', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label} copiado al portapapeles', + 'companionRemote.session.copyToClipboard' => 'Copiar al portapapeles', + 'companionRemote.session.newSession' => 'Nueva sesión', + 'companionRemote.session.minimize' => 'Minimizar', + 'companionRemote.pairing.recent' => 'Recientes', + 'companionRemote.pairing.scan' => 'Escanear', + 'companionRemote.pairing.manual' => 'Manual', + 'companionRemote.pairing.recentConnections' => 'Conexiones recientes', + 'companionRemote.pairing.quickReconnect' => 'Reconectar rápidamente con dispositivos emparejados anteriormente', + 'companionRemote.pairing.pairWithDesktop' => 'Emparejar con escritorio', + 'companionRemote.pairing.enterSessionDetails' => 'Introduce los datos de la sesión que aparecen en tu dispositivo de escritorio', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => 'Introduce ID de sesión de 8 caracteres', + 'companionRemote.pairing.pinHint' => 'Introduce PIN de 6 dígitos', + 'companionRemote.pairing.connecting' => 'Conectando...', + 'companionRemote.pairing.tips' => 'Consejos', + 'companionRemote.pairing.tipDesktop' => 'Abre Plezy en tu escritorio y activa Companion Remote desde los ajustes o el menú', + 'companionRemote.pairing.tipScan' => 'Usa la pestaña Escanear para emparejar rápidamente escaneando el código QR de tu escritorio', + 'companionRemote.pairing.tipWifi' => 'Asegúrate de que ambos dispositivos estén en la misma red WiFi', + 'companionRemote.pairing.cameraPermissionRequired' => 'Se necesita permiso de cámara para escanear códigos QR.\nPor favor, concede acceso a la cámara en los ajustes de tu dispositivo.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => 'No se pudo iniciar la cámara: ${error}', + 'companionRemote.pairing.scanInstruction' => 'Apunta tu cámara al código QR que aparece en tu escritorio', + 'companionRemote.pairing.noRecentConnections' => 'No hay conexiones recientes', + 'companionRemote.pairing.connectUsingManual' => 'Conéctate a un dispositivo usando la entrada manual para empezar', + 'companionRemote.pairing.invalidQrCode' => 'Formato de código QR no válido', + 'companionRemote.pairing.removeRecentConnection' => 'Eliminar conexión reciente', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => '¿Eliminar "${name}" de las conexiones recientes?', + 'companionRemote.pairing.validationHostRequired' => 'Por favor, introduce la dirección del host', + 'companionRemote.pairing.validationHostFormat' => 'El formato debe ser IP:puerto (ej., 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => 'Por favor, introduce un ID de sesión', + 'companionRemote.pairing.validationSessionIdLength' => 'El ID de sesión debe tener 8 caracteres', + 'companionRemote.pairing.validationPinRequired' => 'Por favor, introduce un PIN', + 'companionRemote.pairing.validationPinLength' => 'El PIN debe tener 6 dígitos', + 'companionRemote.pairing.connectionTimedOut' => 'Tiempo de conexión agotado. Verifica el ID de sesión y el PIN.', + 'companionRemote.pairing.sessionNotFound' => 'No se encontró la sesión. Verifica tus credenciales.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => 'Error al conectar: ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => 'Error al cargar sesiones recientes: ${error}', + 'companionRemote.remote.disconnectConfirm' => '¿Quieres desconectarte de la sesión remota?', + 'companionRemote.remote.reconnecting' => 'Reconectando...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => 'Intento ${current} de 5', + 'companionRemote.remote.retryNow' => 'Reintentar ahora', + 'companionRemote.remote.connectionError' => 'Error de conexión', + 'companionRemote.remote.notConnected' => 'No conectado', + 'companionRemote.remote.tabRemote' => 'Remoto', + 'companionRemote.remote.tabPlay' => 'Reproducir', + 'companionRemote.remote.tabMore' => 'Más', + 'companionRemote.remote.menu' => 'Menú', + 'companionRemote.remote.tabNavigation' => 'Navegación por pestañas', + 'companionRemote.remote.tabDiscover' => 'Descubrir', + 'companionRemote.remote.tabLibraries' => 'Bibliotecas', + 'companionRemote.remote.tabSearch' => 'Buscar', + 'companionRemote.remote.tabDownloads' => 'Descargas', + 'companionRemote.remote.tabSettings' => 'Configuración', + 'companionRemote.remote.previous' => 'Anterior', + 'companionRemote.remote.playPause' => 'Reproducir/Pausar', + 'companionRemote.remote.next' => 'Siguiente', + 'companionRemote.remote.seekBack' => 'Retroceder', + 'companionRemote.remote.stop' => 'Detener', + 'companionRemote.remote.seekForward' => 'Avanzar', + 'companionRemote.remote.volume' => 'Volumen', + 'companionRemote.remote.volumeDown' => 'Bajar', + 'companionRemote.remote.volumeUp' => 'Subir', + 'companionRemote.remote.fullscreen' => 'Pantalla completa', + 'companionRemote.remote.subtitles' => 'Subtítulos', + 'companionRemote.remote.audio' => 'Audio', + 'companionRemote.remote.searchHint' => 'Buscar en escritorio...', + 'videoSettings.playbackSettings' => 'Ajustes de reproducción', + 'videoSettings.playbackSpeed' => 'Velocidad de reproducción', + 'videoSettings.sleepTimer' => 'Temporizador de apagado', + 'videoSettings.audioSync' => 'Sincronización de audio', + 'videoSettings.subtitleSync' => 'Sincronización de subtítulos', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => 'Salida de audio', + 'videoSettings.performanceOverlay' => 'Indicador de rendimiento', _ => null, }; } diff --git a/lib/i18n/strings_fr.g.dart b/lib/i18n/strings_fr.g.dart index f0d26140..0a94a75e 100644 --- a/lib/i18n/strings_fr.g.dart +++ b/lib/i18n/strings_fr.g.dart @@ -70,6 +70,8 @@ class TranslationsFr with BaseTranslations implements T @override late final _TranslationsWatchTogetherFr watchTogether = _TranslationsWatchTogetherFr._(_root); @override late final _TranslationsDownloadsFr downloads = _TranslationsDownloadsFr._(_root); @override late final _TranslationsShadersFr shaders = _TranslationsShadersFr._(_root); + @override late final _TranslationsCompanionRemoteFr companionRemote = _TranslationsCompanionRemoteFr._(_root); + @override late final _TranslationsVideoSettingsFr videoSettings = _TranslationsVideoSettingsFr._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppFr implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => 'Chargement...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthFr implements TranslationsAuthEn { // Translations @override String get signInWithPlex => 'S\'inscrire avec Plex'; @override String get showQRCode => 'Afficher le QR Code'; - @override String get cancel => 'Annuler'; @override String get authenticate => 'S\'authentifier'; - @override String get retry => 'Réessayer'; @override String get debugEnterToken => 'Debug: Entrez votre token Plex'; @override String get plexTokenLabel => 'Token d\'authentification Plex'; @override String get plexTokenHint => 'Entrez votre token Plex.tv'; @@ -128,6 +127,21 @@ class _TranslationsCommonFr implements TranslationsCommonEn { @override String get delete => 'Supprimer'; @override String get shuffle => 'Mélanger'; @override String get addTo => 'Ajouter à...'; + @override String get remove => 'Supprimer'; + @override String get paste => 'Coller'; + @override String get connect => 'Connecter'; + @override String get disconnect => 'Déconnecter'; + @override String get play => 'Lire'; + @override String get pause => 'Pause'; + @override String get resume => 'Reprendre'; + @override String get error => 'Erreur'; + @override String get search => 'Recherche'; + @override String get home => 'Accueil'; + @override String get back => 'Retour'; + @override String get settings => 'Paramètres'; + @override String get mute => 'Muet'; + @override String get ok => 'OK'; + @override String get loading => 'Chargement...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensFr implements TranslationsScreensEn { @override String get switchProfile => 'Changer de profil'; @override String get subtitleStyling => 'Configuration des sous-titres'; @override String get mpvConfig => 'Configuration MPV'; - @override String get search => 'Recherche'; @override String get logs => 'Logs'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsFr implements TranslationsVideoControlsEn { @override String get timelineSlider => 'Timeline vidéo'; @override String get volumeSlider => 'Niveau sonore'; @override String endsAt({required Object time}) => 'Fin à ${time}'; - @override String get backButton => 'Retour'; @override String get pipFailed => 'Échec du démarrage du mode image dans l\'image'; @override late final _TranslationsVideoControlsPipErrorsFr pipErrors = _TranslationsVideoControlsPipErrorsFr._(_root); + @override String get chapters => 'Chapitres'; + @override String get noChaptersAvailable => 'Aucun chapitre disponible'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogFr implements TranslationsDialogEn { // Translations @override String get confirmAction => 'Confirmer l\'action'; - @override String get cancel => 'Annuler'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverFr implements TranslationsDiscoverEn { // Translations @override String get title => 'Découvrez'; @override String get switchProfile => 'Changer de profil'; - @override String get logout => 'Déconnexion'; @override String get noContentAvailable => 'Aucun contenu disponible'; @override String get addMediaToLibraries => 'Ajoutez des médias à votre bibliothèque'; @override String get continueWatching => 'Continuer à regarder'; - @override String get play => 'Lire'; @override String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - @override String get pause => 'Pause'; @override String get overview => 'Aperçu'; @override String get cast => 'Cast'; @override String get seasons => 'Saisons'; @@ -748,10 +758,7 @@ class _TranslationsNavigationFr implements TranslationsNavigationEn { final TranslationsFr _root; // ignore: unused_field // Translations - @override String get home => 'Accueil'; - @override String get search => 'Rechercher'; @override String get libraries => 'Bibliothèques'; - @override String get settings => 'Paramètres'; @override String get downloads => 'Téléchargements'; } @@ -893,6 +900,10 @@ class _TranslationsDownloadsFr implements TranslationsDownloadsEn { @override String get downloadDeleted => 'Télécharger supprimé'; @override String deleteConfirm({required Object title}) => 'Êtes-vous sûr de vouloir supprimer "${title}" ? Cela supprimera le fichier téléchargé de votre appareil.'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => 'Suppression de ${title}... (${current} sur ${total})'; + @override String get noDownloadsTree => 'Aucun téléchargement'; + @override String get pauseAll => 'Tout mettre en pause'; + @override String get resumeAll => 'Tout reprendre'; + @override String get deleteAll => 'Tout supprimer'; } // Path: shaders @@ -910,6 +921,42 @@ class _TranslationsShadersFr implements TranslationsShadersEn { @override String get mode => 'Mode'; } +// Path: companionRemote +class _TranslationsCompanionRemoteFr implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteFr._(this._root); + + final TranslationsFr _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => 'Se connecter à un appareil'; + @override String get hostRemoteSession => 'Héberger une session distante'; + @override String get controlThisDevice => 'Contrôlez cet appareil avec votre téléphone'; + @override String get remoteControl => 'Télécommande'; + @override String get controlDesktop => 'Contrôler un appareil de bureau'; + @override String connectedTo({required Object name}) => 'Connecté à ${name}'; + @override late final _TranslationsCompanionRemoteSessionFr session = _TranslationsCompanionRemoteSessionFr._(_root); + @override late final _TranslationsCompanionRemotePairingFr pairing = _TranslationsCompanionRemotePairingFr._(_root); + @override late final _TranslationsCompanionRemoteRemoteFr remote = _TranslationsCompanionRemoteRemoteFr._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsFr implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsFr._(this._root); + + final TranslationsFr _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => 'Paramètres de lecture'; + @override String get playbackSpeed => 'Vitesse de lecture'; + @override String get sleepTimer => 'Minuterie de mise en veille'; + @override String get audioSync => 'Synchronisation audio'; + @override String get subtitleSync => 'Synchronisation des sous-titres'; + @override String get hdr => 'HDR'; + @override String get audioOutput => 'Sortie audio'; + @override String get performanceOverlay => 'Superposition de performance'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsFr implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsFr._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsFr implements TranslationsHotkeysActionsEn { @override String get subSeekNext => 'Rechercher le sous-titre suivant'; @override String get subSeekPrev => 'Rechercher le sous-titre précédent'; @override String get shaderToggle => 'Activer/désactiver les shaders'; + @override String get skipMarker => 'Passer l\'intro/le générique'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsFr implements TranslationsLibrariesGrouping @override String get folders => 'Dossiers'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionFr implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionFr._(this._root); + + final TranslationsFr _root; // ignore: unused_field + + // Translations + @override String get creatingSession => 'Création de la session distante...'; + @override String get failedToCreate => 'Échec de la création de la session distante :'; + @override String get noSession => 'Aucune session disponible'; + @override String get scanQrCode => 'Scanner le QR Code'; + @override String get orEnterManually => 'Ou saisir manuellement'; + @override String get hostAddress => 'Adresse de l\'hôte'; + @override String get sessionId => 'ID de session'; + @override String get pin => 'PIN'; + @override String get connected => 'Connecté'; + @override String get waitingForConnection => 'En attente de connexion...'; + @override String get usePhoneToControl => 'Utilisez votre appareil mobile pour contrôler cette application'; + @override String copiedToClipboard({required Object label}) => '${label} copié dans le presse-papiers'; + @override String get copyToClipboard => 'Copier dans le presse-papiers'; + @override String get newSession => 'Nouvelle session'; + @override String get minimize => 'Réduire'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingFr implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingFr._(this._root); + + final TranslationsFr _root; // ignore: unused_field + + // Translations + @override String get recent => 'Récents'; + @override String get scan => 'Scanner'; + @override String get manual => 'Manuel'; + @override String get recentConnections => 'Connexions récentes'; + @override String get quickReconnect => 'Reconnexion rapide aux appareils précédemment jumelés'; + @override String get pairWithDesktop => 'Jumeler avec un bureau'; + @override String get enterSessionDetails => 'Saisissez les détails de la session affichés sur votre appareil de bureau'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => 'Saisissez l\'ID de session à 8 caractères'; + @override String get pinHint => 'Saisissez le PIN à 6 chiffres'; + @override String get connecting => 'Connexion...'; + @override String get tips => 'Conseils'; + @override String get tipDesktop => 'Ouvrez Plezy sur votre bureau et activez Companion Remote depuis les paramètres ou le menu'; + @override String get tipScan => 'Utilisez l\'onglet Scanner pour jumeler rapidement en scannant le QR code sur votre bureau'; + @override String get tipWifi => 'Assurez-vous que les deux appareils sont sur le même réseau WiFi'; + @override String get cameraPermissionRequired => 'L\'autorisation de la caméra est requise pour scanner les QR codes.\nVeuillez accorder l\'accès à la caméra dans les paramètres de votre appareil.'; + @override String cameraError({required Object error}) => 'Impossible de démarrer la caméra : ${error}'; + @override String get scanInstruction => 'Pointez votre caméra vers le QR code affiché sur votre bureau'; + @override String get noRecentConnections => 'Aucune connexion récente'; + @override String get connectUsingManual => 'Connectez-vous à un appareil via la saisie manuelle pour commencer'; + @override String get invalidQrCode => 'Format de QR code invalide'; + @override String get removeRecentConnection => 'Supprimer la connexion récente'; + @override String removeConfirm({required Object name}) => 'Supprimer "${name}" des connexions récentes ?'; + @override String get validationHostRequired => 'Veuillez saisir l\'adresse de l\'hôte'; + @override String get validationHostFormat => 'Le format doit être IP:port (ex : 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => 'Veuillez saisir un ID de session'; + @override String get validationSessionIdLength => 'L\'ID de session doit contenir 8 caractères'; + @override String get validationPinRequired => 'Veuillez saisir un PIN'; + @override String get validationPinLength => 'Le PIN doit contenir 6 chiffres'; + @override String get connectionTimedOut => 'Délai de connexion expiré. Veuillez vérifier l\'ID de session et le PIN.'; + @override String get sessionNotFound => 'Session introuvable. Veuillez vérifier vos identifiants.'; + @override String failedToConnect({required Object error}) => 'Échec de la connexion : ${error}'; + @override String failedToLoadRecent({required Object error}) => 'Échec du chargement des sessions récentes : ${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteFr implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteFr._(this._root); + + final TranslationsFr _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => 'Voulez-vous vous déconnecter de la session distante ?'; + @override String get reconnecting => 'Reconnexion...'; + @override String attemptOf({required Object current}) => 'Tentative ${current} sur 5'; + @override String get retryNow => 'Réessayer maintenant'; + @override String get connectionError => 'Erreur de connexion'; + @override String get notConnected => 'Non connecté'; + @override String get tabRemote => 'Télécommande'; + @override String get tabPlay => 'Lecture'; + @override String get tabMore => 'Plus'; + @override String get menu => 'Menu'; + @override String get tabNavigation => 'Navigation par onglets'; + @override String get tabDiscover => 'Découvrir'; + @override String get tabLibraries => 'Bibliothèques'; + @override String get tabSearch => 'Rechercher'; + @override String get tabDownloads => 'Téléchargements'; + @override String get tabSettings => 'Paramètres'; + @override String get previous => 'Précédent'; + @override String get playPause => 'Lecture/Pause'; + @override String get next => 'Suivant'; + @override String get seekBack => 'Reculer'; + @override String get stop => 'Arrêter'; + @override String get seekForward => 'Avancer'; + @override String get volume => 'Volume'; + @override String get volumeDown => 'Baisser'; + @override String get volumeUp => 'Augmenter'; + @override String get fullscreen => 'Plein écran'; + @override String get subtitles => 'Sous-titres'; + @override String get audio => 'Audio'; + @override String get searchHint => 'Rechercher sur le bureau...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsFr { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => 'Chargement...', 'auth.signInWithPlex' => 'S\'inscrire avec Plex', 'auth.showQRCode' => 'Afficher le QR Code', - 'auth.cancel' => 'Annuler', 'auth.authenticate' => 'S\'authentifier', - 'auth.retry' => 'Réessayer', 'auth.debugEnterToken' => 'Debug: Entrez votre token Plex', 'auth.plexTokenLabel' => 'Token d\'authentification Plex', 'auth.plexTokenHint' => 'Entrez votre token Plex.tv', @@ -1018,11 +1167,25 @@ extension on TranslationsFr { 'common.delete' => 'Supprimer', 'common.shuffle' => 'Mélanger', 'common.addTo' => 'Ajouter à...', + 'common.remove' => 'Supprimer', + 'common.paste' => 'Coller', + 'common.connect' => 'Connecter', + 'common.disconnect' => 'Déconnecter', + 'common.play' => 'Lire', + 'common.pause' => 'Pause', + 'common.resume' => 'Reprendre', + 'common.error' => 'Erreur', + 'common.search' => 'Recherche', + 'common.home' => 'Accueil', + 'common.back' => 'Retour', + 'common.settings' => 'Paramètres', + 'common.mute' => 'Muet', + 'common.ok' => 'OK', + 'common.loading' => 'Chargement...', 'screens.licenses' => 'Licenses', 'screens.switchProfile' => 'Changer de profil', 'screens.subtitleStyling' => 'Configuration des sous-titres', 'screens.mpvConfig' => 'Configuration MPV', - 'screens.search' => 'Recherche', 'screens.logs' => 'Logs', 'update.available' => 'Mise à jour disponible', 'update.versionAvailable' => ({required Object version}) => 'Version ${version} disponible', @@ -1176,6 +1339,7 @@ extension on TranslationsFr { 'hotkeys.actions.subSeekNext' => 'Rechercher le sous-titre suivant', 'hotkeys.actions.subSeekPrev' => 'Rechercher le sous-titre précédent', 'hotkeys.actions.shaderToggle' => 'Activer/désactiver les shaders', + 'hotkeys.actions.skipMarker' => 'Passer l\'intro/le générique', 'pinEntry.enterPin' => 'Entrer le code PIN', 'pinEntry.showPin' => 'Afficher le code PIN', 'pinEntry.hidePin' => 'Masquer le code PIN', @@ -1266,13 +1430,14 @@ extension on TranslationsFr { 'videoControls.timelineSlider' => 'Timeline vidéo', 'videoControls.volumeSlider' => 'Niveau sonore', 'videoControls.endsAt' => ({required Object time}) => 'Fin à ${time}', - 'videoControls.backButton' => 'Retour', 'videoControls.pipFailed' => 'Échec du démarrage du mode image dans l\'image', 'videoControls.pipErrors.androidVersion' => 'Nécessite Android 8.0 ou plus récent', 'videoControls.pipErrors.permissionDisabled' => 'L\'autorisation Image dans l\'image est désactivée. Activez-la dans Paramètres > Applications > Plezy > Image dans l\'image', 'videoControls.pipErrors.notSupported' => 'Cet appareil ne prend pas en charge le mode image dans l\'image', 'videoControls.pipErrors.failed' => 'Échec du démarrage du mode image dans l\'image', 'videoControls.pipErrors.unknown' => ({required Object error}) => 'Une erreur s\'est produite : ${error}', + 'videoControls.chapters' => 'Chapitres', + 'videoControls.noChaptersAvailable' => 'Aucun chapitre disponible', 'userStatus.admin' => 'Admin', 'userStatus.restricted' => 'Restreint', 'userStatus.protected' => 'Protégé', @@ -1343,16 +1508,12 @@ extension on TranslationsFr { 'mpvConfig.confirmDeleteProperty' => 'Êtes-vous sûr de vouloir supprimer cette propriété ?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} entrées', 'dialog.confirmAction' => 'Confirmer l\'action', - 'dialog.cancel' => 'Annuler', 'discover.title' => 'Découvrez', 'discover.switchProfile' => 'Changer de profil', - 'discover.logout' => 'Déconnexion', 'discover.noContentAvailable' => 'Aucun contenu disponible', 'discover.addMediaToLibraries' => 'Ajoutez des médias à votre bibliothèque', 'discover.continueWatching' => 'Continuer à regarder', - 'discover.play' => 'Lire', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => 'Pause', 'discover.overview' => 'Aperçu', 'discover.cast' => 'Cast', 'discover.seasons' => 'Saisons', @@ -1442,10 +1603,7 @@ extension on TranslationsFr { 'licenses.license' => 'Licence', 'licenses.licenseNumber' => ({required Object number}) => 'Licence ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} licences', - 'navigation.home' => 'Accueil', - 'navigation.search' => 'Rechercher', 'navigation.libraries' => 'Bibliothèques', - 'navigation.settings' => 'Paramètres', 'navigation.downloads' => 'Téléchargements', 'collections.title' => 'Collections', 'collections.collection' => 'Collection', @@ -1493,14 +1651,14 @@ extension on TranslationsFr { 'playlists.errorDeleting' => 'Échec de suppression de playlist', 'playlists.errorLoading' => 'Échec de chargement de playlists', 'playlists.errorAdding' => 'Échec d\'ajout dans la playlist', + _ => null, + } ?? switch (path) { 'playlists.errorReordering' => 'Échec de réordonnacement d\'élément de playlist', 'playlists.errorRemoving' => 'Échec de suppression depuis la playlist', 'watchTogether.title' => 'Regarder ensemble', 'watchTogether.description' => 'Regardez du contenu en synchronisation avec vos amis et votre famille', 'watchTogether.createSession' => 'Créer une session', 'watchTogether.creating' => 'Création...', - _ => null, - } ?? switch (path) { 'watchTogether.joinSession' => 'Rejoindre la session', 'watchTogether.joining' => 'Rejoindre...', 'watchTogether.controlMode' => 'Mode de contrôle', @@ -1553,12 +1711,108 @@ extension on TranslationsFr { 'downloads.downloadDeleted' => 'Télécharger supprimé', 'downloads.deleteConfirm' => ({required Object title}) => 'Êtes-vous sûr de vouloir supprimer "${title}" ? Cela supprimera le fichier téléchargé de votre appareil.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => 'Suppression de ${title}... (${current} sur ${total})', + 'downloads.noDownloadsTree' => 'Aucun téléchargement', + 'downloads.pauseAll' => 'Tout mettre en pause', + 'downloads.resumeAll' => 'Tout reprendre', + 'downloads.deleteAll' => 'Tout supprimer', 'shaders.title' => 'Shaders', 'shaders.noShaderDescription' => 'Aucune amélioration vidéo', 'shaders.nvscalerDescription' => 'Mise à l\'échelle NVIDIA pour une vidéo plus nette', 'shaders.qualityFast' => 'Rapide', 'shaders.qualityHQ' => 'Haute qualité', 'shaders.mode' => 'Mode', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => 'Se connecter à un appareil', + 'companionRemote.hostRemoteSession' => 'Héberger une session distante', + 'companionRemote.controlThisDevice' => 'Contrôlez cet appareil avec votre téléphone', + 'companionRemote.remoteControl' => 'Télécommande', + 'companionRemote.controlDesktop' => 'Contrôler un appareil de bureau', + 'companionRemote.connectedTo' => ({required Object name}) => 'Connecté à ${name}', + 'companionRemote.session.creatingSession' => 'Création de la session distante...', + 'companionRemote.session.failedToCreate' => 'Échec de la création de la session distante :', + 'companionRemote.session.noSession' => 'Aucune session disponible', + 'companionRemote.session.scanQrCode' => 'Scanner le QR Code', + 'companionRemote.session.orEnterManually' => 'Ou saisir manuellement', + 'companionRemote.session.hostAddress' => 'Adresse de l\'hôte', + 'companionRemote.session.sessionId' => 'ID de session', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => 'Connecté', + 'companionRemote.session.waitingForConnection' => 'En attente de connexion...', + 'companionRemote.session.usePhoneToControl' => 'Utilisez votre appareil mobile pour contrôler cette application', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label} copié dans le presse-papiers', + 'companionRemote.session.copyToClipboard' => 'Copier dans le presse-papiers', + 'companionRemote.session.newSession' => 'Nouvelle session', + 'companionRemote.session.minimize' => 'Réduire', + 'companionRemote.pairing.recent' => 'Récents', + 'companionRemote.pairing.scan' => 'Scanner', + 'companionRemote.pairing.manual' => 'Manuel', + 'companionRemote.pairing.recentConnections' => 'Connexions récentes', + 'companionRemote.pairing.quickReconnect' => 'Reconnexion rapide aux appareils précédemment jumelés', + 'companionRemote.pairing.pairWithDesktop' => 'Jumeler avec un bureau', + 'companionRemote.pairing.enterSessionDetails' => 'Saisissez les détails de la session affichés sur votre appareil de bureau', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => 'Saisissez l\'ID de session à 8 caractères', + 'companionRemote.pairing.pinHint' => 'Saisissez le PIN à 6 chiffres', + 'companionRemote.pairing.connecting' => 'Connexion...', + 'companionRemote.pairing.tips' => 'Conseils', + 'companionRemote.pairing.tipDesktop' => 'Ouvrez Plezy sur votre bureau et activez Companion Remote depuis les paramètres ou le menu', + 'companionRemote.pairing.tipScan' => 'Utilisez l\'onglet Scanner pour jumeler rapidement en scannant le QR code sur votre bureau', + 'companionRemote.pairing.tipWifi' => 'Assurez-vous que les deux appareils sont sur le même réseau WiFi', + 'companionRemote.pairing.cameraPermissionRequired' => 'L\'autorisation de la caméra est requise pour scanner les QR codes.\nVeuillez accorder l\'accès à la caméra dans les paramètres de votre appareil.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => 'Impossible de démarrer la caméra : ${error}', + 'companionRemote.pairing.scanInstruction' => 'Pointez votre caméra vers le QR code affiché sur votre bureau', + 'companionRemote.pairing.noRecentConnections' => 'Aucune connexion récente', + 'companionRemote.pairing.connectUsingManual' => 'Connectez-vous à un appareil via la saisie manuelle pour commencer', + 'companionRemote.pairing.invalidQrCode' => 'Format de QR code invalide', + 'companionRemote.pairing.removeRecentConnection' => 'Supprimer la connexion récente', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => 'Supprimer "${name}" des connexions récentes ?', + 'companionRemote.pairing.validationHostRequired' => 'Veuillez saisir l\'adresse de l\'hôte', + 'companionRemote.pairing.validationHostFormat' => 'Le format doit être IP:port (ex : 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => 'Veuillez saisir un ID de session', + 'companionRemote.pairing.validationSessionIdLength' => 'L\'ID de session doit contenir 8 caractères', + 'companionRemote.pairing.validationPinRequired' => 'Veuillez saisir un PIN', + 'companionRemote.pairing.validationPinLength' => 'Le PIN doit contenir 6 chiffres', + 'companionRemote.pairing.connectionTimedOut' => 'Délai de connexion expiré. Veuillez vérifier l\'ID de session et le PIN.', + 'companionRemote.pairing.sessionNotFound' => 'Session introuvable. Veuillez vérifier vos identifiants.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => 'Échec de la connexion : ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => 'Échec du chargement des sessions récentes : ${error}', + 'companionRemote.remote.disconnectConfirm' => 'Voulez-vous vous déconnecter de la session distante ?', + 'companionRemote.remote.reconnecting' => 'Reconnexion...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => 'Tentative ${current} sur 5', + 'companionRemote.remote.retryNow' => 'Réessayer maintenant', + 'companionRemote.remote.connectionError' => 'Erreur de connexion', + 'companionRemote.remote.notConnected' => 'Non connecté', + 'companionRemote.remote.tabRemote' => 'Télécommande', + 'companionRemote.remote.tabPlay' => 'Lecture', + 'companionRemote.remote.tabMore' => 'Plus', + 'companionRemote.remote.menu' => 'Menu', + 'companionRemote.remote.tabNavigation' => 'Navigation par onglets', + 'companionRemote.remote.tabDiscover' => 'Découvrir', + 'companionRemote.remote.tabLibraries' => 'Bibliothèques', + 'companionRemote.remote.tabSearch' => 'Rechercher', + 'companionRemote.remote.tabDownloads' => 'Téléchargements', + 'companionRemote.remote.tabSettings' => 'Paramètres', + 'companionRemote.remote.previous' => 'Précédent', + 'companionRemote.remote.playPause' => 'Lecture/Pause', + 'companionRemote.remote.next' => 'Suivant', + 'companionRemote.remote.seekBack' => 'Reculer', + 'companionRemote.remote.stop' => 'Arrêter', + 'companionRemote.remote.seekForward' => 'Avancer', + 'companionRemote.remote.volume' => 'Volume', + 'companionRemote.remote.volumeDown' => 'Baisser', + 'companionRemote.remote.volumeUp' => 'Augmenter', + 'companionRemote.remote.fullscreen' => 'Plein écran', + 'companionRemote.remote.subtitles' => 'Sous-titres', + 'companionRemote.remote.audio' => 'Audio', + 'companionRemote.remote.searchHint' => 'Rechercher sur le bureau...', + 'videoSettings.playbackSettings' => 'Paramètres de lecture', + 'videoSettings.playbackSpeed' => 'Vitesse de lecture', + 'videoSettings.sleepTimer' => 'Minuterie de mise en veille', + 'videoSettings.audioSync' => 'Synchronisation audio', + 'videoSettings.subtitleSync' => 'Synchronisation des sous-titres', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => 'Sortie audio', + 'videoSettings.performanceOverlay' => 'Superposition de performance', _ => null, }; } diff --git a/lib/i18n/strings_it.g.dart b/lib/i18n/strings_it.g.dart index e2539916..ad040c3e 100644 --- a/lib/i18n/strings_it.g.dart +++ b/lib/i18n/strings_it.g.dart @@ -70,6 +70,8 @@ class TranslationsIt with BaseTranslations implements T @override late final _TranslationsCollectionsIt collections = _TranslationsCollectionsIt._(_root); @override late final _TranslationsWatchTogetherIt watchTogether = _TranslationsWatchTogetherIt._(_root); @override late final _TranslationsShadersIt shaders = _TranslationsShadersIt._(_root); + @override late final _TranslationsCompanionRemoteIt companionRemote = _TranslationsCompanionRemoteIt._(_root); + @override late final _TranslationsVideoSettingsIt videoSettings = _TranslationsVideoSettingsIt._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppIt implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => 'Caricamento...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthIt implements TranslationsAuthEn { // Translations @override String get signInWithPlex => 'Accedi con Plex'; @override String get showQRCode => 'Mostra QR Code'; - @override String get cancel => 'Cancella'; @override String get authenticate => 'Autenticazione'; - @override String get retry => 'Riprova'; @override String get debugEnterToken => 'Debug: Inserisci Token Plex'; @override String get plexTokenLabel => 'Token Auth Plex'; @override String get plexTokenHint => 'Inserisci il tuo token di Plex.tv'; @@ -128,6 +127,21 @@ class _TranslationsCommonIt implements TranslationsCommonEn { @override String get delete => 'Elimina'; @override String get shuffle => 'Casuale'; @override String get addTo => 'Aggiungi a...'; + @override String get remove => 'Rimuovi'; + @override String get paste => 'Incolla'; + @override String get connect => 'Connetti'; + @override String get disconnect => 'Disconnetti'; + @override String get play => 'Riproduci'; + @override String get pause => 'Pausa'; + @override String get resume => 'Riprendi'; + @override String get error => 'Errore'; + @override String get search => 'Cerca'; + @override String get home => 'Home'; + @override String get back => 'Indietro'; + @override String get settings => 'Impostazioni'; + @override String get mute => 'Muto'; + @override String get ok => 'OK'; + @override String get loading => 'Caricamento...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensIt implements TranslationsScreensEn { @override String get switchProfile => 'Cambia profilo'; @override String get subtitleStyling => 'Stile sottotitoli'; @override String get mpvConfig => 'Configurazione MPV'; - @override String get search => 'Cerca'; @override String get logs => 'Registro'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsIt implements TranslationsVideoControlsEn { @override String get timelineSlider => 'Timeline video'; @override String get volumeSlider => 'Livello volume'; @override String endsAt({required Object time}) => 'Finisce alle ${time}'; - @override String get backButton => 'Indietro'; @override String get pipFailed => 'Impossibile avviare la modalità Picture-in-Picture'; @override late final _TranslationsVideoControlsPipErrorsIt pipErrors = _TranslationsVideoControlsPipErrorsIt._(_root); + @override String get chapters => 'Capitoli'; + @override String get noChaptersAvailable => 'Nessun capitolo disponibile'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogIt implements TranslationsDialogEn { // Translations @override String get confirmAction => 'Conferma azione'; - @override String get cancel => 'Cancella'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverIt implements TranslationsDiscoverEn { // Translations @override String get title => 'Esplora'; @override String get switchProfile => 'Cambia profilo'; - @override String get logout => 'Disconnetti'; @override String get noContentAvailable => 'Nessun contenuto disponibile'; @override String get addMediaToLibraries => 'Aggiungi alcuni file multimediali alle tue librerie'; @override String get continueWatching => 'Continua a guardare'; - @override String get play => 'Riproduci'; @override String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - @override String get pause => 'Pausa'; @override String get overview => 'Panoramica'; @override String get cast => 'Attori'; @override String get seasons => 'Stagioni'; @@ -748,10 +758,7 @@ class _TranslationsNavigationIt implements TranslationsNavigationEn { final TranslationsIt _root; // ignore: unused_field // Translations - @override String get home => 'Home'; - @override String get search => 'Cerca'; @override String get libraries => 'Librerie'; - @override String get settings => 'Impostazioni'; @override String get downloads => 'Download'; } @@ -776,6 +783,10 @@ class _TranslationsDownloadsIt implements TranslationsDownloadsEn { @override String get downloadDeleted => 'Download eliminato'; @override String deleteConfirm({required Object title}) => 'Sei sicuro di voler eliminare "${title}"? Il file scaricato verrà rimosso dal tuo dispositivo.'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => 'Eliminazione di ${title}... (${current} di ${total})'; + @override String get noDownloadsTree => 'Nessun download'; + @override String get pauseAll => 'Metti tutto in pausa'; + @override String get resumeAll => 'Riprendi tutto'; + @override String get deleteAll => 'Elimina tutto'; } // Path: playlists @@ -910,6 +921,42 @@ class _TranslationsShadersIt implements TranslationsShadersEn { @override String get mode => 'Modalità'; } +// Path: companionRemote +class _TranslationsCompanionRemoteIt implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteIt._(this._root); + + final TranslationsIt _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => 'Connetti a un dispositivo'; + @override String get hostRemoteSession => 'Ospita sessione remota'; + @override String get controlThisDevice => 'Controlla questo dispositivo con il tuo telefono'; + @override String get remoteControl => 'Telecomando'; + @override String get controlDesktop => 'Controlla un dispositivo desktop'; + @override String connectedTo({required Object name}) => 'Connesso a ${name}'; + @override late final _TranslationsCompanionRemoteSessionIt session = _TranslationsCompanionRemoteSessionIt._(_root); + @override late final _TranslationsCompanionRemotePairingIt pairing = _TranslationsCompanionRemotePairingIt._(_root); + @override late final _TranslationsCompanionRemoteRemoteIt remote = _TranslationsCompanionRemoteRemoteIt._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsIt implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsIt._(this._root); + + final TranslationsIt _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => 'Impostazioni di riproduzione'; + @override String get playbackSpeed => 'Velocità di riproduzione'; + @override String get sleepTimer => 'Timer di spegnimento'; + @override String get audioSync => 'Sincronizzazione audio'; + @override String get subtitleSync => 'Sincronizzazione sottotitoli'; + @override String get hdr => 'HDR'; + @override String get audioOutput => 'Uscita audio'; + @override String get performanceOverlay => 'Overlay prestazioni'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsIt implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsIt._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsIt implements TranslationsHotkeysActionsEn { @override String get subSeekNext => 'Vai al sottotitolo successivo'; @override String get subSeekPrev => 'Vai al sottotitolo precedente'; @override String get shaderToggle => 'Attiva/disattiva shader'; + @override String get skipMarker => 'Salta intro/titoli di coda'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsIt implements TranslationsLibrariesGrouping @override String get folders => 'Cartelle'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionIt implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionIt._(this._root); + + final TranslationsIt _root; // ignore: unused_field + + // Translations + @override String get creatingSession => 'Creazione sessione remota...'; + @override String get failedToCreate => 'Impossibile creare la sessione remota:'; + @override String get noSession => 'Nessuna sessione disponibile'; + @override String get scanQrCode => 'Scansiona QR Code'; + @override String get orEnterManually => 'Oppure inserisci manualmente'; + @override String get hostAddress => 'Indirizzo host'; + @override String get sessionId => 'ID sessione'; + @override String get pin => 'PIN'; + @override String get connected => 'Connesso'; + @override String get waitingForConnection => 'In attesa di connessione...'; + @override String get usePhoneToControl => 'Usa il tuo dispositivo mobile per controllare questa app'; + @override String copiedToClipboard({required Object label}) => '${label} copiato negli appunti'; + @override String get copyToClipboard => 'Copia negli appunti'; + @override String get newSession => 'Nuova sessione'; + @override String get minimize => 'Riduci'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingIt implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingIt._(this._root); + + final TranslationsIt _root; // ignore: unused_field + + // Translations + @override String get recent => 'Recenti'; + @override String get scan => 'Scansiona'; + @override String get manual => 'Manuale'; + @override String get recentConnections => 'Connessioni recenti'; + @override String get quickReconnect => 'Riconnettiti rapidamente ai dispositivi associati in precedenza'; + @override String get pairWithDesktop => 'Associa con desktop'; + @override String get enterSessionDetails => 'Inserisci i dettagli della sessione mostrati sul tuo dispositivo desktop'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => 'Inserisci ID sessione di 8 caratteri'; + @override String get pinHint => 'Inserisci PIN di 6 cifre'; + @override String get connecting => 'Connessione...'; + @override String get tips => 'Suggerimenti'; + @override String get tipDesktop => 'Apri Plezy sul tuo desktop e abilita Companion Remote dalle impostazioni o dal menu'; + @override String get tipScan => 'Usa la scheda Scansiona per associare rapidamente scansionando il QR code sul tuo desktop'; + @override String get tipWifi => 'Assicurati che entrambi i dispositivi siano sulla stessa rete WiFi'; + @override String get cameraPermissionRequired => 'L\'autorizzazione della fotocamera è necessaria per scansionare i QR code.\nConcedi l\'accesso alla fotocamera nelle impostazioni del dispositivo.'; + @override String cameraError({required Object error}) => 'Impossibile avviare la fotocamera: ${error}'; + @override String get scanInstruction => 'Punta la fotocamera verso il QR code mostrato sul tuo desktop'; + @override String get noRecentConnections => 'Nessuna connessione recente'; + @override String get connectUsingManual => 'Connettiti a un dispositivo tramite inserimento manuale per iniziare'; + @override String get invalidQrCode => 'Formato QR code non valido'; + @override String get removeRecentConnection => 'Rimuovi connessione recente'; + @override String removeConfirm({required Object name}) => 'Rimuovere "${name}" dalle connessioni recenti?'; + @override String get validationHostRequired => 'Inserisci l\'indirizzo host'; + @override String get validationHostFormat => 'Il formato deve essere IP:porta (es. 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => 'Inserisci un ID sessione'; + @override String get validationSessionIdLength => 'L\'ID sessione deve essere di 8 caratteri'; + @override String get validationPinRequired => 'Inserisci un PIN'; + @override String get validationPinLength => 'Il PIN deve essere di 6 cifre'; + @override String get connectionTimedOut => 'Connessione scaduta. Verifica l\'ID sessione e il PIN.'; + @override String get sessionNotFound => 'Sessione non trovata. Verifica le tue credenziali.'; + @override String failedToConnect({required Object error}) => 'Connessione fallita: ${error}'; + @override String failedToLoadRecent({required Object error}) => 'Impossibile caricare le sessioni recenti: ${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteIt implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteIt._(this._root); + + final TranslationsIt _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => 'Vuoi disconnetterti dalla sessione remota?'; + @override String get reconnecting => 'Riconnessione...'; + @override String attemptOf({required Object current}) => 'Tentativo ${current} di 5'; + @override String get retryNow => 'Riprova ora'; + @override String get connectionError => 'Errore di connessione'; + @override String get notConnected => 'Non connesso'; + @override String get tabRemote => 'Telecomando'; + @override String get tabPlay => 'Riproduci'; + @override String get tabMore => 'Altro'; + @override String get menu => 'Menu'; + @override String get tabNavigation => 'Navigazione schede'; + @override String get tabDiscover => 'Esplora'; + @override String get tabLibraries => 'Librerie'; + @override String get tabSearch => 'Cerca'; + @override String get tabDownloads => 'Download'; + @override String get tabSettings => 'Impostazioni'; + @override String get previous => 'Precedente'; + @override String get playPause => 'Riproduci/Pausa'; + @override String get next => 'Successivo'; + @override String get seekBack => 'Riavvolgi'; + @override String get stop => 'Ferma'; + @override String get seekForward => 'Avanti'; + @override String get volume => 'Volume'; + @override String get volumeDown => 'Abbassa'; + @override String get volumeUp => 'Alza'; + @override String get fullscreen => 'Schermo intero'; + @override String get subtitles => 'Sottotitoli'; + @override String get audio => 'Audio'; + @override String get searchHint => 'Cerca sul desktop...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsIt { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => 'Caricamento...', 'auth.signInWithPlex' => 'Accedi con Plex', 'auth.showQRCode' => 'Mostra QR Code', - 'auth.cancel' => 'Cancella', 'auth.authenticate' => 'Autenticazione', - 'auth.retry' => 'Riprova', 'auth.debugEnterToken' => 'Debug: Inserisci Token Plex', 'auth.plexTokenLabel' => 'Token Auth Plex', 'auth.plexTokenHint' => 'Inserisci il tuo token di Plex.tv', @@ -1018,11 +1167,25 @@ extension on TranslationsIt { 'common.delete' => 'Elimina', 'common.shuffle' => 'Casuale', 'common.addTo' => 'Aggiungi a...', + 'common.remove' => 'Rimuovi', + 'common.paste' => 'Incolla', + 'common.connect' => 'Connetti', + 'common.disconnect' => 'Disconnetti', + 'common.play' => 'Riproduci', + 'common.pause' => 'Pausa', + 'common.resume' => 'Riprendi', + 'common.error' => 'Errore', + 'common.search' => 'Cerca', + 'common.home' => 'Home', + 'common.back' => 'Indietro', + 'common.settings' => 'Impostazioni', + 'common.mute' => 'Muto', + 'common.ok' => 'OK', + 'common.loading' => 'Caricamento...', 'screens.licenses' => 'Licenze', 'screens.switchProfile' => 'Cambia profilo', 'screens.subtitleStyling' => 'Stile sottotitoli', 'screens.mpvConfig' => 'Configurazione MPV', - 'screens.search' => 'Cerca', 'screens.logs' => 'Registro', 'update.available' => 'Aggiornamento disponibile', 'update.versionAvailable' => ({required Object version}) => 'Versione ${version} disponibile', @@ -1176,6 +1339,7 @@ extension on TranslationsIt { 'hotkeys.actions.subSeekNext' => 'Vai al sottotitolo successivo', 'hotkeys.actions.subSeekPrev' => 'Vai al sottotitolo precedente', 'hotkeys.actions.shaderToggle' => 'Attiva/disattiva shader', + 'hotkeys.actions.skipMarker' => 'Salta intro/titoli di coda', 'pinEntry.enterPin' => 'Inserisci PIN', 'pinEntry.showPin' => 'Mostra PIN', 'pinEntry.hidePin' => 'Nascondi PIN', @@ -1266,13 +1430,14 @@ extension on TranslationsIt { 'videoControls.timelineSlider' => 'Timeline video', 'videoControls.volumeSlider' => 'Livello volume', 'videoControls.endsAt' => ({required Object time}) => 'Finisce alle ${time}', - 'videoControls.backButton' => 'Indietro', 'videoControls.pipFailed' => 'Impossibile avviare la modalità Picture-in-Picture', 'videoControls.pipErrors.androidVersion' => 'Richiede Android 8.0 o versioni successive', 'videoControls.pipErrors.permissionDisabled' => 'L\'autorizzazione Picture-in-Picture è disabilitata. Abilitala in Impostazioni > App > Plezy > Picture-in-Picture', 'videoControls.pipErrors.notSupported' => 'Questo dispositivo non supporta la modalità Picture-in-Picture', 'videoControls.pipErrors.failed' => 'Impossibile avviare la modalità Picture-in-Picture', 'videoControls.pipErrors.unknown' => ({required Object error}) => 'Si è verificato un errore: ${error}', + 'videoControls.chapters' => 'Capitoli', + 'videoControls.noChaptersAvailable' => 'Nessun capitolo disponibile', 'userStatus.admin' => 'Admin', 'userStatus.restricted' => 'Limitato', 'userStatus.protected' => 'Protetto', @@ -1343,16 +1508,12 @@ extension on TranslationsIt { 'mpvConfig.confirmDeleteProperty' => 'Sei sicuro di voler eliminare questa proprietà?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} voci', 'dialog.confirmAction' => 'Conferma azione', - 'dialog.cancel' => 'Cancella', 'discover.title' => 'Esplora', 'discover.switchProfile' => 'Cambia profilo', - 'discover.logout' => 'Disconnetti', 'discover.noContentAvailable' => 'Nessun contenuto disponibile', 'discover.addMediaToLibraries' => 'Aggiungi alcuni file multimediali alle tue librerie', 'discover.continueWatching' => 'Continua a guardare', - 'discover.play' => 'Riproduci', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => 'Pausa', 'discover.overview' => 'Panoramica', 'discover.cast' => 'Attori', 'discover.seasons' => 'Stagioni', @@ -1442,10 +1603,7 @@ extension on TranslationsIt { 'licenses.license' => 'Licenza', 'licenses.licenseNumber' => ({required Object number}) => 'Licenza ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} licenze', - 'navigation.home' => 'Home', - 'navigation.search' => 'Cerca', 'navigation.libraries' => 'Librerie', - 'navigation.settings' => 'Impostazioni', 'navigation.downloads' => 'Download', 'downloads.title' => 'Download', 'downloads.manage' => 'Gestisci', @@ -1461,6 +1619,10 @@ extension on TranslationsIt { 'downloads.downloadDeleted' => 'Download eliminato', 'downloads.deleteConfirm' => ({required Object title}) => 'Sei sicuro di voler eliminare "${title}"? Il file scaricato verrà rimosso dal tuo dispositivo.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => 'Eliminazione di ${title}... (${current} di ${total})', + 'downloads.noDownloadsTree' => 'Nessun download', + 'downloads.pauseAll' => 'Metti tutto in pausa', + 'downloads.resumeAll' => 'Riprendi tutto', + 'downloads.deleteAll' => 'Elimina tutto', 'playlists.title' => 'Playlist', 'playlists.noPlaylists' => 'Nessuna playlist trovata', 'playlists.create' => 'Crea playlist', @@ -1489,6 +1651,8 @@ extension on TranslationsIt { 'playlists.playlist' => 'Playlist', 'collections.title' => 'Raccolte', 'collections.collection' => 'Raccolta', + _ => null, + } ?? switch (path) { 'collections.empty' => 'La raccolta è vuota', 'collections.unknownLibrarySection' => 'Impossibile eliminare: sezione libreria sconosciuta', 'collections.deleteCollection' => 'Elimina raccolta', @@ -1499,8 +1663,6 @@ extension on TranslationsIt { 'collections.failedToLoadItems' => ({required Object error}) => 'Impossibile caricare gli elementi della raccolta: ${error}', 'collections.selectCollection' => 'Seleziona raccolta', 'collections.createNewCollection' => 'Crea nuova raccolta', - _ => null, - } ?? switch (path) { 'collections.collectionName' => 'Nome raccolta', 'collections.enterCollectionName' => 'Inserisci nome raccolta', 'collections.addedToCollection' => 'Aggiunto alla raccolta', @@ -1559,6 +1721,98 @@ extension on TranslationsIt { 'shaders.qualityFast' => 'Veloce', 'shaders.qualityHQ' => 'Alta qualità', 'shaders.mode' => 'Modalità', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => 'Connetti a un dispositivo', + 'companionRemote.hostRemoteSession' => 'Ospita sessione remota', + 'companionRemote.controlThisDevice' => 'Controlla questo dispositivo con il tuo telefono', + 'companionRemote.remoteControl' => 'Telecomando', + 'companionRemote.controlDesktop' => 'Controlla un dispositivo desktop', + 'companionRemote.connectedTo' => ({required Object name}) => 'Connesso a ${name}', + 'companionRemote.session.creatingSession' => 'Creazione sessione remota...', + 'companionRemote.session.failedToCreate' => 'Impossibile creare la sessione remota:', + 'companionRemote.session.noSession' => 'Nessuna sessione disponibile', + 'companionRemote.session.scanQrCode' => 'Scansiona QR Code', + 'companionRemote.session.orEnterManually' => 'Oppure inserisci manualmente', + 'companionRemote.session.hostAddress' => 'Indirizzo host', + 'companionRemote.session.sessionId' => 'ID sessione', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => 'Connesso', + 'companionRemote.session.waitingForConnection' => 'In attesa di connessione...', + 'companionRemote.session.usePhoneToControl' => 'Usa il tuo dispositivo mobile per controllare questa app', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label} copiato negli appunti', + 'companionRemote.session.copyToClipboard' => 'Copia negli appunti', + 'companionRemote.session.newSession' => 'Nuova sessione', + 'companionRemote.session.minimize' => 'Riduci', + 'companionRemote.pairing.recent' => 'Recenti', + 'companionRemote.pairing.scan' => 'Scansiona', + 'companionRemote.pairing.manual' => 'Manuale', + 'companionRemote.pairing.recentConnections' => 'Connessioni recenti', + 'companionRemote.pairing.quickReconnect' => 'Riconnettiti rapidamente ai dispositivi associati in precedenza', + 'companionRemote.pairing.pairWithDesktop' => 'Associa con desktop', + 'companionRemote.pairing.enterSessionDetails' => 'Inserisci i dettagli della sessione mostrati sul tuo dispositivo desktop', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => 'Inserisci ID sessione di 8 caratteri', + 'companionRemote.pairing.pinHint' => 'Inserisci PIN di 6 cifre', + 'companionRemote.pairing.connecting' => 'Connessione...', + 'companionRemote.pairing.tips' => 'Suggerimenti', + 'companionRemote.pairing.tipDesktop' => 'Apri Plezy sul tuo desktop e abilita Companion Remote dalle impostazioni o dal menu', + 'companionRemote.pairing.tipScan' => 'Usa la scheda Scansiona per associare rapidamente scansionando il QR code sul tuo desktop', + 'companionRemote.pairing.tipWifi' => 'Assicurati che entrambi i dispositivi siano sulla stessa rete WiFi', + 'companionRemote.pairing.cameraPermissionRequired' => 'L\'autorizzazione della fotocamera è necessaria per scansionare i QR code.\nConcedi l\'accesso alla fotocamera nelle impostazioni del dispositivo.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => 'Impossibile avviare la fotocamera: ${error}', + 'companionRemote.pairing.scanInstruction' => 'Punta la fotocamera verso il QR code mostrato sul tuo desktop', + 'companionRemote.pairing.noRecentConnections' => 'Nessuna connessione recente', + 'companionRemote.pairing.connectUsingManual' => 'Connettiti a un dispositivo tramite inserimento manuale per iniziare', + 'companionRemote.pairing.invalidQrCode' => 'Formato QR code non valido', + 'companionRemote.pairing.removeRecentConnection' => 'Rimuovi connessione recente', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => 'Rimuovere "${name}" dalle connessioni recenti?', + 'companionRemote.pairing.validationHostRequired' => 'Inserisci l\'indirizzo host', + 'companionRemote.pairing.validationHostFormat' => 'Il formato deve essere IP:porta (es. 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => 'Inserisci un ID sessione', + 'companionRemote.pairing.validationSessionIdLength' => 'L\'ID sessione deve essere di 8 caratteri', + 'companionRemote.pairing.validationPinRequired' => 'Inserisci un PIN', + 'companionRemote.pairing.validationPinLength' => 'Il PIN deve essere di 6 cifre', + 'companionRemote.pairing.connectionTimedOut' => 'Connessione scaduta. Verifica l\'ID sessione e il PIN.', + 'companionRemote.pairing.sessionNotFound' => 'Sessione non trovata. Verifica le tue credenziali.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => 'Connessione fallita: ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => 'Impossibile caricare le sessioni recenti: ${error}', + 'companionRemote.remote.disconnectConfirm' => 'Vuoi disconnetterti dalla sessione remota?', + 'companionRemote.remote.reconnecting' => 'Riconnessione...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => 'Tentativo ${current} di 5', + 'companionRemote.remote.retryNow' => 'Riprova ora', + 'companionRemote.remote.connectionError' => 'Errore di connessione', + 'companionRemote.remote.notConnected' => 'Non connesso', + 'companionRemote.remote.tabRemote' => 'Telecomando', + 'companionRemote.remote.tabPlay' => 'Riproduci', + 'companionRemote.remote.tabMore' => 'Altro', + 'companionRemote.remote.menu' => 'Menu', + 'companionRemote.remote.tabNavigation' => 'Navigazione schede', + 'companionRemote.remote.tabDiscover' => 'Esplora', + 'companionRemote.remote.tabLibraries' => 'Librerie', + 'companionRemote.remote.tabSearch' => 'Cerca', + 'companionRemote.remote.tabDownloads' => 'Download', + 'companionRemote.remote.tabSettings' => 'Impostazioni', + 'companionRemote.remote.previous' => 'Precedente', + 'companionRemote.remote.playPause' => 'Riproduci/Pausa', + 'companionRemote.remote.next' => 'Successivo', + 'companionRemote.remote.seekBack' => 'Riavvolgi', + 'companionRemote.remote.stop' => 'Ferma', + 'companionRemote.remote.seekForward' => 'Avanti', + 'companionRemote.remote.volume' => 'Volume', + 'companionRemote.remote.volumeDown' => 'Abbassa', + 'companionRemote.remote.volumeUp' => 'Alza', + 'companionRemote.remote.fullscreen' => 'Schermo intero', + 'companionRemote.remote.subtitles' => 'Sottotitoli', + 'companionRemote.remote.audio' => 'Audio', + 'companionRemote.remote.searchHint' => 'Cerca sul desktop...', + 'videoSettings.playbackSettings' => 'Impostazioni di riproduzione', + 'videoSettings.playbackSpeed' => 'Velocità di riproduzione', + 'videoSettings.sleepTimer' => 'Timer di spegnimento', + 'videoSettings.audioSync' => 'Sincronizzazione audio', + 'videoSettings.subtitleSync' => 'Sincronizzazione sottotitoli', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => 'Uscita audio', + 'videoSettings.performanceOverlay' => 'Overlay prestazioni', _ => null, }; } diff --git a/lib/i18n/strings_ko.g.dart b/lib/i18n/strings_ko.g.dart index f7779277..336d3079 100644 --- a/lib/i18n/strings_ko.g.dart +++ b/lib/i18n/strings_ko.g.dart @@ -70,6 +70,8 @@ class TranslationsKo with BaseTranslations implements T @override late final _TranslationsWatchTogetherKo watchTogether = _TranslationsWatchTogetherKo._(_root); @override late final _TranslationsDownloadsKo downloads = _TranslationsDownloadsKo._(_root); @override late final _TranslationsShadersKo shaders = _TranslationsShadersKo._(_root); + @override late final _TranslationsCompanionRemoteKo companionRemote = _TranslationsCompanionRemoteKo._(_root); + @override late final _TranslationsVideoSettingsKo videoSettings = _TranslationsVideoSettingsKo._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppKo implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => '로딩 중...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthKo implements TranslationsAuthEn { // Translations @override String get signInWithPlex => 'Plex 계정으로 로그인'; @override String get showQRCode => 'QR 코드'; - @override String get cancel => '취소'; @override String get authenticate => '인증'; - @override String get retry => '재시도'; @override String get debugEnterToken => '디버깅을 위해 Plex 토큰을 입력하세요.'; @override String get plexTokenLabel => 'Plex 인증 토큰'; @override String get plexTokenHint => 'Plex.tv 토큰을 입력하세요'; @@ -128,6 +127,21 @@ class _TranslationsCommonKo implements TranslationsCommonEn { @override String get delete => '삭제'; @override String get shuffle => '무작위 재생'; @override String get addTo => '추가하기...'; + @override String get remove => '삭제'; + @override String get paste => '붙여넣기'; + @override String get connect => '연결'; + @override String get disconnect => '연결 해제'; + @override String get play => '재생'; + @override String get pause => '일시정지'; + @override String get resume => '재개'; + @override String get error => '오류'; + @override String get search => '검색'; + @override String get home => '홈'; + @override String get back => '뒤로'; + @override String get settings => '설정'; + @override String get mute => '음소거'; + @override String get ok => '확인'; + @override String get loading => '로딩 중...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensKo implements TranslationsScreensEn { @override String get switchProfile => '프로필 전환'; @override String get subtitleStyling => '자막 스타일 설정'; @override String get mpvConfig => 'MPV 설정'; - @override String get search => '검색'; @override String get logs => '로그'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsKo implements TranslationsVideoControlsEn { @override String get timelineSlider => '타임라인'; @override String get volumeSlider => '볼륨 조절'; @override String endsAt({required Object time}) => '${time}에 종료'; - @override String get backButton => '뒤로 가기'; @override String get pipFailed => '화면 속 화면 모드를 시작할 수 없습니다'; @override late final _TranslationsVideoControlsPipErrorsKo pipErrors = _TranslationsVideoControlsPipErrorsKo._(_root); + @override String get chapters => '챕터'; + @override String get noChaptersAvailable => '사용 가능한 챕터가 없습니다'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogKo implements TranslationsDialogEn { // Translations @override String get confirmAction => '확인'; - @override String get cancel => '취소'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverKo implements TranslationsDiscoverEn { // Translations @override String get title => '발견'; @override String get switchProfile => '사용자 전환'; - @override String get logout => '로그아웃'; @override String get noContentAvailable => '사용 가능한 콘텐츠가 없습니다'; @override String get addMediaToLibraries => '미디어 라이브러리에 미디어를 추가해 주세요'; @override String get continueWatching => '계속 시청'; - @override String get play => '재생'; @override String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - @override String get pause => '일시정지'; @override String get overview => '개요'; @override String get cast => '출연진'; @override String get seasons => '시즌 수'; @@ -748,10 +758,7 @@ class _TranslationsNavigationKo implements TranslationsNavigationEn { final TranslationsKo _root; // ignore: unused_field // Translations - @override String get home => '홈'; - @override String get search => '검색'; @override String get libraries => '미디어 라이브러리'; - @override String get settings => '설정'; @override String get downloads => '다운로드'; } @@ -893,6 +900,10 @@ class _TranslationsDownloadsKo implements TranslationsDownloadsEn { @override String get downloadDeleted => '다운로드 삭제됨'; @override String deleteConfirm({required Object title}) => '"${title}"를 삭제 하시겠습니까? 다운로드한 파일이 기기에서 삭제됩니다.'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => '${title} 삭제 중... (${current}/${total})'; + @override String get noDownloadsTree => '다운로드 없음'; + @override String get pauseAll => '모두 일시정지'; + @override String get resumeAll => '모두 재개'; + @override String get deleteAll => '모두 삭제'; } // Path: shaders @@ -910,6 +921,42 @@ class _TranslationsShadersKo implements TranslationsShadersEn { @override String get mode => '모드'; } +// Path: companionRemote +class _TranslationsCompanionRemoteKo implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteKo._(this._root); + + final TranslationsKo _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => '기기에 연결'; + @override String get hostRemoteSession => '원격 세션 호스트'; + @override String get controlThisDevice => '휴대폰으로 이 기기를 제어하세요'; + @override String get remoteControl => '원격 제어'; + @override String get controlDesktop => '데스크톱 기기 제어'; + @override String connectedTo({required Object name}) => '${name}에 연결됨'; + @override late final _TranslationsCompanionRemoteSessionKo session = _TranslationsCompanionRemoteSessionKo._(_root); + @override late final _TranslationsCompanionRemotePairingKo pairing = _TranslationsCompanionRemotePairingKo._(_root); + @override late final _TranslationsCompanionRemoteRemoteKo remote = _TranslationsCompanionRemoteRemoteKo._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsKo implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsKo._(this._root); + + final TranslationsKo _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => '재생 설정'; + @override String get playbackSpeed => '재생 속도'; + @override String get sleepTimer => '취침 타이머'; + @override String get audioSync => '오디오 동기화'; + @override String get subtitleSync => '자막 동기화'; + @override String get hdr => 'HDR'; + @override String get audioOutput => '오디오 출력'; + @override String get performanceOverlay => '성능 오버레이'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsKo implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsKo._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsKo implements TranslationsHotkeysActionsEn { @override String get subSeekNext => '다음 자막으로 이동'; @override String get subSeekPrev => '이전 자막으로 이동'; @override String get shaderToggle => '셰이더 전환'; + @override String get skipMarker => '인트로/크레딧 건너뛰기'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsKo implements TranslationsLibrariesGrouping @override String get folders => '폴더'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionKo implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionKo._(this._root); + + final TranslationsKo _root; // ignore: unused_field + + // Translations + @override String get creatingSession => '원격 세션 생성 중...'; + @override String get failedToCreate => '원격 세션 생성 실패:'; + @override String get noSession => '사용 가능한 세션이 없습니다'; + @override String get scanQrCode => 'QR 코드 스캔'; + @override String get orEnterManually => '또는 수동으로 입력'; + @override String get hostAddress => '호스트 주소'; + @override String get sessionId => '세션 ID'; + @override String get pin => 'PIN'; + @override String get connected => '연결됨'; + @override String get waitingForConnection => '연결 대기 중...'; + @override String get usePhoneToControl => '모바일 기기로 이 앱을 제어하세요'; + @override String copiedToClipboard({required Object label}) => '${label}이(가) 클립보드에 복사되었습니다'; + @override String get copyToClipboard => '클립보드에 복사'; + @override String get newSession => '새 세션'; + @override String get minimize => '최소화'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingKo implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingKo._(this._root); + + final TranslationsKo _root; // ignore: unused_field + + // Translations + @override String get recent => '최근'; + @override String get scan => '스캔'; + @override String get manual => '수동'; + @override String get recentConnections => '최근 연결'; + @override String get quickReconnect => '이전에 페어링한 기기에 빠르게 재연결'; + @override String get pairWithDesktop => '데스크톱과 페어링'; + @override String get enterSessionDetails => '데스크톱 기기에 표시된 세션 정보를 입력하세요'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => '8자리 세션 ID 입력'; + @override String get pinHint => '6자리 PIN 입력'; + @override String get connecting => '연결 중...'; + @override String get tips => '팁'; + @override String get tipDesktop => '데스크톱에서 Plezy를 열고 설정 또는 메뉴에서 Companion Remote를 활성화하세요'; + @override String get tipScan => '스캔 탭을 사용하여 데스크톱의 QR 코드를 스캔하면 빠르게 페어링할 수 있습니다'; + @override String get tipWifi => '두 기기가 동일한 WiFi 네트워크에 연결되어 있는지 확인하세요'; + @override String get cameraPermissionRequired => 'QR 코드를 스캔하려면 카메라 권한이 필요합니다.\n기기 설정에서 카메라 접근을 허용해 주세요.'; + @override String cameraError({required Object error}) => '카메라를 시작할 수 없습니다: ${error}'; + @override String get scanInstruction => '데스크톱에 표시된 QR 코드에 카메라를 향하세요'; + @override String get noRecentConnections => '최근 연결 없음'; + @override String get connectUsingManual => '수동 입력으로 기기에 연결하여 시작하세요'; + @override String get invalidQrCode => '유효하지 않은 QR 코드 형식'; + @override String get removeRecentConnection => '최근 연결 삭제'; + @override String removeConfirm({required Object name}) => '"${name}"을(를) 최근 연결에서 삭제하시겠습니까?'; + @override String get validationHostRequired => '호스트 주소를 입력하세요'; + @override String get validationHostFormat => 'IP:포트 형식이어야 합니다 (예: 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => '세션 ID를 입력하세요'; + @override String get validationSessionIdLength => '세션 ID는 8자리여야 합니다'; + @override String get validationPinRequired => 'PIN을 입력하세요'; + @override String get validationPinLength => 'PIN은 6자리여야 합니다'; + @override String get connectionTimedOut => '연결 시간이 초과되었습니다. 세션 ID와 PIN을 확인하세요.'; + @override String get sessionNotFound => '세션을 찾을 수 없습니다. 자격 증명을 확인하세요.'; + @override String failedToConnect({required Object error}) => '연결 실패: ${error}'; + @override String failedToLoadRecent({required Object error}) => '최근 세션 로드 실패: ${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteKo implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteKo._(this._root); + + final TranslationsKo _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => '원격 세션 연결을 해제하시겠습니까?'; + @override String get reconnecting => '재연결 중...'; + @override String attemptOf({required Object current}) => '${current}/5 시도 중'; + @override String get retryNow => '지금 재시도'; + @override String get connectionError => '연결 오류'; + @override String get notConnected => '연결되지 않음'; + @override String get tabRemote => '리모컨'; + @override String get tabPlay => '재생'; + @override String get tabMore => '더 보기'; + @override String get menu => '메뉴'; + @override String get tabNavigation => '탭 탐색'; + @override String get tabDiscover => '발견'; + @override String get tabLibraries => '미디어 라이브러리'; + @override String get tabSearch => '검색'; + @override String get tabDownloads => '다운로드'; + @override String get tabSettings => '설정'; + @override String get previous => '이전'; + @override String get playPause => '재생/일시정지'; + @override String get next => '다음'; + @override String get seekBack => '되감기'; + @override String get stop => '정지'; + @override String get seekForward => '빨리감기'; + @override String get volume => '볼륨'; + @override String get volumeDown => '줄이기'; + @override String get volumeUp => '높이기'; + @override String get fullscreen => '전체 화면'; + @override String get subtitles => '자막'; + @override String get audio => '오디오'; + @override String get searchHint => '데스크톱에서 검색...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsKo { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => '로딩 중...', 'auth.signInWithPlex' => 'Plex 계정으로 로그인', 'auth.showQRCode' => 'QR 코드', - 'auth.cancel' => '취소', 'auth.authenticate' => '인증', - 'auth.retry' => '재시도', 'auth.debugEnterToken' => '디버깅을 위해 Plex 토큰을 입력하세요.', 'auth.plexTokenLabel' => 'Plex 인증 토큰', 'auth.plexTokenHint' => 'Plex.tv 토큰을 입력하세요', @@ -1018,11 +1167,25 @@ extension on TranslationsKo { 'common.delete' => '삭제', 'common.shuffle' => '무작위 재생', 'common.addTo' => '추가하기...', + 'common.remove' => '삭제', + 'common.paste' => '붙여넣기', + 'common.connect' => '연결', + 'common.disconnect' => '연결 해제', + 'common.play' => '재생', + 'common.pause' => '일시정지', + 'common.resume' => '재개', + 'common.error' => '오류', + 'common.search' => '검색', + 'common.home' => '홈', + 'common.back' => '뒤로', + 'common.settings' => '설정', + 'common.mute' => '음소거', + 'common.ok' => '확인', + 'common.loading' => '로딩 중...', 'screens.licenses' => '라이선스', 'screens.switchProfile' => '프로필 전환', 'screens.subtitleStyling' => '자막 스타일 설정', 'screens.mpvConfig' => 'MPV 설정', - 'screens.search' => '검색', 'screens.logs' => '로그', 'update.available' => '사용 가능한 업데이트', 'update.versionAvailable' => ({required Object version}) => '버전 ${version} 출시됨', @@ -1176,6 +1339,7 @@ extension on TranslationsKo { 'hotkeys.actions.subSeekNext' => '다음 자막으로 이동', 'hotkeys.actions.subSeekPrev' => '이전 자막으로 이동', 'hotkeys.actions.shaderToggle' => '셰이더 전환', + 'hotkeys.actions.skipMarker' => '인트로/크레딧 건너뛰기', 'pinEntry.enterPin' => 'PIN 입력', 'pinEntry.showPin' => 'PIN 표시', 'pinEntry.hidePin' => 'PIN 숨기기', @@ -1266,13 +1430,14 @@ extension on TranslationsKo { 'videoControls.timelineSlider' => '타임라인', 'videoControls.volumeSlider' => '볼륨 조절', 'videoControls.endsAt' => ({required Object time}) => '${time}에 종료', - 'videoControls.backButton' => '뒤로 가기', 'videoControls.pipFailed' => '화면 속 화면 모드를 시작할 수 없습니다', 'videoControls.pipErrors.androidVersion' => 'Android 8.0 이상이 필요합니다', 'videoControls.pipErrors.permissionDisabled' => '화면 속 화면 권한이 비활성화되어 있습니다. 설정 > 앱 > Plezy > 화면 속 화면에서 활성화하세요', 'videoControls.pipErrors.notSupported' => '이 기기는 화면 속 화면 모드를 지원하지 않습니다', 'videoControls.pipErrors.failed' => '화면 속 화면 모드를 시작할 수 없습니다', 'videoControls.pipErrors.unknown' => ({required Object error}) => '오류가 발생했습니다: ${error}', + 'videoControls.chapters' => '챕터', + 'videoControls.noChaptersAvailable' => '사용 가능한 챕터가 없습니다', 'userStatus.admin' => '관리자', 'userStatus.restricted' => '제한됨', 'userStatus.protected' => '보호됨', @@ -1343,16 +1508,12 @@ extension on TranslationsKo { 'mpvConfig.confirmDeleteProperty' => '이 속성을 삭제 하시겠습니까?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} 항목', 'dialog.confirmAction' => '확인', - 'dialog.cancel' => '취소', 'discover.title' => '발견', 'discover.switchProfile' => '사용자 전환', - 'discover.logout' => '로그아웃', 'discover.noContentAvailable' => '사용 가능한 콘텐츠가 없습니다', 'discover.addMediaToLibraries' => '미디어 라이브러리에 미디어를 추가해 주세요', 'discover.continueWatching' => '계속 시청', - 'discover.play' => '재생', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => '일시정지', 'discover.overview' => '개요', 'discover.cast' => '출연진', 'discover.seasons' => '시즌 수', @@ -1442,10 +1603,7 @@ extension on TranslationsKo { 'licenses.license' => '라이선스', 'licenses.licenseNumber' => ({required Object number}) => '라이선스 ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} 개의 라이선스', - 'navigation.home' => '홈', - 'navigation.search' => '검색', 'navigation.libraries' => '미디어 라이브러리', - 'navigation.settings' => '설정', 'navigation.downloads' => '다운로드', 'collections.title' => '컬렉션', 'collections.collection' => '컬렉션', @@ -1493,14 +1651,14 @@ extension on TranslationsKo { 'playlists.errorDeleting' => '재생 목록 삭제 실패', 'playlists.errorLoading' => '재생 목록 로드 실패', 'playlists.errorAdding' => '재생 목록에 추가 실패', + _ => null, + } ?? switch (path) { 'playlists.errorReordering' => '재생 목록 항목 재정렬 실패', 'playlists.errorRemoving' => '재생 목록에서 제거 실패', 'watchTogether.title' => '함께 보기', 'watchTogether.description' => '친구 및 가족과 콘텐츠를 동시에 시청하세요', 'watchTogether.createSession' => '세션 생성', 'watchTogether.creating' => '생성 중...', - _ => null, - } ?? switch (path) { 'watchTogether.joinSession' => '세션 참여', 'watchTogether.joining' => '참가 중...', 'watchTogether.controlMode' => '제어 모드', @@ -1553,12 +1711,108 @@ extension on TranslationsKo { 'downloads.downloadDeleted' => '다운로드 삭제됨', 'downloads.deleteConfirm' => ({required Object title}) => '"${title}"를 삭제 하시겠습니까? 다운로드한 파일이 기기에서 삭제됩니다.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => '${title} 삭제 중... (${current}/${total})', + 'downloads.noDownloadsTree' => '다운로드 없음', + 'downloads.pauseAll' => '모두 일시정지', + 'downloads.resumeAll' => '모두 재개', + 'downloads.deleteAll' => '모두 삭제', 'shaders.title' => '셰이더', 'shaders.noShaderDescription' => '비디오 향상 없음', 'shaders.nvscalerDescription' => '더 선명한 비디오를 위한 NVIDIA 이미지 스케일링', 'shaders.qualityFast' => '빠름', 'shaders.qualityHQ' => '고품질', 'shaders.mode' => '모드', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => '기기에 연결', + 'companionRemote.hostRemoteSession' => '원격 세션 호스트', + 'companionRemote.controlThisDevice' => '휴대폰으로 이 기기를 제어하세요', + 'companionRemote.remoteControl' => '원격 제어', + 'companionRemote.controlDesktop' => '데스크톱 기기 제어', + 'companionRemote.connectedTo' => ({required Object name}) => '${name}에 연결됨', + 'companionRemote.session.creatingSession' => '원격 세션 생성 중...', + 'companionRemote.session.failedToCreate' => '원격 세션 생성 실패:', + 'companionRemote.session.noSession' => '사용 가능한 세션이 없습니다', + 'companionRemote.session.scanQrCode' => 'QR 코드 스캔', + 'companionRemote.session.orEnterManually' => '또는 수동으로 입력', + 'companionRemote.session.hostAddress' => '호스트 주소', + 'companionRemote.session.sessionId' => '세션 ID', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => '연결됨', + 'companionRemote.session.waitingForConnection' => '연결 대기 중...', + 'companionRemote.session.usePhoneToControl' => '모바일 기기로 이 앱을 제어하세요', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label}이(가) 클립보드에 복사되었습니다', + 'companionRemote.session.copyToClipboard' => '클립보드에 복사', + 'companionRemote.session.newSession' => '새 세션', + 'companionRemote.session.minimize' => '최소화', + 'companionRemote.pairing.recent' => '최근', + 'companionRemote.pairing.scan' => '스캔', + 'companionRemote.pairing.manual' => '수동', + 'companionRemote.pairing.recentConnections' => '최근 연결', + 'companionRemote.pairing.quickReconnect' => '이전에 페어링한 기기에 빠르게 재연결', + 'companionRemote.pairing.pairWithDesktop' => '데스크톱과 페어링', + 'companionRemote.pairing.enterSessionDetails' => '데스크톱 기기에 표시된 세션 정보를 입력하세요', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => '8자리 세션 ID 입력', + 'companionRemote.pairing.pinHint' => '6자리 PIN 입력', + 'companionRemote.pairing.connecting' => '연결 중...', + 'companionRemote.pairing.tips' => '팁', + 'companionRemote.pairing.tipDesktop' => '데스크톱에서 Plezy를 열고 설정 또는 메뉴에서 Companion Remote를 활성화하세요', + 'companionRemote.pairing.tipScan' => '스캔 탭을 사용하여 데스크톱의 QR 코드를 스캔하면 빠르게 페어링할 수 있습니다', + 'companionRemote.pairing.tipWifi' => '두 기기가 동일한 WiFi 네트워크에 연결되어 있는지 확인하세요', + 'companionRemote.pairing.cameraPermissionRequired' => 'QR 코드를 스캔하려면 카메라 권한이 필요합니다.\n기기 설정에서 카메라 접근을 허용해 주세요.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => '카메라를 시작할 수 없습니다: ${error}', + 'companionRemote.pairing.scanInstruction' => '데스크톱에 표시된 QR 코드에 카메라를 향하세요', + 'companionRemote.pairing.noRecentConnections' => '최근 연결 없음', + 'companionRemote.pairing.connectUsingManual' => '수동 입력으로 기기에 연결하여 시작하세요', + 'companionRemote.pairing.invalidQrCode' => '유효하지 않은 QR 코드 형식', + 'companionRemote.pairing.removeRecentConnection' => '최근 연결 삭제', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => '"${name}"을(를) 최근 연결에서 삭제하시겠습니까?', + 'companionRemote.pairing.validationHostRequired' => '호스트 주소를 입력하세요', + 'companionRemote.pairing.validationHostFormat' => 'IP:포트 형식이어야 합니다 (예: 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => '세션 ID를 입력하세요', + 'companionRemote.pairing.validationSessionIdLength' => '세션 ID는 8자리여야 합니다', + 'companionRemote.pairing.validationPinRequired' => 'PIN을 입력하세요', + 'companionRemote.pairing.validationPinLength' => 'PIN은 6자리여야 합니다', + 'companionRemote.pairing.connectionTimedOut' => '연결 시간이 초과되었습니다. 세션 ID와 PIN을 확인하세요.', + 'companionRemote.pairing.sessionNotFound' => '세션을 찾을 수 없습니다. 자격 증명을 확인하세요.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => '연결 실패: ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => '최근 세션 로드 실패: ${error}', + 'companionRemote.remote.disconnectConfirm' => '원격 세션 연결을 해제하시겠습니까?', + 'companionRemote.remote.reconnecting' => '재연결 중...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => '${current}/5 시도 중', + 'companionRemote.remote.retryNow' => '지금 재시도', + 'companionRemote.remote.connectionError' => '연결 오류', + 'companionRemote.remote.notConnected' => '연결되지 않음', + 'companionRemote.remote.tabRemote' => '리모컨', + 'companionRemote.remote.tabPlay' => '재생', + 'companionRemote.remote.tabMore' => '더 보기', + 'companionRemote.remote.menu' => '메뉴', + 'companionRemote.remote.tabNavigation' => '탭 탐색', + 'companionRemote.remote.tabDiscover' => '발견', + 'companionRemote.remote.tabLibraries' => '미디어 라이브러리', + 'companionRemote.remote.tabSearch' => '검색', + 'companionRemote.remote.tabDownloads' => '다운로드', + 'companionRemote.remote.tabSettings' => '설정', + 'companionRemote.remote.previous' => '이전', + 'companionRemote.remote.playPause' => '재생/일시정지', + 'companionRemote.remote.next' => '다음', + 'companionRemote.remote.seekBack' => '되감기', + 'companionRemote.remote.stop' => '정지', + 'companionRemote.remote.seekForward' => '빨리감기', + 'companionRemote.remote.volume' => '볼륨', + 'companionRemote.remote.volumeDown' => '줄이기', + 'companionRemote.remote.volumeUp' => '높이기', + 'companionRemote.remote.fullscreen' => '전체 화면', + 'companionRemote.remote.subtitles' => '자막', + 'companionRemote.remote.audio' => '오디오', + 'companionRemote.remote.searchHint' => '데스크톱에서 검색...', + 'videoSettings.playbackSettings' => '재생 설정', + 'videoSettings.playbackSpeed' => '재생 속도', + 'videoSettings.sleepTimer' => '취침 타이머', + 'videoSettings.audioSync' => '오디오 동기화', + 'videoSettings.subtitleSync' => '자막 동기화', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => '오디오 출력', + 'videoSettings.performanceOverlay' => '성능 오버레이', _ => null, }; } diff --git a/lib/i18n/strings_nl.g.dart b/lib/i18n/strings_nl.g.dart index c8c844f7..ddbbcbad 100644 --- a/lib/i18n/strings_nl.g.dart +++ b/lib/i18n/strings_nl.g.dart @@ -70,6 +70,8 @@ class TranslationsNl with BaseTranslations implements T @override late final _TranslationsCollectionsNl collections = _TranslationsCollectionsNl._(_root); @override late final _TranslationsWatchTogetherNl watchTogether = _TranslationsWatchTogetherNl._(_root); @override late final _TranslationsShadersNl shaders = _TranslationsShadersNl._(_root); + @override late final _TranslationsCompanionRemoteNl companionRemote = _TranslationsCompanionRemoteNl._(_root); + @override late final _TranslationsVideoSettingsNl videoSettings = _TranslationsVideoSettingsNl._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppNl implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => 'Laden...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthNl implements TranslationsAuthEn { // Translations @override String get signInWithPlex => 'Inloggen met Plex'; @override String get showQRCode => 'Toon QR-code'; - @override String get cancel => 'Annuleren'; @override String get authenticate => 'Authenticeren'; - @override String get retry => 'Opnieuw proberen'; @override String get debugEnterToken => 'Debug: Voer Plex Token in'; @override String get plexTokenLabel => 'Plex Authenticatietoken'; @override String get plexTokenHint => 'Voer je Plex.tv token in'; @@ -128,6 +127,21 @@ class _TranslationsCommonNl implements TranslationsCommonEn { @override String get delete => 'Verwijderen'; @override String get shuffle => 'Willekeurig'; @override String get addTo => 'Toevoegen aan...'; + @override String get remove => 'Verwijderen'; + @override String get paste => 'Plakken'; + @override String get connect => 'Verbinden'; + @override String get disconnect => 'Verbinding verbreken'; + @override String get play => 'Afspelen'; + @override String get pause => 'Pauzeren'; + @override String get resume => 'Hervatten'; + @override String get error => 'Fout'; + @override String get search => 'Zoeken'; + @override String get home => 'Home'; + @override String get back => 'Terug'; + @override String get settings => 'Instellingen'; + @override String get mute => 'Dempen'; + @override String get ok => 'OK'; + @override String get loading => 'Laden...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensNl implements TranslationsScreensEn { @override String get switchProfile => 'Wissel van profiel'; @override String get subtitleStyling => 'Ondertitel opmaak'; @override String get mpvConfig => 'MPV-configuratie'; - @override String get search => 'Zoeken'; @override String get logs => 'Logbestanden'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsNl implements TranslationsVideoControlsEn { @override String get timelineSlider => 'Videotijdlijn'; @override String get volumeSlider => 'Volumeniveau'; @override String endsAt({required Object time}) => 'Eindigt om ${time}'; - @override String get backButton => 'Terug'; @override String get pipFailed => 'Beeld-in-beeld kon niet worden gestart'; @override late final _TranslationsVideoControlsPipErrorsNl pipErrors = _TranslationsVideoControlsPipErrorsNl._(_root); + @override String get chapters => 'Hoofdstukken'; + @override String get noChaptersAvailable => 'Geen hoofdstukken beschikbaar'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogNl implements TranslationsDialogEn { // Translations @override String get confirmAction => 'Bevestig actie'; - @override String get cancel => 'Annuleren'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverNl implements TranslationsDiscoverEn { // Translations @override String get title => 'Ontdekken'; @override String get switchProfile => 'Wissel van profiel'; - @override String get logout => 'Uitloggen'; @override String get noContentAvailable => 'Geen inhoud beschikbaar'; @override String get addMediaToLibraries => 'Voeg wat media toe aan je bibliotheken'; @override String get continueWatching => 'Verder kijken'; - @override String get play => 'Afspelen'; @override String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - @override String get pause => 'Pauzeren'; @override String get overview => 'Overzicht'; @override String get cast => 'Acteurs'; @override String get seasons => 'Seizoenen'; @@ -748,10 +758,7 @@ class _TranslationsNavigationNl implements TranslationsNavigationEn { final TranslationsNl _root; // ignore: unused_field // Translations - @override String get home => 'Thuis'; - @override String get search => 'Zoeken'; @override String get libraries => 'Bibliotheken'; - @override String get settings => 'Instellingen'; @override String get downloads => 'Downloads'; } @@ -776,6 +783,10 @@ class _TranslationsDownloadsNl implements TranslationsDownloadsEn { @override String get downloadDeleted => 'Download verwijderd'; @override String deleteConfirm({required Object title}) => 'Weet je zeker dat je "${title}" wilt verwijderen? Het gedownloade bestand wordt van je apparaat verwijderd.'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => 'Verwijderen van ${title}... (${current} van ${total})'; + @override String get noDownloadsTree => 'Geen downloads'; + @override String get pauseAll => 'Alles pauzeren'; + @override String get resumeAll => 'Alles hervatten'; + @override String get deleteAll => 'Alles verwijderen'; } // Path: playlists @@ -910,6 +921,42 @@ class _TranslationsShadersNl implements TranslationsShadersEn { @override String get mode => 'Modus'; } +// Path: companionRemote +class _TranslationsCompanionRemoteNl implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteNl._(this._root); + + final TranslationsNl _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => 'Verbinden met apparaat'; + @override String get hostRemoteSession => 'Externe sessie hosten'; + @override String get controlThisDevice => 'Bedien dit apparaat met je telefoon'; + @override String get remoteControl => 'Afstandsbediening'; + @override String get controlDesktop => 'Bedien een desktop-apparaat'; + @override String connectedTo({required Object name}) => 'Verbonden met ${name}'; + @override late final _TranslationsCompanionRemoteSessionNl session = _TranslationsCompanionRemoteSessionNl._(_root); + @override late final _TranslationsCompanionRemotePairingNl pairing = _TranslationsCompanionRemotePairingNl._(_root); + @override late final _TranslationsCompanionRemoteRemoteNl remote = _TranslationsCompanionRemoteRemoteNl._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsNl implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsNl._(this._root); + + final TranslationsNl _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => 'Afspeelinstellingen'; + @override String get playbackSpeed => 'Afspeelsnelheid'; + @override String get sleepTimer => 'Slaaptimer'; + @override String get audioSync => 'Audio synchronisatie'; + @override String get subtitleSync => 'Ondertitel synchronisatie'; + @override String get hdr => 'HDR'; + @override String get audioOutput => 'Audio-uitvoer'; + @override String get performanceOverlay => 'Prestatie-overlay'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsNl implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsNl._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsNl implements TranslationsHotkeysActionsEn { @override String get subSeekNext => 'Naar volgende ondertitel'; @override String get subSeekPrev => 'Naar vorige ondertitel'; @override String get shaderToggle => 'Shaders aan/uit'; + @override String get skipMarker => 'Intro/aftiteling overslaan'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsNl implements TranslationsLibrariesGrouping @override String get folders => 'Mappen'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionNl implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionNl._(this._root); + + final TranslationsNl _root; // ignore: unused_field + + // Translations + @override String get creatingSession => 'Externe sessie aanmaken...'; + @override String get failedToCreate => 'Kan externe sessie niet aanmaken:'; + @override String get noSession => 'Geen sessie beschikbaar'; + @override String get scanQrCode => 'Scan QR-code'; + @override String get orEnterManually => 'Of voer handmatig in'; + @override String get hostAddress => 'Hostadres'; + @override String get sessionId => 'Sessie-ID'; + @override String get pin => 'PIN'; + @override String get connected => 'Verbonden'; + @override String get waitingForConnection => 'Wachten op verbinding...'; + @override String get usePhoneToControl => 'Gebruik je mobiele apparaat om deze app te bedienen'; + @override String copiedToClipboard({required Object label}) => '${label} gekopieerd naar klembord'; + @override String get copyToClipboard => 'Kopieer naar klembord'; + @override String get newSession => 'Nieuwe sessie'; + @override String get minimize => 'Minimaliseren'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingNl implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingNl._(this._root); + + final TranslationsNl _root; // ignore: unused_field + + // Translations + @override String get recent => 'Recent'; + @override String get scan => 'Scannen'; + @override String get manual => 'Handmatig'; + @override String get recentConnections => 'Recente verbindingen'; + @override String get quickReconnect => 'Snel opnieuw verbinden met eerder gekoppelde apparaten'; + @override String get pairWithDesktop => 'Koppelen met desktop'; + @override String get enterSessionDetails => 'Voer de sessiegegevens in die op je desktop-apparaat worden getoond'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => 'Voer 8-tekens sessie-ID in'; + @override String get pinHint => 'Voer 6-cijferige PIN in'; + @override String get connecting => 'Verbinden...'; + @override String get tips => 'Tips'; + @override String get tipDesktop => 'Open Plezy op je desktop en schakel Companion Remote in via instellingen of menu'; + @override String get tipScan => 'Gebruik het tabblad Scannen om snel te koppelen door de QR-code op je desktop te scannen'; + @override String get tipWifi => 'Zorg ervoor dat beide apparaten op hetzelfde WiFi-netwerk zitten'; + @override String get cameraPermissionRequired => 'Cameratoestemming is vereist om QR-codes te scannen.\nGeef cameratoegang in je apparaatinstellingen.'; + @override String cameraError({required Object error}) => 'Kan camera niet starten: ${error}'; + @override String get scanInstruction => 'Richt je camera op de QR-code die op je desktop wordt getoond'; + @override String get noRecentConnections => 'Geen recente verbindingen'; + @override String get connectUsingManual => 'Verbind met een apparaat via Handmatige invoer om te beginnen'; + @override String get invalidQrCode => 'Ongeldig QR-codeformaat'; + @override String get removeRecentConnection => 'Recente verbinding verwijderen'; + @override String removeConfirm({required Object name}) => '"${name}" verwijderen uit recente verbindingen?'; + @override String get validationHostRequired => 'Voer een hostadres in'; + @override String get validationHostFormat => 'Formaat moet IP:poort zijn (bijv. 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => 'Voer een sessie-ID in'; + @override String get validationSessionIdLength => 'Sessie-ID moet 8 tekens zijn'; + @override String get validationPinRequired => 'Voer een PIN in'; + @override String get validationPinLength => 'PIN moet 6 cijfers zijn'; + @override String get connectionTimedOut => 'Verbinding verlopen. Controleer de sessie-ID en PIN.'; + @override String get sessionNotFound => 'Kan de sessie niet vinden. Controleer je gegevens.'; + @override String failedToConnect({required Object error}) => 'Verbinden mislukt: ${error}'; + @override String failedToLoadRecent({required Object error}) => 'Kan recente sessies niet laden: ${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteNl implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteNl._(this._root); + + final TranslationsNl _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => 'Wil je de verbinding met de externe sessie verbreken?'; + @override String get reconnecting => 'Opnieuw verbinden...'; + @override String attemptOf({required Object current}) => 'Poging ${current} van 5'; + @override String get retryNow => 'Nu opnieuw proberen'; + @override String get connectionError => 'Verbindingsfout'; + @override String get notConnected => 'Niet verbonden'; + @override String get tabRemote => 'Afstandsbediening'; + @override String get tabPlay => 'Afspelen'; + @override String get tabMore => 'Meer'; + @override String get menu => 'Menu'; + @override String get tabNavigation => 'Tabnavigatie'; + @override String get tabDiscover => 'Ontdekken'; + @override String get tabLibraries => 'Bibliotheken'; + @override String get tabSearch => 'Zoeken'; + @override String get tabDownloads => 'Downloads'; + @override String get tabSettings => 'Instellingen'; + @override String get previous => 'Vorige'; + @override String get playPause => 'Afspelen/Pauzeren'; + @override String get next => 'Volgende'; + @override String get seekBack => 'Terugspoelen'; + @override String get stop => 'Stoppen'; + @override String get seekForward => 'Vooruitspoelen'; + @override String get volume => 'Volume'; + @override String get volumeDown => 'Omlaag'; + @override String get volumeUp => 'Omhoog'; + @override String get fullscreen => 'Volledig scherm'; + @override String get subtitles => 'Ondertitels'; + @override String get audio => 'Audio'; + @override String get searchHint => 'Zoeken op desktop...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsNl { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => 'Laden...', 'auth.signInWithPlex' => 'Inloggen met Plex', 'auth.showQRCode' => 'Toon QR-code', - 'auth.cancel' => 'Annuleren', 'auth.authenticate' => 'Authenticeren', - 'auth.retry' => 'Opnieuw proberen', 'auth.debugEnterToken' => 'Debug: Voer Plex Token in', 'auth.plexTokenLabel' => 'Plex Authenticatietoken', 'auth.plexTokenHint' => 'Voer je Plex.tv token in', @@ -1018,11 +1167,25 @@ extension on TranslationsNl { 'common.delete' => 'Verwijderen', 'common.shuffle' => 'Willekeurig', 'common.addTo' => 'Toevoegen aan...', + 'common.remove' => 'Verwijderen', + 'common.paste' => 'Plakken', + 'common.connect' => 'Verbinden', + 'common.disconnect' => 'Verbinding verbreken', + 'common.play' => 'Afspelen', + 'common.pause' => 'Pauzeren', + 'common.resume' => 'Hervatten', + 'common.error' => 'Fout', + 'common.search' => 'Zoeken', + 'common.home' => 'Home', + 'common.back' => 'Terug', + 'common.settings' => 'Instellingen', + 'common.mute' => 'Dempen', + 'common.ok' => 'OK', + 'common.loading' => 'Laden...', 'screens.licenses' => 'Licenties', 'screens.switchProfile' => 'Wissel van profiel', 'screens.subtitleStyling' => 'Ondertitel opmaak', 'screens.mpvConfig' => 'MPV-configuratie', - 'screens.search' => 'Zoeken', 'screens.logs' => 'Logbestanden', 'update.available' => 'Update beschikbaar', 'update.versionAvailable' => ({required Object version}) => 'Versie ${version} is beschikbaar', @@ -1176,6 +1339,7 @@ extension on TranslationsNl { 'hotkeys.actions.subSeekNext' => 'Naar volgende ondertitel', 'hotkeys.actions.subSeekPrev' => 'Naar vorige ondertitel', 'hotkeys.actions.shaderToggle' => 'Shaders aan/uit', + 'hotkeys.actions.skipMarker' => 'Intro/aftiteling overslaan', 'pinEntry.enterPin' => 'Voer PIN in', 'pinEntry.showPin' => 'Toon PIN', 'pinEntry.hidePin' => 'Verberg PIN', @@ -1266,13 +1430,14 @@ extension on TranslationsNl { 'videoControls.timelineSlider' => 'Videotijdlijn', 'videoControls.volumeSlider' => 'Volumeniveau', 'videoControls.endsAt' => ({required Object time}) => 'Eindigt om ${time}', - 'videoControls.backButton' => 'Terug', 'videoControls.pipFailed' => 'Beeld-in-beeld kon niet worden gestart', 'videoControls.pipErrors.androidVersion' => 'Vereist Android 8.0 of nieuwer', 'videoControls.pipErrors.permissionDisabled' => 'Beeld-in-beeld toestemming is uitgeschakeld. Schakel deze in via Instellingen > Apps > Plezy > Beeld-in-beeld', 'videoControls.pipErrors.notSupported' => 'Dit apparaat ondersteunt geen beeld-in-beeld modus', 'videoControls.pipErrors.failed' => 'Beeld-in-beeld kon niet worden gestart', 'videoControls.pipErrors.unknown' => ({required Object error}) => 'Er is een fout opgetreden: ${error}', + 'videoControls.chapters' => 'Hoofdstukken', + 'videoControls.noChaptersAvailable' => 'Geen hoofdstukken beschikbaar', 'userStatus.admin' => 'Beheerder', 'userStatus.restricted' => 'Beperkt', 'userStatus.protected' => 'Beschermd', @@ -1343,16 +1508,12 @@ extension on TranslationsNl { 'mpvConfig.confirmDeleteProperty' => 'Weet je zeker dat je deze eigenschap wilt verwijderen?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} items', 'dialog.confirmAction' => 'Bevestig actie', - 'dialog.cancel' => 'Annuleren', 'discover.title' => 'Ontdekken', 'discover.switchProfile' => 'Wissel van profiel', - 'discover.logout' => 'Uitloggen', 'discover.noContentAvailable' => 'Geen inhoud beschikbaar', 'discover.addMediaToLibraries' => 'Voeg wat media toe aan je bibliotheken', 'discover.continueWatching' => 'Verder kijken', - 'discover.play' => 'Afspelen', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => 'Pauzeren', 'discover.overview' => 'Overzicht', 'discover.cast' => 'Acteurs', 'discover.seasons' => 'Seizoenen', @@ -1442,10 +1603,7 @@ extension on TranslationsNl { 'licenses.license' => 'Licentie', 'licenses.licenseNumber' => ({required Object number}) => 'Licentie ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} licenties', - 'navigation.home' => 'Thuis', - 'navigation.search' => 'Zoeken', 'navigation.libraries' => 'Bibliotheken', - 'navigation.settings' => 'Instellingen', 'navigation.downloads' => 'Downloads', 'downloads.title' => 'Downloads', 'downloads.manage' => 'Beheren', @@ -1461,6 +1619,10 @@ extension on TranslationsNl { 'downloads.downloadDeleted' => 'Download verwijderd', 'downloads.deleteConfirm' => ({required Object title}) => 'Weet je zeker dat je "${title}" wilt verwijderen? Het gedownloade bestand wordt van je apparaat verwijderd.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => 'Verwijderen van ${title}... (${current} van ${total})', + 'downloads.noDownloadsTree' => 'Geen downloads', + 'downloads.pauseAll' => 'Alles pauzeren', + 'downloads.resumeAll' => 'Alles hervatten', + 'downloads.deleteAll' => 'Alles verwijderen', 'playlists.title' => 'Afspeellijsten', 'playlists.noPlaylists' => 'Geen afspeellijsten gevonden', 'playlists.create' => 'Afspeellijst maken', @@ -1489,6 +1651,8 @@ extension on TranslationsNl { 'playlists.playlist' => 'Afspeellijst', 'collections.title' => 'Collecties', 'collections.collection' => 'Collectie', + _ => null, + } ?? switch (path) { 'collections.empty' => 'Collectie is leeg', 'collections.unknownLibrarySection' => 'Kan niet verwijderen: onbekende bibliotheeksectie', 'collections.deleteCollection' => 'Collectie verwijderen', @@ -1499,8 +1663,6 @@ extension on TranslationsNl { 'collections.failedToLoadItems' => ({required Object error}) => 'Collectie-items laden mislukt: ${error}', 'collections.selectCollection' => 'Selecteer collectie', 'collections.createNewCollection' => 'Nieuwe collectie maken', - _ => null, - } ?? switch (path) { 'collections.collectionName' => 'Collectienaam', 'collections.enterCollectionName' => 'Voer collectienaam in', 'collections.addedToCollection' => 'Toegevoegd aan collectie', @@ -1559,6 +1721,98 @@ extension on TranslationsNl { 'shaders.qualityFast' => 'Snel', 'shaders.qualityHQ' => 'Hoge kwaliteit', 'shaders.mode' => 'Modus', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => 'Verbinden met apparaat', + 'companionRemote.hostRemoteSession' => 'Externe sessie hosten', + 'companionRemote.controlThisDevice' => 'Bedien dit apparaat met je telefoon', + 'companionRemote.remoteControl' => 'Afstandsbediening', + 'companionRemote.controlDesktop' => 'Bedien een desktop-apparaat', + 'companionRemote.connectedTo' => ({required Object name}) => 'Verbonden met ${name}', + 'companionRemote.session.creatingSession' => 'Externe sessie aanmaken...', + 'companionRemote.session.failedToCreate' => 'Kan externe sessie niet aanmaken:', + 'companionRemote.session.noSession' => 'Geen sessie beschikbaar', + 'companionRemote.session.scanQrCode' => 'Scan QR-code', + 'companionRemote.session.orEnterManually' => 'Of voer handmatig in', + 'companionRemote.session.hostAddress' => 'Hostadres', + 'companionRemote.session.sessionId' => 'Sessie-ID', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => 'Verbonden', + 'companionRemote.session.waitingForConnection' => 'Wachten op verbinding...', + 'companionRemote.session.usePhoneToControl' => 'Gebruik je mobiele apparaat om deze app te bedienen', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label} gekopieerd naar klembord', + 'companionRemote.session.copyToClipboard' => 'Kopieer naar klembord', + 'companionRemote.session.newSession' => 'Nieuwe sessie', + 'companionRemote.session.minimize' => 'Minimaliseren', + 'companionRemote.pairing.recent' => 'Recent', + 'companionRemote.pairing.scan' => 'Scannen', + 'companionRemote.pairing.manual' => 'Handmatig', + 'companionRemote.pairing.recentConnections' => 'Recente verbindingen', + 'companionRemote.pairing.quickReconnect' => 'Snel opnieuw verbinden met eerder gekoppelde apparaten', + 'companionRemote.pairing.pairWithDesktop' => 'Koppelen met desktop', + 'companionRemote.pairing.enterSessionDetails' => 'Voer de sessiegegevens in die op je desktop-apparaat worden getoond', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => 'Voer 8-tekens sessie-ID in', + 'companionRemote.pairing.pinHint' => 'Voer 6-cijferige PIN in', + 'companionRemote.pairing.connecting' => 'Verbinden...', + 'companionRemote.pairing.tips' => 'Tips', + 'companionRemote.pairing.tipDesktop' => 'Open Plezy op je desktop en schakel Companion Remote in via instellingen of menu', + 'companionRemote.pairing.tipScan' => 'Gebruik het tabblad Scannen om snel te koppelen door de QR-code op je desktop te scannen', + 'companionRemote.pairing.tipWifi' => 'Zorg ervoor dat beide apparaten op hetzelfde WiFi-netwerk zitten', + 'companionRemote.pairing.cameraPermissionRequired' => 'Cameratoestemming is vereist om QR-codes te scannen.\nGeef cameratoegang in je apparaatinstellingen.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => 'Kan camera niet starten: ${error}', + 'companionRemote.pairing.scanInstruction' => 'Richt je camera op de QR-code die op je desktop wordt getoond', + 'companionRemote.pairing.noRecentConnections' => 'Geen recente verbindingen', + 'companionRemote.pairing.connectUsingManual' => 'Verbind met een apparaat via Handmatige invoer om te beginnen', + 'companionRemote.pairing.invalidQrCode' => 'Ongeldig QR-codeformaat', + 'companionRemote.pairing.removeRecentConnection' => 'Recente verbinding verwijderen', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => '"${name}" verwijderen uit recente verbindingen?', + 'companionRemote.pairing.validationHostRequired' => 'Voer een hostadres in', + 'companionRemote.pairing.validationHostFormat' => 'Formaat moet IP:poort zijn (bijv. 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => 'Voer een sessie-ID in', + 'companionRemote.pairing.validationSessionIdLength' => 'Sessie-ID moet 8 tekens zijn', + 'companionRemote.pairing.validationPinRequired' => 'Voer een PIN in', + 'companionRemote.pairing.validationPinLength' => 'PIN moet 6 cijfers zijn', + 'companionRemote.pairing.connectionTimedOut' => 'Verbinding verlopen. Controleer de sessie-ID en PIN.', + 'companionRemote.pairing.sessionNotFound' => 'Kan de sessie niet vinden. Controleer je gegevens.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => 'Verbinden mislukt: ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => 'Kan recente sessies niet laden: ${error}', + 'companionRemote.remote.disconnectConfirm' => 'Wil je de verbinding met de externe sessie verbreken?', + 'companionRemote.remote.reconnecting' => 'Opnieuw verbinden...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => 'Poging ${current} van 5', + 'companionRemote.remote.retryNow' => 'Nu opnieuw proberen', + 'companionRemote.remote.connectionError' => 'Verbindingsfout', + 'companionRemote.remote.notConnected' => 'Niet verbonden', + 'companionRemote.remote.tabRemote' => 'Afstandsbediening', + 'companionRemote.remote.tabPlay' => 'Afspelen', + 'companionRemote.remote.tabMore' => 'Meer', + 'companionRemote.remote.menu' => 'Menu', + 'companionRemote.remote.tabNavigation' => 'Tabnavigatie', + 'companionRemote.remote.tabDiscover' => 'Ontdekken', + 'companionRemote.remote.tabLibraries' => 'Bibliotheken', + 'companionRemote.remote.tabSearch' => 'Zoeken', + 'companionRemote.remote.tabDownloads' => 'Downloads', + 'companionRemote.remote.tabSettings' => 'Instellingen', + 'companionRemote.remote.previous' => 'Vorige', + 'companionRemote.remote.playPause' => 'Afspelen/Pauzeren', + 'companionRemote.remote.next' => 'Volgende', + 'companionRemote.remote.seekBack' => 'Terugspoelen', + 'companionRemote.remote.stop' => 'Stoppen', + 'companionRemote.remote.seekForward' => 'Vooruitspoelen', + 'companionRemote.remote.volume' => 'Volume', + 'companionRemote.remote.volumeDown' => 'Omlaag', + 'companionRemote.remote.volumeUp' => 'Omhoog', + 'companionRemote.remote.fullscreen' => 'Volledig scherm', + 'companionRemote.remote.subtitles' => 'Ondertitels', + 'companionRemote.remote.audio' => 'Audio', + 'companionRemote.remote.searchHint' => 'Zoeken op desktop...', + 'videoSettings.playbackSettings' => 'Afspeelinstellingen', + 'videoSettings.playbackSpeed' => 'Afspeelsnelheid', + 'videoSettings.sleepTimer' => 'Slaaptimer', + 'videoSettings.audioSync' => 'Audio synchronisatie', + 'videoSettings.subtitleSync' => 'Ondertitel synchronisatie', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => 'Audio-uitvoer', + 'videoSettings.performanceOverlay' => 'Prestatie-overlay', _ => null, }; } diff --git a/lib/i18n/strings_sv.g.dart b/lib/i18n/strings_sv.g.dart index c4e37017..17758d85 100644 --- a/lib/i18n/strings_sv.g.dart +++ b/lib/i18n/strings_sv.g.dart @@ -70,6 +70,8 @@ class TranslationsSv with BaseTranslations implements T @override late final _TranslationsCollectionsSv collections = _TranslationsCollectionsSv._(_root); @override late final _TranslationsWatchTogetherSv watchTogether = _TranslationsWatchTogetherSv._(_root); @override late final _TranslationsShadersSv shaders = _TranslationsShadersSv._(_root); + @override late final _TranslationsCompanionRemoteSv companionRemote = _TranslationsCompanionRemoteSv._(_root); + @override late final _TranslationsVideoSettingsSv videoSettings = _TranslationsVideoSettingsSv._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppSv implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => 'Laddar...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthSv implements TranslationsAuthEn { // Translations @override String get signInWithPlex => 'Logga in med Plex'; @override String get showQRCode => 'Visa QR-kod'; - @override String get cancel => 'Avbryt'; @override String get authenticate => 'Autentisera'; - @override String get retry => 'Försök igen'; @override String get debugEnterToken => 'Debug: Ange Plex-token'; @override String get plexTokenLabel => 'Plex-autentiseringstoken'; @override String get plexTokenHint => 'Ange din Plex.tv-token'; @@ -128,6 +127,21 @@ class _TranslationsCommonSv implements TranslationsCommonEn { @override String get delete => 'Ta bort'; @override String get shuffle => 'Blanda'; @override String get addTo => 'Lägg till i...'; + @override String get remove => 'Ta bort'; + @override String get paste => 'Klistra in'; + @override String get connect => 'Anslut'; + @override String get disconnect => 'Koppla från'; + @override String get play => 'Spela'; + @override String get pause => 'Pausa'; + @override String get resume => 'Återuppta'; + @override String get error => 'Fel'; + @override String get search => 'Sök'; + @override String get home => 'Hem'; + @override String get back => 'Tillbaka'; + @override String get settings => 'Inställningar'; + @override String get mute => 'Ljud av'; + @override String get ok => 'OK'; + @override String get loading => 'Laddar...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensSv implements TranslationsScreensEn { @override String get switchProfile => 'Byt profil'; @override String get subtitleStyling => 'Undertext-styling'; @override String get mpvConfig => 'MPV-konfiguration'; - @override String get search => 'Sök'; @override String get logs => 'Loggar'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsSv implements TranslationsVideoControlsEn { @override String get timelineSlider => 'Videotidslinje'; @override String get volumeSlider => 'Volymnivå'; @override String endsAt({required Object time}) => 'Slutar ${time}'; - @override String get backButton => 'Tillbaka'; @override String get pipFailed => 'Bild-i-bild kunde inte starta'; @override late final _TranslationsVideoControlsPipErrorsSv pipErrors = _TranslationsVideoControlsPipErrorsSv._(_root); + @override String get chapters => 'Kapitel'; + @override String get noChaptersAvailable => 'Inga kapitel tillgängliga'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogSv implements TranslationsDialogEn { // Translations @override String get confirmAction => 'Bekräfta åtgärd'; - @override String get cancel => 'Avbryt'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverSv implements TranslationsDiscoverEn { // Translations @override String get title => 'Upptäck'; @override String get switchProfile => 'Byt profil'; - @override String get logout => 'Logga ut'; @override String get noContentAvailable => 'Inget innehåll tillgängligt'; @override String get addMediaToLibraries => 'Lägg till media till dina bibliotek'; @override String get continueWatching => 'Fortsätt titta'; - @override String get play => 'Spela'; @override String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - @override String get pause => 'Pausa'; @override String get overview => 'Översikt'; @override String get cast => 'Rollbesättning'; @override String get seasons => 'Säsonger'; @@ -748,10 +758,7 @@ class _TranslationsNavigationSv implements TranslationsNavigationEn { final TranslationsSv _root; // ignore: unused_field // Translations - @override String get home => 'Hem'; - @override String get search => 'Sök'; @override String get libraries => 'Bibliotek'; - @override String get settings => 'Inställningar'; @override String get downloads => 'Nedladdningar'; } @@ -776,6 +783,10 @@ class _TranslationsDownloadsSv implements TranslationsDownloadsEn { @override String get downloadDeleted => 'Nedladdning borttagen'; @override String deleteConfirm({required Object title}) => 'Är du säker på att du vill ta bort "${title}"? Den nedladdade filen kommer att tas bort från din enhet.'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => 'Tar bort ${title}... (${current} av ${total})'; + @override String get noDownloadsTree => 'Inga nedladdningar'; + @override String get pauseAll => 'Pausa alla'; + @override String get resumeAll => 'Återuppta alla'; + @override String get deleteAll => 'Ta bort alla'; } // Path: playlists @@ -910,6 +921,42 @@ class _TranslationsShadersSv implements TranslationsShadersEn { @override String get mode => 'Läge'; } +// Path: companionRemote +class _TranslationsCompanionRemoteSv implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteSv._(this._root); + + final TranslationsSv _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => 'Anslut till enhet'; + @override String get hostRemoteSession => 'Starta fjärrsession'; + @override String get controlThisDevice => 'Styr den här enheten med din telefon'; + @override String get remoteControl => 'Fjärrkontroll'; + @override String get controlDesktop => 'Styr en datorenhet'; + @override String connectedTo({required Object name}) => 'Ansluten till ${name}'; + @override late final _TranslationsCompanionRemoteSessionSv session = _TranslationsCompanionRemoteSessionSv._(_root); + @override late final _TranslationsCompanionRemotePairingSv pairing = _TranslationsCompanionRemotePairingSv._(_root); + @override late final _TranslationsCompanionRemoteRemoteSv remote = _TranslationsCompanionRemoteRemoteSv._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsSv implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsSv._(this._root); + + final TranslationsSv _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => 'Uppspelningsinställningar'; + @override String get playbackSpeed => 'Uppspelningshastighet'; + @override String get sleepTimer => 'Sovtimer'; + @override String get audioSync => 'Ljudsynkronisering'; + @override String get subtitleSync => 'Undertextsynkronisering'; + @override String get hdr => 'HDR'; + @override String get audioOutput => 'Ljudutgång'; + @override String get performanceOverlay => 'Prestandaöverlägg'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsSv implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsSv._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsSv implements TranslationsHotkeysActionsEn { @override String get subSeekNext => 'Hoppa till nästa undertext'; @override String get subSeekPrev => 'Hoppa till föregående undertext'; @override String get shaderToggle => 'Växla shaders'; + @override String get skipMarker => 'Hoppa över intro/eftertexter'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsSv implements TranslationsLibrariesGrouping @override String get folders => 'Mappar'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionSv implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionSv._(this._root); + + final TranslationsSv _root; // ignore: unused_field + + // Translations + @override String get creatingSession => 'Skapar fjärrsession...'; + @override String get failedToCreate => 'Kunde inte skapa fjärrsession:'; + @override String get noSession => 'Ingen session tillgänglig'; + @override String get scanQrCode => 'Skanna QR-kod'; + @override String get orEnterManually => 'Eller ange manuellt'; + @override String get hostAddress => 'Värdadress'; + @override String get sessionId => 'Sessions-ID'; + @override String get pin => 'PIN'; + @override String get connected => 'Ansluten'; + @override String get waitingForConnection => 'Väntar på anslutning...'; + @override String get usePhoneToControl => 'Använd din mobila enhet för att styra denna app'; + @override String copiedToClipboard({required Object label}) => '${label} kopierad till urklipp'; + @override String get copyToClipboard => 'Kopiera till urklipp'; + @override String get newSession => 'Ny session'; + @override String get minimize => 'Minimera'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingSv implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingSv._(this._root); + + final TranslationsSv _root; // ignore: unused_field + + // Translations + @override String get recent => 'Senaste'; + @override String get scan => 'Skanna'; + @override String get manual => 'Manuell'; + @override String get recentConnections => 'Senaste anslutningar'; + @override String get quickReconnect => 'Återanslut snabbt till tidigare parkopplade enheter'; + @override String get pairWithDesktop => 'Parkoppla med dator'; + @override String get enterSessionDetails => 'Ange sessionsuppgifterna som visas på din datorenhet'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => 'Ange 8-teckens sessions-ID'; + @override String get pinHint => 'Ange 6-siffrig PIN'; + @override String get connecting => 'Ansluter...'; + @override String get tips => 'Tips'; + @override String get tipDesktop => 'Öppna Plezy på din dator och aktivera Companion Remote via inställningar eller meny'; + @override String get tipScan => 'Använd fliken Skanna för att snabbt parkoppla genom att skanna QR-koden på din dator'; + @override String get tipWifi => 'Se till att båda enheterna är på samma WiFi-nätverk'; + @override String get cameraPermissionRequired => 'Kamerabehörighet krävs för att skanna QR-koder.\nVänligen ge kameraåtkomst i enhetsinställningarna.'; + @override String cameraError({required Object error}) => 'Kunde inte starta kameran: ${error}'; + @override String get scanInstruction => 'Rikta kameran mot QR-koden som visas på din dator'; + @override String get noRecentConnections => 'Inga senaste anslutningar'; + @override String get connectUsingManual => 'Anslut till en enhet via Manuell inmatning för att komma igång'; + @override String get invalidQrCode => 'Ogiltigt QR-kodformat'; + @override String get removeRecentConnection => 'Ta bort senaste anslutning'; + @override String removeConfirm({required Object name}) => 'Ta bort "${name}" från senaste anslutningar?'; + @override String get validationHostRequired => 'Ange en värdadress'; + @override String get validationHostFormat => 'Format måste vara IP:port (t.ex. 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => 'Ange ett sessions-ID'; + @override String get validationSessionIdLength => 'Sessions-ID måste vara 8 tecken'; + @override String get validationPinRequired => 'Ange en PIN'; + @override String get validationPinLength => 'PIN måste vara 6 siffror'; + @override String get connectionTimedOut => 'Anslutningen tog för lång tid. Kontrollera sessions-ID och PIN.'; + @override String get sessionNotFound => 'Kunde inte hitta sessionen. Kontrollera dina uppgifter.'; + @override String failedToConnect({required Object error}) => 'Kunde inte ansluta: ${error}'; + @override String failedToLoadRecent({required Object error}) => 'Kunde inte ladda senaste sessioner: ${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteSv implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteSv._(this._root); + + final TranslationsSv _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => 'Vill du koppla från fjärrsessionen?'; + @override String get reconnecting => 'Återansluter...'; + @override String attemptOf({required Object current}) => 'Försök ${current} av 5'; + @override String get retryNow => 'Försök nu'; + @override String get connectionError => 'Anslutningsfel'; + @override String get notConnected => 'Inte ansluten'; + @override String get tabRemote => 'Fjärrkontroll'; + @override String get tabPlay => 'Spela'; + @override String get tabMore => 'Mer'; + @override String get menu => 'Meny'; + @override String get tabNavigation => 'Fliknavigering'; + @override String get tabDiscover => 'Upptäck'; + @override String get tabLibraries => 'Bibliotek'; + @override String get tabSearch => 'Sök'; + @override String get tabDownloads => 'Nedladdningar'; + @override String get tabSettings => 'Inställningar'; + @override String get previous => 'Föregående'; + @override String get playPause => 'Spela/Pausa'; + @override String get next => 'Nästa'; + @override String get seekBack => 'Spola bakåt'; + @override String get stop => 'Stopp'; + @override String get seekForward => 'Spola framåt'; + @override String get volume => 'Volym'; + @override String get volumeDown => 'Ner'; + @override String get volumeUp => 'Upp'; + @override String get fullscreen => 'Helskärm'; + @override String get subtitles => 'Undertexter'; + @override String get audio => 'Ljud'; + @override String get searchHint => 'Sök på datorn...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsSv { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => 'Laddar...', 'auth.signInWithPlex' => 'Logga in med Plex', 'auth.showQRCode' => 'Visa QR-kod', - 'auth.cancel' => 'Avbryt', 'auth.authenticate' => 'Autentisera', - 'auth.retry' => 'Försök igen', 'auth.debugEnterToken' => 'Debug: Ange Plex-token', 'auth.plexTokenLabel' => 'Plex-autentiseringstoken', 'auth.plexTokenHint' => 'Ange din Plex.tv-token', @@ -1018,11 +1167,25 @@ extension on TranslationsSv { 'common.delete' => 'Ta bort', 'common.shuffle' => 'Blanda', 'common.addTo' => 'Lägg till i...', + 'common.remove' => 'Ta bort', + 'common.paste' => 'Klistra in', + 'common.connect' => 'Anslut', + 'common.disconnect' => 'Koppla från', + 'common.play' => 'Spela', + 'common.pause' => 'Pausa', + 'common.resume' => 'Återuppta', + 'common.error' => 'Fel', + 'common.search' => 'Sök', + 'common.home' => 'Hem', + 'common.back' => 'Tillbaka', + 'common.settings' => 'Inställningar', + 'common.mute' => 'Ljud av', + 'common.ok' => 'OK', + 'common.loading' => 'Laddar...', 'screens.licenses' => 'Licenser', 'screens.switchProfile' => 'Byt profil', 'screens.subtitleStyling' => 'Undertext-styling', 'screens.mpvConfig' => 'MPV-konfiguration', - 'screens.search' => 'Sök', 'screens.logs' => 'Loggar', 'update.available' => 'Uppdatering tillgänglig', 'update.versionAvailable' => ({required Object version}) => 'Version ${version} är tillgänglig', @@ -1176,6 +1339,7 @@ extension on TranslationsSv { 'hotkeys.actions.subSeekNext' => 'Hoppa till nästa undertext', 'hotkeys.actions.subSeekPrev' => 'Hoppa till föregående undertext', 'hotkeys.actions.shaderToggle' => 'Växla shaders', + 'hotkeys.actions.skipMarker' => 'Hoppa över intro/eftertexter', 'pinEntry.enterPin' => 'Ange PIN', 'pinEntry.showPin' => 'Visa PIN', 'pinEntry.hidePin' => 'Dölj PIN', @@ -1266,13 +1430,14 @@ extension on TranslationsSv { 'videoControls.timelineSlider' => 'Videotidslinje', 'videoControls.volumeSlider' => 'Volymnivå', 'videoControls.endsAt' => ({required Object time}) => 'Slutar ${time}', - 'videoControls.backButton' => 'Tillbaka', 'videoControls.pipFailed' => 'Bild-i-bild kunde inte starta', 'videoControls.pipErrors.androidVersion' => 'Kräver Android 8.0 eller nyare', 'videoControls.pipErrors.permissionDisabled' => 'Bild-i-bild-behörighet är inaktiverad. Aktivera den i Inställningar > Appar > Plezy > Bild-i-bild', 'videoControls.pipErrors.notSupported' => 'Denna enhet stöder inte bild-i-bild-läge', 'videoControls.pipErrors.failed' => 'Bild-i-bild kunde inte starta', 'videoControls.pipErrors.unknown' => ({required Object error}) => 'Ett fel uppstod: ${error}', + 'videoControls.chapters' => 'Kapitel', + 'videoControls.noChaptersAvailable' => 'Inga kapitel tillgängliga', 'userStatus.admin' => 'Admin', 'userStatus.restricted' => 'Begränsad', 'userStatus.protected' => 'Skyddad', @@ -1343,16 +1508,12 @@ extension on TranslationsSv { 'mpvConfig.confirmDeleteProperty' => 'Är du säker på att du vill ta bort denna egenskap?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} poster', 'dialog.confirmAction' => 'Bekräfta åtgärd', - 'dialog.cancel' => 'Avbryt', 'discover.title' => 'Upptäck', 'discover.switchProfile' => 'Byt profil', - 'discover.logout' => 'Logga ut', 'discover.noContentAvailable' => 'Inget innehåll tillgängligt', 'discover.addMediaToLibraries' => 'Lägg till media till dina bibliotek', 'discover.continueWatching' => 'Fortsätt titta', - 'discover.play' => 'Spela', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => 'Pausa', 'discover.overview' => 'Översikt', 'discover.cast' => 'Rollbesättning', 'discover.seasons' => 'Säsonger', @@ -1442,10 +1603,7 @@ extension on TranslationsSv { 'licenses.license' => 'Licens', 'licenses.licenseNumber' => ({required Object number}) => 'Licens ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} licenser', - 'navigation.home' => 'Hem', - 'navigation.search' => 'Sök', 'navigation.libraries' => 'Bibliotek', - 'navigation.settings' => 'Inställningar', 'navigation.downloads' => 'Nedladdningar', 'downloads.title' => 'Nedladdningar', 'downloads.manage' => 'Hantera', @@ -1461,6 +1619,10 @@ extension on TranslationsSv { 'downloads.downloadDeleted' => 'Nedladdning borttagen', 'downloads.deleteConfirm' => ({required Object title}) => 'Är du säker på att du vill ta bort "${title}"? Den nedladdade filen kommer att tas bort från din enhet.', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => 'Tar bort ${title}... (${current} av ${total})', + 'downloads.noDownloadsTree' => 'Inga nedladdningar', + 'downloads.pauseAll' => 'Pausa alla', + 'downloads.resumeAll' => 'Återuppta alla', + 'downloads.deleteAll' => 'Ta bort alla', 'playlists.title' => 'Spellistor', 'playlists.noPlaylists' => 'Inga spellistor hittades', 'playlists.create' => 'Skapa spellista', @@ -1489,6 +1651,8 @@ extension on TranslationsSv { 'playlists.playlist' => 'Spellista', 'collections.title' => 'Samlingar', 'collections.collection' => 'Samling', + _ => null, + } ?? switch (path) { 'collections.empty' => 'Samlingen är tom', 'collections.unknownLibrarySection' => 'Kan inte ta bort: okänd bibliotekssektion', 'collections.deleteCollection' => 'Ta bort samling', @@ -1499,8 +1663,6 @@ extension on TranslationsSv { 'collections.failedToLoadItems' => ({required Object error}) => 'Det gick inte att läsa in samlingsobjekt: ${error}', 'collections.selectCollection' => 'Välj samling', 'collections.createNewCollection' => 'Skapa ny samling', - _ => null, - } ?? switch (path) { 'collections.collectionName' => 'Samlingsnamn', 'collections.enterCollectionName' => 'Ange samlingsnamn', 'collections.addedToCollection' => 'Tillagd i samling', @@ -1559,6 +1721,98 @@ extension on TranslationsSv { 'shaders.qualityFast' => 'Snabb', 'shaders.qualityHQ' => 'Hög kvalitet', 'shaders.mode' => 'Läge', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => 'Anslut till enhet', + 'companionRemote.hostRemoteSession' => 'Starta fjärrsession', + 'companionRemote.controlThisDevice' => 'Styr den här enheten med din telefon', + 'companionRemote.remoteControl' => 'Fjärrkontroll', + 'companionRemote.controlDesktop' => 'Styr en datorenhet', + 'companionRemote.connectedTo' => ({required Object name}) => 'Ansluten till ${name}', + 'companionRemote.session.creatingSession' => 'Skapar fjärrsession...', + 'companionRemote.session.failedToCreate' => 'Kunde inte skapa fjärrsession:', + 'companionRemote.session.noSession' => 'Ingen session tillgänglig', + 'companionRemote.session.scanQrCode' => 'Skanna QR-kod', + 'companionRemote.session.orEnterManually' => 'Eller ange manuellt', + 'companionRemote.session.hostAddress' => 'Värdadress', + 'companionRemote.session.sessionId' => 'Sessions-ID', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => 'Ansluten', + 'companionRemote.session.waitingForConnection' => 'Väntar på anslutning...', + 'companionRemote.session.usePhoneToControl' => 'Använd din mobila enhet för att styra denna app', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label} kopierad till urklipp', + 'companionRemote.session.copyToClipboard' => 'Kopiera till urklipp', + 'companionRemote.session.newSession' => 'Ny session', + 'companionRemote.session.minimize' => 'Minimera', + 'companionRemote.pairing.recent' => 'Senaste', + 'companionRemote.pairing.scan' => 'Skanna', + 'companionRemote.pairing.manual' => 'Manuell', + 'companionRemote.pairing.recentConnections' => 'Senaste anslutningar', + 'companionRemote.pairing.quickReconnect' => 'Återanslut snabbt till tidigare parkopplade enheter', + 'companionRemote.pairing.pairWithDesktop' => 'Parkoppla med dator', + 'companionRemote.pairing.enterSessionDetails' => 'Ange sessionsuppgifterna som visas på din datorenhet', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => 'Ange 8-teckens sessions-ID', + 'companionRemote.pairing.pinHint' => 'Ange 6-siffrig PIN', + 'companionRemote.pairing.connecting' => 'Ansluter...', + 'companionRemote.pairing.tips' => 'Tips', + 'companionRemote.pairing.tipDesktop' => 'Öppna Plezy på din dator och aktivera Companion Remote via inställningar eller meny', + 'companionRemote.pairing.tipScan' => 'Använd fliken Skanna för att snabbt parkoppla genom att skanna QR-koden på din dator', + 'companionRemote.pairing.tipWifi' => 'Se till att båda enheterna är på samma WiFi-nätverk', + 'companionRemote.pairing.cameraPermissionRequired' => 'Kamerabehörighet krävs för att skanna QR-koder.\nVänligen ge kameraåtkomst i enhetsinställningarna.', + 'companionRemote.pairing.cameraError' => ({required Object error}) => 'Kunde inte starta kameran: ${error}', + 'companionRemote.pairing.scanInstruction' => 'Rikta kameran mot QR-koden som visas på din dator', + 'companionRemote.pairing.noRecentConnections' => 'Inga senaste anslutningar', + 'companionRemote.pairing.connectUsingManual' => 'Anslut till en enhet via Manuell inmatning för att komma igång', + 'companionRemote.pairing.invalidQrCode' => 'Ogiltigt QR-kodformat', + 'companionRemote.pairing.removeRecentConnection' => 'Ta bort senaste anslutning', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => 'Ta bort "${name}" från senaste anslutningar?', + 'companionRemote.pairing.validationHostRequired' => 'Ange en värdadress', + 'companionRemote.pairing.validationHostFormat' => 'Format måste vara IP:port (t.ex. 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => 'Ange ett sessions-ID', + 'companionRemote.pairing.validationSessionIdLength' => 'Sessions-ID måste vara 8 tecken', + 'companionRemote.pairing.validationPinRequired' => 'Ange en PIN', + 'companionRemote.pairing.validationPinLength' => 'PIN måste vara 6 siffror', + 'companionRemote.pairing.connectionTimedOut' => 'Anslutningen tog för lång tid. Kontrollera sessions-ID och PIN.', + 'companionRemote.pairing.sessionNotFound' => 'Kunde inte hitta sessionen. Kontrollera dina uppgifter.', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => 'Kunde inte ansluta: ${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => 'Kunde inte ladda senaste sessioner: ${error}', + 'companionRemote.remote.disconnectConfirm' => 'Vill du koppla från fjärrsessionen?', + 'companionRemote.remote.reconnecting' => 'Återansluter...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => 'Försök ${current} av 5', + 'companionRemote.remote.retryNow' => 'Försök nu', + 'companionRemote.remote.connectionError' => 'Anslutningsfel', + 'companionRemote.remote.notConnected' => 'Inte ansluten', + 'companionRemote.remote.tabRemote' => 'Fjärrkontroll', + 'companionRemote.remote.tabPlay' => 'Spela', + 'companionRemote.remote.tabMore' => 'Mer', + 'companionRemote.remote.menu' => 'Meny', + 'companionRemote.remote.tabNavigation' => 'Fliknavigering', + 'companionRemote.remote.tabDiscover' => 'Upptäck', + 'companionRemote.remote.tabLibraries' => 'Bibliotek', + 'companionRemote.remote.tabSearch' => 'Sök', + 'companionRemote.remote.tabDownloads' => 'Nedladdningar', + 'companionRemote.remote.tabSettings' => 'Inställningar', + 'companionRemote.remote.previous' => 'Föregående', + 'companionRemote.remote.playPause' => 'Spela/Pausa', + 'companionRemote.remote.next' => 'Nästa', + 'companionRemote.remote.seekBack' => 'Spola bakåt', + 'companionRemote.remote.stop' => 'Stopp', + 'companionRemote.remote.seekForward' => 'Spola framåt', + 'companionRemote.remote.volume' => 'Volym', + 'companionRemote.remote.volumeDown' => 'Ner', + 'companionRemote.remote.volumeUp' => 'Upp', + 'companionRemote.remote.fullscreen' => 'Helskärm', + 'companionRemote.remote.subtitles' => 'Undertexter', + 'companionRemote.remote.audio' => 'Ljud', + 'companionRemote.remote.searchHint' => 'Sök på datorn...', + 'videoSettings.playbackSettings' => 'Uppspelningsinställningar', + 'videoSettings.playbackSpeed' => 'Uppspelningshastighet', + 'videoSettings.sleepTimer' => 'Sovtimer', + 'videoSettings.audioSync' => 'Ljudsynkronisering', + 'videoSettings.subtitleSync' => 'Undertextsynkronisering', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => 'Ljudutgång', + 'videoSettings.performanceOverlay' => 'Prestandaöverlägg', _ => null, }; } diff --git a/lib/i18n/strings_zh.g.dart b/lib/i18n/strings_zh.g.dart index 9313eebc..17d06b14 100644 --- a/lib/i18n/strings_zh.g.dart +++ b/lib/i18n/strings_zh.g.dart @@ -70,6 +70,8 @@ class TranslationsZh with BaseTranslations implements T @override late final _TranslationsCollectionsZh collections = _TranslationsCollectionsZh._(_root); @override late final _TranslationsWatchTogetherZh watchTogether = _TranslationsWatchTogetherZh._(_root); @override late final _TranslationsShadersZh shaders = _TranslationsShadersZh._(_root); + @override late final _TranslationsCompanionRemoteZh companionRemote = _TranslationsCompanionRemoteZh._(_root); + @override late final _TranslationsVideoSettingsZh videoSettings = _TranslationsVideoSettingsZh._(_root); } // Path: app @@ -80,7 +82,6 @@ class _TranslationsAppZh implements TranslationsAppEn { // Translations @override String get title => 'Plezy'; - @override String get loading => '加载中...'; } // Path: auth @@ -92,9 +93,7 @@ class _TranslationsAuthZh implements TranslationsAuthEn { // Translations @override String get signInWithPlex => '使用 Plex 登录'; @override String get showQRCode => '显示二维码'; - @override String get cancel => '取消'; @override String get authenticate => '验证'; - @override String get retry => '重试'; @override String get debugEnterToken => '调试:输入 Plex Token'; @override String get plexTokenLabel => 'Plex 授权令牌 (Auth Token)'; @override String get plexTokenHint => '输入你的 Plex.tv 令牌'; @@ -128,6 +127,21 @@ class _TranslationsCommonZh implements TranslationsCommonEn { @override String get delete => '删除'; @override String get shuffle => '随机播放'; @override String get addTo => '添加到...'; + @override String get remove => '删除'; + @override String get paste => '粘贴'; + @override String get connect => '连接'; + @override String get disconnect => '断开连接'; + @override String get play => '播放'; + @override String get pause => '暂停'; + @override String get resume => '继续'; + @override String get error => '错误'; + @override String get search => '搜索'; + @override String get home => '首页'; + @override String get back => '返回'; + @override String get settings => '设置'; + @override String get mute => '静音'; + @override String get ok => '确定'; + @override String get loading => '加载中...'; } // Path: screens @@ -141,7 +155,6 @@ class _TranslationsScreensZh implements TranslationsScreensEn { @override String get switchProfile => '切换用户'; @override String get subtitleStyling => '字幕样式'; @override String get mpvConfig => 'MPV 配置'; - @override String get search => '搜索'; @override String get logs => '日志'; } @@ -458,9 +471,10 @@ class _TranslationsVideoControlsZh implements TranslationsVideoControlsEn { @override String get timelineSlider => '视频时间轴'; @override String get volumeSlider => '音量调节'; @override String endsAt({required Object time}) => '${time} 结束'; - @override String get backButton => '返回'; @override String get pipFailed => '画中画启动失败'; @override late final _TranslationsVideoControlsPipErrorsZh pipErrors = _TranslationsVideoControlsPipErrorsZh._(_root); + @override String get chapters => '章节'; + @override String get noChaptersAvailable => '没有可用的章节'; } // Path: userStatus @@ -576,7 +590,6 @@ class _TranslationsDialogZh implements TranslationsDialogEn { // Translations @override String get confirmAction => '确认操作'; - @override String get cancel => '取消'; } // Path: discover @@ -588,13 +601,10 @@ class _TranslationsDiscoverZh implements TranslationsDiscoverEn { // Translations @override String get title => '发现'; @override String get switchProfile => '切换用户'; - @override String get logout => '登出'; @override String get noContentAvailable => '没有可用内容'; @override String get addMediaToLibraries => '请向你的媒体库添加一些媒体'; @override String get continueWatching => '继续观看'; - @override String get play => '播放'; @override String playEpisode({required Object season, required Object episode}) => 'S${season}E${episode}'; - @override String get pause => '暂停'; @override String get overview => '概述'; @override String get cast => '演员表'; @override String get seasons => '季数'; @@ -748,10 +758,7 @@ class _TranslationsNavigationZh implements TranslationsNavigationEn { final TranslationsZh _root; // ignore: unused_field // Translations - @override String get home => '主页'; - @override String get search => '搜索'; @override String get libraries => '媒体库'; - @override String get settings => '设置'; @override String get downloads => '下载'; } @@ -776,6 +783,10 @@ class _TranslationsDownloadsZh implements TranslationsDownloadsEn { @override String get downloadDeleted => '下载已删除'; @override String deleteConfirm({required Object title}) => '确定要删除 "${title}" 吗?下载的文件将从您的设备中删除。'; @override String deletingWithProgress({required Object title, required Object current, required Object total}) => '正在删除 ${title}... (${current}/${total})'; + @override String get noDownloadsTree => '暂无下载'; + @override String get pauseAll => '全部暂停'; + @override String get resumeAll => '全部继续'; + @override String get deleteAll => '全部删除'; } // Path: playlists @@ -910,6 +921,42 @@ class _TranslationsShadersZh implements TranslationsShadersEn { @override String get mode => '模式'; } +// Path: companionRemote +class _TranslationsCompanionRemoteZh implements TranslationsCompanionRemoteEn { + _TranslationsCompanionRemoteZh._(this._root); + + final TranslationsZh _root; // ignore: unused_field + + // Translations + @override String get title => 'Companion Remote'; + @override String get connectToDevice => '连接到设备'; + @override String get hostRemoteSession => '创建远程会话'; + @override String get controlThisDevice => '使用手机控制此设备'; + @override String get remoteControl => '远程控制'; + @override String get controlDesktop => '控制桌面设备'; + @override String connectedTo({required Object name}) => '已连接到 ${name}'; + @override late final _TranslationsCompanionRemoteSessionZh session = _TranslationsCompanionRemoteSessionZh._(_root); + @override late final _TranslationsCompanionRemotePairingZh pairing = _TranslationsCompanionRemotePairingZh._(_root); + @override late final _TranslationsCompanionRemoteRemoteZh remote = _TranslationsCompanionRemoteRemoteZh._(_root); +} + +// Path: videoSettings +class _TranslationsVideoSettingsZh implements TranslationsVideoSettingsEn { + _TranslationsVideoSettingsZh._(this._root); + + final TranslationsZh _root; // ignore: unused_field + + // Translations + @override String get playbackSettings => '播放设置'; + @override String get playbackSpeed => '播放速度'; + @override String get sleepTimer => '睡眠定时器'; + @override String get audioSync => '音频同步'; + @override String get subtitleSync => '字幕同步'; + @override String get hdr => 'HDR'; + @override String get audioOutput => '音频输出'; + @override String get performanceOverlay => '性能监控'; +} + // Path: hotkeys.actions class _TranslationsHotkeysActionsZh implements TranslationsHotkeysActionsEn { _TranslationsHotkeysActionsZh._(this._root); @@ -935,6 +982,7 @@ class _TranslationsHotkeysActionsZh implements TranslationsHotkeysActionsEn { @override String get subSeekNext => '跳转到下一字幕'; @override String get subSeekPrev => '跳转到上一字幕'; @override String get shaderToggle => '切换着色器'; + @override String get skipMarker => '跳过片头/片尾'; } // Path: videoControls.pipErrors @@ -979,6 +1027,110 @@ class _TranslationsLibrariesGroupingsZh implements TranslationsLibrariesGrouping @override String get folders => '文件夹'; } +// Path: companionRemote.session +class _TranslationsCompanionRemoteSessionZh implements TranslationsCompanionRemoteSessionEn { + _TranslationsCompanionRemoteSessionZh._(this._root); + + final TranslationsZh _root; // ignore: unused_field + + // Translations + @override String get creatingSession => '正在创建远程会话...'; + @override String get failedToCreate => '创建远程会话失败:'; + @override String get noSession => '没有可用的会话'; + @override String get scanQrCode => '扫描 QR 码'; + @override String get orEnterManually => '或手动输入'; + @override String get hostAddress => '主机地址'; + @override String get sessionId => '会话 ID'; + @override String get pin => 'PIN'; + @override String get connected => '已连接'; + @override String get waitingForConnection => '等待连接中...'; + @override String get usePhoneToControl => '使用移动设备控制此应用'; + @override String copiedToClipboard({required Object label}) => '${label}已复制到剪贴板'; + @override String get copyToClipboard => '复制到剪贴板'; + @override String get newSession => '新建会话'; + @override String get minimize => '最小化'; +} + +// Path: companionRemote.pairing +class _TranslationsCompanionRemotePairingZh implements TranslationsCompanionRemotePairingEn { + _TranslationsCompanionRemotePairingZh._(this._root); + + final TranslationsZh _root; // ignore: unused_field + + // Translations + @override String get recent => '最近'; + @override String get scan => '扫描'; + @override String get manual => '手动'; + @override String get recentConnections => '最近连接'; + @override String get quickReconnect => '快速重新连接之前配对的设备'; + @override String get pairWithDesktop => '与桌面配对'; + @override String get enterSessionDetails => '输入桌面设备上显示的会话信息'; + @override String get hostAddressHint => '192.168.1.100:48632'; + @override String get sessionIdHint => '输入8位会话 ID'; + @override String get pinHint => '输入6位 PIN'; + @override String get connecting => '连接中...'; + @override String get tips => '提示'; + @override String get tipDesktop => '在桌面上打开 Plezy,并从设置或菜单中启用 Companion Remote'; + @override String get tipScan => '使用扫描选项卡扫描桌面上的 QR 码以快速配对'; + @override String get tipWifi => '请确保两台设备连接到同一个 WiFi 网络'; + @override String get cameraPermissionRequired => '扫描 QR 码需要相机权限。\n请在设备设置中授予相机访问权限。'; + @override String cameraError({required Object error}) => '无法启动相机:${error}'; + @override String get scanInstruction => '将相机对准桌面上显示的 QR 码'; + @override String get noRecentConnections => '没有最近的连接'; + @override String get connectUsingManual => '使用手动输入连接设备以开始使用'; + @override String get invalidQrCode => '无效的 QR 码格式'; + @override String get removeRecentConnection => '删除最近连接'; + @override String removeConfirm({required Object name}) => '确定要从最近连接中删除 "${name}" 吗?'; + @override String get validationHostRequired => '请输入主机地址'; + @override String get validationHostFormat => '格式必须为 IP:端口(例如 192.168.1.100:48632)'; + @override String get validationSessionIdRequired => '请输入会话 ID'; + @override String get validationSessionIdLength => '会话 ID 必须为8个字符'; + @override String get validationPinRequired => '请输入 PIN'; + @override String get validationPinLength => 'PIN 必须为6位数字'; + @override String get connectionTimedOut => '连接超时。请检查会话 ID 和 PIN。'; + @override String get sessionNotFound => '找不到会话。请检查您的凭据。'; + @override String failedToConnect({required Object error}) => '连接失败:${error}'; + @override String failedToLoadRecent({required Object error}) => '加载最近会话失败:${error}'; +} + +// Path: companionRemote.remote +class _TranslationsCompanionRemoteRemoteZh implements TranslationsCompanionRemoteRemoteEn { + _TranslationsCompanionRemoteRemoteZh._(this._root); + + final TranslationsZh _root; // ignore: unused_field + + // Translations + @override String get disconnectConfirm => '是否要断开远程会话的连接?'; + @override String get reconnecting => '重新连接中...'; + @override String attemptOf({required Object current}) => '第 ${current} 次尝试,共 5 次'; + @override String get retryNow => '立即重试'; + @override String get connectionError => '连接错误'; + @override String get notConnected => '未连接'; + @override String get tabRemote => '遥控'; + @override String get tabPlay => '播放'; + @override String get tabMore => '更多'; + @override String get menu => '菜单'; + @override String get tabNavigation => '标签导航'; + @override String get tabDiscover => '发现'; + @override String get tabLibraries => '媒体库'; + @override String get tabSearch => '搜索'; + @override String get tabDownloads => '下载'; + @override String get tabSettings => '设置'; + @override String get previous => '上一个'; + @override String get playPause => '播放/暂停'; + @override String get next => '下一个'; + @override String get seekBack => '后退'; + @override String get stop => '停止'; + @override String get seekForward => '快进'; + @override String get volume => '音量'; + @override String get volumeDown => '减小'; + @override String get volumeUp => '增大'; + @override String get fullscreen => '全屏'; + @override String get subtitles => '字幕'; + @override String get audio => '音频'; + @override String get searchHint => '在桌面上搜索...'; +} + /// The flat map containing all translations for locale . /// Only for edge cases! For simple maps, use the map function of this library. /// @@ -988,12 +1140,9 @@ extension on TranslationsZh { dynamic _flatMapFunction(String path) { return switch (path) { 'app.title' => 'Plezy', - 'app.loading' => '加载中...', 'auth.signInWithPlex' => '使用 Plex 登录', 'auth.showQRCode' => '显示二维码', - 'auth.cancel' => '取消', 'auth.authenticate' => '验证', - 'auth.retry' => '重试', 'auth.debugEnterToken' => '调试:输入 Plex Token', 'auth.plexTokenLabel' => 'Plex 授权令牌 (Auth Token)', 'auth.plexTokenHint' => '输入你的 Plex.tv 令牌', @@ -1018,11 +1167,25 @@ extension on TranslationsZh { 'common.delete' => '删除', 'common.shuffle' => '随机播放', 'common.addTo' => '添加到...', + 'common.remove' => '删除', + 'common.paste' => '粘贴', + 'common.connect' => '连接', + 'common.disconnect' => '断开连接', + 'common.play' => '播放', + 'common.pause' => '暂停', + 'common.resume' => '继续', + 'common.error' => '错误', + 'common.search' => '搜索', + 'common.home' => '首页', + 'common.back' => '返回', + 'common.settings' => '设置', + 'common.mute' => '静音', + 'common.ok' => '确定', + 'common.loading' => '加载中...', 'screens.licenses' => '许可证', 'screens.switchProfile' => '切换用户', 'screens.subtitleStyling' => '字幕样式', 'screens.mpvConfig' => 'MPV 配置', - 'screens.search' => '搜索', 'screens.logs' => '日志', 'update.available' => '有可用更新', 'update.versionAvailable' => ({required Object version}) => '版本 ${version} 已发布', @@ -1176,6 +1339,7 @@ extension on TranslationsZh { 'hotkeys.actions.subSeekNext' => '跳转到下一字幕', 'hotkeys.actions.subSeekPrev' => '跳转到上一字幕', 'hotkeys.actions.shaderToggle' => '切换着色器', + 'hotkeys.actions.skipMarker' => '跳过片头/片尾', 'pinEntry.enterPin' => '输入 PIN', 'pinEntry.showPin' => '显示 PIN', 'pinEntry.hidePin' => '隐藏 PIN', @@ -1266,13 +1430,14 @@ extension on TranslationsZh { 'videoControls.timelineSlider' => '视频时间轴', 'videoControls.volumeSlider' => '音量调节', 'videoControls.endsAt' => ({required Object time}) => '${time} 结束', - 'videoControls.backButton' => '返回', 'videoControls.pipFailed' => '画中画启动失败', 'videoControls.pipErrors.androidVersion' => '需要 Android 8.0 或更高版本', 'videoControls.pipErrors.permissionDisabled' => '画中画权限已禁用。请在设置 > 应用 > Plezy > 画中画中启用', 'videoControls.pipErrors.notSupported' => '此设备不支持画中画模式', 'videoControls.pipErrors.failed' => '画中画启动失败', 'videoControls.pipErrors.unknown' => ({required Object error}) => '发生错误:${error}', + 'videoControls.chapters' => '章节', + 'videoControls.noChaptersAvailable' => '没有可用的章节', 'userStatus.admin' => '管理员', 'userStatus.restricted' => '受限', 'userStatus.protected' => '受保护', @@ -1343,16 +1508,12 @@ extension on TranslationsZh { 'mpvConfig.confirmDeleteProperty' => '确定要删除此属性吗?', 'mpvConfig.entriesCount' => ({required Object count}) => '${count} 条目', 'dialog.confirmAction' => '确认操作', - 'dialog.cancel' => '取消', 'discover.title' => '发现', 'discover.switchProfile' => '切换用户', - 'discover.logout' => '登出', 'discover.noContentAvailable' => '没有可用内容', 'discover.addMediaToLibraries' => '请向你的媒体库添加一些媒体', 'discover.continueWatching' => '继续观看', - 'discover.play' => '播放', 'discover.playEpisode' => ({required Object season, required Object episode}) => 'S${season}E${episode}', - 'discover.pause' => '暂停', 'discover.overview' => '概述', 'discover.cast' => '演员表', 'discover.seasons' => '季数', @@ -1442,10 +1603,7 @@ extension on TranslationsZh { 'licenses.license' => '许可证', 'licenses.licenseNumber' => ({required Object number}) => '许可证 ${number}', 'licenses.licensesCount' => ({required Object count}) => '${count} 个许可证', - 'navigation.home' => '主页', - 'navigation.search' => '搜索', 'navigation.libraries' => '媒体库', - 'navigation.settings' => '设置', 'navigation.downloads' => '下载', 'downloads.title' => '下载', 'downloads.manage' => '管理', @@ -1461,6 +1619,10 @@ extension on TranslationsZh { 'downloads.downloadDeleted' => '下载已删除', 'downloads.deleteConfirm' => ({required Object title}) => '确定要删除 "${title}" 吗?下载的文件将从您的设备中删除。', 'downloads.deletingWithProgress' => ({required Object title, required Object current, required Object total}) => '正在删除 ${title}... (${current}/${total})', + 'downloads.noDownloadsTree' => '暂无下载', + 'downloads.pauseAll' => '全部暂停', + 'downloads.resumeAll' => '全部继续', + 'downloads.deleteAll' => '全部删除', 'playlists.title' => '播放列表', 'playlists.noPlaylists' => '未找到播放列表', 'playlists.create' => '创建播放列表', @@ -1489,6 +1651,8 @@ extension on TranslationsZh { 'playlists.playlist' => '播放列表', 'collections.title' => '合集', 'collections.collection' => '合集', + _ => null, + } ?? switch (path) { 'collections.empty' => '合集为空', 'collections.unknownLibrarySection' => '无法删除:未知的媒体库分区', 'collections.deleteCollection' => '删除合集', @@ -1499,8 +1663,6 @@ extension on TranslationsZh { 'collections.failedToLoadItems' => ({required Object error}) => '加载合集项目失败:${error}', 'collections.selectCollection' => '选择合集', 'collections.createNewCollection' => '创建新合集', - _ => null, - } ?? switch (path) { 'collections.collectionName' => '合集名称', 'collections.enterCollectionName' => '输入合集名称', 'collections.addedToCollection' => '已添加到合集', @@ -1559,6 +1721,98 @@ extension on TranslationsZh { 'shaders.qualityFast' => '快速', 'shaders.qualityHQ' => '高质量', 'shaders.mode' => '模式', + 'companionRemote.title' => 'Companion Remote', + 'companionRemote.connectToDevice' => '连接到设备', + 'companionRemote.hostRemoteSession' => '创建远程会话', + 'companionRemote.controlThisDevice' => '使用手机控制此设备', + 'companionRemote.remoteControl' => '远程控制', + 'companionRemote.controlDesktop' => '控制桌面设备', + 'companionRemote.connectedTo' => ({required Object name}) => '已连接到 ${name}', + 'companionRemote.session.creatingSession' => '正在创建远程会话...', + 'companionRemote.session.failedToCreate' => '创建远程会话失败:', + 'companionRemote.session.noSession' => '没有可用的会话', + 'companionRemote.session.scanQrCode' => '扫描 QR 码', + 'companionRemote.session.orEnterManually' => '或手动输入', + 'companionRemote.session.hostAddress' => '主机地址', + 'companionRemote.session.sessionId' => '会话 ID', + 'companionRemote.session.pin' => 'PIN', + 'companionRemote.session.connected' => '已连接', + 'companionRemote.session.waitingForConnection' => '等待连接中...', + 'companionRemote.session.usePhoneToControl' => '使用移动设备控制此应用', + 'companionRemote.session.copiedToClipboard' => ({required Object label}) => '${label}已复制到剪贴板', + 'companionRemote.session.copyToClipboard' => '复制到剪贴板', + 'companionRemote.session.newSession' => '新建会话', + 'companionRemote.session.minimize' => '最小化', + 'companionRemote.pairing.recent' => '最近', + 'companionRemote.pairing.scan' => '扫描', + 'companionRemote.pairing.manual' => '手动', + 'companionRemote.pairing.recentConnections' => '最近连接', + 'companionRemote.pairing.quickReconnect' => '快速重新连接之前配对的设备', + 'companionRemote.pairing.pairWithDesktop' => '与桌面配对', + 'companionRemote.pairing.enterSessionDetails' => '输入桌面设备上显示的会话信息', + 'companionRemote.pairing.hostAddressHint' => '192.168.1.100:48632', + 'companionRemote.pairing.sessionIdHint' => '输入8位会话 ID', + 'companionRemote.pairing.pinHint' => '输入6位 PIN', + 'companionRemote.pairing.connecting' => '连接中...', + 'companionRemote.pairing.tips' => '提示', + 'companionRemote.pairing.tipDesktop' => '在桌面上打开 Plezy,并从设置或菜单中启用 Companion Remote', + 'companionRemote.pairing.tipScan' => '使用扫描选项卡扫描桌面上的 QR 码以快速配对', + 'companionRemote.pairing.tipWifi' => '请确保两台设备连接到同一个 WiFi 网络', + 'companionRemote.pairing.cameraPermissionRequired' => '扫描 QR 码需要相机权限。\n请在设备设置中授予相机访问权限。', + 'companionRemote.pairing.cameraError' => ({required Object error}) => '无法启动相机:${error}', + 'companionRemote.pairing.scanInstruction' => '将相机对准桌面上显示的 QR 码', + 'companionRemote.pairing.noRecentConnections' => '没有最近的连接', + 'companionRemote.pairing.connectUsingManual' => '使用手动输入连接设备以开始使用', + 'companionRemote.pairing.invalidQrCode' => '无效的 QR 码格式', + 'companionRemote.pairing.removeRecentConnection' => '删除最近连接', + 'companionRemote.pairing.removeConfirm' => ({required Object name}) => '确定要从最近连接中删除 "${name}" 吗?', + 'companionRemote.pairing.validationHostRequired' => '请输入主机地址', + 'companionRemote.pairing.validationHostFormat' => '格式必须为 IP:端口(例如 192.168.1.100:48632)', + 'companionRemote.pairing.validationSessionIdRequired' => '请输入会话 ID', + 'companionRemote.pairing.validationSessionIdLength' => '会话 ID 必须为8个字符', + 'companionRemote.pairing.validationPinRequired' => '请输入 PIN', + 'companionRemote.pairing.validationPinLength' => 'PIN 必须为6位数字', + 'companionRemote.pairing.connectionTimedOut' => '连接超时。请检查会话 ID 和 PIN。', + 'companionRemote.pairing.sessionNotFound' => '找不到会话。请检查您的凭据。', + 'companionRemote.pairing.failedToConnect' => ({required Object error}) => '连接失败:${error}', + 'companionRemote.pairing.failedToLoadRecent' => ({required Object error}) => '加载最近会话失败:${error}', + 'companionRemote.remote.disconnectConfirm' => '是否要断开远程会话的连接?', + 'companionRemote.remote.reconnecting' => '重新连接中...', + 'companionRemote.remote.attemptOf' => ({required Object current}) => '第 ${current} 次尝试,共 5 次', + 'companionRemote.remote.retryNow' => '立即重试', + 'companionRemote.remote.connectionError' => '连接错误', + 'companionRemote.remote.notConnected' => '未连接', + 'companionRemote.remote.tabRemote' => '遥控', + 'companionRemote.remote.tabPlay' => '播放', + 'companionRemote.remote.tabMore' => '更多', + 'companionRemote.remote.menu' => '菜单', + 'companionRemote.remote.tabNavigation' => '标签导航', + 'companionRemote.remote.tabDiscover' => '发现', + 'companionRemote.remote.tabLibraries' => '媒体库', + 'companionRemote.remote.tabSearch' => '搜索', + 'companionRemote.remote.tabDownloads' => '下载', + 'companionRemote.remote.tabSettings' => '设置', + 'companionRemote.remote.previous' => '上一个', + 'companionRemote.remote.playPause' => '播放/暂停', + 'companionRemote.remote.next' => '下一个', + 'companionRemote.remote.seekBack' => '后退', + 'companionRemote.remote.stop' => '停止', + 'companionRemote.remote.seekForward' => '快进', + 'companionRemote.remote.volume' => '音量', + 'companionRemote.remote.volumeDown' => '减小', + 'companionRemote.remote.volumeUp' => '增大', + 'companionRemote.remote.fullscreen' => '全屏', + 'companionRemote.remote.subtitles' => '字幕', + 'companionRemote.remote.audio' => '音频', + 'companionRemote.remote.searchHint' => '在桌面上搜索...', + 'videoSettings.playbackSettings' => '播放设置', + 'videoSettings.playbackSpeed' => '播放速度', + 'videoSettings.sleepTimer' => '睡眠定时器', + 'videoSettings.audioSync' => '音频同步', + 'videoSettings.subtitleSync' => '字幕同步', + 'videoSettings.hdr' => 'HDR', + 'videoSettings.audioOutput' => '音频输出', + 'videoSettings.performanceOverlay' => '性能监控', _ => null, }; } diff --git a/lib/i18n/sv.i18n.json b/lib/i18n/sv.i18n.json index d4be883d..ddf941a7 100644 --- a/lib/i18n/sv.i18n.json +++ b/lib/i18n/sv.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "Laddar..." - }, + "title": "Plezy" +}, "auth": { "signInWithPlex": "Logga in med Plex", "showQRCode": "Visa QR-kod", - "cancel": "Avbryt", "authenticate": "Autentisera", - "retry": "Försök igen", "debugEnterToken": "Debug: Ange Plex-token", "plexTokenLabel": "Plex-autentiseringstoken", "plexTokenHint": "Ange din Plex.tv-token", @@ -34,14 +31,28 @@ "no": "Nej", "delete": "Ta bort", "shuffle": "Blanda", - "addTo": "Lägg till i..." + "addTo": "Lägg till i...", + "remove": "Ta bort", + "paste": "Klistra in", + "connect": "Anslut", + "disconnect": "Koppla från", + "play": "Spela", + "pause": "Pausa", + "resume": "Återuppta", + "error": "Fel", + "search": "Sök", + "home": "Hem", + "back": "Tillbaka", + "settings": "Inställningar", + "mute": "Ljud av", + "ok": "OK", + "loading": "Laddar..." }, "screens": { "licenses": "Licenser", "switchProfile": "Byt profil", "subtitleStyling": "Undertext-styling", "mpvConfig": "MPV-konfiguration", - "search": "Sök", "logs": "Loggar" }, "update": { @@ -203,7 +214,8 @@ "speedReset": "Återställ hastighet", "subSeekNext": "Hoppa till nästa undertext", "subSeekPrev": "Hoppa till föregående undertext", - "shaderToggle": "Växla shaders" + "shaderToggle": "Växla shaders", + "skipMarker": "Hoppa över intro/eftertexter" } }, "pinEntry": { @@ -307,7 +319,6 @@ "timelineSlider": "Videotidslinje", "volumeSlider": "Volymnivå", "endsAt": "Slutar ${time}", - "backButton": "Tillbaka", "pipFailed": "Bild-i-bild kunde inte starta", "pipErrors": { "androidVersion": "Kräver Android 8.0 eller nyare", @@ -315,7 +326,9 @@ "notSupported": "Denna enhet stöder inte bild-i-bild-läge", "failed": "Bild-i-bild kunde inte starta", "unknown": "Ett fel uppstod: ${error}" - } + }, + "chapters": "Kapitel", + "noChaptersAvailable": "Inga kapitel tillgängliga" }, "userStatus": { "admin": "Admin", @@ -395,19 +408,15 @@ "entriesCount": "${count} poster" }, "dialog": { - "confirmAction": "Bekräfta åtgärd", - "cancel": "Avbryt" + "confirmAction": "Bekräfta åtgärd" }, "discover": { "title": "Upptäck", "switchProfile": "Byt profil", - "logout": "Logga ut", "noContentAvailable": "Inget innehåll tillgängligt", "addMediaToLibraries": "Lägg till media till dina bibliotek", "continueWatching": "Fortsätt titta", - "play": "Spela", "playEpisode": "S${season}E${episode}", - "pause": "Pausa", "overview": "Översikt", "cast": "Rollbesättning", "seasons": "Säsonger", @@ -517,10 +526,7 @@ "licensesCount": "${count} licenser" }, "navigation": { - "home": "Hem", - "search": "Sök", "libraries": "Bibliotek", - "settings": "Inställningar", "downloads": "Nedladdningar" }, "downloads": { @@ -537,7 +543,11 @@ "episodesQueued": "${count} avsnitt köade för nedladdning", "downloadDeleted": "Nedladdning borttagen", "deleteConfirm": "Är du säker på att du vill ta bort \"${title}\"? Den nedladdade filen kommer att tas bort från din enhet.", - "deletingWithProgress": "Tar bort ${title}... (${current} av ${total})" + "deletingWithProgress": "Tar bort ${title}... (${current} av ${total})", + "noDownloadsTree": "Inga nedladdningar", + "pauseAll": "Pausa alla", + "resumeAll": "Återuppta alla", + "deleteAll": "Ta bort alla" }, "playlists": { "title": "Spellistor", @@ -642,5 +652,107 @@ "qualityFast": "Snabb", "qualityHQ": "Hög kvalitet", "mode": "Läge" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "Anslut till enhet", + "hostRemoteSession": "Starta fjärrsession", + "controlThisDevice": "Styr den här enheten med din telefon", + "remoteControl": "Fjärrkontroll", + "controlDesktop": "Styr en datorenhet", + "connectedTo": "Ansluten till ${name}", + "session": { + "creatingSession": "Skapar fjärrsession...", + "failedToCreate": "Kunde inte skapa fjärrsession:", + "noSession": "Ingen session tillgänglig", + "scanQrCode": "Skanna QR-kod", + "orEnterManually": "Eller ange manuellt", + "hostAddress": "Värdadress", + "sessionId": "Sessions-ID", + "pin": "PIN", + "connected": "Ansluten", + "waitingForConnection": "Väntar på anslutning...", + "usePhoneToControl": "Använd din mobila enhet för att styra denna app", + "copiedToClipboard": "${label} kopierad till urklipp", + "copyToClipboard": "Kopiera till urklipp", + "newSession": "Ny session", + "minimize": "Minimera" + }, + "pairing": { + "recent": "Senaste", + "scan": "Skanna", + "manual": "Manuell", + "recentConnections": "Senaste anslutningar", + "quickReconnect": "Återanslut snabbt till tidigare parkopplade enheter", + "pairWithDesktop": "Parkoppla med dator", + "enterSessionDetails": "Ange sessionsuppgifterna som visas på din datorenhet", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "Ange 8-teckens sessions-ID", + "pinHint": "Ange 6-siffrig PIN", + "connecting": "Ansluter...", + "tips": "Tips", + "tipDesktop": "Öppna Plezy på din dator och aktivera Companion Remote via inställningar eller meny", + "tipScan": "Använd fliken Skanna för att snabbt parkoppla genom att skanna QR-koden på din dator", + "tipWifi": "Se till att båda enheterna är på samma WiFi-nätverk", + "cameraPermissionRequired": "Kamerabehörighet krävs för att skanna QR-koder.\nVänligen ge kameraåtkomst i enhetsinställningarna.", + "cameraError": "Kunde inte starta kameran: ${error}", + "scanInstruction": "Rikta kameran mot QR-koden som visas på din dator", + "noRecentConnections": "Inga senaste anslutningar", + "connectUsingManual": "Anslut till en enhet via Manuell inmatning för att komma igång", + "invalidQrCode": "Ogiltigt QR-kodformat", + "removeRecentConnection": "Ta bort senaste anslutning", + "removeConfirm": "Ta bort \"${name}\" från senaste anslutningar?", + "validationHostRequired": "Ange en värdadress", + "validationHostFormat": "Format måste vara IP:port (t.ex. 192.168.1.100:48632)", + "validationSessionIdRequired": "Ange ett sessions-ID", + "validationSessionIdLength": "Sessions-ID måste vara 8 tecken", + "validationPinRequired": "Ange en PIN", + "validationPinLength": "PIN måste vara 6 siffror", + "connectionTimedOut": "Anslutningen tog för lång tid. Kontrollera sessions-ID och PIN.", + "sessionNotFound": "Kunde inte hitta sessionen. Kontrollera dina uppgifter.", + "failedToConnect": "Kunde inte ansluta: ${error}", + "failedToLoadRecent": "Kunde inte ladda senaste sessioner: ${error}" + }, + "remote": { + "disconnectConfirm": "Vill du koppla från fjärrsessionen?", + "reconnecting": "Återansluter...", + "attemptOf": "Försök ${current} av 5", + "retryNow": "Försök nu", + "connectionError": "Anslutningsfel", + "notConnected": "Inte ansluten", + "tabRemote": "Fjärrkontroll", + "tabPlay": "Spela", + "tabMore": "Mer", + "menu": "Meny", + "tabNavigation": "Fliknavigering", + "tabDiscover": "Upptäck", + "tabLibraries": "Bibliotek", + "tabSearch": "Sök", + "tabDownloads": "Nedladdningar", + "tabSettings": "Inställningar", + "previous": "Föregående", + "playPause": "Spela/Pausa", + "next": "Nästa", + "seekBack": "Spola bakåt", + "stop": "Stopp", + "seekForward": "Spola framåt", + "volume": "Volym", + "volumeDown": "Ner", + "volumeUp": "Upp", + "fullscreen": "Helskärm", + "subtitles": "Undertexter", + "audio": "Ljud", + "searchHint": "Sök på datorn..." + } + }, + "videoSettings": { + "playbackSettings": "Uppspelningsinställningar", + "playbackSpeed": "Uppspelningshastighet", + "sleepTimer": "Sovtimer", + "audioSync": "Ljudsynkronisering", + "subtitleSync": "Undertextsynkronisering", + "hdr": "HDR", + "audioOutput": "Ljudutgång", + "performanceOverlay": "Prestandaöverlägg" } } diff --git a/lib/i18n/zh.i18n.json b/lib/i18n/zh.i18n.json index 3a16bef5..73f93cb1 100644 --- a/lib/i18n/zh.i18n.json +++ b/lib/i18n/zh.i18n.json @@ -1,14 +1,11 @@ { "app": { - "title": "Plezy", - "loading": "加载中..." - }, + "title": "Plezy" +}, "auth": { "signInWithPlex": "使用 Plex 登录", "showQRCode": "显示二维码", - "cancel": "取消", "authenticate": "验证", - "retry": "重试", "debugEnterToken": "调试:输入 Plex Token", "plexTokenLabel": "Plex 授权令牌 (Auth Token)", "plexTokenHint": "输入你的 Plex.tv 令牌", @@ -34,14 +31,28 @@ "no": "否", "delete": "删除", "shuffle": "随机播放", - "addTo": "添加到..." + "addTo": "添加到...", + "remove": "删除", + "paste": "粘贴", + "connect": "连接", + "disconnect": "断开连接", + "play": "播放", + "pause": "暂停", + "resume": "继续", + "error": "错误", + "search": "搜索", + "home": "首页", + "back": "返回", + "settings": "设置", + "mute": "静音", + "ok": "确定", + "loading": "加载中..." }, "screens": { "licenses": "许可证", "switchProfile": "切换用户", "subtitleStyling": "字幕样式", "mpvConfig": "MPV 配置", - "search": "搜索", "logs": "日志" }, "update": { @@ -203,7 +214,8 @@ "speedReset": "重置速度", "subSeekNext": "跳转到下一字幕", "subSeekPrev": "跳转到上一字幕", - "shaderToggle": "切换着色器" + "shaderToggle": "切换着色器", + "skipMarker": "跳过片头/片尾" } }, "pinEntry": { @@ -307,7 +319,6 @@ "timelineSlider": "视频时间轴", "volumeSlider": "音量调节", "endsAt": "${time} 结束", - "backButton": "返回", "pipFailed": "画中画启动失败", "pipErrors": { "androidVersion": "需要 Android 8.0 或更高版本", @@ -315,7 +326,9 @@ "notSupported": "此设备不支持画中画模式", "failed": "画中画启动失败", "unknown": "发生错误:${error}" - } + }, + "chapters": "章节", + "noChaptersAvailable": "没有可用的章节" }, "userStatus": { "admin": "管理员", @@ -395,19 +408,15 @@ "entriesCount": "${count} 条目" }, "dialog": { - "confirmAction": "确认操作", - "cancel": "取消" + "confirmAction": "确认操作" }, "discover": { "title": "发现", "switchProfile": "切换用户", - "logout": "登出", "noContentAvailable": "没有可用内容", "addMediaToLibraries": "请向你的媒体库添加一些媒体", "continueWatching": "继续观看", - "play": "播放", "playEpisode": "S${season}E${episode}", - "pause": "暂停", "overview": "概述", "cast": "演员表", "seasons": "季数", @@ -517,10 +526,7 @@ "licensesCount": "${count} 个许可证" }, "navigation": { - "home": "主页", - "search": "搜索", "libraries": "媒体库", - "settings": "设置", "downloads": "下载" }, "downloads": { @@ -537,7 +543,11 @@ "episodesQueued": "${count} 集已加入下载队列", "downloadDeleted": "下载已删除", "deleteConfirm": "确定要删除 \"${title}\" 吗?下载的文件将从您的设备中删除。", - "deletingWithProgress": "正在删除 ${title}... (${current}/${total})" + "deletingWithProgress": "正在删除 ${title}... (${current}/${total})", + "noDownloadsTree": "暂无下载", + "pauseAll": "全部暂停", + "resumeAll": "全部继续", + "deleteAll": "全部删除" }, "playlists": { "title": "播放列表", @@ -642,5 +652,107 @@ "qualityFast": "快速", "qualityHQ": "高质量", "mode": "模式" + }, + "companionRemote": { + "title": "Companion Remote", + "connectToDevice": "连接到设备", + "hostRemoteSession": "创建远程会话", + "controlThisDevice": "使用手机控制此设备", + "remoteControl": "远程控制", + "controlDesktop": "控制桌面设备", + "connectedTo": "已连接到 ${name}", + "session": { + "creatingSession": "正在创建远程会话...", + "failedToCreate": "创建远程会话失败:", + "noSession": "没有可用的会话", + "scanQrCode": "扫描 QR 码", + "orEnterManually": "或手动输入", + "hostAddress": "主机地址", + "sessionId": "会话 ID", + "pin": "PIN", + "connected": "已连接", + "waitingForConnection": "等待连接中...", + "usePhoneToControl": "使用移动设备控制此应用", + "copiedToClipboard": "${label}已复制到剪贴板", + "copyToClipboard": "复制到剪贴板", + "newSession": "新建会话", + "minimize": "最小化" + }, + "pairing": { + "recent": "最近", + "scan": "扫描", + "manual": "手动", + "recentConnections": "最近连接", + "quickReconnect": "快速重新连接之前配对的设备", + "pairWithDesktop": "与桌面配对", + "enterSessionDetails": "输入桌面设备上显示的会话信息", + "hostAddressHint": "192.168.1.100:48632", + "sessionIdHint": "输入8位会话 ID", + "pinHint": "输入6位 PIN", + "connecting": "连接中...", + "tips": "提示", + "tipDesktop": "在桌面上打开 Plezy,并从设置或菜单中启用 Companion Remote", + "tipScan": "使用扫描选项卡扫描桌面上的 QR 码以快速配对", + "tipWifi": "请确保两台设备连接到同一个 WiFi 网络", + "cameraPermissionRequired": "扫描 QR 码需要相机权限。\n请在设备设置中授予相机访问权限。", + "cameraError": "无法启动相机:${error}", + "scanInstruction": "将相机对准桌面上显示的 QR 码", + "noRecentConnections": "没有最近的连接", + "connectUsingManual": "使用手动输入连接设备以开始使用", + "invalidQrCode": "无效的 QR 码格式", + "removeRecentConnection": "删除最近连接", + "removeConfirm": "确定要从最近连接中删除 \"${name}\" 吗?", + "validationHostRequired": "请输入主机地址", + "validationHostFormat": "格式必须为 IP:端口(例如 192.168.1.100:48632)", + "validationSessionIdRequired": "请输入会话 ID", + "validationSessionIdLength": "会话 ID 必须为8个字符", + "validationPinRequired": "请输入 PIN", + "validationPinLength": "PIN 必须为6位数字", + "connectionTimedOut": "连接超时。请检查会话 ID 和 PIN。", + "sessionNotFound": "找不到会话。请检查您的凭据。", + "failedToConnect": "连接失败:${error}", + "failedToLoadRecent": "加载最近会话失败:${error}" + }, + "remote": { + "disconnectConfirm": "是否要断开远程会话的连接?", + "reconnecting": "重新连接中...", + "attemptOf": "第 ${current} 次尝试,共 5 次", + "retryNow": "立即重试", + "connectionError": "连接错误", + "notConnected": "未连接", + "tabRemote": "遥控", + "tabPlay": "播放", + "tabMore": "更多", + "menu": "菜单", + "tabNavigation": "标签导航", + "tabDiscover": "发现", + "tabLibraries": "媒体库", + "tabSearch": "搜索", + "tabDownloads": "下载", + "tabSettings": "设置", + "previous": "上一个", + "playPause": "播放/暂停", + "next": "下一个", + "seekBack": "后退", + "stop": "停止", + "seekForward": "快进", + "volume": "音量", + "volumeDown": "减小", + "volumeUp": "增大", + "fullscreen": "全屏", + "subtitles": "字幕", + "audio": "音频", + "searchHint": "在桌面上搜索..." + } + }, + "videoSettings": { + "playbackSettings": "播放设置", + "playbackSpeed": "播放速度", + "sleepTimer": "睡眠定时器", + "audioSync": "音频同步", + "subtitleSync": "字幕同步", + "hdr": "HDR", + "audioOutput": "音频输出", + "performanceOverlay": "性能监控" } } diff --git a/lib/main.dart b/lib/main.dart index d6f9fed7..27c8be25 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -438,7 +438,7 @@ class _SetupScreenState extends State { body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [const CircularProgressIndicator(), const SizedBox(height: 16), Text(t.app.loading)], + children: [const CircularProgressIndicator(), const SizedBox(height: 16), Text(t.common.loading)], ), ), ); diff --git a/lib/navigation/navigation_tabs.dart b/lib/navigation/navigation_tabs.dart index d309b48f..8a13590c 100644 --- a/lib/navigation/navigation_tabs.dart +++ b/lib/navigation/navigation_tabs.dart @@ -38,11 +38,11 @@ class NavigationTab { } // Label getters (must be top-level for const constructor) -String _getHomeLabel() => t.navigation.home; +String _getHomeLabel() => t.common.home; String _getLibrariesLabel() => t.navigation.libraries; -String _getSearchLabel() => t.navigation.search; +String _getSearchLabel() => t.common.search; String _getDownloadsLabel() => t.navigation.downloads; -String _getSettingsLabel() => t.navigation.settings; +String _getSettingsLabel() => t.common.settings; /// All navigation tabs in display order const allNavigationTabs = [ diff --git a/lib/screens/auth_screen.dart b/lib/screens/auth_screen.dart index ab4314a0..595e78ba 100644 --- a/lib/screens/auth_screen.dart +++ b/lib/screens/auth_screen.dart @@ -248,7 +248,7 @@ class _AuthScreenState extends State { ], ), actions: [ - TextButton(onPressed: () => Navigator.of(context).pop(), child: Text(t.auth.cancel)), + TextButton(onPressed: () => Navigator.of(context).pop(), child: Text(t.common.cancel)), ElevatedButton( onPressed: () async { final token = tokenController.text.trim(); @@ -452,7 +452,7 @@ class _AuthScreenState extends State { OutlinedButton( onPressed: _retryAuthentication, style: OutlinedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24)), - child: Text(t.auth.retry), + child: Text(t.common.retry), ), ], ); @@ -491,7 +491,7 @@ class _AuthScreenState extends State { autofocus: true, onPressed: _retryAuthentication, style: OutlinedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24)), - child: Text(t.auth.retry), + child: Text(t.common.retry), ), const SizedBox(width: 16), OutlinedButton( diff --git a/lib/screens/base_media_list_detail_screen.dart b/lib/screens/base_media_list_detail_screen.dart index 4ae31e96..9eda93e7 100644 --- a/lib/screens/base_media_list_detail_screen.dart +++ b/lib/screens/base_media_list_detail_screen.dart @@ -161,7 +161,7 @@ abstract class BaseMediaListDetailScreen extends State if (items.isNotEmpty) IconButton( icon: const AppIcon(Symbols.play_arrow_rounded, fill: 1), - tooltip: t.discover.play, + tooltip: t.common.play, onPressed: playItems, ), // Shuffle button diff --git a/lib/screens/collection_detail_screen.dart b/lib/screens/collection_detail_screen.dart index e19f70f2..3d42cb03 100644 --- a/lib/screens/collection_detail_screen.dart +++ b/lib/screens/collection_detail_screen.dart @@ -72,7 +72,7 @@ class _CollectionDetailScreenState extends BaseMediaListDetailScreen getAppBarButtons() { final buttons = []; if (items.isNotEmpty) { - buttons.add(AppBarButtonConfig(icon: Symbols.play_arrow_rounded, tooltip: t.discover.play, onPressed: playItems)); + buttons.add(AppBarButtonConfig(icon: Symbols.play_arrow_rounded, tooltip: t.common.play, onPressed: playItems)); buttons.add( AppBarButtonConfig(icon: Symbols.shuffle_rounded, tooltip: t.common.shuffle, onPressed: shufflePlayItems), ); diff --git a/lib/screens/companion_remote/mobile_remote_screen.dart b/lib/screens/companion_remote/mobile_remote_screen.dart index 1dd780a2..a6863b0d 100644 --- a/lib/screens/companion_remote/mobile_remote_screen.dart +++ b/lib/screens/companion_remote/mobile_remote_screen.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import '../../models/companion_remote/remote_command_type.dart'; import '../../models/companion_remote/remote_session.dart'; +import '../../i18n/strings.g.dart'; import '../../providers/companion_remote_provider.dart'; import '../../utils/platform_detector.dart'; import '../../utils/app_logger.dart'; @@ -21,7 +22,7 @@ class _MobileRemoteScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Companion Remote'), + title: Text(t.companionRemote.title), actions: [ Consumer( builder: (context, provider, child) { @@ -32,11 +33,11 @@ class _MobileRemoteScreenState extends State { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Disconnect'), - content: const Text('Do you want to disconnect from the remote session?'), + title: Text(t.common.disconnect), + content: Text(t.companionRemote.remote.disconnectConfirm), actions: [ - TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('Cancel')), - TextButton(onPressed: () => Navigator.pop(context, true), child: const Text('Disconnect')), + TextButton(onPressed: () => Navigator.pop(context, false), child: Text(t.common.cancel)), + TextButton(onPressed: () => Navigator.pop(context, true), child: Text(t.common.disconnect)), ], ), ); @@ -45,7 +46,7 @@ class _MobileRemoteScreenState extends State { await context.read().leaveSession(); } }, - tooltip: 'Disconnect', + tooltip: t.common.disconnect, ); } return const SizedBox.shrink(); @@ -62,19 +63,19 @@ class _MobileRemoteScreenState extends State { children: [ const CircularProgressIndicator(), const SizedBox(height: 24), - Text('Reconnecting...', style: Theme.of(context).textTheme.titleLarge), + Text(t.companionRemote.remote.reconnecting, style: Theme.of(context).textTheme.titleLarge), const SizedBox(height: 8), Text( - 'Attempt ${provider.reconnectAttempts} of 5', + t.companionRemote.remote.attemptOf(current: provider.reconnectAttempts), style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.grey), ), const SizedBox(height: 32), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - OutlinedButton(onPressed: () => provider.cancelReconnect(), child: const Text('Cancel')), + OutlinedButton(onPressed: () => provider.cancelReconnect(), child: Text(t.common.cancel)), const SizedBox(width: 16), - FilledButton(onPressed: () => provider.retryReconnectNow(), child: const Text('Retry Now')), + FilledButton(onPressed: () => provider.retryReconnectNow(), child: Text(t.companionRemote.remote.retryNow)), ], ), ], @@ -91,8 +92,8 @@ class _MobileRemoteScreenState extends State { const SizedBox(height: 16), Text( provider.status == RemoteSessionStatus.error - ? provider.session?.errorMessage ?? 'Connection error' - : 'Not connected', + ? provider.session?.errorMessage ?? t.companionRemote.remote.connectionError + : t.companionRemote.remote.notConnected, style: const TextStyle(fontSize: 20, color: Colors.grey), textAlign: TextAlign.center, ), @@ -102,7 +103,7 @@ class _MobileRemoteScreenState extends State { Navigator.push(context, MaterialPageRoute(builder: (context) => const PairingScreen())); }, icon: const Icon(Icons.link), - label: const Text('Connect to Device'), + label: Text(t.companionRemote.connectToDevice), ), ], ), @@ -212,10 +213,10 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { children: [ SegmentedButton( showSelectedIcon: false, - segments: const [ - ButtonSegment(value: 0, label: Text('Remote'), icon: Icon(Icons.navigation)), - ButtonSegment(value: 1, label: Text('Play'), icon: Icon(Icons.play_arrow)), - ButtonSegment(value: 2, label: Text('More'), icon: Icon(Icons.flash_on)), + segments: [ + ButtonSegment(value: 0, label: Text(t.companionRemote.remote.tabRemote), icon: const Icon(Icons.navigation)), + ButtonSegment(value: 1, label: Text(t.companionRemote.remote.tabPlay), icon: const Icon(Icons.play_arrow)), + ButtonSegment(value: 2, label: Text(t.companionRemote.remote.tabMore), icon: const Icon(Icons.flash_on)), ], selected: {_selectedTab}, onSelectionChanged: (Set selection) { @@ -245,11 +246,11 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - _RemoteButton(icon: Icons.home, label: 'Home', onPressed: () => _sendCommand(RemoteCommandType.home)), - _RemoteButton(icon: Icons.arrow_back, label: 'Back', onPressed: () => _sendCommand(RemoteCommandType.back)), + _RemoteButton(icon: Icons.home, label: t.common.home, onPressed: () => _sendCommand(RemoteCommandType.home)), + _RemoteButton(icon: Icons.arrow_back, label: t.common.back, onPressed: () => _sendCommand(RemoteCommandType.back)), _RemoteButton( icon: Icons.menu, - label: 'Menu', + label: t.companionRemote.remote.menu, onPressed: () => _sendCommand(RemoteCommandType.contextMenu), ), ], @@ -258,7 +259,7 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { Center(child: _DPad(onCommand: _sendCommand)), if (!isPlayerActive) ...[ const SizedBox(height: 32), - Text('Tab Navigation', style: Theme.of(context).textTheme.titleMedium), + Text(t.companionRemote.remote.tabNavigation, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 16), Wrap( spacing: 8, @@ -267,27 +268,27 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { children: [ _RemoteChip( icon: Icons.explore, - label: 'Discover', + label: t.companionRemote.remote.tabDiscover, onPressed: () => _sendCommand(RemoteCommandType.tabDiscover), ), _RemoteChip( icon: Icons.video_library, - label: 'Libraries', + label: t.companionRemote.remote.tabLibraries, onPressed: () => _sendCommand(RemoteCommandType.tabLibraries), ), _RemoteChip( icon: Icons.search, - label: 'Search', + label: t.companionRemote.remote.tabSearch, onPressed: () => _showSearchSheet(switchToSearchTab: true), ), _RemoteChip( icon: Icons.download, - label: 'Downloads', + label: t.companionRemote.remote.tabDownloads, onPressed: () => _sendCommand(RemoteCommandType.tabDownloads), ), _RemoteChip( icon: Icons.settings, - label: 'Settings', + label: t.companionRemote.remote.tabSettings, onPressed: () => _sendCommand(RemoteCommandType.tabSettings), ), ], @@ -306,13 +307,13 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { children: [ _RemoteButton( icon: Icons.skip_previous, - label: 'Previous', + label: t.companionRemote.remote.previous, onPressed: () => _sendCommand(RemoteCommandType.previousTrack), ), const SizedBox(width: 16), _RemoteButton( icon: Icons.play_arrow, - label: 'Play/Pause', + label: t.companionRemote.remote.playPause, size: 64, iconSize: 36, onPressed: () => _sendCommand(RemoteCommandType.playPause), @@ -320,7 +321,7 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { const SizedBox(width: 16), _RemoteButton( icon: Icons.skip_next, - label: 'Next', + label: t.companionRemote.remote.next, onPressed: () => _sendCommand(RemoteCommandType.nextTrack), ), ], @@ -331,40 +332,40 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { children: [ _RemoteButton( icon: Icons.replay_10, - label: 'Seek Back', + label: t.companionRemote.remote.seekBack, onPressed: () => _sendCommand(RemoteCommandType.seekBackward), ), const SizedBox(width: 16), - _RemoteButton(icon: Icons.stop, label: 'Stop', onPressed: () => _sendCommand(RemoteCommandType.stop)), + _RemoteButton(icon: Icons.stop, label: t.companionRemote.remote.stop, onPressed: () => _sendCommand(RemoteCommandType.stop)), const SizedBox(width: 16), _RemoteButton( icon: Icons.forward_10, - label: 'Seek Fwd', + label: t.companionRemote.remote.seekForward, onPressed: () => _sendCommand(RemoteCommandType.seekForward), ), ], ), const SizedBox(height: 32), - Text('Volume', style: Theme.of(context).textTheme.titleMedium), + Text(t.companionRemote.remote.volume, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ _RemoteButton( icon: Icons.volume_off, - label: 'Mute', + label: t.common.mute, onPressed: () => _sendCommand(RemoteCommandType.volumeMute), ), const SizedBox(width: 16), _RemoteButton( icon: Icons.volume_down, - label: 'Down', + label: t.companionRemote.remote.volumeDown, onPressed: () => _sendCommand(RemoteCommandType.volumeDown), ), const SizedBox(width: 16), _RemoteButton( icon: Icons.volume_up, - label: 'Up', + label: t.companionRemote.remote.volumeUp, onPressed: () => _sendCommand(RemoteCommandType.volumeUp), ), ], @@ -385,21 +386,21 @@ class _RemoteControlContentState extends State<_RemoteControlContent> { alignment: WrapAlignment.center, children: [ if (!isPlayerActive) - _RemoteCard(icon: Icons.search, label: 'Search', onPressed: _showSearchSheet), + _RemoteCard(icon: Icons.search, label: t.common.search, onPressed: _showSearchSheet), if (isPlayerActive) ...[ _RemoteCard( icon: Icons.fullscreen, - label: 'Fullscreen', + label: t.companionRemote.remote.fullscreen, onPressed: () => _sendCommand(RemoteCommandType.fullscreen), ), _RemoteCard( icon: Icons.subtitles, - label: 'Subtitles', + label: t.companionRemote.remote.subtitles, onPressed: () => _sendCommand(RemoteCommandType.subtitles), ), _RemoteCard( icon: Icons.audiotrack, - label: 'Audio', + label: t.companionRemote.remote.audio, onPressed: () => _sendCommand(RemoteCommandType.audioTracks), ), ], @@ -467,7 +468,7 @@ class _DPad extends StatelessWidget { top: size + gap, child: _DPadButton( icon: Icons.check, - label: 'OK', + label: t.common.ok, onPressed: () => onCommand(RemoteCommandType.select), size: size, isPrimary: true, @@ -621,7 +622,7 @@ class _SearchBottomSheetState extends State<_SearchBottomSheet> { controller: _controller, autofocus: true, decoration: InputDecoration( - hintText: 'Search on desktop...', + hintText: t.companionRemote.remote.searchHint, prefixIcon: const Icon(Icons.search), suffixIcon: IconButton(icon: const Icon(Icons.send), onPressed: () => _submit(_controller.text)), border: OutlineInputBorder(borderRadius: BorderRadius.circular(100)), diff --git a/lib/screens/companion_remote/pairing_screen.dart b/lib/screens/companion_remote/pairing_screen.dart index d06956ff..8f328410 100644 --- a/lib/screens/companion_remote/pairing_screen.dart +++ b/lib/screens/companion_remote/pairing_screen.dart @@ -5,7 +5,9 @@ import 'package:flutter/services.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:provider/provider.dart'; +import '../../i18n/strings.g.dart'; import '../../providers/companion_remote_provider.dart'; +import '../../utils/formatters.dart'; import '../../models/companion_remote/recent_remote_session.dart'; import '../../utils/app_logger.dart'; @@ -67,7 +69,7 @@ class _PairingScreenState extends State { appLogger.e('Failed to load recent sessions', error: e); setState(() { _isDiscovering = false; - _errorMessage = 'Failed to load recent sessions: ${e.toString()}'; + _errorMessage = t.companionRemote.pairing.failedToLoadRecent(error: e.toString()); }); } } @@ -127,11 +129,11 @@ class _PairingScreenState extends State { String _parseErrorMessage(String error) { if (error.contains('timeout') || error.contains('Timed out')) { - return 'Connection timed out. Please check the session ID and PIN.'; + return t.companionRemote.pairing.connectionTimedOut; } else if (error.contains('Failed to connect')) { - return 'Could not find the session. Please check your credentials.'; + return t.companionRemote.pairing.sessionNotFound; } - return 'Failed to connect: ${error.replaceAll('Exception: ', '')}'; + return t.companionRemote.pairing.failedToConnect(error: error.replaceAll('Exception: ', '')); } void _handleQrCode(String data) { @@ -157,7 +159,7 @@ class _PairingScreenState extends State { _connectWithCredentials(sessionId, pin, hostAddress); } else { setState(() { - _errorMessage = 'Invalid QR code format - expected 4 parts (ip|port|sessionId|pin)'; + _errorMessage = t.companionRemote.pairing.invalidQrCode; }); } } @@ -194,13 +196,13 @@ class _PairingScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Connect to Device'), + title: Text(t.companionRemote.connectToDevice), actions: [ if (_selectedTab == 0) IconButton( icon: const Icon(Icons.refresh), onPressed: _isDiscovering ? null : _loadRecentSessions, - tooltip: 'Refresh', + tooltip: t.common.refresh, ), ], ), @@ -208,10 +210,10 @@ class _PairingScreenState extends State { children: [ SegmentedButton( segments: [ - const ButtonSegment(value: 0, label: Text('Recent'), icon: Icon(Icons.history)), + ButtonSegment(value: 0, label: Text(t.companionRemote.pairing.recent), icon: const Icon(Icons.history)), if (_isMobile) - ButtonSegment(value: _scanTabIndex, label: const Text('Scan'), icon: const Icon(Icons.qr_code_scanner)), - ButtonSegment(value: _manualTabIndex, label: const Text('Manual'), icon: const Icon(Icons.keyboard)), + ButtonSegment(value: _scanTabIndex, label: Text(t.companionRemote.pairing.scan), icon: const Icon(Icons.qr_code_scanner)), + ButtonSegment(value: _manualTabIndex, label: Text(t.companionRemote.pairing.manual), icon: const Icon(Icons.keyboard)), ], selected: {_selectedTab}, onSelectionChanged: (Set selection) { @@ -261,8 +263,8 @@ class _PairingScreenState extends State { const SizedBox(height: 16), Text( error.errorCode == MobileScannerErrorCode.permissionDenied - ? 'Camera permission is required to scan QR codes.\nPlease grant camera access in your device settings.' - : 'Could not start camera: ${error.errorDetails?.message ?? error.errorCode.name}', + ? t.companionRemote.pairing.cameraPermissionRequired + : t.companionRemote.pairing.cameraError(error: error.errorDetails?.message ?? error.errorCode.name), textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodyMedium, ), @@ -281,7 +283,7 @@ class _PairingScreenState extends State { child: Column( children: [ Text( - 'Point your camera at the QR code shown on your desktop', + t.companionRemote.pairing.scanInstruction, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), @@ -326,13 +328,13 @@ class _PairingScreenState extends State { const Icon(Icons.history, size: 64, color: Colors.blue), const SizedBox(height: 24), Text( - 'Recent Connections', + t.companionRemote.pairing.recentConnections, style: Theme.of(context).textTheme.headlineMedium, textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( - 'Quickly reconnect to previously paired devices', + t.companionRemote.pairing.quickReconnect, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), @@ -340,7 +342,7 @@ class _PairingScreenState extends State { if (_isDiscovering) ...[ const Center(child: CircularProgressIndicator()), const SizedBox(height: 16), - Text('Loading...', style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center), + Text(t.common.loading, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center), ] else if (sessions.isEmpty) ...[ Card( child: Padding( @@ -349,10 +351,10 @@ class _PairingScreenState extends State { children: [ Icon(Icons.devices_other, size: 48, color: Theme.of(context).colorScheme.outline), const SizedBox(height: 16), - Text('No recent connections', style: Theme.of(context).textTheme.titleMedium), + Text(t.companionRemote.pairing.noRecentConnections, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), Text( - 'Connect to a device using Manual entry to get started', + t.companionRemote.pairing.connectUsingManual, style: Theme.of(context).textTheme.bodySmall, textAlign: TextAlign.center, ), @@ -412,31 +414,18 @@ class _PairingScreenState extends State { } String _formatDate(DateTime date) { - final now = DateTime.now(); - final difference = now.difference(date); - - if (difference.inMinutes < 1) { - return 'Just now'; - } else if (difference.inHours < 1) { - return '${difference.inMinutes}m ago'; - } else if (difference.inDays < 1) { - return '${difference.inHours}h ago'; - } else if (difference.inDays < 7) { - return '${difference.inDays}d ago'; - } else { - return '${date.month}/${date.day}/${date.year}'; - } + return formatRelativeTime(date); } Future _showRemoveSessionDialog(RecentRemoteSession session) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Remove Recent Connection'), - content: Text('Remove "${session.deviceName}" from recent connections?'), + title: Text(t.companionRemote.pairing.removeRecentConnection), + content: Text(t.companionRemote.pairing.removeConfirm(name: session.deviceName)), actions: [ - TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('Cancel')), - TextButton(onPressed: () => Navigator.pop(context, true), child: const Text('Remove')), + TextButton(onPressed: () => Navigator.pop(context, false), child: Text(t.common.cancel)), + TextButton(onPressed: () => Navigator.pop(context, true), child: Text(t.common.remove)), ], ), ); @@ -456,10 +445,10 @@ class _PairingScreenState extends State { children: [ const Icon(Icons.keyboard, size: 64, color: Colors.blue), const SizedBox(height: 24), - Text('Pair with Desktop', style: Theme.of(context).textTheme.headlineMedium, textAlign: TextAlign.center), + Text(t.companionRemote.pairing.pairWithDesktop, style: Theme.of(context).textTheme.headlineMedium, textAlign: TextAlign.center), const SizedBox(height: 8), Text( - 'Enter the session details shown on your desktop device', + t.companionRemote.pairing.enterSessionDetails, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), @@ -488,24 +477,24 @@ class _PairingScreenState extends State { TextFormField( controller: _hostAddressController, decoration: InputDecoration( - labelText: 'Host Address', - hintText: '192.168.1.100:48632', + labelText: t.companionRemote.session.hostAddress, + hintText: t.companionRemote.pairing.hostAddressHint, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.computer), suffixIcon: IconButton( icon: const Icon(Icons.paste), onPressed: () => _pasteFromClipboard(_hostAddressController), - tooltip: 'Paste', + tooltip: t.common.paste, ), ), validator: (value) { if (value == null || value.isEmpty) { - return 'Please enter host address'; + return t.companionRemote.pairing.validationHostRequired; } // Validate IP:port format final parts = value.split(':'); if (parts.length != 2) { - return 'Format must be IP:port (e.g., 192.168.1.100:48632)'; + return t.companionRemote.pairing.validationHostFormat; } return null; }, @@ -515,14 +504,14 @@ class _PairingScreenState extends State { TextFormField( controller: _sessionIdController, decoration: InputDecoration( - labelText: 'Session ID', - hintText: 'Enter 8-character session ID', + labelText: t.companionRemote.session.sessionId, + hintText: t.companionRemote.pairing.sessionIdHint, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.vpn_key), suffixIcon: IconButton( icon: const Icon(Icons.paste), onPressed: () => _pasteFromClipboard(_sessionIdController), - tooltip: 'Paste', + tooltip: t.common.paste, ), ), textCapitalization: TextCapitalization.characters, @@ -535,10 +524,10 @@ class _PairingScreenState extends State { ], validator: (value) { if (value == null || value.isEmpty) { - return 'Please enter a session ID'; + return t.companionRemote.pairing.validationSessionIdRequired; } if (value.length != 8) { - return 'Session ID must be 8 characters'; + return t.companionRemote.pairing.validationSessionIdLength; } return null; }, @@ -548,24 +537,24 @@ class _PairingScreenState extends State { TextFormField( controller: _pinController, decoration: InputDecoration( - labelText: 'PIN', - hintText: 'Enter 6-digit PIN', + labelText: t.companionRemote.session.pin, + hintText: t.companionRemote.pairing.pinHint, border: const OutlineInputBorder(), prefixIcon: const Icon(Icons.lock), suffixIcon: IconButton( icon: const Icon(Icons.paste), onPressed: () => _pasteFromClipboard(_pinController), - tooltip: 'Paste', + tooltip: t.common.paste, ), ), keyboardType: TextInputType.number, inputFormatters: [FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(6)], validator: (value) { if (value == null || value.isEmpty) { - return 'Please enter a PIN'; + return t.companionRemote.pairing.validationPinRequired; } if (value.length != 6) { - return 'PIN must be 6 digits'; + return t.companionRemote.pairing.validationPinLength; } return null; }, @@ -577,28 +566,28 @@ class _PairingScreenState extends State { icon: _isConnecting ? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2)) : const Icon(Icons.link), - label: Text(_isConnecting ? 'Connecting...' : 'Connect'), + label: Text(_isConnecting ? t.companionRemote.pairing.connecting : t.common.connect), ), const SizedBox(height: 32), const Divider(), const SizedBox(height: 16), - Text('Tips', style: Theme.of(context).textTheme.titleMedium), + Text(t.companionRemote.pairing.tips, style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), _buildTipCard( context, Icons.computer, - 'Open Plezy on your desktop and enable Companion Remote from settings or menu', + t.companionRemote.pairing.tipDesktop, ), if (_isMobile) ...[ const SizedBox(height: 8), _buildTipCard( context, Icons.qr_code, - 'Use the Scan tab to quickly pair by scanning the QR code on your desktop', + t.companionRemote.pairing.tipScan, ), ], const SizedBox(height: 8), - _buildTipCard(context, Icons.wifi, 'Make sure both devices are on the same WiFi network'), + _buildTipCard(context, Icons.wifi, t.companionRemote.pairing.tipWifi), ], ), ), diff --git a/lib/screens/discover_screen.dart b/lib/screens/discover_screen.dart index 135279d3..80106f76 100644 --- a/lib/screens/discover_screen.dart +++ b/lib/screens/discover_screen.dart @@ -1014,7 +1014,7 @@ class _DiscoverScreenState extends State ), PopupMenuItem( value: 'logout', - child: Row(children: [AppIcon(Symbols.logout_rounded, fill: 1), SizedBox(width: 8), Text(t.discover.logout)]), + child: Row(children: [AppIcon(Symbols.logout_rounded, fill: 1), SizedBox(width: 8), Text(t.common.logout)]), ), ], ).then((value) { @@ -1150,7 +1150,7 @@ class _DiscoverScreenState extends State Navigator.push(context, MaterialPageRoute(builder: (context) => MobileRemoteScreen())); } }, - tooltip: 'Companion Remote', + tooltip: t.companionRemote.title, ), // Badge showing connection status if (companionRemote.isConnected) @@ -1213,7 +1213,7 @@ class _DiscoverScreenState extends State children: [ AppIcon(Symbols.logout_rounded, fill: 1), SizedBox(width: 8), - Text(t.discover.logout), + Text(t.common.logout), ], ), ), @@ -1453,7 +1453,7 @@ class _DiscoverScreenState extends State fill: 1, color: Theme.of(context).colorScheme.onSurface, size: 18, - semanticLabel: '${_isAutoScrollPaused ? t.discover.play : t.discover.pause} auto-scroll', + semanticLabel: '${_isAutoScrollPaused ? t.common.play : t.common.pause} auto-scroll', ), ), // Spacer to separate indicators from button @@ -1821,7 +1821,7 @@ class _DiscoverScreenState extends State ), ] else Text( - t.discover.play, + t.common.play, style: TextStyle(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w600), ), ], diff --git a/lib/screens/playlist/playlist_detail_screen.dart b/lib/screens/playlist/playlist_detail_screen.dart index 64f135a9..3b1019cb 100644 --- a/lib/screens/playlist/playlist_detail_screen.dart +++ b/lib/screens/playlist/playlist_detail_screen.dart @@ -62,7 +62,7 @@ class _PlaylistDetailScreenState extends BaseMediaListDetailScreen getAppBarButtons() { final buttons = []; if (items.isNotEmpty) { - buttons.add(AppBarButtonConfig(icon: Symbols.play_arrow_rounded, tooltip: t.discover.play, onPressed: playItems)); + buttons.add(AppBarButtonConfig(icon: Symbols.play_arrow_rounded, tooltip: t.common.play, onPressed: playItems)); buttons.add( AppBarButtonConfig(icon: Symbols.shuffle_rounded, tooltip: t.common.shuffle, onPressed: shufflePlayItems), ); diff --git a/lib/screens/search_screen.dart b/lib/screens/search_screen.dart index b404ab00..8e7d76ca 100644 --- a/lib/screens/search_screen.dart +++ b/lib/screens/search_screen.dart @@ -212,7 +212,7 @@ class _SearchScreenState extends State with Refreshable, FullRefre body: SafeArea( child: CustomScrollView( slivers: [ - DesktopSliverAppBar(title: Text(t.screens.search), floating: true), + DesktopSliverAppBar(title: Text(t.common.search), floating: true), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), diff --git a/lib/screens/settings/settings_screen.dart b/lib/screens/settings/settings_screen.dart index cee45320..b4b796fd 100644 --- a/lib/screens/settings/settings_screen.dart +++ b/lib/screens/settings/settings_screen.dart @@ -791,17 +791,17 @@ class _SettingsScreenState extends State with FocusableTab { Padding( padding: const EdgeInsets.all(16), child: Text( - 'Companion Remote', + t.companionRemote.title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), ), ), if (PlatformDetector.isDesktop(context)) ListTile( leading: const AppIcon(Symbols.phone_android_rounded, fill: 1), - title: const Text('Host Remote Session'), + title: Text(t.companionRemote.hostRemoteSession), subtitle: companionRemote.isConnected - ? Text('Connected to ${companionRemote.connectedDevice?.name}') - : const Text('Control this device with your phone'), + ? Text(t.companionRemote.connectedTo(name: companionRemote.connectedDevice?.name ?? '')) + : Text(t.companionRemote.controlThisDevice), trailing: companionRemote.isConnected ? const AppIcon(Symbols.check_circle_rounded, fill: 1, color: Colors.green) : const AppIcon(Symbols.chevron_right_rounded, fill: 1), @@ -810,10 +810,10 @@ class _SettingsScreenState extends State with FocusableTab { else ListTile( leading: const AppIcon(Symbols.phone_android_rounded, fill: 1), - title: const Text('Remote Control'), + title: Text(t.companionRemote.remoteControl), subtitle: companionRemote.isConnected - ? Text('Connected to ${companionRemote.connectedDevice?.name}') - : const Text('Control a desktop device'), + ? Text(t.companionRemote.connectedTo(name: companionRemote.connectedDevice?.name ?? '')) + : Text(t.companionRemote.controlDesktop), trailing: const AppIcon(Symbols.chevron_right_rounded, fill: 1), onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) => const MobileRemoteScreen())); diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index f5e9f936..6a50bd76 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -2157,7 +2157,7 @@ class VideoPlayerScreenState extends State with WidgetsBindin side: BorderSide(color: Colors.white.withValues(alpha: 0.5)), padding: const EdgeInsets.symmetric(vertical: 12), ), - child: Text(t.dialog.cancel), + child: Text(t.common.cancel), ), ), ), diff --git a/lib/services/play_queue_launcher.dart b/lib/services/play_queue_launcher.dart index 78ffba4d..191e40dd 100644 --- a/lib/services/play_queue_launcher.dart +++ b/lib/services/play_queue_launcher.dart @@ -115,7 +115,7 @@ class PlayQueueLauncher { }) async { return _executeWithLoading( showLoading: showLoadingIndicator, - action: t.discover.play, + action: t.common.play, execute: (dismissLoading) async { final playQueue = await client.createPlayQueue( playlistID: int.parse(playlist.ratingKey), diff --git a/lib/utils/formatters.dart b/lib/utils/formatters.dart index 0ed1383d..3fc2f57a 100644 --- a/lib/utils/formatters.dart +++ b/lib/utils/formatters.dart @@ -189,6 +189,43 @@ String formatFinishTime(Duration remaining, {double rate = 1.0}) { return formatter.format(finishTime); } +/// Formats a DateTime as a relative time string (e.g., "just now", "5m", "3h", "2d", or a full date). +/// Uses the `duration` package for localized unit names. +/// +/// Used for: recent connections timestamps. +String formatRelativeTime(DateTime date) { + final now = DateTime.now(); + final difference = now.difference(date); + + if (difference.inMinutes < 1) { + return prettyDuration( + Duration.zero, + abbreviated: true, + locale: _getDurationLocale(), + tersity: DurationTersity.minute, + upperTersity: DurationTersity.minute, + ); + } else if (difference.inDays < 7) { + return prettyDuration( + difference, + abbreviated: true, + locale: _getDurationLocale(), + delimiter: ' ', + spacer: '', + tersity: DurationTersity.minute, + upperTersity: difference.inDays >= 1 + ? DurationTersity.day + : difference.inHours >= 1 + ? DurationTersity.hour + : DurationTersity.minute, + maxUnits: 1, + ); + } else { + final formatter = DateFormat.yMd(LocaleSettings.currentLocale.languageCode); + return formatter.format(date); + } +} + /// Takes a list of strings and returns one long string with each item in the list concatenated by a bullet String toBulletedString(List parts) { return parts.join(' · '); diff --git a/lib/widgets/companion_remote/remote_session_dialog.dart b/lib/widgets/companion_remote/remote_session_dialog.dart index 59c22497..2b6eb37a 100644 --- a/lib/widgets/companion_remote/remote_session_dialog.dart +++ b/lib/widgets/companion_remote/remote_session_dialog.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:qr_flutter/qr_flutter.dart'; +import '../../i18n/strings.g.dart'; import '../../providers/companion_remote_provider.dart'; import '../../utils/app_logger.dart'; @@ -61,7 +62,7 @@ class _RemoteSessionDialogState extends State { Clipboard.setData(ClipboardData(text: text)); ScaffoldMessenger.of( context, - ).showSnackBar(SnackBar(content: Text('$label copied to clipboard'), duration: const Duration(seconds: 2))); + ).showSnackBar(SnackBar(content: Text(t.companionRemote.session.copiedToClipboard(label: label)), duration: const Duration(seconds: 2))); } @override @@ -77,7 +78,7 @@ class _RemoteSessionDialogState extends State { children: [ const CircularProgressIndicator(), const SizedBox(height: 16), - Text('Creating remote session...', style: Theme.of(context).textTheme.titleMedium), + Text(t.companionRemote.session.creatingSession, style: Theme.of(context).textTheme.titleMedium), ], ), ), @@ -86,19 +87,19 @@ class _RemoteSessionDialogState extends State { if (_errorMessage != null) { return AlertDialog( - title: const Text('Error'), + title: Text(t.common.error), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Failed to create remote session:'), + Text(t.companionRemote.session.failedToCreate), const SizedBox(height: 8), Text(_errorMessage!, style: const TextStyle(fontFamily: 'monospace')), ], ), actions: [ - TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('Close')), - TextButton(onPressed: _createSession, child: const Text('Retry')), + TextButton(onPressed: () => Navigator.of(context).pop(), child: Text(t.common.close)), + TextButton(onPressed: _createSession, child: Text(t.common.retry)), ], ); } @@ -106,9 +107,9 @@ class _RemoteSessionDialogState extends State { final session = provider.session; if (session == null || _hostAddress == null) { return AlertDialog( - title: const Text('Error'), - content: const Text('No session available'), - actions: [TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('Close'))], + title: Text(t.common.error), + content: Text(t.companionRemote.session.noSession), + actions: [TextButton(onPressed: () => Navigator.of(context).pop(), child: Text(t.common.close))], ); } @@ -137,12 +138,12 @@ class _RemoteSessionDialogState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Companion Remote', style: Theme.of(context).textTheme.headlineSmall), + Text(t.companionRemote.title, style: Theme.of(context).textTheme.headlineSmall), const SizedBox(height: 4), Text( session.connectedDevice != null - ? 'Connected to ${session.connectedDevice!.name}' - : 'Waiting for connection...', + ? t.companionRemote.connectedTo(name: session.connectedDevice!.name) + : t.companionRemote.session.waitingForConnection, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: session.connectedDevice != null ? Colors.green @@ -157,7 +158,7 @@ class _RemoteSessionDialogState extends State { ), const SizedBox(height: 24), if (session.connectedDevice == null) ...[ - Text('Scan QR Code', style: Theme.of(context).textTheme.titleMedium, textAlign: TextAlign.center), + Text(t.companionRemote.session.scanQrCode, style: Theme.of(context).textTheme.titleMedium, textAlign: TextAlign.center), const SizedBox(height: 16), Center( child: Container( @@ -175,26 +176,26 @@ class _RemoteSessionDialogState extends State { const Divider(), const SizedBox(height: 16), Text( - 'Or enter manually', + t.companionRemote.session.orEnterManually, style: Theme.of(context).textTheme.titleMedium, textAlign: TextAlign.center, ), const SizedBox(height: 16), _buildCodeCard( context, - 'Host Address', + t.companionRemote.session.hostAddress, _hostAddress!, - onCopy: () => _copyToClipboard(_hostAddress!, 'Host Address'), + onCopy: () => _copyToClipboard(_hostAddress!, t.companionRemote.session.hostAddress), ), const SizedBox(height: 12), _buildCodeCard( context, - 'Session ID', + t.companionRemote.session.sessionId, session.sessionId, - onCopy: () => _copyToClipboard(session.sessionId, 'Session ID'), + onCopy: () => _copyToClipboard(session.sessionId, t.companionRemote.session.sessionId), ), const SizedBox(height: 12), - _buildCodeCard(context, 'PIN', session.pin, onCopy: () => _copyToClipboard(session.pin, 'PIN')), + _buildCodeCard(context, t.companionRemote.session.pin, session.pin, onCopy: () => _copyToClipboard(session.pin, t.companionRemote.session.pin)), ] else ...[ Card( child: Padding( @@ -203,7 +204,7 @@ class _RemoteSessionDialogState extends State { children: [ const Icon(Icons.check_circle, color: Colors.green, size: 48), const SizedBox(height: 8), - Text('Connected', style: Theme.of(context).textTheme.titleLarge), + Text(t.companionRemote.session.connected, style: Theme.of(context).textTheme.titleLarge), const SizedBox(height: 8), Text(session.connectedDevice!.name, style: Theme.of(context).textTheme.bodyLarge), Text(session.connectedDevice!.platform, style: Theme.of(context).textTheme.bodySmall), @@ -213,7 +214,7 @@ class _RemoteSessionDialogState extends State { ), const SizedBox(height: 16), Text( - 'Use your mobile device to control this app', + t.companionRemote.session.usePhoneToControl, style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), @@ -229,7 +230,7 @@ class _RemoteSessionDialogState extends State { await _createSession(); }, icon: const Icon(Icons.refresh), - label: const Text('New Session'), + label: Text(t.companionRemote.session.newSession), ), const SizedBox(width: 8), TextButton( @@ -239,10 +240,10 @@ class _RemoteSessionDialogState extends State { Navigator.of(context).pop(); } }, - child: const Text('Disconnect'), + child: Text(t.common.disconnect), ), const SizedBox(width: 8), - FilledButton(onPressed: () => Navigator.of(context).pop(), child: const Text('Minimize')), + FilledButton(onPressed: () => Navigator.of(context).pop(), child: Text(t.companionRemote.session.minimize)), ], ), ], @@ -273,7 +274,7 @@ class _RemoteSessionDialogState extends State { ], ), ), - IconButton(icon: const Icon(Icons.copy), onPressed: onCopy, tooltip: 'Copy to clipboard'), + IconButton(icon: const Icon(Icons.copy), onPressed: onCopy, tooltip: t.companionRemote.session.copyToClipboard), ], ), ), diff --git a/lib/widgets/download_tree_view.dart b/lib/widgets/download_tree_view.dart index c6d3a9ec..098f1d92 100644 --- a/lib/widgets/download_tree_view.dart +++ b/lib/widgets/download_tree_view.dart @@ -109,7 +109,7 @@ class _DownloadTreeViewState extends State { final flattenedNodes = _flattenTree(tree); if (flattenedNodes.isEmpty) { - return const Center(child: Text('No downloads')); + return Center(child: Text(t.downloads.noDownloadsTree)); } return ListView.builder( @@ -741,7 +741,7 @@ class _DownloadTreeItemState extends State<_DownloadTreeItem> { actions.add( _buildActionButton( icon: Symbols.pause_rounded, - tooltip: 'Pause', + tooltip: t.common.pause, onPressed: () => widget.onPause!(globalKey), buttonIndex: buttonIndex++, ), @@ -753,7 +753,7 @@ class _DownloadTreeItemState extends State<_DownloadTreeItem> { actions.add( _buildActionButton( icon: Symbols.play_arrow_rounded, - tooltip: 'Resume', + tooltip: t.common.resume, onPressed: () => widget.onResume!(globalKey), buttonIndex: buttonIndex++, ), @@ -765,7 +765,7 @@ class _DownloadTreeItemState extends State<_DownloadTreeItem> { actions.add( _buildActionButton( icon: Symbols.close_rounded, - tooltip: 'Cancel', + tooltip: t.common.cancel, onPressed: () => widget.onCancel!(globalKey), buttonIndex: buttonIndex++, ), @@ -790,7 +790,7 @@ class _DownloadTreeItemState extends State<_DownloadTreeItem> { actions.add( _buildActionButton( icon: Symbols.delete_rounded, - tooltip: 'Delete', + tooltip: t.common.delete, onPressed: () async { final confirmed = await showDeleteConfirmation( context, @@ -817,7 +817,7 @@ class _DownloadTreeItemState extends State<_DownloadTreeItem> { actions.add( _buildActionButton( icon: Symbols.pause_rounded, - tooltip: 'Pause all', + tooltip: t.downloads.pauseAll, onPressed: () => widget.pauseAllChildren(widget.node), buttonIndex: buttonIndex++, ), @@ -829,7 +829,7 @@ class _DownloadTreeItemState extends State<_DownloadTreeItem> { actions.add( _buildActionButton( icon: Symbols.play_arrow_rounded, - tooltip: 'Resume all', + tooltip: t.downloads.resumeAll, onPressed: () => widget.resumeAllChildren(widget.node), buttonIndex: buttonIndex++, ), @@ -841,7 +841,7 @@ class _DownloadTreeItemState extends State<_DownloadTreeItem> { actions.add( _buildActionButton( icon: Symbols.delete_sweep_rounded, - tooltip: 'Delete all', + tooltip: t.downloads.deleteAll, onPressed: () async { final confirmed = await showDeleteConfirmation( context, diff --git a/lib/widgets/media_context_menu.dart b/lib/widgets/media_context_menu.dart index f5a5130c..90e2e0d0 100644 --- a/lib/widgets/media_context_menu.dart +++ b/lib/widgets/media_context_menu.dart @@ -140,7 +140,7 @@ class MediaContextMenuState extends State { // Special actions for collections and playlists if (isCollection || isPlaylist) { // Play - menuActions.add(_MenuAction(value: 'play', icon: Symbols.play_arrow_rounded, label: t.discover.play)); + menuActions.add(_MenuAction(value: 'play', icon: Symbols.play_arrow_rounded, label: t.common.play)); // Shuffle menuActions.add(_MenuAction(value: 'shuffle', icon: Symbols.shuffle_rounded, label: t.mediaMenu.shufflePlay)); diff --git a/lib/widgets/side_navigation_rail.dart b/lib/widgets/side_navigation_rail.dart index ddfb3a71..457c1a88 100644 --- a/lib/widgets/side_navigation_rail.dart +++ b/lib/widgets/side_navigation_rail.dart @@ -323,7 +323,7 @@ class SideNavigationRailState extends State { _buildNavItem( icon: Symbols.home_rounded, selectedIcon: Symbols.home_rounded, - label: Translations.of(context).navigation.home, + label: Translations.of(context).common.home, isSelected: widget.selectedIndex == 0, isFocused: _focusTracker.isFocused(_kHome), onTap: () => widget.onDestinationSelected(0), @@ -342,7 +342,7 @@ class SideNavigationRailState extends State { _buildNavItem( icon: Symbols.search_rounded, selectedIcon: Symbols.search_rounded, - label: Translations.of(context).navigation.search, + label: Translations.of(context).common.search, isSelected: widget.selectedIndex == 2, isFocused: _focusTracker.isFocused(_kSearch), onTap: () => widget.onDestinationSelected(2), @@ -377,7 +377,7 @@ class SideNavigationRailState extends State { _buildNavItem( icon: Symbols.settings_rounded, selectedIcon: Symbols.settings_rounded, - label: Translations.of(context).navigation.settings, + label: Translations.of(context).common.settings, isSelected: NavigationTab.isTabAtIndex( NavigationTabId.settings, widget.selectedIndex, diff --git a/lib/widgets/video_controls/desktop_video_controls.dart b/lib/widgets/video_controls/desktop_video_controls.dart index 8052fbbc..928f780c 100644 --- a/lib/widgets/video_controls/desktop_video_controls.dart +++ b/lib/widgets/video_controls/desktop_video_controls.dart @@ -540,38 +540,51 @@ class DesktopVideoControlsState extends State { semanticLabel: t.videoControls.nextButton, ), ), - // Finish time - StreamBuilder( - stream: widget.player.streams.position, - initialData: widget.player.state.position, - builder: (context, posSnap) { - return StreamBuilder( - stream: widget.player.streams.duration, - initialData: widget.player.state.duration, - builder: (context, durSnap) { - return StreamBuilder( - stream: widget.player.streams.rate, - initialData: widget.player.state.rate, - builder: (context, rateSnap) { - final position = posSnap.data ?? Duration.zero; - final duration = durSnap.data ?? Duration.zero; - final remaining = duration - position; - final rate = rateSnap.data ?? 1.0; - if (remaining.inSeconds <= 0) return const SizedBox.shrink(); - return Padding( - padding: const EdgeInsets.only(left: 8), - child: Text( - t.videoControls.endsAt(time: formatFinishTime(remaining, rate: rate)), - style: const TextStyle(color: Colors.white70, fontSize: 13), - ), - ); - }, - ); - }, - ); - }, + // Finish time (hidden when too narrow to fit) + Expanded( + child: StreamBuilder( + stream: widget.player.streams.position, + initialData: widget.player.state.position, + builder: (context, posSnap) { + return StreamBuilder( + stream: widget.player.streams.duration, + initialData: widget.player.state.duration, + builder: (context, durSnap) { + return StreamBuilder( + stream: widget.player.streams.rate, + initialData: widget.player.state.rate, + builder: (context, rateSnap) { + final position = posSnap.data ?? Duration.zero; + final duration = durSnap.data ?? Duration.zero; + final remaining = duration - position; + final rate = rateSnap.data ?? 1.0; + if (remaining.inSeconds <= 0) return const SizedBox.shrink(); + + final text = t.videoControls.endsAt(time: formatFinishTime(remaining, rate: rate)); + const style = TextStyle(color: Colors.white70, fontSize: 13); + + return LayoutBuilder( + builder: (context, constraints) { + final tp = TextPainter( + text: TextSpan(text: text, style: style), + textDirection: TextDirection.ltr, + )..layout(); + final textWidth = tp.width + 8; + tp.dispose(); + if (textWidth > constraints.maxWidth) return const SizedBox.shrink(); + return Padding( + padding: const EdgeInsets.only(left: 8), + child: Text(text, style: style), + ); + }, + ); + }, + ); + }, + ); + }, + ), ), - const Spacer(), // Volume control VolumeControl( player: widget.player, diff --git a/lib/widgets/video_controls/sheets/chapter_sheet.dart b/lib/widgets/video_controls/sheets/chapter_sheet.dart index 1c9cd197..0e07fbcf 100644 --- a/lib/widgets/video_controls/sheets/chapter_sheet.dart +++ b/lib/widgets/video_controls/sheets/chapter_sheet.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:plezy/widgets/app_icon.dart'; import 'package:material_symbols_icons/symbols.dart'; +import '../../../i18n/strings.g.dart'; import '../../../mpv/mpv.dart'; import '../../../services/plex_client.dart'; import '../../../services/download_storage_service.dart'; @@ -108,8 +109,8 @@ class _ChapterSheetState extends State { if (!widget.chaptersLoaded) { content = const Center(child: CircularProgressIndicator()); } else if (widget.chapters.isEmpty) { - content = const Center( - child: Text('No chapters available', style: TextStyle(color: Colors.white70)), + content = Center( + child: Text(t.videoControls.noChaptersAvailable, style: const TextStyle(color: Colors.white70)), ); } else { content = ListView.builder( @@ -179,7 +180,7 @@ class _ChapterSheetState extends State { ); } - return BaseVideoControlSheet(title: 'Chapters', icon: Symbols.video_library_rounded, child: content); + return BaseVideoControlSheet(title: t.videoControls.chapters, icon: Symbols.video_library_rounded, child: content); }, ), ); diff --git a/lib/widgets/video_controls/sheets/video_settings_sheet.dart b/lib/widgets/video_controls/sheets/video_settings_sheet.dart index 54df647a..d432ca37 100644 --- a/lib/widgets/video_controls/sheets/video_settings_sheet.dart +++ b/lib/widgets/video_controls/sheets/video_settings_sheet.dart @@ -200,17 +200,17 @@ class _VideoSettingsSheetState extends State { String _getTitle() { switch (_currentView) { case _SettingsView.menu: - return 'Playback Settings'; + return t.videoSettings.playbackSettings; case _SettingsView.speed: - return 'Playback Speed'; + return t.videoSettings.playbackSpeed; case _SettingsView.sleep: - return 'Sleep Timer'; + return t.videoSettings.sleepTimer; case _SettingsView.audioSync: - return 'Audio Sync'; + return t.videoSettings.audioSync; case _SettingsView.subtitleSync: - return 'Subtitle Sync'; + return t.videoSettings.subtitleSync; case _SettingsView.audioDevice: - return 'Audio Output'; + return t.videoSettings.audioOutput; case _SettingsView.shader: return t.shaders.title; } @@ -263,7 +263,7 @@ class _VideoSettingsSheetState extends State { return _SettingsMenuItem( focusNode: _initialFocusNode, icon: Symbols.speed_rounded, - title: 'Playback Speed', + title: t.videoSettings.playbackSpeed, valueText: _formatSpeed(currentRate), onTap: () => _navigateTo(_SettingsView.speed), ); @@ -277,7 +277,7 @@ class _VideoSettingsSheetState extends State { final isActive = sleepTimer.isActive; return _SettingsMenuItem( icon: isActive ? Symbols.bedtime_rounded : Symbols.bedtime_rounded, - title: 'Sleep Timer', + title: t.videoSettings.sleepTimer, valueText: _formatSleepTimer(sleepTimer), isHighlighted: isActive, onTap: () => _navigateTo(_SettingsView.sleep), @@ -288,7 +288,7 @@ class _VideoSettingsSheetState extends State { // Audio Sync _SettingsMenuItem( icon: Symbols.sync_rounded, - title: 'Audio Sync', + title: t.videoSettings.audioSync, valueText: formatSyncOffset(_audioSyncOffset.toDouble()), isHighlighted: _audioSyncOffset != 0, onTap: () => _navigateTo(_SettingsView.audioSync), @@ -297,7 +297,7 @@ class _VideoSettingsSheetState extends State { // Subtitle Sync _SettingsMenuItem( icon: Symbols.subtitles_rounded, - title: 'Subtitle Sync', + title: t.videoSettings.subtitleSync, valueText: formatSyncOffset(_subtitleSyncOffset.toDouble()), isHighlighted: _subtitleSyncOffset != 0, onTap: () => _navigateTo(_SettingsView.subtitleSync), @@ -307,7 +307,7 @@ class _VideoSettingsSheetState extends State { if (Platform.isIOS || Platform.isMacOS || Platform.isWindows) ListTile( leading: AppIcon(Symbols.hdr_strong_rounded, fill: 1, color: _enableHDR ? Colors.amber : Colors.white70), - title: const Text('HDR', style: TextStyle(color: Colors.white)), + title: Text(t.videoSettings.hdr, style: const TextStyle(color: Colors.white)), trailing: Switch(value: _enableHDR, onChanged: (_) => _toggleHDR(), activeThumbColor: Colors.amber), onTap: _toggleHDR, ), @@ -341,7 +341,7 @@ class _VideoSettingsSheetState extends State { return _SettingsMenuItem( icon: Symbols.speaker_rounded, - title: 'Audio Output', + title: t.videoSettings.audioOutput, valueText: deviceLabel, allowValueOverflow: true, onTap: () => _navigateTo(_SettingsView.audioDevice), @@ -366,7 +366,7 @@ class _VideoSettingsSheetState extends State { fill: 1, color: _showPerformanceOverlay ? Colors.amber : Colors.white70, ), - title: const Text('Performance Overlay', style: TextStyle(color: Colors.white)), + title: Text(t.videoSettings.performanceOverlay, style: const TextStyle(color: Colors.white)), trailing: Switch( value: _showPerformanceOverlay, onChanged: (_) => _togglePerformanceOverlay(), diff --git a/lib/widgets/video_controls/video_controls.dart b/lib/widgets/video_controls/video_controls.dart index efa41286..71413013 100644 --- a/lib/widgets/video_controls/video_controls.dart +++ b/lib/widgets/video_controls/video_controls.dart @@ -1,6 +1,7 @@ import 'dart:async' show StreamSubscription, Timer; import 'dart:io' show Platform; +import 'package:flutter/gestures.dart' show PointerSignalEvent, PointerScrollEvent; import 'package:flutter/material.dart'; import 'package:plezy/widgets/app_icon.dart'; import 'package:material_symbols_icons/symbols.dart'; diff --git a/lib/widgets/video_controls/widgets/video_controls_header.dart b/lib/widgets/video_controls/widgets/video_controls_header.dart index 011a2de6..088bc237 100644 --- a/lib/widgets/video_controls/widgets/video_controls_header.dart +++ b/lib/widgets/video_controls/widgets/video_controls_header.dart @@ -42,7 +42,7 @@ class VideoControlsHeader extends StatelessWidget { children: [ AppBarBackButton( style: BackButtonStyle.video, - semanticLabel: t.videoControls.backButton, + semanticLabel: t.common.back, onPressed: onBack ?? () => Navigator.of(context).pop(true), ), const SizedBox(width: 16),