Files
PinchChat/src/lib/i18n.ts
2026-03-04 11:45:28 +08:00

1558 lines
60 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Lightweight reactive i18n — no external deps.
*
* Locale priority: localStorage > VITE_LOCALE > navigator.language > 'en'
* Changing locale at runtime triggers subscribed React components to re-render.
*/
const STORAGE_KEY = 'pinchchat-locale';
const en = {
// Login screen
'login.title': 'PinchChat',
'login.subtitle': 'Connect to your OpenClaw gateway',
'login.gatewayUrl': 'Gateway URL',
'login.token': 'Token',
'login.tokenPlaceholder': 'Enter your gateway token',
'login.authToken': 'Token',
'login.authPassword': 'Password',
'login.password': 'Password',
'login.passwordPlaceholder': 'Enter your gateway password',
'login.connect': 'Connect',
'login.connecting': 'Connecting…',
'login.showToken': 'Show token',
'login.hideToken': 'Hide token',
'login.storedLocally': 'Credentials are stored locally in your browser',
'login.wsHint': 'URL must start with ws:// or wss://',
'login.advanced': 'Advanced',
'login.clientId': 'Client ID',
'login.clientIdHint': 'Sent in the WebSocket connect frame. Default: webchat',
// Header
'header.title': 'PinchChat',
'header.connected': 'Connected',
'header.disconnected': 'Disconnected',
'header.logout': 'Logout',
'header.toggleSidebar': 'Toggle sidebar',
'header.changeLanguage': 'Change language',
'header.soundOn': 'Enable notification sound',
'header.soundOff': 'Disable notification sound',
// Chat
'chat.welcome': 'PinchChat',
'chat.welcomeSub': 'Send a message to get started',
'chat.suggestions': 'Try asking...',
'chat.suggestion1': 'Summarize my recent emails',
'chat.suggestion2': "What's on my calendar today?",
'chat.suggestion3': 'Search the web for latest news',
'chat.suggestion4': 'Help me write a script',
'chat.loadingHistory': 'Loading messages…',
'chat.inputPlaceholder': 'Type a message…',
'chat.inputLabel': 'Message',
'chat.attachFile': 'Attach file',
'chat.send': 'Send',
'chat.stop': 'Stop',
'chat.showPreview': 'Preview markdown',
'chat.hidePreview': 'Hide preview',
'chat.scrollToBottom': 'New messages',
'chat.scrollDown': 'Scroll to bottom',
'chat.collapseTools': 'Collapse all tools',
'chat.expandTools': 'Expand all tools',
'chat.messages': 'Chat messages',
'chat.thinking': 'Thinking…',
// Sidebar
'sidebar.title': 'Sessions',
'sidebar.empty': 'No sessions',
'sidebar.search': 'Search sessions…',
'sidebar.noResults': 'No matching sessions',
'sidebar.pin': 'Pin session',
'sidebar.unpin': 'Unpin session',
'sidebar.pinned': 'Pinned',
'sidebar.delete': 'Delete session',
'sidebar.rename': 'Rename session',
'sidebar.deleteConfirm': 'Delete this session? This cannot be undone.',
'sidebar.deleteCancel': 'Cancel',
'sidebar.openSplit': 'Open in split view',
'sidebar.close': 'Close sidebar',
'sidebar.clearSearch': 'Clear search',
'sidebar.filterAll': 'All',
'sidebar.filterActive': 'Active',
'split.close': 'Close split view',
'app.mainChat': 'Main chat',
'app.splitPane': 'Split pane',
'app.skipToChat': 'Skip to chat input',
// Thinking
'thinking.label': 'Thinking',
'thinking.reasoning': 'Reasoning…',
// Tool call
'tool.parameters': 'Parameters',
'tool.result': 'Result',
// Connection banner
'connection.reconnecting': 'Connection lost — reconnecting…',
'connection.reconnected': 'Reconnected!',
'connection.pairing': 'Device pairing pending — run `openclaw devices approve` on your gateway',
// Message actions
'message.copy': 'Copy message',
'message.copied': 'Copied!',
'message.retry': 'Resend message',
'message.showMore': 'Show more',
'message.showLess': 'Show less',
'message.metadata': 'Message details',
'message.rawJson': 'Raw JSON',
'message.hideRawJson': 'Hide raw JSON',
// Timestamps
'time.yesterday': 'Yesterday',
'time.today': 'Today',
// Keyboard shortcuts
'shortcuts.title': 'Keyboard Shortcuts',
'shortcuts.send': 'Send message',
'shortcuts.newline': 'New line',
'shortcuts.search': 'Search sessions',
'shortcuts.switchSession': 'Previous / next session',
'shortcuts.closeSidebar': 'Close sidebar / search',
'shortcuts.stop': 'Stop generation',
'shortcuts.help': 'Show shortcuts',
'shortcuts.close': 'Close',
'shortcuts.chatSection': 'Chat',
// Error boundary
'error.title': 'Something went wrong',
'error.description': 'An unexpected error occurred while rendering the interface. You can try again or reload the page.',
'error.retry': 'Try again',
'error.reload': 'Reload page',
'shortcuts.navigationSection': 'Navigation',
'shortcuts.generalSection': 'General',
// Export
'header.export': 'Export conversation as Markdown',
'header.compact': 'Compact',
'header.compacting': 'Compacting…',
'header.sessionInfo': 'Session Info',
'sessionInfo.sessionKey': 'Session Key',
'sessionInfo.channel': 'Channel',
'sessionInfo.kind': 'Kind',
'sessionInfo.model': 'Model',
'sessionInfo.agent': 'Agent',
'sessionInfo.messages': 'Messages',
'sessionInfo.totalTokens': 'Total Tokens',
'sessionInfo.inputTokens': 'Input',
'sessionInfo.outputTokens': 'Output',
'sessionInfo.contextWindow': 'Context',
'sessionInfo.lastActive': 'Last Active',
// Theme
'theme.title': 'Theme',
'theme.mode': 'Mode',
'theme.accent': 'Accent',
'theme.system': 'System',
'theme.dark': 'Dark',
'theme.light': 'Light',
'theme.oled': 'OLED',
// Message search
'search.placeholder': 'Search messages…',
'search.noResults': '0 results',
'search.prev': 'Previous match',
'search.next': 'Next match',
'shortcuts.searchMessages': 'Search messages',
// Send shortcut setting
'settings.title': 'Settings',
'settings.appearance': 'Appearance',
'settings.typography': 'Typography',
'settings.chat': 'Chat',
'settings.notifications': 'Notifications',
'settings.notificationSound': 'Notification sound',
'settings.language': 'Language',
'settings.sendShortcut': 'Send with',
'settings.sendEnter': 'Enter',
'settings.sendCtrlEnter': 'Ctrl+Enter',
'settings.tab.appearance': 'Appearance',
'settings.tab.typography': 'Typography',
'settings.tab.chat': 'Chat',
'settings.tab.notifications': 'Notifications',
'settings.fontUi': 'UI font',
'settings.fontMono': 'Code font',
'settings.fontSize': 'UI font size',
'settings.fontMonoSize': 'Code font size',
'settings.preview': 'Preview',
'settings.previewText': 'The quick brown fox jumps over the lazy dog — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira load automatically; Cascadia and SF use your system if installed.',
// Bookmarks
'message.bookmark': 'Bookmark message',
'message.removeBookmark': 'Remove bookmark',
'message.reply': 'Reply',
'chat.replyingTo': 'Replying to',
'chat.bookmarks': 'Bookmarks',
'chat.export': 'Export conversation',
'chat.contextCompacted': 'Context compacted — older messages cached locally',
'slash.commands': 'Commands',
'slash.status': 'Show session status & usage',
'slash.reasoning': 'Toggle reasoning mode',
'slash.verbose': 'Toggle verbose output',
'slash.model': 'Switch model for this session',
'slash.compact': 'Compact conversation context',
'slash.reset': 'Reset the session',
'slash.new': 'Create a new chat session',
'slash.help': 'Show available commands',
} as const;
const fr: Record<keyof typeof en, string> = {
'login.title': 'PinchChat',
'login.subtitle': 'Connectez-vous à votre gateway OpenClaw',
'login.gatewayUrl': 'URL de la gateway',
'login.token': 'Token',
'login.tokenPlaceholder': 'Entrez votre token gateway',
'login.authToken': 'Token',
'login.authPassword': 'Mot de passe',
'login.password': 'Mot de passe',
'login.passwordPlaceholder': 'Entrez votre mot de passe gateway',
'login.connect': 'Connexion',
'login.connecting': 'Connexion…',
'login.showToken': 'Afficher le token',
'login.hideToken': 'Masquer le token',
'login.storedLocally': 'Les identifiants sont stockés localement dans votre navigateur',
'login.wsHint': 'L\'URL doit commencer par ws:// ou wss://',
'login.advanced': 'Avancé',
'login.clientId': 'ID client',
'login.clientIdHint': 'Envoyé dans la trame de connexion WebSocket. Par défaut : webchat',
'header.title': 'PinchChat',
'header.connected': 'Connecté',
'header.disconnected': 'Déconnecté',
'header.logout': 'Déconnexion',
'header.toggleSidebar': 'Afficher/masquer la barre latérale',
'header.changeLanguage': 'Changer de langue',
'header.soundOn': 'Activer le son de notification',
'header.soundOff': 'Désactiver le son de notification',
'chat.welcome': 'PinchChat',
'chat.welcomeSub': 'Envoyez un message pour commencer',
'chat.suggestions': 'Essayez par exemple...',
'chat.suggestion1': 'Résume mes derniers emails',
'chat.suggestion2': "Qu'est-ce que j'ai au calendrier aujourd'hui ?",
'chat.suggestion3': 'Cherche sur le web les dernières actus',
'chat.suggestion4': "Aide-moi à écrire un script",
'chat.loadingHistory': 'Chargement des messages…',
'chat.inputPlaceholder': 'Tapez un message…',
'chat.inputLabel': 'Message',
'chat.attachFile': 'Joindre un fichier',
'chat.send': 'Envoyer',
'chat.stop': 'Arrêter',
'chat.showPreview': 'Aperçu markdown',
'chat.hidePreview': 'Masquer l\'aperçu',
'chat.scrollToBottom': 'Nouveaux messages',
'chat.scrollDown': 'Défiler en bas',
'chat.collapseTools': 'Replier tous les outils',
'chat.expandTools': 'Déplier tous les outils',
'chat.messages': 'Messages du chat',
'chat.thinking': 'Réflexion…',
'sidebar.title': 'Sessions',
'sidebar.empty': 'Aucune session',
'sidebar.search': 'Rechercher…',
'sidebar.noResults': 'Aucun résultat',
'sidebar.pin': 'Épingler la session',
'sidebar.unpin': 'Désépingler la session',
'sidebar.pinned': 'Épinglées',
'sidebar.delete': 'Supprimer la session',
'sidebar.rename': 'Renommer la session',
'sidebar.deleteConfirm': 'Supprimer cette session ? Cette action est irréversible.',
'sidebar.deleteCancel': 'Annuler',
'sidebar.openSplit': 'Ouvrir en vue scindée',
'sidebar.close': 'Fermer la barre latérale',
'sidebar.clearSearch': 'Effacer la recherche',
'sidebar.filterAll': 'Tout',
'sidebar.filterActive': 'Actives',
'split.close': 'Fermer la vue scindée',
'app.mainChat': 'Chat principal',
'app.splitPane': 'Volet scindé',
'app.skipToChat': 'Aller au champ de saisie',
'thinking.label': 'Réflexion',
'thinking.reasoning': 'Réflexion…',
'tool.parameters': 'Paramètres',
'tool.result': 'Résultat',
'connection.reconnecting': 'Connexion perdue — reconnexion…',
'connection.reconnected': 'Reconnecté !',
'connection.pairing': 'Appairage en attente — exécutez `openclaw devices approve` sur votre gateway',
'message.copy': 'Copier le message',
'message.copied': 'Copié !',
'message.retry': 'Renvoyer le message',
'message.showMore': 'Afficher plus',
'message.showLess': 'Afficher moins',
'message.metadata': 'Détails du message',
'message.rawJson': 'JSON brut',
'message.hideRawJson': 'Masquer le JSON brut',
'time.yesterday': 'Hier',
'time.today': "Aujourd'hui",
'shortcuts.title': 'Raccourcis clavier',
'shortcuts.send': 'Envoyer le message',
'shortcuts.newline': 'Nouvelle ligne',
'shortcuts.search': 'Rechercher des sessions',
'shortcuts.switchSession': 'Session précédente / suivante',
'shortcuts.closeSidebar': 'Fermer la barre / recherche',
'shortcuts.stop': 'Arrêter la génération',
'shortcuts.help': 'Afficher les raccourcis',
'shortcuts.close': 'Fermer',
'shortcuts.chatSection': 'Chat',
'error.title': 'Quelque chose s\'est mal passé',
'error.description': 'Une erreur inattendue est survenue lors de l\'affichage. Vous pouvez réessayer ou recharger la page.',
'error.retry': 'Réessayer',
'error.reload': 'Recharger',
'shortcuts.navigationSection': 'Navigation',
'shortcuts.generalSection': 'Général',
'header.export': 'Exporter la conversation en Markdown',
'header.compact': 'Compacter',
'header.compacting': 'Compaction…',
'header.sessionInfo': 'Infos session',
'sessionInfo.sessionKey': 'Clé session',
'sessionInfo.channel': 'Canal',
'sessionInfo.kind': 'Type',
'sessionInfo.model': 'Modèle',
'sessionInfo.agent': 'Agent',
'sessionInfo.messages': 'Messages',
'sessionInfo.totalTokens': 'Tokens total',
'sessionInfo.inputTokens': 'Entrée',
'sessionInfo.outputTokens': 'Sortie',
'sessionInfo.contextWindow': 'Contexte',
'sessionInfo.lastActive': 'Dernière activité',
'theme.title': 'Thème',
'theme.mode': 'Mode',
'theme.accent': 'Accent',
'theme.system': 'Système',
'theme.dark': 'Sombre',
'theme.light': 'Clair',
'theme.oled': 'OLED',
'search.placeholder': 'Rechercher dans les messages…',
'search.noResults': '0 résultat',
'search.prev': 'Résultat précédent',
'search.next': 'Résultat suivant',
'shortcuts.searchMessages': 'Rechercher dans les messages',
'settings.title': 'Paramètres',
'settings.appearance': 'Apparence',
'settings.typography': 'Typographie',
'settings.chat': 'Chat',
'settings.notifications': 'Notifications',
'settings.notificationSound': 'Son de notification',
'settings.language': 'Langue',
'settings.sendShortcut': 'Envoyer avec',
'settings.sendEnter': 'Entrée',
'settings.sendCtrlEnter': 'Ctrl+Entrée',
'settings.tab.appearance': 'Apparence',
'settings.tab.typography': 'Typographie',
'settings.tab.chat': 'Chat',
'settings.tab.notifications': 'Notifications',
'settings.fontUi': 'Police UI',
'settings.fontMono': 'Police code',
'settings.fontSize': 'Taille police UI',
'settings.fontMonoSize': 'Taille police code',
'settings.preview': 'Aperçu',
'settings.previewText': 'Le vif renard brun saute par-dessus le chien paresseux — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira se chargent automatiquement ; Cascadia et SF dépendent des polices installées.',
'message.bookmark': 'Marquer le message',
'message.removeBookmark': 'Retirer le marque-page',
'message.reply': 'Répondre',
'chat.replyingTo': 'En réponse à',
'chat.bookmarks': 'Marque-pages',
'chat.export': 'Exporter la conversation',
'chat.contextCompacted': 'Contexte compacté — anciens messages en cache local',
'slash.commands': 'Commandes',
'slash.status': 'Afficher le statut et l\'utilisation',
'slash.reasoning': 'Activer/désactiver le raisonnement',
'slash.verbose': 'Activer/désactiver le mode verbeux',
'slash.model': 'Changer de modèle pour cette session',
'slash.compact': 'Compacter le contexte',
'slash.reset': 'Réinitialiser la session',
'slash.new': 'Créer une nouvelle session de chat',
'slash.help': 'Afficher les commandes disponibles',
};
const es: Record<keyof typeof en, string> = {
'login.title': 'PinchChat',
'login.subtitle': 'Conéctate a tu gateway OpenClaw',
'login.gatewayUrl': 'URL del gateway',
'login.token': 'Token',
'login.tokenPlaceholder': 'Introduce tu token de gateway',
'login.authToken': 'Token',
'login.authPassword': 'Contraseña',
'login.password': 'Contraseña',
'login.passwordPlaceholder': 'Introduce tu contraseña de gateway',
'login.connect': 'Conectar',
'login.connecting': 'Conectando…',
'login.showToken': 'Mostrar token',
'login.hideToken': 'Ocultar token',
'login.storedLocally': 'Las credenciales se guardan localmente en tu navegador',
'login.wsHint': 'La URL debe empezar con ws:// o wss://',
'login.advanced': 'Avanzado',
'login.clientId': 'ID de cliente',
'login.clientIdHint': 'Enviado en la trama de conexión WebSocket. Por defecto: webchat',
'header.title': 'PinchChat',
'header.connected': 'Conectado',
'header.disconnected': 'Desconectado',
'header.logout': 'Cerrar sesión',
'header.toggleSidebar': 'Mostrar/ocultar barra lateral',
'header.changeLanguage': 'Cambiar idioma',
'header.soundOn': 'Activar sonido de notificación',
'header.soundOff': 'Desactivar sonido de notificación',
'chat.welcome': 'PinchChat',
'chat.welcomeSub': 'Envía un mensaje para comenzar',
'chat.suggestions': 'Prueba a preguntar...',
'chat.suggestion1': 'Resume mis últimos correos',
'chat.suggestion2': '¿Qué tengo en el calendario hoy?',
'chat.suggestion3': 'Busca en la web las últimas noticias',
'chat.suggestion4': 'Ayúdame a escribir un script',
'chat.loadingHistory': 'Cargando mensajes…',
'chat.inputPlaceholder': 'Escribe un mensaje…',
'chat.inputLabel': 'Mensaje',
'chat.attachFile': 'Adjuntar archivo',
'chat.send': 'Enviar',
'chat.stop': 'Detener',
'chat.showPreview': 'Vista previa markdown',
'chat.hidePreview': 'Ocultar vista previa',
'chat.scrollToBottom': 'Nuevos mensajes',
'chat.scrollDown': 'Ir al final',
'chat.collapseTools': 'Contraer todas las herramientas',
'chat.expandTools': 'Expandir todas las herramientas',
'chat.messages': 'Mensajes del chat',
'chat.thinking': 'Pensando…',
'sidebar.title': 'Sesiones',
'sidebar.empty': 'Sin sesiones',
'sidebar.search': 'Buscar sesiones…',
'sidebar.noResults': 'Sin resultados',
'sidebar.pin': 'Fijar sesión',
'sidebar.unpin': 'Desfijar sesión',
'sidebar.pinned': 'Fijadas',
'sidebar.delete': 'Eliminar sesión',
'sidebar.rename': 'Renombrar sesión',
'sidebar.deleteConfirm': '¿Eliminar esta sesión? Esta acción no se puede deshacer.',
'sidebar.deleteCancel': 'Cancelar',
'sidebar.openSplit': 'Abrir en vista dividida',
'sidebar.close': 'Cerrar barra lateral',
'sidebar.clearSearch': 'Limpiar búsqueda',
'sidebar.filterAll': 'Todas',
'sidebar.filterActive': 'Activas',
'split.close': 'Cerrar vista dividida',
'app.mainChat': 'Chat principal',
'app.splitPane': 'Panel dividido',
'app.skipToChat': 'Ir al campo de entrada',
'thinking.label': 'Pensamiento',
'thinking.reasoning': 'Razonando…',
'tool.parameters': 'Parámetros',
'tool.result': 'Resultado',
'connection.reconnecting': 'Conexión perdida — reconectando…',
'connection.reconnected': '¡Reconectado!',
'connection.pairing': 'Emparejamiento pendiente — ejecute `openclaw devices approve` en su gateway',
'message.copy': 'Copiar mensaje',
'message.copied': '¡Copiado!',
'message.retry': 'Reenviar mensaje',
'message.showMore': 'Ver más',
'message.showLess': 'Ver menos',
'message.metadata': 'Detalles del mensaje',
'message.rawJson': 'JSON sin formato',
'message.hideRawJson': 'Ocultar JSON sin formato',
'time.yesterday': 'Ayer',
'time.today': 'Hoy',
'shortcuts.title': 'Atajos de teclado',
'shortcuts.send': 'Enviar mensaje',
'shortcuts.newline': 'Nueva línea',
'shortcuts.search': 'Buscar sesiones',
'shortcuts.switchSession': 'Sesión anterior / siguiente',
'shortcuts.closeSidebar': 'Cerrar barra / búsqueda',
'shortcuts.stop': 'Detener generación',
'shortcuts.help': 'Mostrar atajos',
'shortcuts.close': 'Cerrar',
'shortcuts.chatSection': 'Chat',
'error.title': 'Algo salió mal',
'error.description': 'Ocurrió un error inesperado al mostrar la interfaz. Puedes intentar de nuevo o recargar la página.',
'error.retry': 'Reintentar',
'error.reload': 'Recargar página',
'shortcuts.navigationSection': 'Navegación',
'shortcuts.generalSection': 'General',
'header.export': 'Exportar conversación como Markdown',
'header.compact': 'Compactar',
'header.compacting': 'Compactando…',
'header.sessionInfo': 'Info de sesión',
'sessionInfo.sessionKey': 'Clave de sesión',
'sessionInfo.channel': 'Canal',
'sessionInfo.kind': 'Tipo',
'sessionInfo.model': 'Modelo',
'sessionInfo.agent': 'Agente',
'sessionInfo.messages': 'Mensajes',
'sessionInfo.totalTokens': 'Tokens totales',
'sessionInfo.inputTokens': 'Entrada',
'sessionInfo.outputTokens': 'Salida',
'sessionInfo.contextWindow': 'Contexto',
'sessionInfo.lastActive': 'Última actividad',
'theme.title': 'Tema',
'theme.mode': 'Modo',
'theme.accent': 'Acento',
'theme.system': 'Sistema',
'theme.dark': 'Oscuro',
'theme.light': 'Claro',
'theme.oled': 'OLED',
'search.placeholder': 'Buscar en mensajes…',
'search.noResults': '0 resultados',
'search.prev': 'Resultado anterior',
'search.next': 'Resultado siguiente',
'shortcuts.searchMessages': 'Buscar en mensajes',
'settings.title': 'Ajustes',
'settings.appearance': 'Apariencia',
'settings.typography': 'Tipografía',
'settings.chat': 'Chat',
'settings.notifications': 'Notificaciones',
'settings.notificationSound': 'Sonido de notificación',
'settings.language': 'Idioma',
'settings.sendShortcut': 'Enviar con',
'settings.sendEnter': 'Enter',
'settings.sendCtrlEnter': 'Ctrl+Enter',
'settings.tab.appearance': 'Apariencia',
'settings.tab.typography': 'Tipografía',
'settings.tab.chat': 'Chat',
'settings.tab.notifications': 'Notificaciones',
'settings.fontUi': 'Fuente UI',
'settings.fontMono': 'Fuente de código',
'settings.fontSize': 'Tamaño fuente UI',
'settings.fontMonoSize': 'Tamaño fuente código',
'settings.preview': 'Vista previa',
'settings.previewText': 'El veloz zorro marrón salta sobre el perro perezoso — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira se cargan automáticamente; Cascadia y SF dependen de que estén instaladas.',
'message.bookmark': 'Marcar mensaje',
'message.removeBookmark': 'Quitar marcador',
'message.reply': 'Responder',
'chat.replyingTo': 'Respondiendo a',
'chat.bookmarks': 'Marcadores',
'chat.export': 'Exportar conversación',
'chat.contextCompacted': 'Contexto compactado — mensajes anteriores en caché local',
'slash.commands': 'Comandos',
'slash.status': 'Mostrar estado y uso de la sesión',
'slash.reasoning': 'Activar/desactivar razonamiento',
'slash.verbose': 'Activar/desactivar modo detallado',
'slash.model': 'Cambiar modelo para esta sesión',
'slash.compact': 'Compactar contexto de conversación',
'slash.reset': 'Reiniciar la sesión',
'slash.new': 'Crear una nueva sesión de chat',
'slash.help': 'Mostrar comandos disponibles',
};
export type TranslationKey = keyof typeof en;
const de: Record<keyof typeof en, string> = {
'login.title': 'PinchChat',
'login.subtitle': 'Mit deinem OpenClaw-Gateway verbinden',
'login.gatewayUrl': 'Gateway-URL',
'login.token': 'Token',
'login.tokenPlaceholder': 'Gateway-Token eingeben',
'login.authToken': 'Token',
'login.authPassword': 'Passwort',
'login.password': 'Passwort',
'login.passwordPlaceholder': 'Gateway-Passwort eingeben',
'login.connect': 'Verbinden',
'login.connecting': 'Verbinde…',
'login.showToken': 'Token anzeigen',
'login.hideToken': 'Token verbergen',
'login.storedLocally': 'Zugangsdaten werden lokal in deinem Browser gespeichert',
'login.wsHint': 'URL muss mit ws:// oder wss:// beginnen',
'login.advanced': 'Erweitert',
'login.clientId': 'Client-ID',
'login.clientIdHint': 'Wird im WebSocket-Connect-Frame gesendet. Standard: webchat',
'header.title': 'PinchChat',
'header.connected': 'Verbunden',
'header.disconnected': 'Getrennt',
'header.logout': 'Abmelden',
'header.toggleSidebar': 'Seitenleiste ein-/ausblenden',
'header.changeLanguage': 'Sprache ändern',
'header.soundOn': 'Benachrichtigungston aktivieren',
'header.soundOff': 'Benachrichtigungston deaktivieren',
'chat.welcome': 'PinchChat',
'chat.welcomeSub': 'Sende eine Nachricht, um zu beginnen',
'chat.suggestions': 'Probiere z.\u00a0B. …',
'chat.suggestion1': 'Fasse meine letzten E-Mails zusammen',
'chat.suggestion2': 'Was steht heute in meinem Kalender?',
'chat.suggestion3': 'Suche im Web nach aktuellen Nachrichten',
'chat.suggestion4': 'Hilf mir, ein Skript zu schreiben',
'chat.loadingHistory': 'Nachrichten werden geladen…',
'chat.inputPlaceholder': 'Nachricht eingeben…',
'chat.inputLabel': 'Nachricht',
'chat.attachFile': 'Datei anhängen',
'chat.send': 'Senden',
'chat.stop': 'Stoppen',
'chat.showPreview': 'Markdown-Vorschau',
'chat.hidePreview': 'Vorschau ausblenden',
'chat.scrollToBottom': 'Neue Nachrichten',
'chat.scrollDown': 'Nach unten scrollen',
'chat.collapseTools': 'Alle Tools einklappen',
'chat.expandTools': 'Alle Tools ausklappen',
'chat.messages': 'Chat-Nachrichten',
'chat.thinking': 'Denkt nach…',
'sidebar.title': 'Sitzungen',
'sidebar.empty': 'Keine Sitzungen',
'sidebar.search': 'Sitzungen suchen…',
'sidebar.noResults': 'Keine Treffer',
'sidebar.pin': 'Sitzung anheften',
'sidebar.unpin': 'Sitzung lösen',
'sidebar.pinned': 'Angeheftet',
'sidebar.delete': 'Sitzung löschen',
'sidebar.rename': 'Sitzung umbenennen',
'sidebar.deleteConfirm': 'Diese Sitzung löschen? Dies kann nicht rückgängig gemacht werden.',
'sidebar.deleteCancel': 'Abbrechen',
'sidebar.openSplit': 'In geteilter Ansicht öffnen',
'sidebar.close': 'Seitenleiste schließen',
'sidebar.clearSearch': 'Suche leeren',
'sidebar.filterAll': 'Alle',
'sidebar.filterActive': 'Aktive',
'split.close': 'Geteilte Ansicht schließen',
'app.mainChat': 'Haupt-Chat',
'app.splitPane': 'Geteiltes Fenster',
'app.skipToChat': 'Zum Eingabefeld springen',
'thinking.label': 'Nachdenken',
'thinking.reasoning': 'Denkt nach…',
'tool.parameters': 'Parameter',
'tool.result': 'Ergebnis',
'connection.reconnecting': 'Verbindung verloren — wird wiederhergestellt…',
'connection.reconnected': 'Wieder verbunden!',
'connection.pairing': 'Gerätekopplung ausstehend — führen Sie `openclaw devices approve` auf Ihrem Gateway aus',
'message.copy': 'Nachricht kopieren',
'message.copied': 'Kopiert!',
'message.retry': 'Nachricht erneut senden',
'message.showMore': 'Mehr anzeigen',
'message.showLess': 'Weniger anzeigen',
'message.metadata': 'Nachrichtendetails',
'message.rawJson': 'Roh-JSON',
'message.hideRawJson': 'Roh-JSON ausblenden',
'time.yesterday': 'Gestern',
'time.today': 'Heute',
'shortcuts.title': 'Tastenkürzel',
'shortcuts.send': 'Nachricht senden',
'shortcuts.newline': 'Neue Zeile',
'shortcuts.search': 'Sitzungen suchen',
'shortcuts.switchSession': 'Vorherige / nächste Sitzung',
'shortcuts.closeSidebar': 'Seitenleiste / Suche schließen',
'shortcuts.stop': 'Generierung stoppen',
'shortcuts.help': 'Tastenkürzel anzeigen',
'shortcuts.close': 'Schließen',
'shortcuts.chatSection': 'Chat',
'error.title': 'Etwas ist schiefgelaufen',
'error.description': 'Beim Rendern der Oberfläche ist ein unerwarteter Fehler aufgetreten. Du kannst es erneut versuchen oder die Seite neu laden.',
'error.retry': 'Erneut versuchen',
'error.reload': 'Seite neu laden',
'shortcuts.navigationSection': 'Navigation',
'shortcuts.generalSection': 'Allgemein',
'header.export': 'Unterhaltung als Markdown exportieren',
'header.compact': 'Kompaktieren',
'header.compacting': 'Kompaktiere…',
'header.sessionInfo': 'Sitzungsinfo',
'sessionInfo.sessionKey': 'Sitzungsschlüssel',
'sessionInfo.channel': 'Kanal',
'sessionInfo.kind': 'Typ',
'sessionInfo.model': 'Modell',
'sessionInfo.agent': 'Agent',
'sessionInfo.messages': 'Nachrichten',
'sessionInfo.totalTokens': 'Tokens gesamt',
'sessionInfo.inputTokens': 'Eingabe',
'sessionInfo.outputTokens': 'Ausgabe',
'sessionInfo.contextWindow': 'Kontext',
'sessionInfo.lastActive': 'Letzte Aktivität',
'theme.title': 'Design',
'theme.mode': 'Modus',
'theme.accent': 'Akzent',
'theme.system': 'System',
'theme.dark': 'Dunkel',
'theme.light': 'Hell',
'theme.oled': 'OLED',
'search.placeholder': 'In Nachrichten suchen…',
'search.noResults': '0 Ergebnisse',
'search.prev': 'Vorheriger Treffer',
'search.next': 'Nächster Treffer',
'shortcuts.searchMessages': 'In Nachrichten suchen',
'settings.title': 'Einstellungen',
'settings.appearance': 'Darstellung',
'settings.typography': 'Typografie',
'settings.chat': 'Chat',
'settings.notifications': 'Benachrichtigungen',
'settings.notificationSound': 'Benachrichtigungston',
'settings.language': 'Sprache',
'settings.sendShortcut': 'Senden mit',
'settings.sendEnter': 'Enter',
'settings.sendCtrlEnter': 'Strg+Enter',
'settings.tab.appearance': 'Darstellung',
'settings.tab.typography': 'Typografie',
'settings.tab.chat': 'Chat',
'settings.tab.notifications': 'Benachrichtigungen',
'settings.fontUi': 'UI-Schriftart',
'settings.fontMono': 'Code-Schriftart',
'settings.fontSize': 'UI-Schriftgröße',
'settings.fontMonoSize': 'Code-Schriftgröße',
'settings.preview': 'Vorschau',
'settings.previewText': 'Falsches Üben von Xylophonmusik quält jeden größeren Zwerg — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira werden automatisch geladen; Cascadia und SF erfordern Systeminstallation.',
'message.bookmark': 'Nachricht markieren',
'message.reply': 'Antworten',
'chat.replyingTo': 'Antwort auf',
'message.removeBookmark': 'Lesezeichen entfernen',
'chat.bookmarks': 'Lesezeichen',
'chat.export': 'Unterhaltung exportieren',
'chat.contextCompacted': 'Kontext kompaktiert — ältere Nachrichten lokal zwischengespeichert',
'slash.commands': 'Befehle',
'slash.status': 'Sitzungsstatus und Nutzung anzeigen',
'slash.reasoning': 'Reasoning-Modus umschalten',
'slash.verbose': 'Ausführliche Ausgabe umschalten',
'slash.model': 'Modell für diese Sitzung wechseln',
'slash.compact': 'Gesprächskontext kompaktieren',
'slash.reset': 'Sitzung zurücksetzen',
'slash.new': 'Neue Chat-Sitzung erstellen',
'slash.help': 'Verfügbare Befehle anzeigen',
};
const ja: Record<keyof typeof en, string> = {
'login.title': 'PinchChat',
'login.subtitle': 'OpenClawゲートウェイに接続',
'login.gatewayUrl': 'ゲートウェイURL',
'login.token': 'トークン',
'login.tokenPlaceholder': 'ゲートウェイトークンを入力',
'login.authToken': 'トークン',
'login.authPassword': 'パスワード',
'login.password': 'パスワード',
'login.passwordPlaceholder': 'ゲートウェイパスワードを入力',
'login.connect': '接続',
'login.connecting': '接続中…',
'login.showToken': 'トークンを表示',
'login.hideToken': 'トークンを非表示',
'login.storedLocally': '認証情報はブラウザにローカル保存されます',
'login.wsHint': 'URLはws://またはwss://で始まる必要があります',
'login.advanced': '詳細設定',
'login.clientId': 'クライアントID',
'login.clientIdHint': 'WebSocket接続フレームで送信されます。デフォルト: webchat',
'header.title': 'PinchChat',
'header.connected': '接続済み',
'header.disconnected': '切断',
'header.logout': 'ログアウト',
'header.toggleSidebar': 'サイドバーの表示切替',
'header.changeLanguage': '言語を変更',
'header.soundOn': '通知音を有効にする',
'header.soundOff': '通知音を無効にする',
'chat.welcome': 'PinchChat',
'chat.welcomeSub': 'メッセージを送信して始めましょう',
'chat.suggestions': '例えば…',
'chat.suggestion1': '最近のメールをまとめて',
'chat.suggestion2': '今日のカレンダーは?',
'chat.suggestion3': '最新ニュースをウェブで検索して',
'chat.suggestion4': 'スクリプトを書くのを手伝って',
'chat.loadingHistory': 'メッセージを読み込み中…',
'chat.inputPlaceholder': 'メッセージを入力…',
'chat.inputLabel': 'メッセージ',
'chat.attachFile': 'ファイルを添付',
'chat.send': '送信',
'chat.stop': '停止',
'chat.showPreview': 'Markdownプレビュー',
'chat.hidePreview': 'プレビューを非表示',
'chat.scrollToBottom': '新しいメッセージ',
'chat.scrollDown': '一番下へスクロール',
'chat.collapseTools': 'すべてのツールを折りたたむ',
'chat.expandTools': 'すべてのツールを展開',
'chat.messages': 'チャットメッセージ',
'chat.thinking': '思考中…',
'sidebar.title': 'セッション',
'sidebar.empty': 'セッションなし',
'sidebar.search': 'セッションを検索…',
'sidebar.noResults': '結果なし',
'sidebar.pin': 'セッションをピン留め',
'sidebar.unpin': 'ピン留めを解除',
'sidebar.pinned': 'ピン留め',
'sidebar.delete': 'セッションを削除',
'sidebar.rename': 'セッション名変更',
'sidebar.deleteConfirm': 'このセッションを削除しますか?元に戻せません。',
'sidebar.deleteCancel': 'キャンセル',
'sidebar.openSplit': '分割ビューで開く',
'sidebar.close': 'サイドバーを閉じる',
'sidebar.clearSearch': '検索をクリア',
'sidebar.filterAll': 'すべて',
'sidebar.filterActive': 'アクティブ',
'split.close': '分割ビューを閉じる',
'app.mainChat': 'メインチャット',
'app.splitPane': '分割ペイン',
'app.skipToChat': '入力欄へ移動',
'thinking.label': '思考',
'thinking.reasoning': '推論中…',
'tool.parameters': 'パラメータ',
'tool.result': '結果',
'connection.reconnecting': '接続が切断されました — 再接続中…',
'connection.reconnected': '再接続しました!',
'connection.pairing': 'デバイスペアリング保留中 — ゲートウェイで `openclaw devices approve` を実行してください',
'message.copy': 'メッセージをコピー',
'message.copied': 'コピーしました!',
'message.retry': 'メッセージを再送信',
'message.showMore': 'もっと見る',
'message.showLess': '折りたたむ',
'message.metadata': 'メッセージの詳細',
'message.rawJson': '生JSON',
'message.hideRawJson': '生JSONを非表示',
'time.yesterday': '昨日',
'time.today': '今日',
'shortcuts.title': 'キーボードショートカット',
'shortcuts.send': 'メッセージを送信',
'shortcuts.newline': '改行',
'shortcuts.search': 'セッションを検索',
'shortcuts.switchSession': '前 / 次のセッション',
'shortcuts.closeSidebar': 'サイドバー / 検索を閉じる',
'shortcuts.stop': '生成を停止',
'shortcuts.help': 'ショートカットを表示',
'shortcuts.close': '閉じる',
'shortcuts.chatSection': 'チャット',
'error.title': 'エラーが発生しました',
'error.description': 'インターフェースの表示中に予期しないエラーが発生しました。再試行するかページをリロードしてください。',
'error.retry': '再試行',
'error.reload': 'ページをリロード',
'shortcuts.navigationSection': 'ナビゲーション',
'shortcuts.generalSection': '全般',
'header.export': '会話をMarkdownでエクスポート',
'header.compact': 'コンパクト化',
'header.compacting': 'コンパクト化中…',
'header.sessionInfo': 'セッション情報',
'sessionInfo.sessionKey': 'セッションキー',
'sessionInfo.channel': 'チャンネル',
'sessionInfo.kind': '種類',
'sessionInfo.model': 'モデル',
'sessionInfo.agent': 'エージェント',
'sessionInfo.messages': 'メッセージ',
'sessionInfo.totalTokens': '合計トークン',
'sessionInfo.inputTokens': '入力',
'sessionInfo.outputTokens': '出力',
'sessionInfo.contextWindow': 'コンテキスト',
'sessionInfo.lastActive': '最終アクティブ',
'theme.title': 'テーマ',
'theme.mode': 'モード',
'theme.accent': 'アクセント',
'theme.system': 'システム',
'theme.dark': 'ダーク',
'theme.light': 'ライト',
'theme.oled': 'OLED',
'search.placeholder': 'メッセージを検索…',
'search.noResults': '0件',
'search.prev': '前の結果',
'search.next': '次の結果',
'shortcuts.searchMessages': 'メッセージを検索',
'settings.title': '設定',
'settings.appearance': '外観',
'settings.typography': 'タイポグラフィ',
'settings.chat': 'チャット',
'settings.notifications': '通知',
'settings.notificationSound': '通知音',
'settings.language': '言語',
'settings.sendShortcut': '送信キー',
'settings.sendEnter': 'Enter',
'settings.sendCtrlEnter': 'Ctrl+Enter',
'settings.tab.appearance': '外観',
'settings.tab.typography': 'タイポグラフィ',
'settings.tab.chat': 'チャット',
'settings.tab.notifications': '通知',
'settings.fontUi': 'UIフォント',
'settings.fontMono': 'コードフォント',
'settings.fontSize': 'UIフォントサイズ',
'settings.fontMonoSize': 'コードフォントサイズ',
'settings.preview': 'プレビュー',
'settings.previewText': '素早い茶色の狐はのんびり犬を飛び越える — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira は自動読み込み。Cascadia と SF はシステムにある場合のみ使用。',
'message.bookmark': 'メッセージをブックマーク',
'message.reply': '返信',
'chat.replyingTo': '返信先',
'message.removeBookmark': 'ブックマークを削除',
'chat.bookmarks': 'ブックマーク',
'chat.export': '会話をエクスポート',
'chat.contextCompacted': 'コンテキストがコンパクト化されました — 古いメッセージはローカルキャッシュに保存',
'slash.commands': 'コマンド',
'slash.status': 'セッションのステータスと使用量を表示',
'slash.reasoning': '推論モードの切替',
'slash.verbose': '詳細出力の切替',
'slash.model': 'このセッションのモデルを変更',
'slash.compact': '会話コンテキストをコンパクト化',
'slash.reset': 'セッションをリセット',
'slash.new': '新しいチャットセッションを作成',
'slash.help': '利用可能なコマンドを表示',
};
const pt: Record<keyof typeof en, string> = {
'login.title': 'PinchChat',
'login.subtitle': 'Conectar ao seu gateway OpenClaw',
'login.gatewayUrl': 'URL do Gateway',
'login.token': 'Token',
'login.tokenPlaceholder': 'Insira o token do gateway',
'login.authToken': 'Token',
'login.authPassword': 'Senha',
'login.password': 'Senha',
'login.passwordPlaceholder': 'Insira a senha do gateway',
'login.connect': 'Conectar',
'login.connecting': 'Conectando…',
'login.showToken': 'Mostrar token',
'login.hideToken': 'Ocultar token',
'login.storedLocally': 'As credenciais são armazenadas localmente no navegador',
'login.wsHint': 'A URL deve começar com ws:// ou wss://',
'login.advanced': 'Avançado',
'login.clientId': 'ID do cliente',
'login.clientIdHint': 'Enviado no frame de conexão WebSocket. Padrão: webchat',
'header.title': 'PinchChat',
'header.connected': 'Conectado',
'header.disconnected': 'Desconectado',
'header.logout': 'Sair',
'header.toggleSidebar': 'Alternar barra lateral',
'header.changeLanguage': 'Alterar idioma',
'header.soundOn': 'Ativar som de notificação',
'header.soundOff': 'Desativar som de notificação',
'chat.welcome': 'PinchChat',
'chat.welcomeSub': 'Envie uma mensagem para começar',
'chat.suggestions': 'Tente perguntar…',
'chat.suggestion1': 'Resuma meus e-mails recentes',
'chat.suggestion2': 'O que há na minha agenda hoje?',
'chat.suggestion3': 'Pesquise na web as últimas notícias',
'chat.suggestion4': 'Ajude-me a escrever um script',
'chat.loadingHistory': 'Carregando mensagens…',
'chat.inputPlaceholder': 'Digite uma mensagem…',
'chat.inputLabel': 'Mensagem',
'chat.attachFile': 'Anexar arquivo',
'chat.send': 'Enviar',
'chat.stop': 'Parar',
'chat.showPreview': 'Pré-visualizar markdown',
'chat.hidePreview': 'Ocultar pré-visualização',
'chat.scrollToBottom': 'Novas mensagens',
'chat.scrollDown': 'Rolar para baixo',
'chat.collapseTools': 'Recolher todas as ferramentas',
'chat.expandTools': 'Expandir todas as ferramentas',
'chat.messages': 'Mensagens do chat',
'chat.thinking': 'Pensando…',
'sidebar.title': 'Sessões',
'sidebar.empty': 'Nenhuma sessão',
'sidebar.search': 'Pesquisar sessões…',
'sidebar.noResults': 'Nenhuma sessão encontrada',
'sidebar.pin': 'Fixar sessão',
'sidebar.unpin': 'Desafixar sessão',
'sidebar.pinned': 'Fixada',
'sidebar.delete': 'Excluir sessão',
'sidebar.rename': 'Renomear sessão',
'sidebar.deleteConfirm': 'Excluir esta sessão? Esta ação não pode ser desfeita.',
'sidebar.deleteCancel': 'Cancelar',
'sidebar.openSplit': 'Abrir em visualização dividida',
'sidebar.close': 'Fechar barra lateral',
'sidebar.clearSearch': 'Limpar pesquisa',
'sidebar.filterAll': 'Todas',
'sidebar.filterActive': 'Ativas',
'split.close': 'Fechar visualização dividida',
'app.mainChat': 'Chat principal',
'app.splitPane': 'Painel dividido',
'app.skipToChat': 'Ir para o campo de entrada',
'thinking.label': 'Pensamento',
'thinking.reasoning': 'Raciocinando…',
'tool.parameters': 'Parâmetros',
'tool.result': 'Resultado',
'connection.reconnecting': 'Conexão perdida — reconectando…',
'connection.reconnected': 'Reconectado!',
'connection.pairing': 'Emparelhamento pendente — execute `openclaw devices approve` no seu gateway',
'message.copy': 'Copiar mensagem',
'message.copied': 'Copiado!',
'message.retry': 'Reenviar mensagem',
'message.showMore': 'Ver mais',
'message.showLess': 'Ver menos',
'message.metadata': 'Detalhes da mensagem',
'message.rawJson': 'JSON bruto',
'message.hideRawJson': 'Ocultar JSON bruto',
'time.yesterday': 'Ontem',
'time.today': 'Hoje',
'shortcuts.title': 'Atalhos de teclado',
'shortcuts.send': 'Enviar mensagem',
'shortcuts.newline': 'Nova linha',
'shortcuts.search': 'Pesquisar sessões',
'shortcuts.switchSession': 'Sessão anterior / próxima',
'shortcuts.closeSidebar': 'Fechar barra lateral / pesquisa',
'shortcuts.stop': 'Parar geração',
'shortcuts.help': 'Mostrar atalhos',
'shortcuts.close': 'Fechar',
'shortcuts.chatSection': 'Chat',
'error.title': 'Algo deu errado',
'error.description': 'Ocorreu um erro inesperado ao renderizar a interface. Tente novamente ou recarregue a página.',
'error.retry': 'Tentar novamente',
'error.reload': 'Recarregar página',
'shortcuts.navigationSection': 'Navegação',
'shortcuts.generalSection': 'Geral',
'header.export': 'Exportar conversa em Markdown',
'header.compact': 'Compactar',
'header.compacting': 'Compactando…',
'header.sessionInfo': 'Informações da sessão',
'sessionInfo.sessionKey': 'Chave da sessão',
'sessionInfo.channel': 'Canal',
'sessionInfo.kind': 'Tipo',
'sessionInfo.model': 'Modelo',
'sessionInfo.agent': 'Agente',
'sessionInfo.messages': 'Mensagens',
'sessionInfo.totalTokens': 'Total de tokens',
'sessionInfo.inputTokens': 'Entrada',
'sessionInfo.outputTokens': 'Saída',
'sessionInfo.contextWindow': 'Contexto',
'sessionInfo.lastActive': 'Última atividade',
'theme.title': 'Tema',
'theme.mode': 'Modo',
'theme.accent': 'Cor de destaque',
'theme.system': 'Sistema',
'theme.dark': 'Escuro',
'theme.light': 'Claro',
'theme.oled': 'OLED',
'search.placeholder': 'Pesquisar mensagens…',
'search.noResults': '0 resultados',
'search.prev': 'Resultado anterior',
'search.next': 'Próximo resultado',
'shortcuts.searchMessages': 'Pesquisar mensagens',
'settings.title': 'Configurações',
'settings.appearance': 'Aparência',
'settings.typography': 'Tipografia',
'settings.chat': 'Chat',
'settings.notifications': 'Notificações',
'settings.notificationSound': 'Som de notificação',
'settings.language': 'Idioma',
'settings.sendShortcut': 'Tecla de envio',
'settings.sendEnter': 'Enter',
'settings.sendCtrlEnter': 'Ctrl+Enter',
'settings.tab.appearance': 'Aparência',
'settings.tab.typography': 'Tipografia',
'settings.tab.chat': 'Chat',
'settings.tab.notifications': 'Notificações',
'settings.fontUi': 'Fonte da UI',
'settings.fontMono': 'Fonte de código',
'settings.fontSize': 'Tamanho da fonte UI',
'settings.fontMonoSize': 'Tamanho da fonte de código',
'settings.preview': 'Pré-visualização',
'settings.previewText': 'A rápida raposa marrom pula sobre o cão preguiçoso — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira carregam automaticamente; Cascadia e SF dependem de estarem instaladas.',
'message.bookmark': 'Marcar mensagem',
'message.reply': 'Responder',
'chat.replyingTo': 'Respondendo a',
'message.removeBookmark': 'Remover marcador',
'chat.bookmarks': 'Marcadores',
'chat.export': 'Exportar conversa',
'chat.contextCompacted': 'Contexto compactado — mensagens antigas salvas no cache local',
'slash.commands': 'Comandos',
'slash.status': 'Mostrar status e uso da sessão',
'slash.reasoning': 'Alternar modo de raciocínio',
'slash.verbose': 'Alternar saída detalhada',
'slash.model': 'Alterar modelo desta sessão',
'slash.compact': 'Compactar contexto da conversa',
'slash.reset': 'Redefinir sessão',
'slash.new': 'Criar uma nova sessão de chat',
'slash.help': 'Mostrar comandos disponíveis',
};
const zh: Record<keyof typeof en, string> = {
'login.title': 'PinchChat',
'login.subtitle': '连接到您的 OpenClaw 网关',
'login.gatewayUrl': '网关地址',
'login.token': '令牌',
'login.tokenPlaceholder': '输入网关令牌',
'login.authToken': '令牌',
'login.authPassword': '密码',
'login.password': '密码',
'login.passwordPlaceholder': '输入网关密码',
'login.connect': '连接',
'login.connecting': '连接中…',
'login.showToken': '显示令牌',
'login.hideToken': '隐藏令牌',
'login.storedLocally': '凭据仅存储在浏览器本地',
'login.wsHint': '地址必须以 ws:// 或 wss:// 开头',
'login.advanced': '高级',
'login.clientId': '客户端 ID',
'login.clientIdHint': '在 WebSocket 连接帧中发送。默认值webchat',
'header.title': 'PinchChat',
'header.connected': '已连接',
'header.disconnected': '未连接',
'header.logout': '退出',
'header.toggleSidebar': '切换侧边栏',
'header.changeLanguage': '切换语言',
'header.soundOn': '开启通知音',
'header.soundOff': '关闭通知音',
'chat.welcome': 'PinchChat',
'chat.welcomeSub': '发送消息开始对话',
'chat.suggestions': '试试问…',
'chat.suggestion1': '总结我最近的邮件',
'chat.suggestion2': '今天的日程安排是什么?',
'chat.suggestion3': '搜索最新新闻',
'chat.suggestion4': '帮我写一个脚本',
'chat.loadingHistory': '加载消息中…',
'chat.inputPlaceholder': '输入消息…',
'chat.inputLabel': '消息',
'chat.attachFile': '添加附件',
'chat.send': '发送',
'chat.stop': '停止',
'chat.showPreview': '预览 Markdown',
'chat.hidePreview': '隐藏预览',
'chat.scrollToBottom': '新消息',
'chat.scrollDown': '滚动到底部',
'chat.collapseTools': '折叠所有工具',
'chat.expandTools': '展开所有工具',
'chat.messages': '聊天消息',
'chat.thinking': '思考中…',
'sidebar.title': '会话',
'sidebar.empty': '没有会话',
'sidebar.search': '搜索会话…',
'sidebar.noResults': '未找到匹配会话',
'sidebar.pin': '置顶会话',
'sidebar.unpin': '取消置顶',
'sidebar.pinned': '已置顶',
'sidebar.delete': '删除会话',
'sidebar.rename': '重命名会话',
'sidebar.deleteConfirm': '删除此会话?此操作无法撤消。',
'sidebar.deleteCancel': '取消',
'sidebar.openSplit': '在分屏中打开',
'sidebar.close': '关闭侧边栏',
'sidebar.clearSearch': '清除搜索',
'sidebar.filterAll': '全部',
'sidebar.filterActive': '活跃',
'split.close': '关闭分屏',
'app.mainChat': '主聊天',
'app.splitPane': '分屏面板',
'app.skipToChat': '跳转到输入框',
'thinking.label': '思考',
'thinking.reasoning': '推理中…',
'tool.parameters': '参数',
'tool.result': '结果',
'connection.reconnecting': '连接中断 — 正在重连…',
'connection.reconnected': '已重新连接!',
'connection.pairing': '设备配对待处理 — 在网关上运行 `openclaw devices approve`',
'message.copy': '复制消息',
'message.copied': '已复制!',
'message.retry': '重新发送',
'message.showMore': '展开更多',
'message.showLess': '收起',
'message.metadata': '消息详情',
'message.rawJson': '原始 JSON',
'message.hideRawJson': '隐藏原始 JSON',
'time.yesterday': '昨天',
'time.today': '今天',
'shortcuts.title': '键盘快捷键',
'shortcuts.send': '发送消息',
'shortcuts.newline': '换行',
'shortcuts.search': '搜索会话',
'shortcuts.switchSession': '上一个 / 下一个会话',
'shortcuts.closeSidebar': '关闭侧边栏 / 搜索',
'shortcuts.stop': '停止生成',
'shortcuts.help': '显示快捷键',
'shortcuts.close': '关闭',
'shortcuts.chatSection': '聊天',
'error.title': '出错了',
'error.description': '渲染界面时发生意外错误。您可以重试或刷新页面。',
'error.retry': '重试',
'error.reload': '刷新页面',
'shortcuts.navigationSection': '导航',
'shortcuts.generalSection': '通用',
'header.export': '导出会话为 Markdown',
'header.compact': '压缩',
'header.compacting': '压缩中…',
'header.sessionInfo': '会话信息',
'sessionInfo.sessionKey': '会话密钥',
'sessionInfo.channel': '频道',
'sessionInfo.kind': '类型',
'sessionInfo.model': '模型',
'sessionInfo.agent': '智能体',
'sessionInfo.messages': '消息数',
'sessionInfo.totalTokens': '总令牌数',
'sessionInfo.inputTokens': '输入',
'sessionInfo.outputTokens': '输出',
'sessionInfo.contextWindow': '上下文',
'sessionInfo.lastActive': '最后活跃',
'theme.title': '主题',
'theme.mode': '模式',
'theme.accent': '强调色',
'theme.system': '跟随系统',
'theme.dark': '深色',
'theme.light': '浅色',
'theme.oled': 'OLED',
'search.placeholder': '搜索消息…',
'search.noResults': '无结果',
'search.prev': '上一个',
'search.next': '下一个',
'shortcuts.searchMessages': '搜索消息',
'settings.title': '设置',
'settings.appearance': '外观',
'settings.typography': '排版',
'settings.chat': '聊天',
'settings.notifications': '通知',
'settings.notificationSound': '通知声音',
'settings.language': '语言',
'settings.sendShortcut': '发送方式',
'settings.sendEnter': 'Enter',
'settings.sendCtrlEnter': 'Ctrl+Enter',
'settings.tab.appearance': '外观',
'settings.tab.typography': '排版',
'settings.tab.chat': '聊天',
'settings.tab.notifications': '通知',
'settings.fontUi': '界面字体',
'settings.fontMono': '代码字体',
'settings.fontSize': '界面字号',
'settings.fontMonoSize': '代码字号',
'settings.preview': '预览',
'settings.previewText': '敏捷的棕狐跳过懒狗 — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira 自动加载Cascadia 和 SF 依赖系统已安装字体。',
'message.bookmark': '收藏消息',
'message.reply': '回复',
'chat.replyingTo': '回复',
'message.removeBookmark': '取消收藏',
'chat.bookmarks': '收藏',
'chat.export': '导出会话',
'chat.contextCompacted': '上下文已压缩 — 旧消息已缓存到本地',
'slash.commands': '命令',
'slash.status': '显示会话状态和用量',
'slash.reasoning': '切换推理模式',
'slash.verbose': '切换详细输出',
'slash.model': '切换当前会话模型',
'slash.compact': '压缩会话上下文',
'slash.reset': '重置会话',
'slash.new': '创建新的聊天会话',
'slash.help': '显示可用命令',
};
const it: Record<keyof typeof en, string> = {
'login.title': 'PinchChat',
'login.subtitle': 'Connettiti al tuo gateway OpenClaw',
'login.gatewayUrl': 'URL del Gateway',
'login.token': 'Token',
'login.tokenPlaceholder': 'Inserisci il token del gateway',
'login.authToken': 'Token',
'login.authPassword': 'Password',
'login.password': 'Password',
'login.passwordPlaceholder': 'Inserisci la password del gateway',
'login.connect': 'Connetti',
'login.connecting': 'Connessione…',
'login.showToken': 'Mostra token',
'login.hideToken': 'Nascondi token',
'login.storedLocally': 'Le credenziali vengono salvate localmente nel browser',
'login.wsHint': 'L\'URL deve iniziare con ws:// o wss://',
'login.advanced': 'Avanzate',
'login.clientId': 'ID client',
'login.clientIdHint': 'Inviato nel frame di connessione WebSocket. Predefinito: webchat',
'header.title': 'PinchChat',
'header.connected': 'Connesso',
'header.disconnected': 'Disconnesso',
'header.logout': 'Esci',
'header.toggleSidebar': 'Mostra/nascondi barra laterale',
'header.changeLanguage': 'Cambia lingua',
'header.soundOn': 'Attiva suono notifiche',
'header.soundOff': 'Disattiva suono notifiche',
'chat.welcome': 'PinchChat',
'chat.welcomeSub': 'Invia un messaggio per iniziare',
'chat.suggestions': 'Prova a chiedere…',
'chat.suggestion1': 'Riassumi le mie ultime email',
'chat.suggestion2': 'Cosa c\'è nel mio calendario oggi?',
'chat.suggestion3': 'Cerca sul web le ultime notizie',
'chat.suggestion4': 'Aiutami a scrivere uno script',
'chat.loadingHistory': 'Caricamento messaggi…',
'chat.inputPlaceholder': 'Scrivi un messaggio…',
'chat.inputLabel': 'Messaggio',
'chat.attachFile': 'Allega file',
'chat.send': 'Invia',
'chat.stop': 'Ferma',
'chat.showPreview': 'Anteprima markdown',
'chat.hidePreview': 'Nascondi anteprima',
'chat.scrollToBottom': 'Nuovi messaggi',
'chat.scrollDown': 'Scorri in fondo',
'chat.collapseTools': 'Comprimi tutti gli strumenti',
'chat.expandTools': 'Espandi tutti gli strumenti',
'chat.messages': 'Messaggi della chat',
'chat.thinking': 'Sto pensando…',
'sidebar.title': 'Sessioni',
'sidebar.empty': 'Nessuna sessione',
'sidebar.search': 'Cerca sessioni…',
'sidebar.noResults': 'Nessun risultato',
'sidebar.pin': 'Fissa sessione',
'sidebar.unpin': 'Sgancia sessione',
'sidebar.pinned': 'Fissate',
'sidebar.delete': 'Elimina sessione',
'sidebar.rename': 'Rinomina sessione',
'sidebar.deleteConfirm': 'Eliminare questa sessione? L\'azione è irreversibile.',
'sidebar.deleteCancel': 'Annulla',
'sidebar.openSplit': 'Apri in vista divisa',
'sidebar.close': 'Chiudi barra laterale',
'sidebar.clearSearch': 'Cancella ricerca',
'sidebar.filterAll': 'Tutte',
'sidebar.filterActive': 'Attive',
'split.close': 'Chiudi vista divisa',
'app.mainChat': 'Chat principale',
'app.splitPane': 'Pannello diviso',
'app.skipToChat': 'Vai al campo di input',
'thinking.label': 'Pensiero',
'thinking.reasoning': 'Ragionamento…',
'tool.parameters': 'Parametri',
'tool.result': 'Risultato',
'connection.reconnecting': 'Connessione persa — riconnessione…',
'connection.reconnected': 'Riconnesso!',
'connection.pairing': 'Accoppiamento dispositivo in attesa — esegui `openclaw devices approve` sul tuo gateway',
'message.copy': 'Copia messaggio',
'message.copied': 'Copiato!',
'message.retry': 'Reinvia messaggio',
'message.showMore': 'Mostra di più',
'message.showLess': 'Mostra meno',
'message.metadata': 'Dettagli messaggio',
'message.rawJson': 'JSON grezzo',
'message.hideRawJson': 'Nascondi JSON grezzo',
'time.yesterday': 'Ieri',
'time.today': 'Oggi',
'shortcuts.title': 'Scorciatoie da tastiera',
'shortcuts.send': 'Invia messaggio',
'shortcuts.newline': 'Nuova riga',
'shortcuts.search': 'Cerca sessioni',
'shortcuts.switchSession': 'Sessione precedente / successiva',
'shortcuts.closeSidebar': 'Chiudi barra laterale / ricerca',
'shortcuts.stop': 'Ferma generazione',
'shortcuts.help': 'Mostra scorciatoie',
'shortcuts.close': 'Chiudi',
'shortcuts.chatSection': 'Chat',
'error.title': 'Qualcosa è andato storto',
'error.description': 'Si è verificato un errore imprevisto durante il rendering dell\'interfaccia. Puoi riprovare o ricaricare la pagina.',
'error.retry': 'Riprova',
'error.reload': 'Ricarica pagina',
'shortcuts.navigationSection': 'Navigazione',
'shortcuts.generalSection': 'Generale',
'header.export': 'Esporta conversazione in Markdown',
'header.compact': 'Compatta',
'header.compacting': 'Compattamento…',
'header.sessionInfo': 'Info sessione',
'sessionInfo.sessionKey': 'Chiave sessione',
'sessionInfo.channel': 'Canale',
'sessionInfo.kind': 'Tipo',
'sessionInfo.model': 'Modello',
'sessionInfo.agent': 'Agente',
'sessionInfo.messages': 'Messaggi',
'sessionInfo.totalTokens': 'Token totali',
'sessionInfo.inputTokens': 'Input',
'sessionInfo.outputTokens': 'Output',
'sessionInfo.contextWindow': 'Contesto',
'sessionInfo.lastActive': 'Ultima attività',
'theme.title': 'Tema',
'theme.mode': 'Modalità',
'theme.accent': 'Accento',
'theme.system': 'Sistema',
'theme.dark': 'Scuro',
'theme.light': 'Chiaro',
'theme.oled': 'OLED',
'search.placeholder': 'Cerca nei messaggi…',
'search.noResults': '0 risultati',
'search.prev': 'Risultato precedente',
'search.next': 'Risultato successivo',
'shortcuts.searchMessages': 'Cerca nei messaggi',
'settings.title': 'Impostazioni',
'settings.appearance': 'Aspetto',
'settings.typography': 'Tipografia',
'settings.chat': 'Chat',
'settings.notifications': 'Notifiche',
'settings.notificationSound': 'Suono di notifica',
'settings.language': 'Lingua',
'settings.sendShortcut': 'Invia con',
'settings.sendEnter': 'Invio',
'settings.sendCtrlEnter': 'Ctrl+Invio',
'settings.tab.appearance': 'Aspetto',
'settings.tab.typography': 'Tipografia',
'settings.tab.chat': 'Chat',
'settings.tab.notifications': 'Notifiche',
'settings.fontUi': 'Font UI',
'settings.fontMono': 'Font codice',
'settings.fontSize': 'Dimensione font UI',
'settings.fontMonoSize': 'Dimensione font codice',
'settings.preview': 'Anteprima',
'settings.previewText': 'Quel vitello jazz fonde sciolto whiskey e cioccolato — 1234567890',
'settings.fontNote': 'Inter / JetBrains / Fira si caricano automaticamente; Cascadia e SF richiedono font di sistema.',
'message.bookmark': 'Aggiungi ai segnalibri',
'message.reply': 'Rispondi',
'chat.replyingTo': 'In risposta a',
'message.removeBookmark': 'Rimuovi segnalibro',
'chat.bookmarks': 'Segnalibri',
'chat.export': 'Esporta conversazione',
'chat.contextCompacted': 'Contesto compattato — messaggi precedenti nella cache locale',
'slash.commands': 'Comandi',
'slash.status': 'Mostra stato e utilizzo della sessione',
'slash.reasoning': 'Attiva/disattiva ragionamento',
'slash.verbose': 'Attiva/disattiva output dettagliato',
'slash.model': 'Cambia modello per questa sessione',
'slash.compact': 'Compatta il contesto della conversazione',
'slash.reset': 'Reimposta sessione',
'slash.new': 'Crea una nuova sessione chat',
'slash.help': 'Mostra comandi disponibili',
};
const messages: Record<string, Record<string, string>> = { en, fr, es, de, ja, pt, zh, it };
export const supportedLocales = Object.keys(messages) as string[];
/** Labels shown in the language selector */
export const localeLabels: Record<string, string> = {
en: 'EN',
fr: 'FR',
es: 'ES',
de: 'DE',
ja: 'JA',
pt: 'PT',
zh: '中文',
it: 'IT',
};
function resolveInitialLocale(): string {
// 1. localStorage
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored && messages[stored]) return stored;
} catch { /* SSR or blocked storage */ }
// 2. VITE_LOCALE env var
const envLocale = (import.meta.env.VITE_LOCALE as string) || '';
if (envLocale && messages[envLocale]) return envLocale;
// 3. navigator.language
if (typeof navigator !== 'undefined') {
const navLang = navigator.language?.split('-')[0];
if (navLang && messages[navLang]) return navLang;
}
// 4. fallback
return 'en';
}
let currentLocale = resolveInitialLocale();
let dict = messages[currentLocale] || messages.en;
// Sync <html lang> on initial load
try { document.documentElement.lang = currentLocale; } catch { /* SSR */ }
type Listener = () => void;
const listeners = new Set<Listener>();
/** Subscribe to locale changes. Returns unsubscribe function. */
export function onLocaleChange(fn: Listener): () => void {
listeners.add(fn);
return () => listeners.delete(fn);
}
/** Get the current locale code */
export function getLocale(): string {
return currentLocale;
}
/** Switch locale at runtime. Persists to localStorage and notifies subscribers. */
export function setLocale(loc: string): void {
if (!messages[loc] || loc === currentLocale) return;
currentLocale = loc;
dict = messages[loc];
try { localStorage.setItem(STORAGE_KEY, loc); } catch { /* noop */ }
try { document.documentElement.lang = loc; } catch { /* SSR */ }
listeners.forEach((fn) => fn());
}
/** Return the translated string for the given key, falling back to English. */
export function t(key: TranslationKey): string {
return dict[key] ?? (messages.en as Record<string, string>)[key] ?? key;
}
// Keep backward-compat named export
export { currentLocale as locale };