From 608f742f8394cfe78a510d3484ea8e1ac5b9ab6e Mon Sep 17 00:00:00 2001 From: Timo <6156589+Shik3i@users.noreply.github.com> Date: Mon, 1 Jun 2026 05:47:08 +0200 Subject: [PATCH] fix(i18n): resolve hardcoded strings, missing translation keys, SW notification race conditions, and toast username bugs --- extension/background.js | 63 ++++++++++++++++++++++++------- extension/locales/de.json | 31 ++++++++------- extension/locales/en.json | 31 ++++++++------- extension/locales/es.json | 31 ++++++++------- extension/locales/fr.json | 31 ++++++++------- extension/locales/pt-BR.json | 31 ++++++++------- extension/locales/ru.json | 31 ++++++++------- extension/popup.js | 73 +++++++++++++++++++----------------- 8 files changed, 190 insertions(+), 132 deletions(-) diff --git a/extension/background.js b/extension/background.js index 7810752..949bfac 100644 --- a/extension/background.js +++ b/extension/background.js @@ -1,6 +1,6 @@ import { EVENTS, PROTOCOL_VERSION, OFFICIAL_SERVER_URL, OFFICIAL_SERVER_TOKEN, APP_VERSION, EPISODE_LOBBY_TIMEOUT, FORCE_SYNC_TIMEOUT } from './shared/constants.js'; import { generateUsername } from './shared/names.js'; -import { loadLocale, getMessage } from './i18n.js'; +import { loadLocale, getMessage, SUPPORTED_LANGUAGES } from './i18n.js'; // --- State Management --- @@ -476,7 +476,11 @@ function showNotification(senderName, action) { chrome.storage.sync.get(['browserNotifications', 'locale'], async (settings) => { if (!settings.browserNotifications) return; - const lang = settings.locale || 'en'; + let lang = settings.locale; + if (!lang) { + const systemLang = (navigator.language || chrome.i18n.getUILanguage()).split('-')[0]; + lang = SUPPORTED_LANGUAGES.includes(systemLang) ? systemLang : 'en'; + } await loadLocale(lang); let labelKey = ''; @@ -650,11 +654,19 @@ function handleServerEvent(event, data) { isConnecting = false; broadcastConnectionStatus('disconnected'); addLog(`Server Error: ${data.message}`, 'error'); - chrome.notifications.create(`error_${Date.now()}`, { - type: 'basic', - iconUrl: 'icons/icon128.png', - title: 'KoalaSync Error', - message: data.message + chrome.storage.sync.get(['locale'], async (settings) => { + let lang = settings.locale; + if (!lang) { + const systemLang = (navigator.language || chrome.i18n.getUILanguage()).split('-')[0]; + lang = SUPPORTED_LANGUAGES.includes(systemLang) ? systemLang : 'en'; + } + await loadLocale(lang); + chrome.notifications.create(`error_${Date.now()}`, { + type: 'basic', + iconUrl: 'icons/icon128.png', + title: getMessage('NOTIF_ERROR_TITLE') || 'KoalaSync Error', + message: data.message + }); }); // Inform Website Bridge & Popup const errStatusMsg = { type: 'JOIN_STATUS', success: false, message: data.message }; @@ -969,13 +981,38 @@ function cancelEpisodeLobby(reason) { clearEpisodeLobbyState(); addLog(`Episode lobby cancelled: ${reason} for "${title}"`, 'warn'); + const reasonKeys = { + 'Timeout': 'LOBBY_CANCEL_TIMEOUT', + 'Timeout (recovered)': 'LOBBY_CANCEL_TIMEOUT_RECOVERED', + 'All other peers left': 'LOBBY_CANCEL_PEERS_LEFT', + 'Timeout — not all peers loaded the episode': 'LOBBY_CANCEL_TIMEOUT_PEERS_LOAD', + 'Cancelled by user': 'LOBBY_CANCEL_USER' + }; + // Chrome notification on failure (per Q2: only notify on failure) - chrome.notifications.create(`episode_${Date.now()}`, { - type: 'basic', - iconUrl: 'icons/icon128.png', - title: 'KoalaSync — Episode Sync Failed', - message: `Auto-sync cancelled: ${reason}. You may need to manually sync.`, - priority: 1 + chrome.storage.sync.get(['browserNotifications', 'locale'], async (settings) => { + if (!settings.browserNotifications) return; + + let lang = settings.locale; + if (!lang) { + const systemLang = (navigator.language || chrome.i18n.getUILanguage()).split('-')[0]; + lang = SUPPORTED_LANGUAGES.includes(systemLang) ? systemLang : 'en'; + } + await loadLocale(lang); + + const reasonKey = reasonKeys[reason]; + const localizedReason = reasonKey ? getMessage(reasonKey) : reason; + + const titleText = getMessage('NOTIF_LOBBY_CANCEL_TITLE') || 'KoalaSync — Episode Sync Failed'; + const messageText = getMessage('NOTIF_LOBBY_CANCEL_MSG', { reason: localizedReason }) || `Auto-sync cancelled: ${localizedReason}. You may need to manually sync.`; + + chrome.notifications.create(`episode_${Date.now()}`, { + type: 'basic', + iconUrl: 'icons/icon128.png', + title: titleText, + message: messageText, + priority: 1 + }); }); } diff --git a/extension/locales/de.json b/extension/locales/de.json index 0c03d28..fb4089a 100644 --- a/extension/locales/de.json +++ b/extension/locales/de.json @@ -1,7 +1,6 @@ { "LANG_CODE": "de", "HTML_CLASS": "lang-de", - "APP_TITLE": "KoalaSync", "TAB_ROOM": "Raum", "TAB_ROOM_TOOLTIP": "Raum-Einstellungen und Verbindung", @@ -11,7 +10,6 @@ "TAB_SETTINGS_TOOLTIP": "Erweiterungseinstellungen", "TAB_STATUS": "Status", "TAB_STATUS_TOOLTIP": "Erweiterte Diagnose & Protokolle", - "BTN_CREATE_ROOM": "+ Neuer Raum", "MANUAL_CONNECT_HEADER": "Manuell verbinden / Erweitert", "LABEL_SERVER": "Server", @@ -35,7 +33,6 @@ "BTN_REFRESH": "AKTUALISIEREN", "BTN_REFRESH_TOOLTIP": "Die Liste der öffentlichen Räume aktualisieren", "PUBLIC_ROOMS_REFRESHING": "Aktualisiere...", - "LABEL_ACTIVE_ROOM": "Aktiver Raum", "LABEL_ACTIVE_ROOM_TOOLTIP": "Der Raum, mit dem du gerade verbunden bist", "ACTIVE_ROOM_NONE": "KEINER", @@ -46,7 +43,6 @@ "LABEL_PEERS_IN_ROOM_TOOLTIP": "Andere Benutzer, die derzeit mit diesem Raum verbunden sind", "NO_PEERS_CONNECTED": "Keine Teilnehmer verbunden", "BTN_LEAVE_ROOM": "Raum verlassen", - "LABEL_SELECT_VIDEO": "Video auswählen", "LABEL_SELECT_VIDEO_TOOLTIP": "Wähle den Browser-Tab aus, der das zu synchronisierende Video enthält", "OPTION_SELECT_TAB": "-- Wähle einen Tab --", @@ -74,7 +70,6 @@ "LOBBY_CONNECT_FIRST_DESC": "Du musst über einen Einladungslink beitreten oder einen neuen Raum erstellen, um Videos zu synchronisieren.", "BTN_CREATE_ROOM_ALT": "Neuen Raum erstellen", "BTN_CREATE_ROOM_ALT_TOOLTIP": "Einen neuen zufälligen Raum erstellen und beitreten", - "LABEL_USERNAME": "Dein Benutzername", "LABEL_USERNAME_TOOLTIP": "Der Benutzername hilft anderen, dich zu identifizieren.", "PLACEHOLDER_USERNAME": "Anonymer Koala", @@ -93,7 +88,6 @@ "BTN_REGEN_ID": "Peer-ID neu generieren", "BTN_REGEN_ID_TOOLTIP": "Generiere deine interne ID neu und verbinde dich erneut", "REGEN_ID_DESC": "Verwende dies, wenn du Fehler wegen doppelter Identität siehst.", - "LABEL_CONN_STATUS": "Verbindungsstatus", "LABEL_CONN_STATUS_TOOLTIP": "Aktueller WebSocket-Verbindungsstatus", "CONN_STATUS_DISCONNECTED": "Getrennt", @@ -112,7 +106,6 @@ "BTN_CLEAR": "LEEREN", "BTN_CLEAR_TOOLTIP": "Protokollausgabe leeren", "LABEL_GITHUB": "GitHub-Repository", - "BTN_ONBOARDING_SKIP": "Überspringen", "BTN_ONBOARDING_SKIP_TOOLTIP": "Einführung überspringen", "BTN_ONBOARDING_NEXT": "Weiter", @@ -127,7 +120,6 @@ "ONBOARDING_4_TEXT": "Wähle einen lustigen Benutzernamen, damit deine Freunde wissen, wer du bist.", "ONBOARDING_5_TITLE": "Alles startklar!", "ONBOARDING_5_TEXT": "Zeit, das Popcorn zu holen. Viel Spaß beim gemeinsamen Schauen!", - "ERR_CONN_TIMEOUT": "Verbindung abgelaufen. Bitte versuche es erneut.", "ERR_INVALID_SERVER_URL": "Ungültiges Server-URL-Format.", "ERR_IDENTITY_NOT_LOADED": "Identität noch nicht geladen. Warte kurz und versuche es erneut.", @@ -142,13 +134,11 @@ "TOAST_PEER_JOINED": "{name} ist dem Raum beigetreten", "TOAST_PEER_LEFT": "{name} hat den Raum verlassen", "TOAST_PEER_ACTION": "{name} hat {action}", - "STATUS_CONNECTED": "Verbunden", "STATUS_RECONNECTING": "Verbinde erneut...", "STATUS_CONNECTING": "Verbinde...", "STATUS_FAILED": "Fehlgeschlagen", "STATUS_DISCONNECTED": "Getrennt", - "BTN_STATE_JOINING": "🚀 Trete bei...", "BTN_STATE_RECONNECTING": "🔄 Verbinde erneut...", "BTN_STATE_PLAYING": "▶ Spiele ab...", @@ -156,16 +146,13 @@ "BTN_STATE_SYNCING_GROUP": "Synce zur Gruppe ({time})...", "BTN_STATE_SYNCING": "Synchronisiere...", "BTN_STATE_SYNCED": "✅ Synchronisiert!", - "NOTIF_PLAY": "die Wiedergabe gestartet", "NOTIF_PAUSE": "die Wiedergabe pausiert", "NOTIF_SEEK": "im Video gespult", "NOTIF_FORCE_PREPARE": "eine erzwungene Synchronisation gestartet", "NOTIF_FORCE_EXECUTE": "alle Teilnehmer synchronisiert", - "DEBUG_NO_TAB": "Kein Ziel-Tab ausgewählt.", "DEBUG_COMM_FAIL": "Kommunikation mit dem Tab-Video fehlgeschlagen.", - "EMPTY_PEERS_TITLE": "Noch keine Teilnehmer", "EMPTY_PEERS_HINT": "Teile deinen Einladungslink, um loszulegen", "EMPTY_HISTORY_TITLE": "Noch keine Aktivität", @@ -173,5 +160,21 @@ "EMPTY_LOGS_TITLE": "Keine Logs", "EMPTY_LOGS_HINT": "Verbindungsereignisse werden hier angezeigt", "EMPTY_ROOMS_TITLE": "Keine aktiven Räume", - "EMPTY_ROOMS_HINT": "Raum erstellen oder aktualisieren, um öffentliche zu finden" + "EMPTY_ROOMS_HINT": "Raum erstellen oder aktualisieren, um öffentliche zu finden", + "LABEL_YOU": "Du", + "ONBOARDING_DONE": "Fertig!", + "LABEL_LOBBY_PEER_READY": "Bereit", + "LABEL_LOBBY_PEER_LOADING": "Lädt...", + "LABEL_PASSWORD_PROTECTED": "Passwortgeschützt", + "LABEL_PEERS_COUNT": "{count} Teilnehmer", + "LABEL_CUSTOM_SERVER": "Eigener Server", + "BTN_STATE_CREATING": "🚀 Erstelle Raum...", + "NOTIF_LOBBY_CANCEL_TITLE": "KoalaSync — Episoden-Synchronisation fehlgeschlagen", + "NOTIF_LOBBY_CANCEL_MSG": "Auto-Sync abgebrochen: {reason}. Du musst eventuell manuell synchronisieren.", + "LOBBY_CANCEL_TIMEOUT": "Zeitüberschreitung", + "LOBBY_CANCEL_TIMEOUT_RECOVERED": "Zeitüberschreitung (wiederhergestellt)", + "LOBBY_CANCEL_PEERS_LEFT": "Alle anderen Teilnehmer haben den Raum verlassen", + "LOBBY_CANCEL_TIMEOUT_PEERS_LOAD": "Zeitüberschreitung — nicht alle Teilnehmer haben die Episode geladen", + "LOBBY_CANCEL_USER": "Vom Benutzer abgebrochen", + "NOTIF_ERROR_TITLE": "KoalaSync-Fehler" } diff --git a/extension/locales/en.json b/extension/locales/en.json index 3611ef1..386412d 100644 --- a/extension/locales/en.json +++ b/extension/locales/en.json @@ -1,7 +1,6 @@ { "LANG_CODE": "en", "HTML_CLASS": "lang-en", - "APP_TITLE": "KoalaSync", "TAB_ROOM": "Room", "TAB_ROOM_TOOLTIP": "Room settings and connection", @@ -11,7 +10,6 @@ "TAB_SETTINGS_TOOLTIP": "Extension preferences", "TAB_STATUS": "Status", "TAB_STATUS_TOOLTIP": "Advanced Diagnostics & Logs", - "BTN_CREATE_ROOM": "+ Create New Room", "MANUAL_CONNECT_HEADER": "Manual Connect / Advanced", "LABEL_SERVER": "Server", @@ -35,7 +33,6 @@ "BTN_REFRESH": "REFRESH", "BTN_REFRESH_TOOLTIP": "Refresh the list of public rooms", "PUBLIC_ROOMS_REFRESHING": "Refreshing...", - "LABEL_ACTIVE_ROOM": "Active Room", "LABEL_ACTIVE_ROOM_TOOLTIP": "The room you are currently connected to", "ACTIVE_ROOM_NONE": "NONE", @@ -46,7 +43,6 @@ "LABEL_PEERS_IN_ROOM_TOOLTIP": "Other users currently connected to this room", "NO_PEERS_CONNECTED": "No peers connected", "BTN_LEAVE_ROOM": "Leave Room", - "LABEL_SELECT_VIDEO": "Select Video", "LABEL_SELECT_VIDEO_TOOLTIP": "Choose the browser tab containing the video to sync", "OPTION_SELECT_TAB": "-- Select a Tab --", @@ -74,7 +70,6 @@ "LOBBY_CONNECT_FIRST_DESC": "You need to join a room via an invite link or create a new one to sync videos.", "BTN_CREATE_ROOM_ALT": "Create New Room", "BTN_CREATE_ROOM_ALT_TOOLTIP": "Create a new random room and join it", - "LABEL_USERNAME": "Your Username", "LABEL_USERNAME_TOOLTIP": "Username helps others identify you.", "PLACEHOLDER_USERNAME": "Anonymous Koala", @@ -93,7 +88,6 @@ "BTN_REGEN_ID": "Regenerate Peer ID", "BTN_REGEN_ID_TOOLTIP": "Regenerate your internal ID and reconnect", "REGEN_ID_DESC": "Use this if you see \"Duplicate Identity\" errors.", - "LABEL_CONN_STATUS": "Connection Status", "LABEL_CONN_STATUS_TOOLTIP": "Current WebSocket connection state", "CONN_STATUS_DISCONNECTED": "Disconnected", @@ -112,7 +106,6 @@ "BTN_CLEAR": "CLEAR", "BTN_CLEAR_TOOLTIP": "Clear log output", "LABEL_GITHUB": "GitHub Repository", - "BTN_ONBOARDING_SKIP": "Skip", "BTN_ONBOARDING_SKIP_TOOLTIP": "Skip the tutorial", "BTN_ONBOARDING_NEXT": "Next", @@ -127,7 +120,6 @@ "ONBOARDING_4_TEXT": "Pick a fun username so your friends know who you are.", "ONBOARDING_5_TITLE": "You're all set!", "ONBOARDING_5_TEXT": "Time to grab some popcorn. Enjoy watching together!", - "ERR_CONN_TIMEOUT": "Connection timed out. Please try again.", "ERR_INVALID_SERVER_URL": "Invalid Server URL format.", "ERR_IDENTITY_NOT_LOADED": "Identity not yet loaded. Wait a moment and try again.", @@ -142,13 +134,11 @@ "TOAST_PEER_JOINED": "{name} joined the room", "TOAST_PEER_LEFT": "{name} left the room", "TOAST_PEER_ACTION": "{name} {action}", - "STATUS_CONNECTED": "Connected", "STATUS_RECONNECTING": "Reconnecting...", "STATUS_CONNECTING": "Connecting...", "STATUS_FAILED": "Failed", "STATUS_DISCONNECTED": "Disconnected", - "BTN_STATE_JOINING": "🚀 Joining...", "BTN_STATE_RECONNECTING": "🔄 Reconnecting...", "BTN_STATE_PLAYING": "▶ Playing...", @@ -156,16 +146,13 @@ "BTN_STATE_SYNCING_GROUP": "Syncing to group ({time})...", "BTN_STATE_SYNCING": "Syncing...", "BTN_STATE_SYNCED": "✅ Synced!", - "NOTIF_PLAY": "started playback", "NOTIF_PAUSE": "paused playback", "NOTIF_SEEK": "seeked the video", "NOTIF_FORCE_PREPARE": "started force sync", "NOTIF_FORCE_EXECUTE": "synchronized everyone", - "DEBUG_NO_TAB": "No target tab selected.", "DEBUG_COMM_FAIL": "Could not communicate with tab video.", - "EMPTY_PEERS_TITLE": "No peers yet", "EMPTY_PEERS_HINT": "Share your invite link to get started", "EMPTY_HISTORY_TITLE": "No activity yet", @@ -173,5 +160,21 @@ "EMPTY_LOGS_TITLE": "No logs", "EMPTY_LOGS_HINT": "Connection events will appear here", "EMPTY_ROOMS_TITLE": "No active rooms", - "EMPTY_ROOMS_HINT": "Create a room or refresh to find public ones" + "EMPTY_ROOMS_HINT": "Create a room or refresh to find public ones", + "LABEL_YOU": "You", + "ONBOARDING_DONE": "Done!", + "LABEL_LOBBY_PEER_READY": "Ready", + "LABEL_LOBBY_PEER_LOADING": "Loading...", + "LABEL_PASSWORD_PROTECTED": "Password Protected", + "LABEL_PEERS_COUNT": "{count} peers", + "LABEL_CUSTOM_SERVER": "Custom Server", + "BTN_STATE_CREATING": "🚀 Creating Room...", + "NOTIF_LOBBY_CANCEL_TITLE": "KoalaSync — Episode Sync Failed", + "NOTIF_LOBBY_CANCEL_MSG": "Auto-sync cancelled: {reason}. You may need to manually sync.", + "LOBBY_CANCEL_TIMEOUT": "Timeout", + "LOBBY_CANCEL_TIMEOUT_RECOVERED": "Timeout (recovered)", + "LOBBY_CANCEL_PEERS_LEFT": "All other peers left", + "LOBBY_CANCEL_TIMEOUT_PEERS_LOAD": "Timeout — not all peers loaded the episode", + "LOBBY_CANCEL_USER": "Cancelled by user", + "NOTIF_ERROR_TITLE": "KoalaSync Error" } diff --git a/extension/locales/es.json b/extension/locales/es.json index 42fd884..20edae4 100644 --- a/extension/locales/es.json +++ b/extension/locales/es.json @@ -1,7 +1,6 @@ { "LANG_CODE": "es", "HTML_CLASS": "lang-es", - "APP_TITLE": "KoalaSync", "TAB_ROOM": "Sala", "TAB_ROOM_TOOLTIP": "Configuración de sala y conexión", @@ -11,7 +10,6 @@ "TAB_SETTINGS_TOOLTIP": "Preferencias de la extensión", "TAB_STATUS": "Estado", "TAB_STATUS_TOOLTIP": "Diagnósticos avanzados y registros", - "BTN_CREATE_ROOM": "+ Crear nueva sala", "MANUAL_CONNECT_HEADER": "Conexión manual / Avanzado", "LABEL_SERVER": "Servidor", @@ -35,7 +33,6 @@ "BTN_REFRESH": "ACTUALIZAR", "BTN_REFRESH_TOOLTIP": "Actualizar la lista de salas públicas", "PUBLIC_ROOMS_REFRESHING": "Actualizando...", - "LABEL_ACTIVE_ROOM": "Sala activa", "LABEL_ACTIVE_ROOM_TOOLTIP": "La sala a la que estás conectado actualmente", "ACTIVE_ROOM_NONE": "NINGUNA", @@ -46,7 +43,6 @@ "LABEL_PEERS_IN_ROOM_TOOLTIP": "Otros usuarios conectados actualmente a esta sala", "NO_PEERS_CONNECTED": "Sin participantes conectados", "BTN_LEAVE_ROOM": "Salir de la sala", - "LABEL_SELECT_VIDEO": "Seleccionar video", "LABEL_SELECT_VIDEO_TOOLTIP": "Elige la pestaña del navegador que contiene el video a sincronizar", "OPTION_SELECT_TAB": "-- Selecciona una pestaña --", @@ -74,7 +70,6 @@ "LOBBY_CONNECT_FIRST_DESC": "Necesitas unirte a una sala a través de un enlace de invitación o crear una nueva para sincronizar videos.", "BTN_CREATE_ROOM_ALT": "Crear nueva sala", "BTN_CREATE_ROOM_ALT_TOOLTIP": "Crear una nueva sala aleatoria y unirse", - "LABEL_USERNAME": "Tu nombre de usuario", "LABEL_USERNAME_TOOLTIP": "El nombre de usuario ayuda a otros a identificarte.", "PLACEHOLDER_USERNAME": "Koala anónimo", @@ -93,7 +88,6 @@ "BTN_REGEN_ID": "Regenerar ID de participante", "BTN_REGEN_ID_TOOLTIP": "Regenerar tu ID interno y volver a conectarte", "REGEN_ID_DESC": "Usa esto si ves errores de 'Identidad duplicada'.", - "LABEL_CONN_STATUS": "Estado de la conexión", "LABEL_CONN_STATUS_TOOLTIP": "Estado actual de la conexión WebSocket", "CONN_STATUS_DISCONNECTED": "Desconectado", @@ -112,7 +106,6 @@ "BTN_CLEAR": "LIMPIAR", "BTN_CLEAR_TOOLTIP": "Limpiar salida de registros", "LABEL_GITHUB": "Repositorio de GitHub", - "BTN_ONBOARDING_SKIP": "Omitir", "BTN_ONBOARDING_SKIP_TOOLTIP": "Omitir el tutorial", "BTN_ONBOARDING_NEXT": "Siguiente", @@ -127,7 +120,6 @@ "ONBOARDING_4_TEXT": "Elige un nombre de usuario divertido para que tus amigos sepan quién eres.", "ONBOARDING_5_TITLE": "¡Todo listo!", "ONBOARDING_5_TEXT": "Hora de preparar las palomitas. ¡Disfruta viendo con tus amigos!", - "ERR_CONN_TIMEOUT": "Tiempo de conexión agotado. Inténtalo de nuevo.", "ERR_INVALID_SERVER_URL": "Formato de URL de servidor no válido.", "ERR_IDENTITY_NOT_LOADED": "Identidad no cargada aún. Espera un momento e inténtalo de nuevo.", @@ -142,13 +134,11 @@ "TOAST_PEER_JOINED": "{name} se unió a la sala", "TOAST_PEER_LEFT": "{name} salió de la sala", "TOAST_PEER_ACTION": "{name} ha {action}", - "STATUS_CONNECTED": "Conectado", "STATUS_RECONNECTING": "Reconectando...", "STATUS_CONNECTING": "Conectando...", "STATUS_FAILED": "Error", "STATUS_DISCONNECTED": "Desconectado", - "BTN_STATE_JOINING": "🚀 Uniéndose...", "BTN_STATE_RECONNECTING": "🔄 Reconectando...", "BTN_STATE_PLAYING": "▶ Reproduciendo...", @@ -156,16 +146,13 @@ "BTN_STATE_SYNCING_GROUP": "Sincronizando al grupo ({time})...", "BTN_STATE_SYNCING": "Sincronizando...", "BTN_STATE_SYNCED": "✅ ¡Sincronizado!", - "NOTIF_PLAY": "inició la reproducción", "NOTIF_PAUSE": "pausó la reproducción", "NOTIF_SEEK": "cambió la posición del video", "NOTIF_FORCE_PREPARE": "inició una sincronización forzada", "NOTIF_FORCE_EXECUTE": "sincronizó a todos", - "DEBUG_NO_TAB": "No hay pestaña objetivo seleccionada.", "DEBUG_COMM_FAIL": "No se pudo comunicar con el video de la pestaña.", - "EMPTY_PEERS_TITLE": "Sin participantes aún", "EMPTY_PEERS_HINT": "Comparte tu enlace de invitación para comenzar", "EMPTY_HISTORY_TITLE": "Sin actividad aún", @@ -173,5 +160,21 @@ "EMPTY_LOGS_TITLE": "Sin registros", "EMPTY_LOGS_HINT": "Los eventos de conexión aparecerán aquí", "EMPTY_ROOMS_TITLE": "Sin salas activas", - "EMPTY_ROOMS_HINT": "Crea una sala o actualiza para buscar salas públicas" + "EMPTY_ROOMS_HINT": "Crea una sala o actualiza para buscar salas públicas", + "LABEL_YOU": "Tú", + "ONBOARDING_DONE": "¡Hecho!", + "LABEL_LOBBY_PEER_READY": "Listo", + "LABEL_LOBBY_PEER_LOADING": "Cargando...", + "LABEL_PASSWORD_PROTECTED": "Protegido con contraseña", + "LABEL_PEERS_COUNT": "{count} participantes", + "LABEL_CUSTOM_SERVER": "Servidor personalizado", + "BTN_STATE_CREATING": "🚀 Creando sala...", + "NOTIF_LOBBY_CANCEL_TITLE": "KoalaSync — Error al sincronizar episodio", + "NOTIF_LOBBY_CANCEL_MSG": "Sincronización automática cancelada: {reason}. Es posible que debas sincronizar manualmente.", + "LOBBY_CANCEL_TIMEOUT": "Tiempo de espera agotado", + "LOBBY_CANCEL_TIMEOUT_RECOVERED": "Tiempo de espera agotado (recuperado)", + "LOBBY_CANCEL_PEERS_LEFT": "Todos los demás participantes se han ido", + "LOBBY_CANCEL_TIMEOUT_PEERS_LOAD": "Tiempo de espera agotado: no todos los participantes cargaron el episodio", + "LOBBY_CANCEL_USER": "Cancelado por el usuario", + "NOTIF_ERROR_TITLE": "Error de KoalaSync" } diff --git a/extension/locales/fr.json b/extension/locales/fr.json index 2a9d82a..8cd4ba5 100644 --- a/extension/locales/fr.json +++ b/extension/locales/fr.json @@ -1,7 +1,6 @@ { "LANG_CODE": "fr", "HTML_CLASS": "lang-fr", - "APP_TITLE": "KoalaSync", "TAB_ROOM": "Salon", "TAB_ROOM_TOOLTIP": "Paramètres de salon et connexion", @@ -11,7 +10,6 @@ "TAB_SETTINGS_TOOLTIP": "Préférences de l'extension", "TAB_STATUS": "Statut", "TAB_STATUS_TOOLTIP": "Diagnostics avancés & Journaux", - "BTN_CREATE_ROOM": "+ Créer un nouveau salon", "MANUAL_CONNECT_HEADER": "Connexion manuelle / Avancé", "LABEL_SERVER": "Serveur", @@ -35,7 +33,6 @@ "BTN_REFRESH": "ACTUALISER", "BTN_REFRESH_TOOLTIP": "Actualiser la liste des salons publics", "PUBLIC_ROOMS_REFRESHING": "Actualisation...", - "LABEL_ACTIVE_ROOM": "Salon actif", "LABEL_ACTIVE_ROOM_TOOLTIP": "Le salon auquel vous êtes actuellement connecté", "ACTIVE_ROOM_NONE": "AUCUN", @@ -46,7 +43,6 @@ "LABEL_PEERS_IN_ROOM_TOOLTIP": "Autres utilisateurs connectés à ce salon", "NO_PEERS_CONNECTED": "Aucun membre connecté", "BTN_LEAVE_ROOM": "Quitter le salon", - "LABEL_SELECT_VIDEO": "Choisir une vidéo", "LABEL_SELECT_VIDEO_TOOLTIP": "Choisissez l'onglet du navigateur contenant la vidéo à synchroniser", "OPTION_SELECT_TAB": "-- Choisir un onglet --", @@ -74,7 +70,6 @@ "LOBBY_CONNECT_FIRST_DESC": "Vous devez rejoindre un salon via un lien d'invitation ou en créer un nouveau pour synchroniser des vidéos.", "BTN_CREATE_ROOM_ALT": "Créer un nouveau salon", "BTN_CREATE_ROOM_ALT_TOOLTIP": "Créer un salon aléatoire et le rejoindre", - "LABEL_USERNAME": "Votre pseudo", "LABEL_USERNAME_TOOLTIP": "Votre pseudo permet aux autres de vous identifier.", "PLACEHOLDER_USERNAME": "Koala anonyme", @@ -93,7 +88,6 @@ "BTN_REGEN_ID": "Régénérer l'identifiant", "BTN_REGEN_ID_TOOLTIP": "Régénérer votre identifiant interne et vous reconnecter", "REGEN_ID_DESC": "Utilisez cette option si vous rencontrez des erreurs de 'Double identité'.", - "LABEL_CONN_STATUS": "Statut de la connexion", "LABEL_CONN_STATUS_TOOLTIP": "Statut actuel de la connexion WebSocket", "CONN_STATUS_DISCONNECTED": "Déconnecté", @@ -112,7 +106,6 @@ "BTN_CLEAR": "EFFACER", "BTN_CLEAR_TOOLTIP": "Effacer la sortie des journaux", "LABEL_GITHUB": "Dépôt GitHub", - "BTN_ONBOARDING_SKIP": "Passer", "BTN_ONBOARDING_SKIP_TOOLTIP": "Passer le didacticiel", "BTN_ONBOARDING_NEXT": "Suivant", @@ -127,7 +120,6 @@ "ONBOARDING_4_TEXT": "Choisissez un pseudo sympa pour que vos amis sachent qui vous êtes.", "ONBOARDING_5_TITLE": "Vous êtes prêt !", "ONBOARDING_5_TEXT": "Il est temps de préparer le pop-corn. Bon visionnage !", - "ERR_CONN_TIMEOUT": "Délai de connexion dépassé. Veuillez réessayer.", "ERR_INVALID_SERVER_URL": "Format d'adresse de serveur non valide.", "ERR_IDENTITY_NOT_LOADED": "Identifiant non encore chargé. Veuillez patienter et réessayer.", @@ -142,13 +134,11 @@ "TOAST_PEER_JOINED": "{name} a rejoint le salon", "TOAST_PEER_LEFT": "{name} a quitté le salon", "TOAST_PEER_ACTION": "{name} a {action}", - "STATUS_CONNECTED": "Connecté", "STATUS_RECONNECTING": "Reconnexion...", "STATUS_CONNECTING": "Connexion...", "STATUS_FAILED": "Échec", "STATUS_DISCONNECTED": "Déconnecté", - "BTN_STATE_JOINING": "🚀 Connexion...", "BTN_STATE_RECONNECTING": "🔄 Reconnexion...", "BTN_STATE_PLAYING": "▶ Lecture...", @@ -156,16 +146,13 @@ "BTN_STATE_SYNCING_GROUP": "Synchro au groupe ({time})...", "BTN_STATE_SYNCING": "Synchronisation...", "BTN_STATE_SYNCED": "✅ Synchronisé !", - "NOTIF_PLAY": "lancé la lecture", "NOTIF_PAUSE": "mis la lecture en pause", "NOTIF_SEEK": "déplacé la position dans la vidéo", "NOTIF_FORCE_PREPARE": "lancé une synchronisation forcée", "NOTIF_FORCE_EXECUTE": "synchronisé tout le monde", - "DEBUG_NO_TAB": "Aucun onglet cible sélectionné.", "DEBUG_COMM_FAIL": "Impossible de communiquer avec l'onglet vidéo.", - "EMPTY_PEERS_TITLE": "Aucun membre pour l'instant", "EMPTY_PEERS_HINT": "Partagez votre lien d'invitation pour commencer", "EMPTY_HISTORY_TITLE": "Aucune activité pour l'instant", @@ -173,5 +160,21 @@ "EMPTY_LOGS_TITLE": "Aucun journal", "EMPTY_LOGS_HINT": "Les événements de connexion s'afficheront ici", "EMPTY_ROOMS_TITLE": "Aucun salon actif", - "EMPTY_ROOMS_HINT": "Créez un salon ou actualisez pour trouver des salons publics" + "EMPTY_ROOMS_HINT": "Créez un salon ou actualisez pour trouver des salons publics", + "LABEL_YOU": "Vous", + "ONBOARDING_DONE": "Terminé !", + "LABEL_LOBBY_PEER_READY": "Prêt", + "LABEL_LOBBY_PEER_LOADING": "Chargement...", + "LABEL_PASSWORD_PROTECTED": "Protégé par mot de passe", + "LABEL_PEERS_COUNT": "{count} membres", + "LABEL_CUSTOM_SERVER": "Serveur personnalisé", + "BTN_STATE_CREATING": "🚀 Création de la salle...", + "NOTIF_LOBBY_CANCEL_TITLE": "KoalaSync — Échec de la synchronisation de l'épisode", + "NOTIF_LOBBY_CANCEL_MSG": "Synchronisation automatique annulée : {reason}. Vous devrez peut-être synchroniser manuellement.", + "LOBBY_CANCEL_TIMEOUT": "Délai d'attente dépassé", + "LOBBY_CANCEL_TIMEOUT_RECOVERED": "Délai dépassé (récupéré)", + "LOBBY_CANCEL_PEERS_LEFT": "Tous les autres membres sont partis", + "LOBBY_CANCEL_TIMEOUT_PEERS_LOAD": "Délai dépassé — tous les membres n'ont pas chargé l'épisode", + "LOBBY_CANCEL_USER": "Annulé par l'utilisateur", + "NOTIF_ERROR_TITLE": "Erreur KoalaSync" } diff --git a/extension/locales/pt-BR.json b/extension/locales/pt-BR.json index 17c3b6e..b5d3618 100644 --- a/extension/locales/pt-BR.json +++ b/extension/locales/pt-BR.json @@ -1,7 +1,6 @@ { "LANG_CODE": "pt-BR", "HTML_CLASS": "lang-pt-br", - "APP_TITLE": "KoalaSync", "TAB_ROOM": "Sala", "TAB_ROOM_TOOLTIP": "Configurações da sala e conexão", @@ -11,7 +10,6 @@ "TAB_SETTINGS_TOOLTIP": "Preferências da extensão", "TAB_STATUS": "Status", "TAB_STATUS_TOOLTIP": "Diagnósticos avançados e logs", - "BTN_CREATE_ROOM": "+ Criar nova sala", "MANUAL_CONNECT_HEADER": "Conexão manual / Avançado", "LABEL_SERVER": "Servidor", @@ -35,7 +33,6 @@ "BTN_REFRESH": "ATUALIZAR", "BTN_REFRESH_TOOLTIP": "Atualizar a lista de salas públicas", "PUBLIC_ROOMS_REFRESHING": "Atualizando...", - "LABEL_ACTIVE_ROOM": "Sala ativa", "LABEL_ACTIVE_ROOM_TOOLTIP": "A sala à qual você está conectado no momento", "ACTIVE_ROOM_NONE": "NENHUMA", @@ -46,7 +43,6 @@ "LABEL_PEERS_IN_ROOM_TOOLTIP": "Outros usuários conectados atualmente a esta sala", "NO_PEERS_CONNECTED": "Sem participantes conectados", "BTN_LEAVE_ROOM": "Sair da sala", - "LABEL_SELECT_VIDEO": "Selecionar vídeo", "LABEL_SELECT_VIDEO_TOOLTIP": "Escolha a aba do navegador contendo o vídeo a ser sincronizado", "OPTION_SELECT_TAB": "-- Selecione uma aba --", @@ -74,7 +70,6 @@ "LOBBY_CONNECT_FIRST_DESC": "Você precisa entrar em uma sala através de um link de convite ou criar uma nova para sincronizar vídeos.", "BTN_CREATE_ROOM_ALT": "Criar nova sala", "BTN_CREATE_ROOM_ALT_TOOLTIP": "Criar uma nova sala aleatória e entrar", - "LABEL_USERNAME": "Seu nome de usuário", "LABEL_USERNAME_TOOLTIP": "O nome de usuário ajuda os outros a identificá-lo.", "PLACEHOLDER_USERNAME": "Coala anônimo", @@ -93,7 +88,6 @@ "BTN_REGEN_ID": "Regenerar ID de participante", "BTN_REGEN_ID_TOOLTIP": "Regenerar seu ID interno e conectar novamente", "REGEN_ID_DESC": "Use esta opção se notar erros de 'Identidade duplicada'.", - "LABEL_CONN_STATUS": "Status da conexão", "LABEL_CONN_STATUS_TOOLTIP": "Status atual da conexão WebSocket", "CONN_STATUS_DISCONNECTED": "Desconectado", @@ -112,7 +106,6 @@ "BTN_CLEAR": "LIMPAR", "BTN_CLEAR_TOOLTIP": "Limpar a saída dos logs", "LABEL_GITHUB": "Repositório GitHub", - "BTN_ONBOARDING_SKIP": "Pular", "BTN_ONBOARDING_SKIP_TOOLTIP": "Pular o tutorial", "BTN_ONBOARDING_NEXT": "Próximo", @@ -127,7 +120,6 @@ "ONBOARDING_4_TEXT": "Escolha um nome de usuário divertido para que seus amigos saibam quem você é.", "ONBOARDING_5_TITLE": "Tudo pronto!", "ONBOARDING_5_TEXT": "Hora de pegar a pipoca. Divirta-se assistindo com seus amigos!", - "ERR_CONN_TIMEOUT": "Tempo limite de conexão esgotado. Tente novamente.", "ERR_INVALID_SERVER_URL": "Formato de URL do servidor inválido.", "ERR_IDENTITY_NOT_LOADED": "Identidade não carregada ainda. Aguarde um momento e tente novamente.", @@ -142,13 +134,11 @@ "TOAST_PEER_JOINED": "{name} entrou na sala", "TOAST_PEER_LEFT": "{name} saiu da sala", "TOAST_PEER_ACTION": "{name} {action}", - "STATUS_CONNECTED": "Conectado", "STATUS_RECONNECTING": "Reconectando...", "STATUS_CONNECTING": "Conectando...", "STATUS_FAILED": "Falhou", "STATUS_DISCONNECTED": "Desconectado", - "BTN_STATE_JOINING": "🚀 Entrando...", "BTN_STATE_RECONNECTING": "🔄 Reconectando...", "BTN_STATE_PLAYING": "▶ Reproduzindo...", @@ -156,16 +146,13 @@ "BTN_STATE_SYNCING_GROUP": "Sincronizando com o grupo ({time})...", "BTN_STATE_SYNCING": "Sincronizando...", "BTN_STATE_SYNCED": "✅ Sincronizado!", - "NOTIF_PLAY": "iniciou a reprodução", "NOTIF_PAUSE": "pausou a reprodução", "NOTIF_SEEK": "mudou a posição do vídeo", "NOTIF_FORCE_PREPARE": "iniciou uma sincronização forçada", "NOTIF_FORCE_EXECUTE": "sincronizou todos", - "DEBUG_NO_TAB": "Nenhuma aba alvo selecionada.", "DEBUG_COMM_FAIL": "Não foi possível comunicar com o vídeo da aba.", - "EMPTY_PEERS_TITLE": "Nenhum participante ainda", "EMPTY_PEERS_HINT": "Compartilhe seu link de convite para começar", "EMPTY_HISTORY_TITLE": "Sem atividade ainda", @@ -173,5 +160,21 @@ "EMPTY_LOGS_TITLE": "Sem logs", "EMPTY_LOGS_HINT": "Os eventos de conexão aparecerão aqui", "EMPTY_ROOMS_TITLE": "Sem salas ativas", - "EMPTY_ROOMS_HINT": "Crie uma sala ou atualize para buscar salas públicas" + "EMPTY_ROOMS_HINT": "Crie uma sala ou atualize para buscar salas públicas", + "LABEL_YOU": "Você", + "ONBOARDING_DONE": "Concluído!", + "LABEL_LOBBY_PEER_READY": "Pronto", + "LABEL_LOBBY_PEER_LOADING": "Carregando...", + "LABEL_PASSWORD_PROTECTED": "Protegido por senha", + "LABEL_PEERS_COUNT": "{count} participantes", + "LABEL_CUSTOM_SERVER": "Servidor personalizado", + "BTN_STATE_CREATING": "🚀 Criando sala...", + "NOTIF_LOBBY_CANCEL_TITLE": "KoalaSync — Falha na sincronização do episódio", + "NOTIF_LOBBY_CANCEL_MSG": "Sincronização automática cancelada: {reason}. Pode ser necessário sincronizar manualmente.", + "LOBBY_CANCEL_TIMEOUT": "Tempo limite esgotado", + "LOBBY_CANCEL_TIMEOUT_RECOVERED": "Tempo limite esgotado (recuperado)", + "LOBBY_CANCEL_PEERS_LEFT": "Todos os outros participantes saíram", + "LOBBY_CANCEL_TIMEOUT_PEERS_LOAD": "Tempo limite esgotado — nem todos os participantes carregaram o episódio", + "LOBBY_CANCEL_USER": "Cancelado pelo usuário", + "NOTIF_ERROR_TITLE": "Erro do KoalaSync" } diff --git a/extension/locales/ru.json b/extension/locales/ru.json index 514f6f7..cbca229 100644 --- a/extension/locales/ru.json +++ b/extension/locales/ru.json @@ -1,7 +1,6 @@ { "LANG_CODE": "ru", "HTML_CLASS": "lang-ru", - "APP_TITLE": "KoalaSync", "TAB_ROOM": "Комната", "TAB_ROOM_TOOLTIP": "Настройки комнаты и подключение", @@ -11,7 +10,6 @@ "TAB_SETTINGS_TOOLTIP": "Настройки расширения", "TAB_STATUS": "Статус", "TAB_STATUS_TOOLTIP": "Дополнительная диагностика и журналы", - "BTN_CREATE_ROOM": "+ Создать комнату", "MANUAL_CONNECT_HEADER": "Ручное подключение / Дополнительно", "LABEL_SERVER": "Сервер", @@ -35,7 +33,6 @@ "BTN_REFRESH": "ОБНОВИТЬ", "BTN_REFRESH_TOOLTIP": "Обновить список публичных комнат", "PUBLIC_ROOMS_REFRESHING": "Обновление...", - "LABEL_ACTIVE_ROOM": "Активная комната", "LABEL_ACTIVE_ROOM_TOOLTIP": "Комната, к которой вы сейчас подключены", "ACTIVE_ROOM_NONE": "НЕТ", @@ -46,7 +43,6 @@ "LABEL_PEERS_IN_ROOM_TOOLTIP": "Другие пользователи, подключенные к этой комнате", "NO_PEERS_CONNECTED": "Нет подключенных участников", "BTN_LEAVE_ROOM": "Выйти из комнаты", - "LABEL_SELECT_VIDEO": "Выбрать видео", "LABEL_SELECT_VIDEO_TOOLTIP": "Выберите вкладку браузера, содержащую видео для синхронизации", "OPTION_SELECT_TAB": "-- Выберите вкладку --", @@ -74,7 +70,6 @@ "LOBBY_CONNECT_FIRST_DESC": "Вам необходимо войти в комнату по ссылке-приглашению или создать новую, чтобы синхронизировать видео.", "BTN_CREATE_ROOM_ALT": "Создать новую комнату", "BTN_CREATE_ROOM_ALT_TOOLTIP": "Создать новую случайную комнату и войти", - "LABEL_USERNAME": "Ваше имя пользователя", "LABEL_USERNAME_TOOLTIP": "Имя пользователя помогает другим узнать вас.", "PLACEHOLDER_USERNAME": "Анонимный Коала", @@ -93,7 +88,6 @@ "BTN_REGEN_ID": "Сбросить Peer ID", "BTN_REGEN_ID_TOOLTIP": "Сбросить ваш внутренний идентификатор и переподключиться", "REGEN_ID_DESC": "Используйте при появлении ошибок дублирования идентификации.", - "LABEL_CONN_STATUS": "Статус подключения", "LABEL_CONN_STATUS_TOOLTIP": "Текущий статус WebSocket-соединения с сервером", "CONN_STATUS_DISCONNECTED": "Отключено", @@ -112,7 +106,6 @@ "BTN_CLEAR": "ОЧИСТИТЬ", "BTN_CLEAR_TOOLTIP": "Очистить вывод логов", "LABEL_GITHUB": "Репозиторий GitHub", - "BTN_ONBOARDING_SKIP": "Пропустить", "BTN_ONBOARDING_SKIP_TOOLTIP": "Пропустить руководство", "BTN_ONBOARDING_NEXT": "Далее", @@ -127,7 +120,6 @@ "ONBOARDING_4_TEXT": "Введите имя пользователя, чтобы друзья знали, кто совершает действия.", "ONBOARDING_5_TITLE": "Всё готово!", "ONBOARDING_5_TEXT": "Время готовить попкорн. Приятного совместного просмотра!", - "ERR_CONN_TIMEOUT": "Время ожидания подключения истекло. Пожалуйста, попробуйте снова.", "ERR_INVALID_SERVER_URL": "Неверный формат URL-адреса сервера.", "ERR_IDENTITY_NOT_LOADED": "Идентификатор еще не загружен. Подождите немного и повторите попытку.", @@ -142,13 +134,11 @@ "TOAST_PEER_JOINED": "{name} вошел в комнату", "TOAST_PEER_LEFT": "{name} вышел из комнаты", "TOAST_PEER_ACTION": "{name}: {action}", - "STATUS_CONNECTED": "Подключено", "STATUS_RECONNECTING": "Переподключение...", "STATUS_CONNECTING": "Подключение...", "STATUS_FAILED": "Ошибка", "STATUS_DISCONNECTED": "Отключено", - "BTN_STATE_JOINING": "🚀 Вход...", "BTN_STATE_RECONNECTING": "🔄 Переподключение...", "BTN_STATE_PLAYING": "▶ Запуск...", @@ -156,16 +146,13 @@ "BTN_STATE_SYNCING_GROUP": "Синхронизация по группе ({time})...", "BTN_STATE_SYNCING": "Синхронизация...", "BTN_STATE_SYNCED": "✅ Синхронно!", - "NOTIF_PLAY": "запустил воспроизведение", "NOTIF_PAUSE": "приостановил воспроизведение", "NOTIF_SEEK": "перемотал видео", "NOTIF_FORCE_PREPARE": "запустил принудительный синхрон", "NOTIF_FORCE_EXECUTE": "синхронизировал воспроизведение у всех", - "DEBUG_NO_TAB": "Целевая вкладка не выбрана.", "DEBUG_COMM_FAIL": "Не удалось связаться с плеером на вкладке.", - "EMPTY_PEERS_TITLE": "Участников пока нет", "EMPTY_PEERS_HINT": "Поделитесь ссылкой-приглашением, чтобы начать", "EMPTY_HISTORY_TITLE": "История действий пуста", @@ -173,5 +160,21 @@ "EMPTY_LOGS_TITLE": "Журнал пуст", "EMPTY_LOGS_HINT": "События подключения будут отображаться здесь", "EMPTY_ROOMS_TITLE": "Нет активных комнат", - "EMPTY_ROOMS_HINT": "Создайте комнату или обновите список, чтобы найти публичные" + "EMPTY_ROOMS_HINT": "Создайте комнату или обновите список, чтобы найти публичные", + "LABEL_YOU": "Вы", + "ONBOARDING_DONE": "Готово!", + "LABEL_LOBBY_PEER_READY": "Готов", + "LABEL_LOBBY_PEER_LOADING": "Загрузка...", + "LABEL_PASSWORD_PROTECTED": "Защищено паролем", + "LABEL_PEERS_COUNT": "{count} участников", + "LABEL_CUSTOM_SERVER": "Свой сервер", + "BTN_STATE_CREATING": "🚀 Создание комнаты...", + "NOTIF_LOBBY_CANCEL_TITLE": "KoalaSync — Ошибка синхронизации серии", + "NOTIF_LOBBY_CANCEL_MSG": "Автосинхронизация отменена: {reason}. Возможно, вам придется выполнить синхронизацию вручную.", + "LOBBY_CANCEL_TIMEOUT": "Время ожидания истекло", + "LOBBY_CANCEL_TIMEOUT_RECOVERED": "Время ожидания истекло (восстановлено)", + "LOBBY_CANCEL_PEERS_LEFT": "Все остальные участники вышли", + "LOBBY_CANCEL_TIMEOUT_PEERS_LOAD": "Время ожидания истекло — не все участники загрузили серию", + "LOBBY_CANCEL_USER": "Отменено пользователем", + "NOTIF_ERROR_TITLE": "Ошибка KoalaSync" } diff --git a/extension/popup.js b/extension/popup.js index a4f3a7e..11f6f16 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -190,7 +190,7 @@ function updateUI(roomId, password, useCustomServer = false, serverUrl = '') { if (elements.activeRoomId) elements.activeRoomId.textContent = roomId; if (elements.activeServer) { - elements.activeServer.textContent = useCustomServer ? (serverUrl || 'Custom Server') : 'Official Server'; + elements.activeServer.textContent = useCustomServer ? (serverUrl || getMessage('LABEL_CUSTOM_SERVER')) : getMessage('ACTIVE_SERVER_OFFICIAL'); elements.activeServer.title = useCustomServer ? (serverUrl || '') : 'syncserver.koalastuff.net'; } } else { @@ -741,7 +741,7 @@ function updateHistory(history) { const senderSpan = document.createElement('span'); if (item.senderId === 'You') { senderSpan.style.color = 'var(--accent)'; - senderSpan.textContent = 'You'; + senderSpan.textContent = getMessage('LABEL_YOU') || 'You'; } else { senderSpan.textContent = item.senderId; } @@ -787,14 +787,14 @@ function updateRoomList(rooms) { if (r.hasPassword) { const lock = document.createElement('span'); - lock.title = 'Password Protected'; + lock.title = getMessage('LABEL_PASSWORD_PROTECTED'); lock.textContent = '🔒'; leftSide.appendChild(lock); } const peerCount = document.createElement('span'); peerCount.style.cssText = 'font-size:11px; color:var(--accent)'; - peerCount.textContent = `${parseInt(r.peerCount)} peers`; + peerCount.textContent = getMessage('LABEL_PEERS_COUNT', { count: parseInt(r.peerCount) }); item.appendChild(leftSide); item.appendChild(peerCount); @@ -979,14 +979,14 @@ elements.joinBtn.addEventListener('click', async () => { const isCreating = !roomIdInput; elements.joinBtn.disabled = true; - elements.joinBtn.textContent = isCreating ? 'Creating Room...' : 'Joining...'; + elements.joinBtn.textContent = isCreating ? getMessage('BTN_STATE_CREATING') : getMessage('BTN_STATE_JOINING'); if (joinBtnTimeout) clearTimeout(joinBtnTimeout); joinBtnTimeout = setTimeout(() => { elements.joinBtn.disabled = false; - elements.joinBtn.textContent = 'Join Room'; + elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM'); joinBtnTimeout = null; - showError('Connection timed out. Please try again.'); + showError(getMessage('ERR_CONN_TIMEOUT')); }, 15000); const serverUrl = elements.serverUrl.value.trim(); @@ -998,9 +998,9 @@ elements.joinBtn.addEventListener('click', async () => { const urlToCheck = serverUrl.includes('://') ? serverUrl : 'ws://' + serverUrl; new URL(urlToCheck); } catch (_e) { - showError('Invalid Server URL format.'); + showError(getMessage('ERR_INVALID_SERVER_URL')); elements.joinBtn.disabled = false; - elements.joinBtn.textContent = 'Join Room'; + elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM'); return; } } @@ -1054,8 +1054,8 @@ if (syncTabCreateRoomBtn) syncTabCreateRoomBtn.addEventListener('click', () => { elements.refreshRooms.addEventListener('click', () => { elements.publicRooms.replaceChildren(); const el = document.createElement('div'); - el.style.cssText = 'text-align:center; padding: 10px; color:var(--text-muted);'; - el.textContent = 'Refreshing...'; + el.style.cssText = 'text-align:center; color: var(--text-muted); font-size: 11px; padding: 10px;'; + el.textContent = getMessage('PUBLIC_ROOMS_REFRESHING'); elements.publicRooms.appendChild(el); chrome.runtime.sendMessage({ type: 'GET_ROOM_LIST' }); }); @@ -1082,7 +1082,7 @@ elements.forceSyncBtn.addEventListener('click', async () => { if (mode === 'jump-to-others') { if (!localPeerId) { - showError('Identity not yet loaded. Wait a moment and try again.'); + showError(getMessage('ERR_IDENTITY_NOT_LOADED')); return; } const peers = status.peers || []; @@ -1091,7 +1091,7 @@ elements.forceSyncBtn.addEventListener('click', async () => { .map(p => p.currentTime); if (otherTimes.length === 0) { - showError('No other peers with a known time. Switch to "Jump to Me".'); + showError(getMessage('ERR_NO_PEERS_TIME')); return; } @@ -1102,7 +1102,7 @@ elements.forceSyncBtn.addEventListener('click', async () => { const originalText = elements.forceSyncBtn.textContent; elements.forceSyncBtn.disabled = true; - elements.forceSyncBtn.textContent = mode === 'jump-to-others' ? `Syncing to group (${formatTime(targetTime)})...` : 'Syncing...'; + elements.forceSyncBtn.textContent = mode === 'jump-to-others' ? getMessage('BTN_STATE_SYNCING_GROUP', { time: formatTime(targetTime) }) : getMessage('BTN_STATE_SYNCING'); forceSyncDone = false; const peerCount = (status.peers || []).filter(p => (typeof p === 'object' ? p.peerId : p) !== localPeerId).length; const syncTimeoutMs = peerCount === 0 ? 3000 : 12000; @@ -1139,7 +1139,7 @@ elements.forceSyncBtn.addEventListener('click', async () => { }); }, 500); }).catch(() => { - showError('Could not connect to video tab.'); + showError(getMessage('ERR_NO_VIDEO_TAB')); forceSyncDone = true; elements.forceSyncBtn.disabled = false; elements.forceSyncBtn.textContent = originalText; @@ -1155,10 +1155,10 @@ elements.forceSyncBtn.addEventListener('click', async () => { elements.playBtn.addEventListener('click', () => { if (!elements.targetTab.value) { - showToast('Please select a video first!', 'warning'); + showToast(getMessage('ERR_SELECT_VIDEO'), 'warning'); return; } - elements.playBtn.textContent = '▶ Playing...'; + elements.playBtn.textContent = getMessage('BTN_STATE_PLAYING'); elements.playBtn.disabled = true; chrome.runtime.sendMessage({ type: 'CONTENT_EVENT', @@ -1166,14 +1166,14 @@ elements.playBtn.addEventListener('click', () => { payload: {} }, (response) => { if (response && response.status === 'ok_solo') { - elements.playBtn.textContent = '▶ Play'; + elements.playBtn.textContent = getMessage('BTN_PLAY'); elements.playBtn.disabled = false; } }); // Safety reset: restore button after 2.5s in case no peers respond setTimeout(() => { if (elements.playBtn.disabled) { - elements.playBtn.textContent = '▶ Play'; + elements.playBtn.textContent = getMessage('BTN_PLAY'); elements.playBtn.disabled = false; } }, 2500); @@ -1181,10 +1181,10 @@ elements.playBtn.addEventListener('click', () => { elements.pauseBtn.addEventListener('click', () => { if (!elements.targetTab.value) { - showToast('Please select a video first!', 'warning'); + showToast(getMessage('ERR_SELECT_VIDEO'), 'warning'); return; } - elements.pauseBtn.textContent = '⏸ Pausing...'; + elements.pauseBtn.textContent = getMessage('BTN_STATE_PAUSING'); elements.pauseBtn.disabled = true; chrome.runtime.sendMessage({ type: 'CONTENT_EVENT', @@ -1192,14 +1192,14 @@ elements.pauseBtn.addEventListener('click', () => { payload: {} }, (response) => { if (response && response.status === 'ok_solo') { - elements.pauseBtn.textContent = '⏸ Pause'; + elements.pauseBtn.textContent = getMessage('BTN_PAUSE'); elements.pauseBtn.disabled = false; } }); // Safety reset: restore button after 2.5s in case no peers respond setTimeout(() => { if (elements.pauseBtn.disabled) { - elements.pauseBtn.textContent = '⏸ Pause'; + elements.pauseBtn.textContent = getMessage('BTN_PAUSE'); elements.pauseBtn.disabled = false; } }, 2500); @@ -1288,14 +1288,17 @@ chrome.runtime.onMessage.addListener((msg) => { const state = msg.state; if (state && state.senderId && state.senderId !== 'You') { const actionNames = { - 'play': getMessage('BTN_PLAY'), - 'pause': getMessage('BTN_PAUSE'), + 'play': getMessage('NOTIF_PLAY'), + 'pause': getMessage('NOTIF_PAUSE'), 'seek': getMessage('NOTIF_SEEK'), - 'force_sync_prepare': getMessage('BTN_STATE_SYNCING'), - 'force_sync_execute': getMessage('BTN_STATE_SYNCED') + 'force_sync_prepare': getMessage('NOTIF_FORCE_PREPARE'), + 'force_sync_execute': getMessage('NOTIF_FORCE_EXECUTE') }; const action = actionNames[state.action] || state.action; - showToast(getMessage('TOAST_PEER_ACTION', { name: state.senderId, action }), 'info', 2000); + let displayName = state.senderId; + const peer = lastKnownPeers.find(p => (p.peerId || p) === state.senderId); + if (peer && peer.username) displayName = peer.username; + showToast(getMessage('TOAST_PEER_ACTION', { name: displayName, action }), 'info', 2000); } if (state && (state.action === 'play' || state.action === 'pause')) { @@ -1388,10 +1391,10 @@ elements.copyLogs.addEventListener('click', () => { const text = logs.map(l => `[${l.timestamp}] [${l.type}] ${l.message}`).join('\n'); navigator.clipboard.writeText(text).then(() => { const original = elements.copyLogs.textContent; - elements.copyLogs.textContent = 'Copied!'; + elements.copyLogs.textContent = getMessage('TOAST_LOGS_COPIED'); setTimeout(() => elements.copyLogs.textContent = original, 2000); }).catch(() => { - showToast('Failed to copy to clipboard', 'error'); + showToast(getMessage('TOAST_COPY_FAILED'), 'error'); }); }); }); @@ -1403,14 +1406,14 @@ function refreshDebugInfo() { chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => { if (!res || !res.targetTabId) { - if (elements.videoDebug) elements.videoDebug.textContent = 'No target tab selected.'; + if (elements.videoDebug) elements.videoDebug.textContent = getMessage('DEBUG_NO_TAB'); return; } // Request direct state from the content script via background chrome.runtime.sendMessage({ type: 'GET_VIDEO_STATE', tabId: res.targetTabId }, (state) => { if (!state || state.error) { - if (elements.videoDebug) elements.videoDebug.textContent = 'Could not communicate with tab video.'; + if (elements.videoDebug) elements.videoDebug.textContent = getMessage('DEBUG_COMM_FAIL'); return; } @@ -1502,7 +1505,7 @@ function updateLobbyUI(lobby, peers) { } elements.episodeLobbyCard.style.display = 'block'; - elements.lobbyTitle.textContent = `\u{1F3AC} Waiting for: "${lobby.expectedTitle}"`; + elements.lobbyTitle.textContent = getMessage('LOBBY_WAITING_FOR', { title: lobby.expectedTitle }); // Build peer readiness list const readySet = new Set(lobby.readyPeers || []); @@ -1515,7 +1518,7 @@ function updateLobbyUI(lobby, peers) { const avatar = getAvatarForName(pName); const isReady = readySet.has(pId); const icon = isReady ? '\u2705' : '\u23f3'; - const label = isReady ? 'Ready' : 'Loading...'; + const label = isReady ? getMessage('LABEL_LOBBY_PEER_READY') : getMessage('LABEL_LOBBY_PEER_LOADING'); peerLines.push(`${icon} ${avatar} ${pName} \u2014 ${label}`); }); } @@ -1523,7 +1526,7 @@ function updateLobbyUI(lobby, peers) { if (peerLines.length > 0 && elements.lobbyPeerStatus) { elements.lobbyPeerStatus.textContent = peerLines.join(' | '); } else if (elements.lobbyPeerStatus) { - elements.lobbyPeerStatus.textContent = 'Waiting for peers...'; + elements.lobbyPeerStatus.textContent = getMessage('LOBBY_WAITING_PEERS'); } // Show elapsed time