diff --git a/priv/i18n/locales/es.json b/priv/i18n/locales/es.json index c1d5c10..710e2b1 100644 --- a/priv/i18n/locales/es.json +++ b/priv/i18n/locales/es.json @@ -44,5 +44,122 @@ "render.taxonomy.ariaLabel": "Taxonomía", "render.video.vimeoTitle": "Vídeo de Vimeo", "render.video.youtubeTitle": "Vídeo de YouTube", - "sidebar.chat.yesterday": "Ayer" + "sidebar.chat.yesterday": "Ayer", + "%{count} media": "%{count} medios", + "%{count} posts": "%{count} publicaciones", + "2 langs": "2 idiomas", + "AI Assistant": "Asistente de IA", + "Across draft, published, and archive": "Entre borradores, publicaciones y archivo", + "Activated %{name}": "%{name} activado", + "Archived": "Archivado", + "Archived Jan 12, 2026": "Archivado el 12 ene 2026", + "Assistant": "Asistente", + "Automatic AI actions stay gated by airplane mode.": "Las acciones automáticas de IA siguen bloqueadas por el modo avión.", + "Automation can boot the shell in a separate process and capture screenshots": "La automatización puede iniciar el shell en un proceso separado y capturar pantallas", + "Blog": "Blog", + "Calendar regeneration is not wired yet, but the base shell now surfaces the command and keeps the Output tab selectable.": "La regeneración del calendario aún no está conectada, pero el shell base ahora muestra el comando y mantiene seleccionable la pestaña Salida.", + "Chat": "Chat", + "Close %{title}": "Cerrar %{title}", + "Close tab": "Cerrar pestaña", + "Command completed": "Comando completado", + "Command failed": "El comando falló", + "Command failed with HTTP %{status}": "El comando falló con HTTP %{status}", + "Create Project": "Crear proyecto", + "Dashboard": "Panel", + "Desktop Runtime": "Entorno de escritorio", + "Desktop workbench content routed through the Elixir shell.": "El contenido del área de trabajo de escritorio se enruta a través del shell de Elixir.", + "Desktop workbench shell wired through Elixir": "Shell del área de trabajo de escritorio conectado mediante Elixir", + "Diff Reports": "Informes de diff", + "Diffs": "Diferencias", + "Documentation": "Documentación", + "Drafts": "Borradores", + "Drafts, published entries, and archive history": "Borradores, entradas publicadas e historial de archivo", + "Edit": "Editar", + "Extra": "Extra", + "Extra Pages": "Páginas extra", + "File": "Archivo", + "Filesystem Sync": "Sincronización del sistema de archivos", + "Fill Missing Translations": "Completar traducciones faltantes", + "Find Duplicates": "Buscar duplicados", + "Git": "Git", + "Git Log": "Registro Git", + "Help": "Ayuda", + "Idle": "Inactivo", + "Images and documents indexed": "Imágenes y documentos indexados", + "Import": "Importar", + "Launch plan": "Plan de lanzamiento", + "Main Language": "Idioma principal", + "Media": "Medios", + "Menu": "Menú", + "Metadata": "Metadatos", + "Metadata Diff": "Diff de metadatos", + "Metadata flush, diffing, and rebuild hooks still need editor wiring.": "El guardado de metadatos, el diff y los hooks de reconstrucción todavía necesitan la conexión del editor.", + "Missing": "Faltante", + "Missing Pages": "Páginas faltantes", + "Missing Translations": "Traducciones faltantes", + "Mode": "Modo", + "Native menu groups mirror the old application shell": "Los grupos de menús nativos reflejan el antiguo shell de la aplicación", + "New Project": "Nuevo proyecto", + "New project name": "Nombre del nuevo proyecto", + "No active background tasks": "No hay tareas activas en segundo plano", + "No background tasks running": "No hay tareas en segundo plano en ejecución", + "No items": "No hay elementos", + "No missing pages": "No faltan páginas", + "No orphan translation files": "No hay archivos de traducción huérfanos", + "No shell output yet": "Aún no hay salida del shell", + "Offline": "Sin conexión", + "Offline Gate": "Bloqueo sin conexión", + "Open": "Abrir", + "Open Data Folder": "Abrir carpeta de datos", + "Open in Browser": "Abrir en el navegador", + "Opened URL": "URL abierta", + "Orphan Files": "Archivos huérfanos", + "Orphan Reports": "Informes de huérfanos", + "Orphans": "Huérfanos", + "Output": "Salida", + "Pages": "Páginas", + "Pairs": "Pares", + "Post": "Publicación", + "Posts": "Publicaciones", + "Preview": "Vista previa", + "Projects": "Proyectos", + "Published": "Publicado", + "Published Feb 10, 2026": "Publicado el 10 feb 2026", + "Queued": "En cola", + "Regenerate Calendar": "Regenerar calendario", + "Retrospective": "Retrospectiva", + "Roadmap": "Hoja de ruta", + "Running": "En ejecución", + "Script": "Script", + "Scripts": "Scripts", + "Select Project": "Seleccionar proyecto", + "Settings": "Configuración", + "Sidebar, tabs, panel, and assistant panes are inspectable DOM regions": "La barra lateral, las pestañas, el panel y el asistente son regiones DOM inspeccionables", + "Site Validation": "Validación del sitio", + "Source Control": "Control de código fuente", + "Stale": "Desactualizado", + "Stale Pages": "Páginas desactualizadas", + "Status": "Estado", + "Style": "Estilo", + "Switch project": "Cambiar proyecto", + "Tags": "Etiquetas", + "Tasks": "Tareas", + "Template": "Plantilla", + "Templates": "Plantillas", + "The app window is now served from the Elixir shell renderer.": "La ventana de la aplicación ahora se sirve desde el renderizador shell de Elixir.", + "The shared lower panel is available for tasks, output, git details, and editor-specific diagnostics.": "El panel inferior compartido está disponible para tareas, salida, detalles de Git y diagnósticos específicos del editor.", + "Toggle assistant": "Alternar asistente", + "Toggle offline mode": "Alternar modo sin conexión", + "Toggle panel": "Alternar panel", + "Toggle sidebar": "Alternar barra lateral", + "Translation fill is not wired yet, but the command is now routed into Output instead of being ignored.": "El completado de traducciones aún no está conectado, pero el comando ahora se enruta a Salida en lugar de ignorarse.", + "Translations": "Traducciones", + "UI": "UI", + "Updated today": "Actualizado hoy", + "Updated yesterday": "Actualizado ayer", + "Upload Site": "Subir sitio", + "View": "Ver", + "Welcome to bDS2": "Bienvenido a bDS2", + "Workbench Notes": "Notas del área de trabajo", + "Working tree integration is not wired yet in the shell, but the tab is selectable and ready for command output.": "La integración del árbol de trabajo aún no está conectada en el shell, pero la pestaña es seleccionable y está lista para la salida de comandos." } \ No newline at end of file diff --git a/priv/i18n/locales/fr.json b/priv/i18n/locales/fr.json index 44f8b43..d8824f8 100644 --- a/priv/i18n/locales/fr.json +++ b/priv/i18n/locales/fr.json @@ -44,5 +44,122 @@ "render.taxonomy.ariaLabel": "Taxonomie", "render.video.vimeoTitle": "Vidéo Vimeo", "render.video.youtubeTitle": "Vidéo YouTube", - "sidebar.chat.yesterday": "Hier" + "sidebar.chat.yesterday": "Hier", + "%{count} media": "%{count} médias", + "%{count} posts": "%{count} articles", + "2 langs": "2 langues", + "AI Assistant": "Assistant IA", + "Across draft, published, and archive": "Répartis entre brouillons, publications et archives", + "Activated %{name}": "%{name} activé", + "Archived": "Archivé", + "Archived Jan 12, 2026": "Archivé le 12 janv. 2026", + "Assistant": "Assistant", + "Automatic AI actions stay gated by airplane mode.": "Les actions IA automatiques restent bloquées par le mode avion.", + "Automation can boot the shell in a separate process and capture screenshots": "L’automatisation peut démarrer le shell dans un processus séparé et capturer des captures d’écran", + "Blog": "Blog", + "Calendar regeneration is not wired yet, but the base shell now surfaces the command and keeps the Output tab selectable.": "La régénération du calendrier n’est pas encore câblée, mais le shell de base expose maintenant la commande et garde l’onglet Sortie sélectionnable.", + "Chat": "Chat", + "Close %{title}": "Fermer %{title}", + "Close tab": "Fermer l’onglet", + "Command completed": "Commande terminée", + "Command failed": "La commande a échoué", + "Command failed with HTTP %{status}": "La commande a échoué avec HTTP %{status}", + "Create Project": "Créer un projet", + "Dashboard": "Tableau de bord", + "Desktop Runtime": "Exécution bureau", + "Desktop workbench content routed through the Elixir shell.": "Le contenu de l’atelier bureau est acheminé via le shell Elixir.", + "Desktop workbench shell wired through Elixir": "Shell d’atelier bureau câblé via Elixir", + "Diff Reports": "Rapports de diff", + "Diffs": "Différences", + "Documentation": "Documentation", + "Drafts": "Brouillons", + "Drafts, published entries, and archive history": "Brouillons, éléments publiés et historique d’archives", + "Edit": "Édition", + "Extra": "Supplémentaire", + "Extra Pages": "Pages supplémentaires", + "File": "Fichier", + "Filesystem Sync": "Synchronisation du système de fichiers", + "Fill Missing Translations": "Compléter les traductions manquantes", + "Find Duplicates": "Trouver les doublons", + "Git": "Git", + "Git Log": "Journal Git", + "Help": "Aide", + "Idle": "Inactif", + "Images and documents indexed": "Images et documents indexés", + "Import": "Importer", + "Launch plan": "Plan de lancement", + "Main Language": "Langue principale", + "Media": "Médias", + "Menu": "Menu", + "Metadata": "Métadonnées", + "Metadata Diff": "Diff des métadonnées", + "Metadata flush, diffing, and rebuild hooks still need editor wiring.": "L’écriture des métadonnées, le diff et les hooks de reconstruction ont encore besoin du câblage de l’éditeur.", + "Missing": "Manquant", + "Missing Pages": "Pages manquantes", + "Missing Translations": "Traductions manquantes", + "Mode": "Mode", + "Native menu groups mirror the old application shell": "Les groupes de menus natifs reflètent l’ancien shell de l’application", + "New Project": "Nouveau projet", + "New project name": "Nom du nouveau projet", + "No active background tasks": "Aucune tâche d’arrière-plan active", + "No background tasks running": "Aucune tâche d’arrière-plan en cours", + "No items": "Aucun élément", + "No missing pages": "Aucune page manquante", + "No orphan translation files": "Aucun fichier de traduction orphelin", + "No shell output yet": "Aucune sortie du shell pour l’instant", + "Offline": "Hors ligne", + "Offline Gate": "Verrou hors ligne", + "Open": "Ouvrir", + "Open Data Folder": "Ouvrir le dossier de données", + "Open in Browser": "Ouvrir dans le navigateur", + "Opened URL": "URL ouverte", + "Orphan Files": "Fichiers orphelins", + "Orphan Reports": "Rapports d’orphelins", + "Orphans": "Orphelins", + "Output": "Sortie", + "Pages": "Pages", + "Pairs": "Paires", + "Post": "Article", + "Posts": "Articles", + "Preview": "Aperçu", + "Projects": "Projets", + "Published": "Publié", + "Published Feb 10, 2026": "Publié le 10 févr. 2026", + "Queued": "En file", + "Regenerate Calendar": "Régénérer le calendrier", + "Retrospective": "Rétrospective", + "Roadmap": "Feuille de route", + "Running": "En cours", + "Script": "Script", + "Scripts": "Scripts", + "Select Project": "Sélectionner un projet", + "Settings": "Paramètres", + "Sidebar, tabs, panel, and assistant panes are inspectable DOM regions": "La barre latérale, les onglets, le panneau et l’assistant sont des régions DOM inspectables", + "Site Validation": "Validation du site", + "Source Control": "Contrôle de source", + "Stale": "Obsolète", + "Stale Pages": "Pages obsolètes", + "Status": "Statut", + "Style": "Style", + "Switch project": "Changer de projet", + "Tags": "Tags", + "Tasks": "Tâches", + "Template": "Modèle", + "Templates": "Modèles", + "The app window is now served from the Elixir shell renderer.": "La fenêtre de l’application est maintenant servie par le moteur de rendu shell Elixir.", + "The shared lower panel is available for tasks, output, git details, and editor-specific diagnostics.": "Le panneau inférieur partagé est disponible pour les tâches, la sortie, les détails Git et les diagnostics spécifiques à l’éditeur.", + "Toggle assistant": "Afficher ou masquer l’assistant", + "Toggle offline mode": "Basculer le mode hors ligne", + "Toggle panel": "Afficher ou masquer le panneau", + "Toggle sidebar": "Afficher ou masquer la barre latérale", + "Translation fill is not wired yet, but the command is now routed into Output instead of being ignored.": "Le remplissage des traductions n’est pas encore câblé, mais la commande est maintenant envoyée vers Sortie au lieu d’être ignorée.", + "Translations": "Traductions", + "UI": "UI", + "Updated today": "Mis à jour aujourd’hui", + "Updated yesterday": "Mis à jour hier", + "Upload Site": "Téléverser le site", + "View": "Affichage", + "Welcome to bDS2": "Bienvenue dans bDS2", + "Workbench Notes": "Notes d’atelier", + "Working tree integration is not wired yet in the shell, but the tab is selectable and ready for command output.": "L’intégration de l’arbre de travail n’est pas encore câblée dans le shell, mais l’onglet est sélectionnable et prêt pour la sortie des commandes." } \ No newline at end of file diff --git a/priv/i18n/locales/it.json b/priv/i18n/locales/it.json index 23a70d3..aa0387c 100644 --- a/priv/i18n/locales/it.json +++ b/priv/i18n/locales/it.json @@ -44,5 +44,122 @@ "render.taxonomy.ariaLabel": "Tassonomia", "render.video.vimeoTitle": "Video Vimeo", "render.video.youtubeTitle": "Video YouTube", - "sidebar.chat.yesterday": "Ieri" + "sidebar.chat.yesterday": "Ieri", + "%{count} media": "%{count} media", + "%{count} posts": "%{count} post", + "2 langs": "2 lingue", + "AI Assistant": "Assistente IA", + "Across draft, published, and archive": "Tra bozze, pubblicati e archivio", + "Activated %{name}": "%{name} attivato", + "Archived": "Archiviato", + "Archived Jan 12, 2026": "Archiviato il 12 gen 2026", + "Assistant": "Assistente", + "Automatic AI actions stay gated by airplane mode.": "Le azioni IA automatiche restano bloccate dalla modalità aereo.", + "Automation can boot the shell in a separate process and capture screenshots": "L’automazione può avviare la shell in un processo separato e catturare schermate", + "Blog": "Blog", + "Calendar regeneration is not wired yet, but the base shell now surfaces the command and keeps the Output tab selectable.": "La rigenerazione del calendario non è ancora collegata, ma la shell di base ora espone il comando e mantiene selezionabile la scheda Output.", + "Chat": "Chat", + "Close %{title}": "Chiudi %{title}", + "Close tab": "Chiudi scheda", + "Command completed": "Comando completato", + "Command failed": "Comando non riuscito", + "Command failed with HTTP %{status}": "Comando non riuscito con HTTP %{status}", + "Create Project": "Crea progetto", + "Dashboard": "Dashboard", + "Desktop Runtime": "Runtime desktop", + "Desktop workbench content routed through the Elixir shell.": "I contenuti del banco di lavoro desktop vengono instradati tramite la shell Elixir.", + "Desktop workbench shell wired through Elixir": "Shell del banco di lavoro desktop collegata tramite Elixir", + "Diff Reports": "Report diff", + "Diffs": "Differenze", + "Documentation": "Documentazione", + "Drafts": "Bozze", + "Drafts, published entries, and archive history": "Bozze, elementi pubblicati e cronologia archivio", + "Edit": "Modifica", + "Extra": "Extra", + "Extra Pages": "Pagine extra", + "File": "File", + "Filesystem Sync": "Sincronizzazione filesystem", + "Fill Missing Translations": "Completa traduzioni mancanti", + "Find Duplicates": "Trova duplicati", + "Git": "Git", + "Git Log": "Log Git", + "Help": "Aiuto", + "Idle": "Inattivo", + "Images and documents indexed": "Immagini e documenti indicizzati", + "Import": "Importa", + "Launch plan": "Piano di lancio", + "Main Language": "Lingua principale", + "Media": "Media", + "Menu": "Menu", + "Metadata": "Metadati", + "Metadata Diff": "Diff metadati", + "Metadata flush, diffing, and rebuild hooks still need editor wiring.": "Il salvataggio dei metadati, il diff e gli hook di ricostruzione hanno ancora bisogno del collegamento nell’editor.", + "Missing": "Mancante", + "Missing Pages": "Pagine mancanti", + "Missing Translations": "Traduzioni mancanti", + "Mode": "Modalità", + "Native menu groups mirror the old application shell": "I gruppi di menu nativi rispecchiano la vecchia shell dell’applicazione", + "New Project": "Nuovo progetto", + "New project name": "Nome nuovo progetto", + "No active background tasks": "Nessuna attività in background attiva", + "No background tasks running": "Nessuna attività in background in esecuzione", + "No items": "Nessun elemento", + "No missing pages": "Nessuna pagina mancante", + "No orphan translation files": "Nessun file di traduzione orfano", + "No shell output yet": "Nessun output della shell per ora", + "Offline": "Offline", + "Offline Gate": "Blocco offline", + "Open": "Apri", + "Open Data Folder": "Apri cartella dati", + "Open in Browser": "Apri nel browser", + "Opened URL": "URL aperto", + "Orphan Files": "File orfani", + "Orphan Reports": "Report orfani", + "Orphans": "Orfani", + "Output": "Output", + "Pages": "Pagine", + "Pairs": "Coppie", + "Post": "Post", + "Posts": "Post", + "Preview": "Anteprima", + "Projects": "Progetti", + "Published": "Pubblicato", + "Published Feb 10, 2026": "Pubblicato il 10 feb 2026", + "Queued": "In coda", + "Regenerate Calendar": "Rigenera calendario", + "Retrospective": "Retrospettiva", + "Roadmap": "Roadmap", + "Running": "In esecuzione", + "Script": "Script", + "Scripts": "Script", + "Select Project": "Seleziona progetto", + "Settings": "Impostazioni", + "Sidebar, tabs, panel, and assistant panes are inspectable DOM regions": "Barra laterale, schede, pannello e assistente sono regioni DOM ispezionabili", + "Site Validation": "Validazione sito", + "Source Control": "Controllo del codice sorgente", + "Stale": "Obsoleto", + "Stale Pages": "Pagine obsolete", + "Status": "Stato", + "Style": "Stile", + "Switch project": "Cambia progetto", + "Tags": "Tag", + "Tasks": "Attività", + "Template": "Template", + "Templates": "Template", + "The app window is now served from the Elixir shell renderer.": "La finestra dell’app è ora servita dal renderer shell Elixir.", + "The shared lower panel is available for tasks, output, git details, and editor-specific diagnostics.": "Il pannello inferiore condiviso è disponibile per attività, output, dettagli Git e diagnostica specifica dell’editor.", + "Toggle assistant": "Attiva/disattiva assistente", + "Toggle offline mode": "Attiva/disattiva modalità offline", + "Toggle panel": "Attiva/disattiva pannello", + "Toggle sidebar": "Attiva/disattiva barra laterale", + "Translation fill is not wired yet, but the command is now routed into Output instead of being ignored.": "Il completamento delle traduzioni non è ancora collegato, ma il comando ora viene instradato in Output invece di essere ignorato.", + "Translations": "Traduzioni", + "UI": "UI", + "Updated today": "Aggiornato oggi", + "Updated yesterday": "Aggiornato ieri", + "Upload Site": "Carica sito", + "View": "Vista", + "Welcome to bDS2": "Benvenuto in bDS2", + "Workbench Notes": "Note del banco di lavoro", + "Working tree integration is not wired yet in the shell, but the tab is selectable and ready for command output.": "L’integrazione del working tree non è ancora collegata nella shell, ma la scheda è selezionabile e pronta per l’output dei comandi." } \ No newline at end of file diff --git a/test/bds/i18n_test.exs b/test/bds/i18n_test.exs index c78ad1c..37623b7 100644 --- a/test/bds/i18n_test.exs +++ b/test/bds/i18n_test.exs @@ -46,4 +46,39 @@ defmodule BDS.I18nTest do test "supported locales do not silently fall back to english per key" do assert BDS.I18n.translate("de", "missing.key") == "missing.key" end + + test "supported locale files expose the same translation keys" do + catalogs = locale_catalogs() + english_keys = catalogs["en"] |> Map.keys() |> Enum.sort() + + for {locale, catalog} <- catalogs, locale != "en" do + assert Map.keys(catalog) |> Enum.sort() == english_keys + end + end + + test "supported non-english locales translate representative keys differently from english" do + catalogs = locale_catalogs() + + representative_keys = [ + "activity.posts", + "common.settings", + "render.calendar.title", + "render.notFound.back", + "render.search.ariaLabel" + ] + + for locale <- ["de", "fr", "it", "es"], key <- representative_keys do + assert Map.fetch!(catalogs, locale)[key] != Map.fetch!(catalogs, "en")[key] + end + end + + defp locale_catalogs do + locale_dir = Application.app_dir(:bds, "priv/i18n/locales") + + Path.wildcard(Path.join(locale_dir, "*.json")) + |> Enum.sort() + |> Enum.into(%{}, fn path -> + {Path.basename(path, ".json"), Jason.decode!(File.read!(path))} + end) + end end