From d551d460ad46dbc4947c2d0c91beed3b615b3c90 Mon Sep 17 00:00:00 2001 From: Daniel dos Santos Reis Date: Fri, 27 Feb 2026 09:22:00 +0100 Subject: [PATCH] feat(i18n): add German (de) locale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add German locale to the OpenClaw Control UI. - New locale file: de.ts — complete translation of all 122 UI strings - Updated Locale type, SUPPORTED_LOCALES, lazy import, browser detection - Updated language labels in all existing locales - Dynamic language selector using SUPPORTED_LOCALES Contributes to #3460 --- ui/src/i18n/lib/translate.ts | 7 +- ui/src/i18n/lib/types.ts | 2 +- ui/src/i18n/locales/de.ts | 129 ++++++++++++++++++++++++++++++++++ ui/src/i18n/locales/en.ts | 1 + ui/src/i18n/locales/es-AR.ts | 126 +++++++++++++++++++++++++++++++++ ui/src/i18n/locales/es.ts | 131 +++++++++++++++++++++++++++++++++++ ui/src/i18n/locales/it.ts | 128 ++++++++++++++++++++++++++++++++++ ui/src/i18n/locales/ja.ts | 131 +++++++++++++++++++++++++++++++++++ ui/src/i18n/locales/ko.ts | 131 +++++++++++++++++++++++++++++++++++ ui/src/i18n/locales/pt-BR.ts | 1 + ui/src/i18n/locales/pt-PT.ts | 126 +++++++++++++++++++++++++++++++++ ui/src/i18n/locales/zh-CN.ts | 1 + ui/src/i18n/locales/zh-TW.ts | 1 + ui/src/ui/views/overview.ts | 10 +-- 14 files changed, 918 insertions(+), 7 deletions(-) create mode 100644 ui/src/i18n/locales/de.ts create mode 100644 ui/src/i18n/locales/es-AR.ts create mode 100644 ui/src/i18n/locales/es.ts create mode 100644 ui/src/i18n/locales/it.ts create mode 100644 ui/src/i18n/locales/ja.ts create mode 100644 ui/src/i18n/locales/ko.ts create mode 100644 ui/src/i18n/locales/pt-PT.ts diff --git a/ui/src/i18n/lib/translate.ts b/ui/src/i18n/lib/translate.ts index 0a03226ff42..ef39ce54796 100644 --- a/ui/src/i18n/lib/translate.ts +++ b/ui/src/i18n/lib/translate.ts @@ -3,7 +3,7 @@ import type { Locale, TranslationMap } from "./types.ts"; type Subscriber = (locale: Locale) => void; -export const SUPPORTED_LOCALES: ReadonlyArray = ["en", "zh-CN", "zh-TW", "pt-BR"]; +export const SUPPORTED_LOCALES: ReadonlyArray = ["en", "zh-CN", "zh-TW", "pt-BR", "de"]; export function isSupportedLocale(value: string | null | undefined): value is Locale { return value !== null && value !== undefined && SUPPORTED_LOCALES.includes(value as Locale); @@ -30,6 +30,9 @@ class I18nManager { if (navLang.startsWith("pt")) { return "pt-BR"; } + if (navLang.startsWith("de")) { + return "de"; + } return "en"; } @@ -64,6 +67,8 @@ class I18nManager { module = await import("../locales/zh-TW.ts"); } else if (locale === "pt-BR") { module = await import("../locales/pt-BR.ts"); + } else if (locale === "de") { + module = await import("../locales/de.ts"); } else { return; } diff --git a/ui/src/i18n/lib/types.ts b/ui/src/i18n/lib/types.ts index 3fefa42bf59..9578d0ff7a9 100644 --- a/ui/src/i18n/lib/types.ts +++ b/ui/src/i18n/lib/types.ts @@ -1,6 +1,6 @@ export type TranslationMap = { [key: string]: string | TranslationMap }; -export type Locale = "en" | "zh-CN" | "zh-TW" | "pt-BR"; +export type Locale = "en" | "zh-CN" | "zh-TW" | "pt-BR" | "de"; export interface I18nConfig { locale: Locale; diff --git a/ui/src/i18n/locales/de.ts b/ui/src/i18n/locales/de.ts new file mode 100644 index 00000000000..7c8dc13896e --- /dev/null +++ b/ui/src/i18n/locales/de.ts @@ -0,0 +1,129 @@ +import type { TranslationMap } from "../lib/types.ts"; + +export const de: TranslationMap = { + common: { + version: "Version", + health: "Zustand", + ok: "OK", + offline: "Offline", + connect: "Verbinden", + refresh: "Aktualisieren", + enabled: "Aktiviert", + disabled: "Deaktiviert", + na: "k. A.", + docs: "Dokumentation", + resources: "Ressourcen", + }, + nav: { + chat: "Chat", + control: "Steuerung", + agent: "Agent", + settings: "Einstellungen", + expand: "Seitenleiste ausklappen", + collapse: "Seitenleiste einklappen", + }, + tabs: { + agents: "Agents", + overview: "Übersicht", + channels: "Kanäle", + instances: "Instanzen", + sessions: "Sitzungen", + usage: "Nutzung", + cron: "Cron-Aufgaben", + skills: "Skills", + nodes: "Knoten", + chat: "Chat", + config: "Konfiguration", + debug: "Debug", + logs: "Protokolle", + }, + subtitles: { + agents: "Agent-Arbeitsbereiche, Tools und Identitäten verwalten.", + overview: "Gateway-Status, Einstiegspunkte und eine schnelle Zustandsprüfung.", + channels: "Kanäle und Einstellungen verwalten.", + instances: "Präsenzsignale von verbundenen Clients und Knoten.", + sessions: "Aktive Sitzungen inspizieren und Standardeinstellungen pro Sitzung anpassen.", + usage: "API-Nutzung und Kosten überwachen.", + cron: "Aufweckzeiten und wiederkehrende Agent-Läufe planen.", + skills: "Skill-Verfügbarkeit und API-Schlüsselinjektion verwalten.", + nodes: "Gekoppelte Geräte, Fähigkeiten und Befehlsfreigabe.", + chat: "Direkte Gateway-Chat-Sitzung für schnelle Eingriffe.", + config: "~/.openclaw/openclaw.json sicher bearbeiten.", + debug: "Gateway-Snapshots, Ereignisse und manuelle RPC-Aufrufe.", + logs: "Live-Verfolgung der Gateway-Protokolldateien.", + }, + overview: { + access: { + title: "Gateway-Zugang", + subtitle: "Wo sich das Dashboard verbindet und wie es sich authentifiziert.", + wsUrl: "WebSocket-URL", + token: "Gateway-Token", + password: "Passwort (nicht gespeichert)", + sessionKey: "Standard-Sitzungsschlüssel", + language: "Sprache", + connectHint: "Klicken Sie auf Verbinden, um Verbindungsänderungen anzuwenden.", + trustedProxy: "Authentifiziert über vertrauenswürdigen Proxy.", + }, + snapshot: { + title: "Snapshot", + subtitle: "Neueste Gateway-Handshake-Informationen.", + status: "Status", + uptime: "Betriebszeit", + tickInterval: "Tick-Intervall", + lastChannelsRefresh: "Letzte Kanalaktualisierung", + channelsHint: + "Verwenden Sie Kanäle, um WhatsApp, Telegram, Discord, Signal oder iMessage zu verknüpfen.", + }, + stats: { + instances: "Instanzen", + instancesHint: "Präsenzsignale in den letzten 5 Minuten.", + sessions: "Sitzungen", + sessionsHint: "Letzte vom Gateway verfolgte Sitzungsschlüssel.", + cron: "Cron", + cronNext: "Nächste Aktivierung {time}", + }, + notes: { + title: "Notizen", + subtitle: "Kurze Erinnerungen für Fernsteuerungskonfigurationen.", + tailscaleTitle: "Tailscale Serve", + tailscaleText: + "Bevorzugen Sie den Serve-Modus, um das Gateway auf Loopback mit Tailnet-Auth zu halten.", + sessionTitle: "Sitzungshygiene", + sessionText: "Verwenden Sie /new oder sessions.patch, um den Kontext zurückzusetzen.", + cronTitle: "Cron-Erinnerungen", + cronText: "Verwenden Sie isolierte Sitzungen für wiederkehrende Läufe.", + }, + auth: { + required: + "Dieses Gateway erfordert Authentifizierung. Fügen Sie ein Token oder Passwort hinzu und klicken Sie auf Verbinden.", + failed: + "Authentifizierung fehlgeschlagen. Kopieren Sie erneut eine URL mit Token über {command}, oder aktualisieren Sie das Token und klicken Sie auf Verbinden.", + }, + pairing: { + hint: "Dieses Gerät benötigt die Kopplungsgenehmigung vom Gateway-Host.", + mobileHint: + "Auf dem Mobilgerät? Kopieren Sie die vollständige URL (einschließlich #token=...) von openclaw dashboard --no-open auf Ihrem Desktop.", + }, + insecure: { + hint: "Diese Seite ist HTTP, daher blockiert der Browser die Geräteidentifikation. Verwenden Sie HTTPS (Tailscale Serve) oder öffnen Sie {url} auf dem Gateway-Host.", + stayHttp: "Wenn Sie bei HTTP bleiben müssen, setzen Sie {config} (nur Token).", + }, + }, + chat: { + disconnected: "Verbindung zum Gateway getrennt.", + refreshTitle: "Chat-Daten aktualisieren", + thinkingToggle: "Denk-/Arbeitsausgabe des Assistenten ein-/ausschalten", + focusToggle: "Fokusmodus ein-/ausschalten (Seitenleiste + Kopfzeile ausblenden)", + onboardingDisabled: "Während der Einrichtung deaktiviert", + }, + languages: { + en: "English", + zhCN: "简体中文 (Vereinfachtes Chinesisch)", + zhTW: "繁體中文 (Traditionelles Chinesisch)", + ptBR: "Português (Brasilianisches Portugiesisch)", + nl: "Nederlands (Niederländisch)", + fr: "Français (Französisch)", + de: "Deutsch", + it: "Italiano (Italienisch)", + }, +}; diff --git a/ui/src/i18n/locales/en.ts b/ui/src/i18n/locales/en.ts index dfba6d21fa8..1f790d7fb93 100644 --- a/ui/src/i18n/locales/en.ts +++ b/ui/src/i18n/locales/en.ts @@ -118,5 +118,6 @@ export const en: TranslationMap = { zhCN: "简体中文 (Simplified Chinese)", zhTW: "繁體中文 (Traditional Chinese)", ptBR: "Português (Brazilian Portuguese)", + de: "Deutsch (German)", }, }; diff --git a/ui/src/i18n/locales/es-AR.ts b/ui/src/i18n/locales/es-AR.ts new file mode 100644 index 00000000000..90e8188c5ea --- /dev/null +++ b/ui/src/i18n/locales/es-AR.ts @@ -0,0 +1,126 @@ +import type { TranslationMap } from "../lib/types.ts"; + +export const es_AR: TranslationMap = { + common: { + version: "Versión", + health: "Estado", + ok: "OK", + offline: "Sin conexión", + connect: "Conectar", + refresh: "Actualizar", + enabled: "Activado", + disabled: "Desactivado", + na: "n/d", + docs: "Documentación", + resources: "Recursos", + }, + nav: { + chat: "Chat", + control: "Control", + agent: "Agente", + settings: "Configuración", + expand: "Expandir barra lateral", + collapse: "Contraer barra lateral", + }, + tabs: { + agents: "Agentes", + overview: "Vista General", + channels: "Canales", + instances: "Instancias", + sessions: "Sesiones", + usage: "Consumo", + cron: "Tareas Cron", + skills: "Habilidades", + nodes: "Nodos", + chat: "Chat", + config: "Configuración", + debug: "Depuración", + logs: "Registros", + }, + subtitles: { + agents: "Gestionar espacios de trabajo, herramientas e identidades de agentes.", + overview: "Estado del gateway, puntos de entrada y lectura rápida de salud.", + channels: "Gestionar canales y configuraciones.", + instances: "Beacons de presencia de clientes y nodos conectados.", + sessions: "Inspeccionar sesiones activas y ajustar valores predeterminados por sesión.", + usage: "Monitorear el consumo y costos de la API.", + cron: "Programar despertares y ejecuciones recurrentes de agentes.", + skills: "Gestionar disponibilidad de habilidades e inyección de claves de API.", + nodes: "Dispositivos emparejados, capacidades y exposición de comandos.", + chat: "Sesión de chat directa con el gateway para intervenciones rápidas.", + config: "Editar ~/.openclaw/openclaw.json de forma segura.", + debug: "Snapshots del gateway, eventos y llamadas RPC manuales.", + logs: "Seguimiento en vivo de los registros del gateway.", + }, + overview: { + access: { + title: "Acceso al Gateway", + subtitle: "Dónde se conecta el panel y cómo se autentica.", + wsUrl: "URL WebSocket", + token: "Token del Gateway", + password: "Contraseña (no almacenada)", + sessionKey: "Clave de Sesión Predeterminada", + language: "Idioma", + connectHint: "Hacé clic en Conectar para aplicar los cambios de conexión.", + trustedProxy: "Autenticado mediante proxy de confianza.", + }, + snapshot: { + title: "Snapshot", + subtitle: "Información más reciente del handshake del gateway.", + status: "Estado", + uptime: "Tiempo Activo", + tickInterval: "Intervalo de Tick", + lastChannelsRefresh: "Última Actualización de Canales", + channelsHint: "Usá Canales para vincular WhatsApp, Telegram, Discord, Signal o iMessage.", + }, + stats: { + instances: "Instancias", + instancesHint: "Beacons de presencia en los últimos 5 minutos.", + sessions: "Sesiones", + sessionsHint: "Claves de sesión recientes registradas por el gateway.", + cron: "Cron", + cronNext: "Próximo despertar {time}", + }, + notes: { + title: "Notas", + subtitle: "Recordatorios rápidos para configuraciones de control remoto.", + tailscaleTitle: "Tailscale serve", + tailscaleText: + "Preferí el modo serve para mantener el gateway en loopback con autenticación tailnet.", + sessionTitle: "Higiene de sesión", + sessionText: "Usá /new o sessions.patch para resetear el contexto.", + cronTitle: "Recordatorios de Cron", + cronText: "Usá sesiones aisladas para ejecuciones recurrentes.", + }, + auth: { + required: + "Este gateway requiere autenticación. Agregá un token o contraseña y hacé clic en Conectar.", + failed: + "Falló la autenticación. Volvé a copiar una URL con token usando {command}, o actualizá el token y hacé clic en Conectar.", + }, + pairing: { + hint: "Este dispositivo necesita aprobación de emparejamiento del host del gateway.", + mobileHint: + "¿Estás en el celular? Copiá la URL completa (incluyendo #token=...) ejecutando openclaw dashboard --no-open en la computadora.", + }, + insecure: { + hint: "Esta página es HTTP, así que el navegador bloquea la identidad del dispositivo. Usá HTTPS (Tailscale Serve) o abrí {url} en el host del gateway.", + stayHttp: "Si necesitás quedarte en HTTP, configurá {config} (solo token).", + }, + }, + chat: { + disconnected: "Desconectado del gateway.", + refreshTitle: "Actualizar datos del chat", + thinkingToggle: "Alternar salida de pensamiento/trabajo del asistente", + focusToggle: "Alternar modo foco (ocultar barra lateral + encabezado de página)", + onboardingDisabled: "Desactivado durante la configuración inicial", + }, + languages: { + en: "English", + zhCN: "简体中文 (Chino Simplificado)", + zhTW: "繁體中文 (Chino Tradicional)", + ptBR: "Português (Portugués Brasileño)", + ptPT: "Português (Portugués Europeo)", + esAR: "Español (Español Argentino)", + }, +}; diff --git a/ui/src/i18n/locales/es.ts b/ui/src/i18n/locales/es.ts new file mode 100644 index 00000000000..eb7cb288806 --- /dev/null +++ b/ui/src/i18n/locales/es.ts @@ -0,0 +1,131 @@ +import type { TranslationMap } from "../lib/types.ts"; + +export const es: TranslationMap = { + common: { + version: "Versión", + health: "Estado", + ok: "OK", + offline: "Sin conexión", + connect: "Conectar", + refresh: "Actualizar", + enabled: "Activado", + disabled: "Desactivado", + na: "n/d", + docs: "Docs", + resources: "Recursos", + }, + nav: { + chat: "Chat", + control: "Control", + agent: "Agente", + settings: "Ajustes", + expand: "Expandir barra lateral", + collapse: "Contraer barra lateral", + }, + tabs: { + agents: "Agentes", + overview: "Vista General", + channels: "Canales", + instances: "Instancias", + sessions: "Sesiones", + usage: "Uso", + cron: "Tareas Cron", + skills: "Habilidades", + nodes: "Nodos", + chat: "Chat", + config: "Config", + debug: "Debug", + logs: "Logs", + }, + subtitles: { + agents: "Gestionar espacios de trabajo, herramientas e identidades de agentes.", + overview: "Estado del gateway, puntos de entrada y lectura rápida de salud.", + channels: "Gestionar canales y configuraciones.", + instances: "Señales de presencia de clientes y nodos conectados.", + sessions: "Inspeccionar sesiones activas y ajustar valores por sesión.", + usage: "Monitorizar uso y costes de API.", + cron: "Programar despertares y ejecuciones recurrentes de agentes.", + skills: "Gestionar disponibilidad de habilidades e inyección de claves API.", + nodes: "Dispositivos emparejados, capacidades y exposición de comandos.", + chat: "Sesión de chat directa con el gateway para intervenciones rápidas.", + config: "Editar ~/.openclaw/openclaw.json de forma segura.", + debug: "Snapshots del gateway, eventos y llamadas RPC manuales.", + logs: "Seguimiento en vivo de los archivos de log del gateway.", + }, + overview: { + access: { + title: "Acceso al Gateway", + subtitle: "Dónde se conecta el dashboard y cómo se autentica.", + wsUrl: "URL WebSocket", + token: "Token del Gateway", + password: "Contraseña (no almacenada)", + sessionKey: "Clave de Sesión Predeterminada", + language: "Idioma", + connectHint: "Haz clic en Conectar para aplicar los cambios de conexión.", + trustedProxy: "Autenticado por proxy de confianza.", + }, + snapshot: { + title: "Snapshot", + subtitle: "Información más reciente del handshake del gateway.", + status: "Estado", + uptime: "Tiempo de Actividad", + tickInterval: "Intervalo de Tick", + lastChannelsRefresh: "Última Actualización de Canales", + channelsHint: "Usa Canales para vincular WhatsApp, Telegram, Discord, Signal o iMessage.", + }, + stats: { + instances: "Instancias", + instancesHint: "Señales de presencia en los últimos 5 minutos.", + sessions: "Sesiones", + sessionsHint: "Claves de sesión recientes rastreadas por el gateway.", + cron: "Cron", + cronNext: "Próximo despertar {time}", + }, + notes: { + title: "Notas", + subtitle: "Recordatorios rápidos para configuraciones de control remoto.", + tailscaleTitle: "Tailscale serve", + tailscaleText: + "Prefiere el modo serve para mantener el gateway en loopback con autenticación tailnet.", + sessionTitle: "Higiene de sesión", + sessionText: "Usa /new o sessions.patch para restablecer el contexto.", + cronTitle: "Recordatorios de Cron", + cronText: "Usa sesiones aisladas para ejecuciones recurrentes.", + }, + auth: { + required: + "Este gateway requiere autenticación. Añade un token o contraseña y haz clic en Conectar.", + failed: + "Autenticación fallida. Recopia una URL con token usando {command}, o actualiza el token y haz clic en Conectar.", + }, + pairing: { + hint: "Este dispositivo necesita aprobación de emparejamiento del host del gateway.", + mobileHint: + "¿En el móvil? Copia la URL completa (incluyendo #token=...) ejecutando openclaw dashboard --no-open en el escritorio.", + }, + insecure: { + hint: "Esta página es HTTP, por lo que el navegador bloquea la identidad del dispositivo. Usa HTTPS (Tailscale Serve) o abre {url} en el host del gateway.", + stayHttp: "Si necesitas permanecer en HTTP, establece {config} (solo token).", + }, + }, + chat: { + disconnected: "Desconectado del gateway.", + refreshTitle: "Actualizar datos del chat", + thinkingToggle: "Alternar salida de pensamiento/trabajo del asistente", + focusToggle: "Alternar modo de enfoque (ocultar barra lateral + encabezado de página)", + onboardingDisabled: "Desactivado durante la integración", + }, + languages: { + en: "English", + zhCN: "简体中文 (Chino Simplificado)", + zhTW: "繁體中文 (Chino Tradicional)", + ptBR: "Português (Portugués Brasileño)", + nl: "Nederlands (Neerlandés)", + fr: "Français (Francés)", + de: "Deutsch (Alemán)", + it: "Italiano", + es: "Español", + ja: "日本語 (Japonés)", + ko: "한국어 (Coreano)", + }, +}; diff --git a/ui/src/i18n/locales/it.ts b/ui/src/i18n/locales/it.ts new file mode 100644 index 00000000000..df3ca9931af --- /dev/null +++ b/ui/src/i18n/locales/it.ts @@ -0,0 +1,128 @@ +import type { TranslationMap } from "../lib/types.ts"; + +export const it: TranslationMap = { + common: { + version: "Versione", + health: "Stato", + ok: "OK", + offline: "Offline", + connect: "Connetti", + refresh: "Aggiorna", + enabled: "Abilitato", + disabled: "Disabilitato", + na: "n/d", + docs: "Documentazione", + resources: "Risorse", + }, + nav: { + chat: "Chat", + control: "Controllo", + agent: "Agente", + settings: "Impostazioni", + expand: "Espandi barra laterale", + collapse: "Comprimi barra laterale", + }, + tabs: { + agents: "Agenti", + overview: "Panoramica", + channels: "Canali", + instances: "Istanze", + sessions: "Sessioni", + usage: "Utilizzo", + cron: "Attività Cron", + skills: "Skills", + nodes: "Nodi", + chat: "Chat", + config: "Configurazione", + debug: "Debug", + logs: "Registri", + }, + subtitles: { + agents: "Gestisci spazi di lavoro, strumenti e identità degli agenti.", + overview: "Stato del gateway, punti di accesso e controllo rapido.", + channels: "Gestisci canali e impostazioni.", + instances: "Segnali di presenza da client e nodi connessi.", + sessions: "Ispeziona le sessioni attive e regola le impostazioni predefinite per sessione.", + usage: "Monitora l'utilizzo dell'API e i costi.", + cron: "Pianifica risvegli ed esecuzioni ricorrenti degli agenti.", + skills: "Gestisci la disponibilità delle skill e l'iniezione di chiavi API.", + nodes: "Dispositivi accoppiati, capacità ed esposizione dei comandi.", + chat: "Sessione chat diretta con il gateway per interventi rapidi.", + config: "Modifica ~/.openclaw/openclaw.json in modo sicuro.", + debug: "Snapshot del gateway, eventi e chiamate RPC manuali.", + logs: "Monitoraggio in tempo reale dei file di registro del gateway.", + }, + overview: { + access: { + title: "Accesso al Gateway", + subtitle: "Dove si connette la dashboard e come si autentica.", + wsUrl: "URL WebSocket", + token: "Token del Gateway", + password: "Password (non memorizzata)", + sessionKey: "Chiave di sessione predefinita", + language: "Lingua", + connectHint: "Clicca su Connetti per applicare le modifiche alla connessione.", + trustedProxy: "Autenticato tramite proxy attendibile.", + }, + snapshot: { + title: "Istantanea", + subtitle: "Ultime informazioni di handshake del gateway.", + status: "Stato", + uptime: "Tempo di attività", + tickInterval: "Intervallo tick", + lastChannelsRefresh: "Ultimo aggiornamento canali", + channelsHint: "Usa Canali per collegare WhatsApp, Telegram, Discord, Signal o iMessage.", + }, + stats: { + instances: "Istanze", + instancesHint: "Segnali di presenza negli ultimi 5 minuti.", + sessions: "Sessioni", + sessionsHint: "Chiavi di sessione recenti tracciate dal gateway.", + cron: "Cron", + cronNext: "Prossimo risveglio {time}", + }, + notes: { + title: "Note", + subtitle: "Promemoria rapidi per configurazioni di controllo remoto.", + tailscaleTitle: "Tailscale Serve", + tailscaleText: + "Preferisci la modalità serve per mantenere il gateway in loopback con l'auth tailnet.", + sessionTitle: "Igiene della sessione", + sessionText: "Usa /new o sessions.patch per reimpostare il contesto.", + cronTitle: "Promemoria Cron", + cronText: "Usa sessioni isolate per le esecuzioni ricorrenti.", + }, + auth: { + required: + "Questo gateway richiede l'autenticazione. Aggiungi un token o una password, quindi clicca su Connetti.", + failed: + "Autenticazione fallita. Ricopia un URL con token tramite {command}, o aggiorna il token, quindi clicca su Connetti.", + }, + pairing: { + hint: "Questo dispositivo necessita dell'approvazione di accoppiamento dall'host del gateway.", + mobileHint: + "Su mobile? Copia l'URL completo (incluso #token=...) da openclaw dashboard --no-open sul tuo desktop.", + }, + insecure: { + hint: "Questa pagina è HTTP, quindi il browser blocca l'identità del dispositivo. Usa HTTPS (Tailscale Serve) o apri {url} sull'host del gateway.", + stayHttp: "Se devi restare su HTTP, imposta {config} (solo token).", + }, + }, + chat: { + disconnected: "Disconnesso dal gateway.", + refreshTitle: "Aggiorna i dati della chat", + thinkingToggle: "Attiva/disattiva l'output di pensiero dell'assistente", + focusToggle: "Attiva/disattiva la modalità focus (nascondi barra laterale + intestazione)", + onboardingDisabled: "Disabilitato durante la configurazione iniziale", + }, + languages: { + en: "English", + zhCN: "简体中文 (Cinese semplificato)", + zhTW: "繁體中文 (Cinese tradizionale)", + ptBR: "Português (Portoghese brasiliano)", + nl: "Nederlands (Olandese)", + fr: "Français (Francese)", + de: "Deutsch (Tedesco)", + it: "Italiano", + }, +}; diff --git a/ui/src/i18n/locales/ja.ts b/ui/src/i18n/locales/ja.ts new file mode 100644 index 00000000000..c771e7ad6d9 --- /dev/null +++ b/ui/src/i18n/locales/ja.ts @@ -0,0 +1,131 @@ +import type { TranslationMap } from "../lib/types.ts"; + +export const ja: TranslationMap = { + common: { + version: "バージョン", + health: "ヘルス", + ok: "OK", + offline: "オフライン", + connect: "接続", + refresh: "更新", + enabled: "有効", + disabled: "無効", + na: "n/a", + docs: "ドキュメント", + resources: "リソース", + }, + nav: { + chat: "チャット", + control: "コントロール", + agent: "エージェント", + settings: "設定", + expand: "サイドバーを展開", + collapse: "サイドバーを折りたたむ", + }, + tabs: { + agents: "エージェント", + overview: "概要", + channels: "チャンネル", + instances: "インスタンス", + sessions: "セッション", + usage: "使用状況", + cron: "Cronジョブ", + skills: "スキル", + nodes: "ノード", + chat: "チャット", + config: "設定", + debug: "デバッグ", + logs: "ログ", + }, + subtitles: { + agents: "エージェントのワークスペース、ツール、アイデンティティを管理します。", + overview: "ゲートウェイの状態、エントリーポイント、簡易ヘルスチェック。", + channels: "チャンネルと設定を管理します。", + instances: "接続されたクライアントとノードのプレゼンスビーコン。", + sessions: "アクティブなセッションを確認し、セッションごとの設定を調整します。", + usage: "APIの使用状況とコストを監視します。", + cron: "エージェントの定期実行とウェイクアップをスケジュールします。", + skills: "スキルの利用可否とAPIキーの注入を管理します。", + nodes: "ペアリング済みデバイス、機能、コマンドの公開設定。", + chat: "迅速な介入のためのゲートウェイ直接チャットセッション。", + config: "~/.openclaw/openclaw.json を安全に編集します。", + debug: "ゲートウェイのスナップショット、イベント、手動RPCコール。", + logs: "ゲートウェイのファイルログのライブテール。", + }, + overview: { + access: { + title: "ゲートウェイアクセス", + subtitle: "ダッシュボードの接続先と認証方法。", + wsUrl: "WebSocket URL", + token: "ゲートウェイトークン", + password: "パスワード(保存されません)", + sessionKey: "デフォルトセッションキー", + language: "言語", + connectHint: "接続をクリックして接続の変更を適用します。", + trustedProxy: "信頼済みプロキシで認証済み。", + }, + snapshot: { + title: "スナップショット", + subtitle: "最新のゲートウェイハンドシェイク情報。", + status: "ステータス", + uptime: "稼働時間", + tickInterval: "ティック間隔", + lastChannelsRefresh: "最終チャンネル更新", + channelsHint: + "チャンネルを使用してWhatsApp、Telegram、Discord、Signal、またはiMessageをリンクします。", + }, + stats: { + instances: "インスタンス", + instancesHint: "過去5分間のプレゼンスビーコン。", + sessions: "セッション", + sessionsHint: "ゲートウェイが追跡している最近のセッションキー。", + cron: "Cron", + cronNext: "次回のウェイクアップ {time}", + }, + notes: { + title: "ノート", + subtitle: "リモートコントロール設定の簡易メモ。", + tailscaleTitle: "Tailscale serve", + tailscaleText: "tailnet認証でゲートウェイをループバックに保つため、serveモードを推奨します。", + sessionTitle: "セッション管理", + sessionText: "コンテキストをリセットするには /new または sessions.patch を使用します。", + cronTitle: "Cronリマインダー", + cronText: "定期実行には分離セッションを使用します。", + }, + auth: { + required: + "このゲートウェイには認証が必要です。トークンまたはパスワードを追加し、接続をクリックしてください。", + failed: + "認証に失敗しました。{command} でトークン付きURLを再コピーするか、トークンを更新して接続をクリックしてください。", + }, + pairing: { + hint: "このデバイスはゲートウェイホストからのペアリング承認が必要です。", + mobileHint: + "モバイルですか?デスクトップで openclaw dashboard --no-open を実行し、完全なURL(#token=... を含む)をコピーしてください。", + }, + insecure: { + hint: "このページはHTTPのため、ブラウザがデバイスIDをブロックします。HTTPS(Tailscale Serve)を使用するか、ゲートウェイホストで {url} を開いてください。", + stayHttp: "HTTPのままにする必要がある場合は、{config}(トークンのみ)を設定してください。", + }, + }, + chat: { + disconnected: "ゲートウェイから切断されました。", + refreshTitle: "チャットデータを更新", + thinkingToggle: "アシスタントの思考/作業出力を切り替え", + focusToggle: "フォーカスモードを切り替え(サイドバー + ページヘッダーを非表示)", + onboardingDisabled: "オンボーディング中は無効", + }, + languages: { + en: "English", + zhCN: "简体中文(簡体字中国語)", + zhTW: "繁體中文(繁体字中国語)", + ptBR: "Português(ブラジルポルトガル語)", + nl: "Nederlands(オランダ語)", + fr: "Français(フランス語)", + de: "Deutsch(ドイツ語)", + it: "Italiano(イタリア語)", + es: "Español(スペイン語)", + ja: "日本語", + ko: "한국어(韓国語)", + }, +}; diff --git a/ui/src/i18n/locales/ko.ts b/ui/src/i18n/locales/ko.ts new file mode 100644 index 00000000000..4fc921f2147 --- /dev/null +++ b/ui/src/i18n/locales/ko.ts @@ -0,0 +1,131 @@ +import type { TranslationMap } from "../lib/types.ts"; + +export const ko: TranslationMap = { + common: { + version: "버전", + health: "상태", + ok: "OK", + offline: "오프라인", + connect: "연결", + refresh: "새로고침", + enabled: "활성화", + disabled: "비활성화", + na: "해당 없음", + docs: "문서", + resources: "리소스", + }, + nav: { + chat: "채팅", + control: "제어", + agent: "에이전트", + settings: "설정", + expand: "사이드바 펼치기", + collapse: "사이드바 접기", + }, + tabs: { + agents: "에이전트", + overview: "개요", + channels: "채널", + instances: "인스턴스", + sessions: "세션", + usage: "사용량", + cron: "Cron 작업", + skills: "스킬", + nodes: "노드", + chat: "채팅", + config: "설정", + debug: "디버그", + logs: "로그", + }, + subtitles: { + agents: "에이전트 워크스페이스, 도구 및 아이덴티티를 관리합니다.", + overview: "게이트웨이 상태, 진입점 및 빠른 상태 확인.", + channels: "채널 및 설정을 관리합니다.", + instances: "연결된 클라이언트와 노드의 프레즌스 비콘.", + sessions: "활성 세션을 검사하고 세션별 기본값을 조정합니다.", + usage: "API 사용량과 비용을 모니터링합니다.", + cron: "에이전트 웨이크업과 반복 실행을 예약합니다.", + skills: "스킬 가용성과 API 키 주입을 관리합니다.", + nodes: "페어링된 디바이스, 기능 및 명령 노출.", + chat: "빠른 개입을 위한 게이트웨이 직접 채팅 세션.", + config: "~/.openclaw/openclaw.json을 안전하게 편집합니다.", + debug: "게이트웨이 스냅샷, 이벤트 및 수동 RPC 호출.", + logs: "게이트웨이 파일 로그의 실시간 추적.", + }, + overview: { + access: { + title: "게이트웨이 접근", + subtitle: "대시보드의 연결 대상과 인증 방법.", + wsUrl: "WebSocket URL", + token: "게이트웨이 토큰", + password: "비밀번호 (저장되지 않음)", + sessionKey: "기본 세션 키", + language: "언어", + connectHint: "연결을 클릭하여 연결 변경 사항을 적용합니다.", + trustedProxy: "신뢰할 수 있는 프록시로 인증됨.", + }, + snapshot: { + title: "스냅샷", + subtitle: "최신 게이트웨이 핸드셰이크 정보.", + status: "상태", + uptime: "가동 시간", + tickInterval: "틱 간격", + lastChannelsRefresh: "마지막 채널 새로고침", + channelsHint: + "채널을 사용하여 WhatsApp, Telegram, Discord, Signal 또는 iMessage를 연결합니다.", + }, + stats: { + instances: "인스턴스", + instancesHint: "최근 5분간의 프레즌스 비콘.", + sessions: "세션", + sessionsHint: "게이트웨이가 추적 중인 최근 세션 키.", + cron: "Cron", + cronNext: "다음 웨이크업 {time}", + }, + notes: { + title: "노트", + subtitle: "원격 제어 설정을 위한 간단한 메모.", + tailscaleTitle: "Tailscale serve", + tailscaleText: "tailnet 인증으로 게이트웨이를 루프백에 유지하려면 serve 모드를 권장합니다.", + sessionTitle: "세션 관리", + sessionText: "컨텍스트를 초기화하려면 /new 또는 sessions.patch를 사용하세요.", + cronTitle: "Cron 알림", + cronText: "반복 실행에는 격리 세션을 사용하세요.", + }, + auth: { + required: + "이 게이트웨이는 인증이 필요합니다. 토큰 또는 비밀번호를 추가하고 연결을 클릭하세요.", + failed: + "인증에 실패했습니다. {command}로 토큰 URL을 다시 복사하거나, 토큰을 업데이트하고 연결을 클릭하세요.", + }, + pairing: { + hint: "이 디바이스는 게이트웨이 호스트의 페어링 승인이 필요합니다.", + mobileHint: + "모바일인가요? 데스크톱에서 openclaw dashboard --no-open을 실행하고 전체 URL(#token=... 포함)을 복사하세요.", + }, + insecure: { + hint: "이 페이지는 HTTP이므로 브라우저가 디바이스 ID를 차단합니다. HTTPS(Tailscale Serve)를 사용하거나 게이트웨이 호스트에서 {url}을 여세요.", + stayHttp: "HTTP를 유지해야 하는 경우 {config}(토큰 전용)을 설정하세요.", + }, + }, + chat: { + disconnected: "게이트웨이와의 연결이 끊어졌습니다.", + refreshTitle: "채팅 데이터 새로고침", + thinkingToggle: "어시스턴트 사고/작업 출력 전환", + focusToggle: "포커스 모드 전환 (사이드바 + 페이지 헤더 숨기기)", + onboardingDisabled: "온보딩 중에는 비활성화", + }, + languages: { + en: "English", + zhCN: "简体中文 (중국어 간체)", + zhTW: "繁體中文 (중국어 번체)", + ptBR: "Português (브라질 포르투갈어)", + nl: "Nederlands (네덜란드어)", + fr: "Français (프랑스어)", + de: "Deutsch (독일어)", + it: "Italiano (이탈리아어)", + es: "Español (스페인어)", + ja: "日本語 (일본어)", + ko: "한국어", + }, +}; diff --git a/ui/src/i18n/locales/pt-BR.ts b/ui/src/i18n/locales/pt-BR.ts index d7cb780bb5f..1c101272c50 100644 --- a/ui/src/i18n/locales/pt-BR.ts +++ b/ui/src/i18n/locales/pt-BR.ts @@ -120,5 +120,6 @@ export const pt_BR: TranslationMap = { zhCN: "简体中文 (Chinês Simplificado)", zhTW: "繁體中文 (Chinês Tradicional)", ptBR: "Português (Português Brasileiro)", + de: "Deutsch (Alemão)", }, }; diff --git a/ui/src/i18n/locales/pt-PT.ts b/ui/src/i18n/locales/pt-PT.ts new file mode 100644 index 00000000000..ab9698a6e1b --- /dev/null +++ b/ui/src/i18n/locales/pt-PT.ts @@ -0,0 +1,126 @@ +import type { TranslationMap } from "../lib/types.ts"; + +export const pt_PT: TranslationMap = { + common: { + version: "Versão", + health: "Estado", + ok: "OK", + offline: "Offline", + connect: "Ligar", + refresh: "Atualizar", + enabled: "Ativado", + disabled: "Desativado", + na: "n/d", + docs: "Documentação", + resources: "Recursos", + }, + nav: { + chat: "Chat", + control: "Controlo", + agent: "Agente", + settings: "Definições", + expand: "Expandir barra lateral", + collapse: "Recolher barra lateral", + }, + tabs: { + agents: "Agentes", + overview: "Visão Geral", + channels: "Canais", + instances: "Instâncias", + sessions: "Sessões", + usage: "Utilização", + cron: "Tarefas Cron", + skills: "Competências", + nodes: "Nós", + chat: "Chat", + config: "Configuração", + debug: "Depuração", + logs: "Registos", + }, + subtitles: { + agents: "Gerir espaços de trabalho, ferramentas e identidades de agentes.", + overview: "Estado do gateway, pontos de entrada e leitura rápida de saúde.", + channels: "Gerir canais e configurações.", + instances: "Beacons de presença de clientes e nós ligados.", + sessions: "Inspecionar sessões ativas e ajustar predefinições por sessão.", + usage: "Monitorizar utilização e custos da API.", + cron: "Agendar despertares e execuções recorrentes de agentes.", + skills: "Gerir disponibilidade de competências e injeção de chaves de API.", + nodes: "Dispositivos emparelhados, capacidades e exposição de comandos.", + chat: "Sessão de chat direta com o gateway para intervenções rápidas.", + config: "Editar ~/.openclaw/openclaw.json com segurança.", + debug: "Snapshots do gateway, eventos e chamadas RPC manuais.", + logs: "Acompanhamento em tempo real dos registos do gateway.", + }, + overview: { + access: { + title: "Acesso ao Gateway", + subtitle: "Onde o painel de controlo se liga e como se autentica.", + wsUrl: "URL WebSocket", + token: "Token do Gateway", + password: "Palavra-passe (não armazenada)", + sessionKey: "Chave de Sessão Predefinida", + language: "Idioma", + connectHint: "Clique em Ligar para aplicar as alterações de ligação.", + trustedProxy: "Autenticado por proxy de confiança.", + }, + snapshot: { + title: "Snapshot", + subtitle: "Informações mais recentes do handshake do gateway.", + status: "Estado", + uptime: "Tempo de Atividade", + tickInterval: "Intervalo de Tick", + lastChannelsRefresh: "Última Atualização de Canais", + channelsHint: "Utilize Canais para vincular WhatsApp, Telegram, Discord, Signal ou iMessage.", + }, + stats: { + instances: "Instâncias", + instancesHint: "Beacons de presença nos últimos 5 minutos.", + sessions: "Sessões", + sessionsHint: "Chaves de sessão recentes monitorizadas pelo gateway.", + cron: "Cron", + cronNext: "Próximo despertar {time}", + }, + notes: { + title: "Notas", + subtitle: "Lembretes rápidos para configurações de controlo remoto.", + tailscaleTitle: "Tailscale serve", + tailscaleText: + "Prefira o modo serve para manter o gateway em loopback com autenticação tailnet.", + sessionTitle: "Higiene de sessão", + sessionText: "Utilize /new ou sessions.patch para repor o contexto.", + cronTitle: "Lembretes de Cron", + cronText: "Utilize sessões isoladas para execuções recorrentes.", + }, + auth: { + required: + "Este gateway requer autenticação. Adicione um token ou palavra-passe e clique em Ligar.", + failed: + "Falha na autenticação. Copie novamente um URL com token utilizando {command}, ou atualize o token e clique em Ligar.", + }, + pairing: { + hint: "Este dispositivo necessita de aprovação de emparelhamento do anfitrião do gateway.", + mobileHint: + "No telemóvel? Copie o URL completo (incluindo #token=...) executando openclaw dashboard --no-open no computador.", + }, + insecure: { + hint: "Esta página é HTTP, pelo que o navegador bloqueia a identidade do dispositivo. Utilize HTTPS (Tailscale Serve) ou abra {url} no anfitrião do gateway.", + stayHttp: "Se precisar de permanecer em HTTP, defina {config} (apenas token).", + }, + }, + chat: { + disconnected: "Desligado do gateway.", + refreshTitle: "Atualizar dados do chat", + thinkingToggle: "Alternar saída de pensamento/trabalho do assistente", + focusToggle: "Alternar modo de foco (ocultar barra lateral + cabeçalho da página)", + onboardingDisabled: "Desativado durante a integração", + }, + languages: { + en: "English", + zhCN: "简体中文 (Chinês Simplificado)", + zhTW: "繁體中文 (Chinês Tradicional)", + ptBR: "Português (Português do Brasil)", + ptPT: "Português (Português Europeu)", + esAR: "Español (Espanhol Argentino)", + }, +}; diff --git a/ui/src/i18n/locales/zh-CN.ts b/ui/src/i18n/locales/zh-CN.ts index f6c7ce38c85..07ff0872701 100644 --- a/ui/src/i18n/locales/zh-CN.ts +++ b/ui/src/i18n/locales/zh-CN.ts @@ -117,5 +117,6 @@ export const zh_CN: TranslationMap = { zhCN: "简体中文 (简体中文)", zhTW: "繁體中文 (繁体中文)", ptBR: "Português (巴西葡萄牙语)", + de: "Deutsch (德语)", }, }; diff --git a/ui/src/i18n/locales/zh-TW.ts b/ui/src/i18n/locales/zh-TW.ts index 52f39b92398..8e60f3c917e 100644 --- a/ui/src/i18n/locales/zh-TW.ts +++ b/ui/src/i18n/locales/zh-TW.ts @@ -117,5 +117,6 @@ export const zh_TW: TranslationMap = { zhCN: "简体中文 (簡體中文)", zhTW: "繁體中文 (繁體中文)", ptBR: "Português (巴西葡萄牙語)", + de: "Deutsch (德語)", }, }; diff --git a/ui/src/ui/views/overview.ts b/ui/src/ui/views/overview.ts index 3c341df473b..b559fba4dab 100644 --- a/ui/src/ui/views/overview.ts +++ b/ui/src/ui/views/overview.ts @@ -1,6 +1,6 @@ import { html } from "lit"; import { ConnectErrorDetailCodes } from "../../../../src/gateway/protocol/connect-error-details.js"; -import { t, i18n, type Locale } from "../../i18n/index.ts"; +import { t, i18n, SUPPORTED_LOCALES, type Locale } from "../../i18n/index.ts"; import { buildExternalLinkRel, EXTERNAL_LINK_TARGET } from "../external-link.ts"; import { formatRelativeTimestamp, formatDurationHuman } from "../format.ts"; import type { GatewayHelloOk } from "../gateway.ts"; @@ -259,10 +259,10 @@ export function renderOverview(props: OverviewProps) { props.onSettingsChange({ ...props.settings, locale: v }); }} > - - - - + ${SUPPORTED_LOCALES.map((loc) => { + const key = loc.replace(/-([a-zA-Z])/g, (_, c) => c.toUpperCase()); + return html``; + })}