diff --git a/web/src/components/controls/LanguageSelector.tsx b/web/src/components/controls/LanguageSelector.tsx index 2c60ab3b5..43eb1a1d2 100644 --- a/web/src/components/controls/LanguageSelector.tsx +++ b/web/src/components/controls/LanguageSelector.tsx @@ -2,7 +2,6 @@ import { Check, ChevronDown } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; import { getLanguageOption, - getLanguageOptionLabel, getLocaleDirection, LANGUAGE_OPTIONS, type Locale, @@ -58,7 +57,6 @@ export default function LanguageSelector({ return (
@@ -115,7 +113,7 @@ export default function LanguageSelector({ {option.flag} - {getLanguageOptionLabel(option)} + {option.label} {selected ? : null} diff --git a/web/src/lib/i18n.ts b/web/src/lib/i18n.ts deleted file mode 100644 index 3a3d2fe04..000000000 --- a/web/src/lib/i18n.ts +++ /dev/null @@ -1,1702 +0,0 @@ -import { useState, useEffect } from 'react'; -import { getStatus } from './api'; - -export type Locale = - | 'en' - | 'zh-CN' - | 'ja' - | 'ko' - | 'vi' - | 'tl' - | 'es' - | 'pt' - | 'it' - | 'de' - | 'fr' - | 'ar' - | 'hi' - | 'ru' - | 'bn' - | 'he' - | 'pl' - | 'cs' - | 'nl' - | 'tr' - | 'uk' - | 'id' - | 'th' - | 'ur' - | 'ro' - | 'sv' - | 'el' - | 'hu' - | 'fi' - | 'da' - | 'nb'; - -export const LANGUAGE_SWITCH_ORDER: ReadonlyArray = [ - 'en', - 'zh-CN', - 'ja', - 'ko', - 'vi', - 'tl', - 'es', - 'pt', - 'it', - 'de', - 'fr', - 'ar', - 'hi', - 'ru', - 'bn', - 'he', - 'pl', - 'cs', - 'nl', - 'tr', - 'uk', - 'id', - 'th', - 'ur', - 'ro', - 'sv', - 'el', - 'hu', - 'fi', - 'da', - 'nb', -]; - -export type LocaleDirection = 'ltr' | 'rtl'; - -export interface LanguageOption { - value: Locale; - label: string; - flag: string; - direction: LocaleDirection; -} - -export const LANGUAGE_OPTIONS: ReadonlyArray = [ - { value: 'en', label: 'English', flag: '🇺🇸', direction: 'ltr' }, - { value: 'zh-CN', label: '简体中文', flag: '🇨🇳', direction: 'ltr' }, - { value: 'ja', label: '日本語', flag: '🇯🇵', direction: 'ltr' }, - { value: 'ko', label: '한국어', flag: '🇰🇷', direction: 'ltr' }, - { value: 'vi', label: 'Tiếng Việt', flag: '🇻🇳', direction: 'ltr' }, - { value: 'tl', label: 'Tagalog', flag: '🇵🇭', direction: 'ltr' }, - { value: 'es', label: 'Español', flag: '🇪🇸', direction: 'ltr' }, - { value: 'pt', label: 'Português', flag: '🇵🇹', direction: 'ltr' }, - { value: 'it', label: 'Italiano', flag: '🇮🇹', direction: 'ltr' }, - { value: 'de', label: 'Deutsch', flag: '🇩🇪', direction: 'ltr' }, - { value: 'fr', label: 'Français', flag: '🇫🇷', direction: 'ltr' }, - { value: 'ar', label: 'العربية', flag: '🇸🇦', direction: 'rtl' }, - { value: 'hi', label: 'हिन्दी', flag: '🇮🇳', direction: 'ltr' }, - { value: 'ru', label: 'Русский', flag: '🇷🇺', direction: 'ltr' }, - { value: 'bn', label: 'বাংলা', flag: '🇧🇩', direction: 'ltr' }, - { value: 'he', label: 'עברית', flag: '🇮🇱', direction: 'rtl' }, - { value: 'pl', label: 'Polski', flag: '🇵🇱', direction: 'ltr' }, - { value: 'cs', label: 'Čeština', flag: '🇨🇿', direction: 'ltr' }, - { value: 'nl', label: 'Nederlands', flag: '🇳🇱', direction: 'ltr' }, - { value: 'tr', label: 'Türkçe', flag: '🇹🇷', direction: 'ltr' }, - { value: 'uk', label: 'Українська', flag: '🇺🇦', direction: 'ltr' }, - { value: 'id', label: 'Bahasa Indonesia', flag: '🇮🇩', direction: 'ltr' }, - { value: 'th', label: 'ไทย', flag: '🇹🇭', direction: 'ltr' }, - { value: 'ur', label: 'اردو', flag: '🇵🇰', direction: 'rtl' }, - { value: 'ro', label: 'Română', flag: '🇷🇴', direction: 'ltr' }, - { value: 'sv', label: 'Svenska', flag: '🇸🇪', direction: 'ltr' }, - { value: 'el', label: 'Ελληνικά', flag: '🇬🇷', direction: 'ltr' }, - { value: 'hu', label: 'Magyar', flag: '🇭🇺', direction: 'ltr' }, - { value: 'fi', label: 'Suomi', flag: '🇫🇮', direction: 'ltr' }, - { value: 'da', label: 'Dansk', flag: '🇩🇰', direction: 'ltr' }, - { value: 'nb', label: 'Norsk Bokmål', flag: '🇳🇴', direction: 'ltr' }, -]; - -const RTL_LOCALES = new Set(['ar', 'he', 'ur']); - -export function getLocaleDirection(locale: Locale): LocaleDirection { - return RTL_LOCALES.has(locale) ? 'rtl' : 'ltr'; -} - -export function getLanguageOption(locale: Locale): LanguageOption { - const matched = LANGUAGE_OPTIONS.find((option) => option.value === locale); - if (matched) { - return matched; - } - - const fallback = LANGUAGE_OPTIONS.find((option) => option.value === 'en'); - if (!fallback) { - throw new Error('English locale metadata is missing.'); - } - - return fallback; -} - -export function getLanguageOptionLabel(option: LanguageOption): string { - return option.label; -} - -export interface LocaleDocumentTarget { - documentElement?: { lang?: string; dir?: string }; - body?: { dir?: string } | null; -} - -export function applyLocaleToDocument(locale: Locale, target: LocaleDocumentTarget): void { - const direction = getLocaleDirection(locale); - - if (target.documentElement) { - target.documentElement.lang = locale; - target.documentElement.dir = direction; - } - - if (target.body) { - target.body.dir = direction; - } -} - -export const LANGUAGE_BUTTON_LABELS: Record = { - en: 'EN', - 'zh-CN': '中文', - ja: '日本語', - ko: 'KO', - vi: 'VI', - tl: 'TL', - es: 'ES', - pt: 'PT', - it: 'IT', - de: 'DE', - fr: 'FR', - ar: 'AR', - hi: 'HI', - ru: 'RU', - bn: 'BN', - he: 'HE', - pl: 'PL', - cs: 'CS', - nl: 'NL', - tr: 'TR', - uk: 'UK', - id: 'ID', - th: 'TH', - ur: 'UR', - ro: 'RO', - sv: 'SV', - el: 'EL', - hu: 'HU', - fi: 'FI', - da: 'DA', - nb: 'NB', -}; - -const en = { - 'nav.dashboard': 'Dashboard', - 'nav.agent': 'Agent', - 'nav.tools': 'Tools', - 'nav.cron': 'Scheduled Jobs', - 'nav.integrations': 'Integrations', - 'nav.memory': 'Memory', - 'nav.config': 'Configuration', - 'nav.cost': 'Cost Tracker', - 'nav.logs': 'Logs', - 'nav.doctor': 'Doctor', - - 'dashboard.title': 'Dashboard', - 'dashboard.provider': 'Provider', - 'dashboard.model': 'Model', - 'dashboard.uptime': 'Uptime', - 'dashboard.temperature': 'Temperature', - 'dashboard.gateway_port': 'Gateway Port', - 'dashboard.locale': 'Locale', - 'dashboard.memory_backend': 'Memory Backend', - 'dashboard.paired': 'Paired', - 'dashboard.channels': 'Channels', - 'dashboard.health': 'Health', - 'dashboard.status': 'Status', - 'dashboard.overview': 'Overview', - 'dashboard.system_info': 'System Information', - 'dashboard.quick_actions': 'Quick Actions', - 'dashboard.load_failed': 'Dashboard load failed', - 'dashboard.load_unknown_error': 'Unknown dashboard load error', - 'dashboard.hero_eyebrow': 'ZeroClaw Command Deck', - 'dashboard.hero_title': 'Electric Runtime Dashboard', - 'dashboard.hero_subtitle': 'Real-time telemetry, cost pulse, and operations status in a single collapsible surface.', - 'dashboard.live_gateway': 'Live Gateway', - 'dashboard.unpaired': 'Unpaired', - 'dashboard.provider_model': 'Provider / Model', - 'dashboard.since_last_restart': 'Since last restart', - 'dashboard.pairing_active': 'Pairing active', - 'dashboard.no_paired_devices': 'No paired devices', - 'dashboard.cost_pulse': 'Cost Pulse', - 'dashboard.cost_subtitle': 'Session, daily, and monthly runtime spend', - 'dashboard.session': 'Session', - 'dashboard.daily': 'Daily', - 'dashboard.monthly': 'Monthly', - 'dashboard.channel_activity': 'Channel Activity', - 'dashboard.channel_subtitle': 'Live integrations and route connectivity', - 'dashboard.no_channels': 'No channels configured.', - 'dashboard.active': 'Active', - 'dashboard.inactive': 'Inactive', - 'dashboard.component_health': 'Component Health', - 'dashboard.component_subtitle': 'Runtime heartbeat and restart awareness', - 'dashboard.no_component_health': 'No component health is currently available.', - 'dashboard.restarts': 'Restarts', - 'dashboard.unknown_provider': 'Unknown', - - 'agent.title': 'Agent Chat', - 'agent.send': 'Send', - 'agent.placeholder': 'Type a message...', - 'agent.connecting': 'Connecting...', - 'agent.connected': 'Connected', - 'agent.disconnected': 'Disconnected', - 'agent.reconnecting': 'Reconnecting...', - 'agent.thinking': 'Thinking...', - 'agent.tool_call': 'Tool Call', - 'agent.tool_result': 'Tool Result', - 'agent.connection_error': 'Connection error. Attempting to reconnect...', - 'agent.failed_send': 'Failed to send message. Please try again.', - 'agent.empty_title': 'ZeroClaw Agent', - 'agent.empty_subtitle': 'Send a message to start the conversation', - 'agent.unknown_error': 'Unknown error', - - 'tools.title': 'Available Tools', - 'tools.name': 'Name', - 'tools.description': 'Description', - 'tools.parameters': 'Parameters', - 'tools.search': 'Search tools...', - 'tools.empty': 'No tools available.', - 'tools.count': 'Total tools', - 'tools.agent_tools': 'Agent Tools', - 'tools.cli_tools': 'CLI Tools', - 'tools.no_search_results': 'No tools match your search.', - 'tools.parameter_schema': 'Parameter Schema', - 'tools.path': 'Path', - 'tools.version': 'Version', - 'tools.load_failed': 'Failed to load tools', - - 'cron.title': 'Scheduled Jobs', - 'cron.add': 'Add Job', - 'cron.delete': 'Delete', - 'cron.enable': 'Enable', - 'cron.disable': 'Disable', - 'cron.name': 'Name', - 'cron.command': 'Command', - 'cron.schedule': 'Schedule', - 'cron.next_run': 'Next Run', - 'cron.last_run': 'Last Run', - 'cron.last_status': 'Last Status', - 'cron.enabled': 'Enabled', - 'cron.empty': 'No scheduled jobs.', - 'cron.confirm_delete': 'Are you sure you want to delete this job?', - 'cron.scheduled_tasks': 'Scheduled Tasks', - 'cron.add_cron_job': 'Add Cron Job', - 'cron.name_optional': 'Name (optional)', - 'cron.schedule_required_command_required': 'Schedule and command are required.', - 'cron.adding': 'Adding...', - 'cron.no_tasks_configured': 'No scheduled tasks configured.', - 'cron.load_failed': 'Failed to load cron jobs', - 'cron.failed_add': 'Failed to add job', - 'cron.failed_delete': 'Failed to delete job', - 'cron.delete_prompt': 'Delete?', - 'cron.id': 'ID', - 'cron.disabled': 'Disabled', - - 'integrations.title': 'Integrations', - 'integrations.available': 'Available', - 'integrations.active': 'Active', - 'integrations.coming_soon': 'Coming Soon', - 'integrations.category': 'Category', - 'integrations.status': 'Status', - 'integrations.search': 'Search integrations...', - 'integrations.empty': 'No integrations found.', - 'integrations.activate': 'Activate', - 'integrations.deactivate': 'Deactivate', - 'integrations.load_failed': 'Failed to load integrations', - 'integrations.all': 'all', - - 'memory.title': 'Memory Store', - 'memory.search': 'Search memory...', - 'memory.add': 'Store Memory', - 'memory.delete': 'Delete', - 'memory.key': 'Key', - 'memory.content': 'Content', - 'memory.category': 'Category', - 'memory.timestamp': 'Timestamp', - 'memory.session': 'Session', - 'memory.score': 'Score', - 'memory.empty': 'No memory entries found.', - 'memory.confirm_delete': 'Are you sure you want to delete this memory entry?', - 'memory.all_categories': 'All Categories', - 'memory.add_memory': 'Add Memory', - 'memory.search_entries': 'Search memory entries...', - 'memory.load_failed': 'Failed to load memory', - 'memory.key_content_required': 'Key and content are required.', - 'memory.failed_store': 'Failed to store memory', - 'memory.failed_delete': 'Failed to delete memory', - 'memory.category_optional': 'Category (optional)', - 'memory.key_placeholder': 'e.g. user_preferences', - 'memory.content_placeholder': 'Memory content...', - 'memory.category_placeholder': 'e.g. preferences, context, facts', - 'memory.search_button': 'Search', - 'memory.saving': 'Saving...', - 'memory.delete_prompt': 'Delete?', - - 'config.title': 'Configuration', - 'config.save': 'Save', - 'config.reset': 'Reset', - 'config.saved': 'Configuration saved successfully.', - 'config.error': 'Failed to save configuration.', - 'config.loading': 'Loading configuration...', - 'config.editor_placeholder': 'TOML configuration...', - 'config.saving': 'Saving...', - 'config.masked_title': 'Sensitive fields are masked', - 'config.masked_description': 'API keys, tokens, and passwords are hidden for security. To update a masked field, replace the entire masked value with your new value.', - 'config.toml_configuration': 'TOML Configuration', - 'config.lines': 'lines', - - 'cost.title': 'Cost Tracker', - 'cost.session': 'Session Cost', - 'cost.daily': 'Daily Cost', - 'cost.monthly': 'Monthly Cost', - 'cost.total_tokens': 'Total Tokens', - 'cost.request_count': 'Requests', - 'cost.by_model': 'Cost by Model', - 'cost.model': 'Model', - 'cost.tokens': 'Tokens', - 'cost.requests': 'Requests', - 'cost.usd': 'Cost (USD)', - 'cost.total_requests': 'Total Requests', - 'cost.token_statistics': 'Token Statistics', - 'cost.avg_tokens_per_request': 'Avg Tokens / Request', - 'cost.cost_per_1k_tokens': 'Cost per 1K Tokens', - 'cost.model_breakdown': 'Model Breakdown', - 'cost.no_model_data': 'No model data available.', - 'cost.share': 'Share', - 'cost.load_failed': 'Failed to load cost data', - - 'logs.title': 'Live Logs', - 'logs.clear': 'Clear', - 'logs.pause': 'Pause', - 'logs.resume': 'Resume', - 'logs.filter': 'Filter logs...', - 'logs.empty': 'No log entries.', - 'logs.connected': 'Connected to event stream.', - 'logs.disconnected': 'Disconnected from event stream.', - 'logs.events': 'events', - 'logs.jump_to_bottom': 'Jump to bottom', - 'logs.filter_label': 'Filter:', - 'logs.paused_stream': 'Log streaming is paused.', - 'logs.waiting_for_events': 'Waiting for events...', - - 'doctor.title': 'System Diagnostics', - 'doctor.run': 'Run Diagnostics', - 'doctor.running': 'Running diagnostics...', - 'doctor.ok': 'OK', - 'doctor.warn': 'Warning', - 'doctor.error': 'Error', - 'doctor.severity': 'Severity', - 'doctor.category': 'Category', - 'doctor.message': 'Message', - 'doctor.empty': 'No diagnostics have been run yet.', - 'doctor.summary': 'Diagnostic Summary', - 'doctor.running_short': 'Running...', - 'doctor.running_hint': 'This may take a few seconds.', - 'doctor.issues_found': 'Issues Found', - 'doctor.warnings': 'Warnings', - 'doctor.all_clear': 'All Clear', - 'doctor.instructions': 'Click "Run Diagnostics" to check your ZeroClaw installation.', - - 'auth.pair': 'Pair Device', - 'auth.pairing_code': 'Pairing Code', - 'auth.pair_button': 'Pair', - 'auth.logout': 'Logout', - 'auth.pairing_success': 'Pairing successful!', - 'auth.pairing_failed': 'Pairing failed. Please try again.', - 'auth.enter_code': 'Enter the one-time pairing code from your terminal', - 'auth.code_placeholder': '6-digit code', - 'auth.pairing_progress': 'Pairing...', - - 'common.loading': 'Loading...', - 'common.error': 'An error occurred.', - 'common.retry': 'Retry', - 'common.cancel': 'Cancel', - 'common.confirm': 'Confirm', - 'common.save': 'Save', - 'common.delete': 'Delete', - 'common.edit': 'Edit', - 'common.close': 'Close', - 'common.yes': 'Yes', - 'common.no': 'No', - 'common.search': 'Search...', - 'common.no_data': 'No data available.', - 'common.refresh': 'Refresh', - 'common.back': 'Back', - 'common.actions': 'Actions', - 'common.name': 'Name', - 'common.description': 'Description', - 'common.status': 'Status', - 'common.created': 'Created', - 'common.updated': 'Updated', - 'common.languages': 'Languages', - 'common.select_language': 'Select language', - 'common.connecting': 'Connecting...', - - 'health.title': 'System Health', - 'health.component': 'Component', - 'health.status': 'Status', - 'health.last_ok': 'Last OK', - 'health.last_error': 'Last Error', - 'health.restart_count': 'Restart Count', - 'health.pid': 'Process ID', - 'health.uptime': 'Uptime', - 'health.updated_at': 'Updated At', - - 'header.dashboard_tagline': 'ZeroClaw dashboard', - 'sidebar.gateway_dashboard': 'Gateway + Dashboard', - 'sidebar.runtime_mode': 'Runtime Mode', - 'navigation.open': 'Open navigation', - 'navigation.close': 'Close navigation', - 'navigation.expand': 'Expand navigation', - 'navigation.collapse': 'Collapse navigation', -} satisfies Record; - -const tr = { - ...en, - 'nav.dashboard': 'Kontrol Paneli', - 'nav.agent': 'Ajan', - 'nav.tools': 'Araçlar', - 'nav.cron': 'Zamanlanmış Görevler', - 'nav.integrations': 'Entegrasyonlar', - 'nav.memory': 'Hafıza', - 'nav.config': 'Yapılandırma', - 'nav.cost': 'Maliyet Takibi', - 'nav.logs': 'Kayıtlar', - 'nav.doctor': 'Doktor', - 'agent.title': 'Ajan Sohbeti', - 'agent.send': 'Gönder', - 'agent.placeholder': 'Bir mesaj yazın...', - 'agent.connecting': 'Bağlanıyor...', - 'agent.connected': 'Bağlı', - 'agent.disconnected': 'Bağlantı Kesildi', - 'agent.reconnecting': 'Yeniden bağlanıyor...', - 'agent.thinking': 'Düşünüyor...', - 'agent.tool_call': 'Araç Çağrısı', - 'agent.tool_result': 'Araç Sonucu', - 'agent.connection_error': 'Bağlantı hatası. Yeniden bağlanmaya çalışılıyor...', - 'agent.failed_send': 'Mesaj gönderilemedi. Lütfen tekrar deneyin.', - 'agent.empty_title': 'ZeroClaw Ajanı', - 'agent.empty_subtitle': 'Konuşmayı başlatmak için bir mesaj gönderin', - 'dashboard.title': 'Kontrol Paneli', - 'dashboard.provider': 'Sağlayıcı', - 'dashboard.model': 'Model', - 'dashboard.uptime': 'Çalışma Süresi', - 'dashboard.temperature': 'Sıcaklık', - 'dashboard.gateway_port': 'Ağ Geçidi Portu', - 'dashboard.locale': 'Yerel Ayar', - 'dashboard.memory_backend': 'Hafıza Arka Ucu', - 'dashboard.hero_eyebrow': 'ZeroClaw Komuta Güvertesi', - 'dashboard.hero_title': 'Elektrik Çalışma Zamanı Paneli', - 'dashboard.hero_subtitle': 'Gerçek zamanlı telemetri, maliyet akışı ve operasyon durumunu tek bir daraltılabilir yüzeyde görün.', - 'dashboard.live_gateway': 'Canlı Ağ Geçidi', - 'dashboard.unpaired': 'Eşleşmemiş', - 'dashboard.provider_model': 'Sağlayıcı / Model', - 'dashboard.since_last_restart': 'Son yeniden başlatmadan beri', - 'dashboard.pairing_active': 'Eşleştirme etkin', - 'dashboard.no_paired_devices': 'Eşleşmiş cihaz yok', - 'dashboard.cost_pulse': 'Maliyet Nabzı', - 'dashboard.cost_subtitle': 'Oturum, günlük ve aylık çalışma zamanı harcaması', - 'dashboard.session': 'Oturum', - 'dashboard.daily': 'Günlük', - 'dashboard.monthly': 'Aylık', - 'dashboard.channel_activity': 'Kanal Etkinliği', - 'dashboard.channel_subtitle': 'Canlı entegrasyonlar ve rota bağlantısı', - 'dashboard.no_channels': 'Hiç kanal yapılandırılmamış.', - 'dashboard.active': 'Aktif', - 'dashboard.inactive': 'Pasif', - 'dashboard.component_health': 'Bileşen Sağlığı', - 'dashboard.component_subtitle': 'Çalışma zamanı nabzı ve yeniden başlatma farkındalığı', - 'dashboard.no_component_health': 'Şu anda bileşen sağlığı bilgisi yok.', - 'dashboard.restarts': 'Yeniden Başlatmalar', - 'tools.title': 'Mevcut Araçlar', - 'tools.search': 'Araç ara...', - 'tools.agent_tools': 'Ajan Araçları', - 'tools.cli_tools': 'CLI Araçları', - 'tools.no_search_results': 'Aramanızla eşleşen araç yok.', - 'tools.parameter_schema': 'Parametre Şeması', - 'tools.path': 'Yol', - 'tools.version': 'Sürüm', - 'cron.title': 'Zamanlanmış Görevler', - 'cron.add': 'Görev Ekle', - 'cron.scheduled_tasks': 'Zamanlanmış Görevler', - 'cron.add_cron_job': 'Cron Görevi Ekle', - 'cron.name_optional': 'Ad (isteğe bağlı)', - 'cron.schedule_required_command_required': 'Zamanlama ve komut gereklidir.', - 'cron.adding': 'Ekleniyor...', - 'cron.no_tasks_configured': 'Zamanlanmış görev yapılandırılmamış.', - 'cron.load_failed': 'Cron görevleri yüklenemedi', - 'cron.failed_add': 'Görev eklenemedi', - 'cron.failed_delete': 'Görev silinemedi', - 'cron.delete_prompt': 'Silinsin mi?', - 'cron.disabled': 'Devre Dışı', - 'integrations.title': 'Entegrasyonlar', - 'integrations.available': 'Mevcut', - 'integrations.active': 'Aktif', - 'integrations.coming_soon': 'Yakında', - 'integrations.empty': 'Entegrasyon bulunamadı.', - 'integrations.load_failed': 'Entegrasyonlar yüklenemedi', - 'memory.title': 'Hafıza Deposu', - 'memory.add_memory': 'Hafıza Ekle', - 'memory.search_entries': 'Hafıza girdilerinde ara...', - 'memory.all_categories': 'Tüm Kategoriler', - 'memory.search_button': 'Ara', - 'memory.load_failed': 'Hafıza yüklenemedi', - 'memory.key_content_required': 'Anahtar ve içerik gereklidir.', - 'memory.failed_store': 'Hafıza kaydedilemedi', - 'memory.failed_delete': 'Hafıza silinemedi', - 'memory.category_optional': 'Kategori (isteğe bağlı)', - 'memory.key_placeholder': 'örn. kullanici_tercihleri', - 'memory.content_placeholder': 'Hafıza içeriği...', - 'memory.category_placeholder': 'örn. tercihler, bağlam, gerçekler', - 'memory.saving': 'Kaydediliyor...', - 'memory.delete_prompt': 'Silinsin mi?', - 'config.title': 'Yapılandırma', - 'config.save': 'Kaydet', - 'config.saved': 'Yapılandırma başarıyla kaydedildi.', - 'config.saving': 'Kaydediliyor...', - 'config.masked_title': 'Hassas alanlar maskelendi', - 'config.masked_description': 'Güvenlik için API anahtarları, belirteçler ve parolalar gizlenir. Maskelenmiş bir alanı güncellemek için tüm maskeli değeri yeni değerinizle değiştirin.', - 'config.toml_configuration': 'TOML Yapılandırması', - 'config.lines': 'satır', - 'cost.title': 'Maliyet Takibi', - 'cost.session': 'Oturum Maliyeti', - 'cost.daily': 'Günlük Maliyet', - 'cost.monthly': 'Aylık Maliyet', - 'cost.total_requests': 'Toplam İstek', - 'cost.token_statistics': 'Belirteç İstatistikleri', - 'cost.avg_tokens_per_request': 'İstek Başına Ort. Belirteç', - 'cost.cost_per_1k_tokens': '1K Belirteç Başına Maliyet', - 'cost.model_breakdown': 'Model Dağılımı', - 'cost.no_model_data': 'Model verisi yok.', - 'cost.share': 'Pay', - 'cost.load_failed': 'Maliyet verisi yüklenemedi', - 'logs.title': 'Canlı Kayıtlar', - 'logs.pause': 'Duraklat', - 'logs.resume': 'Sürdür', - 'logs.events': 'olay', - 'logs.jump_to_bottom': 'Alta git', - 'logs.filter_label': 'Filtre:', - 'logs.paused_stream': 'Kayıt akışı duraklatıldı.', - 'logs.waiting_for_events': 'Olaylar bekleniyor...', - 'doctor.title': 'Sistem Teşhisleri', - 'doctor.run': 'Teşhisleri Çalıştır', - 'doctor.running': 'Teşhisler çalıştırılıyor...', - 'doctor.running_short': 'Çalışıyor...', - 'doctor.running_hint': 'Bu birkaç saniye sürebilir.', - 'doctor.warn': 'Uyarı', - 'doctor.issues_found': 'Sorunlar Bulundu', - 'doctor.warnings': 'Uyarılar', - 'doctor.all_clear': 'Temiz', - 'doctor.instructions': 'ZeroClaw kurulumunuzu kontrol etmek için "Teşhisleri Çalıştır" düğmesine tıklayın.', - 'auth.pair': 'Cihazı Eşle', - 'auth.pair_button': 'Eşle', - 'auth.logout': 'Çıkış Yap', - 'auth.enter_code': 'Terminalinizdeki tek kullanımlık eşleştirme kodunu girin', - 'auth.code_placeholder': '6 haneli kod', - 'auth.pairing_progress': 'Eşleştiriliyor...', - 'common.languages': 'Diller', - 'common.select_language': 'Dil seçin', - 'common.connecting': 'Bağlanıyor...', - 'header.dashboard_tagline': 'ZeroClaw paneli', - 'sidebar.gateway_dashboard': 'Ağ Geçidi + Panel', - 'sidebar.runtime_mode': 'Çalışma Modu', - 'navigation.open': 'Gezinmeyi aç', - 'navigation.close': 'Gezinmeyi kapat', - 'navigation.expand': 'Gezinmeyi genişlet', - 'navigation.collapse': 'Gezinmeyi daralt', -}; - -const zhCn = { - ...en, - 'nav.dashboard': '仪表盘', - 'nav.agent': '代理', - 'nav.tools': '工具', - 'nav.cron': '定时任务', - 'nav.integrations': '集成', - 'nav.memory': '记忆', - 'nav.config': '配置', - 'nav.cost': '成本跟踪', - 'nav.logs': '日志', - 'nav.doctor': '诊断', - 'dashboard.hero_title': '电光运行仪表盘', - 'dashboard.live_gateway': '在线网关', - 'dashboard.unpaired': '未配对', - 'agent.title': '代理聊天', - 'agent.placeholder': '输入消息…', - 'agent.connecting': '正在连接…', - 'agent.connected': '已连接', - 'agent.disconnected': '已断开', - 'tools.search': '搜索工具…', - 'tools.agent_tools': '代理工具', - 'tools.cli_tools': 'CLI 工具', - 'cron.add': '添加任务', - 'cron.scheduled_tasks': '定时任务', - 'integrations.title': '集成', - 'memory.add_memory': '添加记忆', - 'memory.search_entries': '搜索记忆条目…', - 'config.save': '保存', - 'config.saving': '正在保存…', - 'cost.session': '会话成本', - 'cost.daily': '每日成本', - 'cost.monthly': '每月成本', - 'logs.title': '实时日志', - 'logs.pause': '暂停', - 'logs.resume': '继续', - 'doctor.title': '系统诊断', - 'doctor.run': '运行诊断', - 'doctor.running_short': '运行中…', - 'auth.pair_button': '配对', - 'auth.enter_code': '输入终端中的一次性配对码', - 'auth.code_placeholder': '6 位代码', - 'auth.pairing_progress': '正在配对…', - 'auth.logout': '退出', - 'common.languages': '语言', - 'common.select_language': '选择语言', - 'header.dashboard_tagline': 'ZeroClaw 仪表盘', -}; - -const ja = { - ...en, - 'nav.dashboard': 'ダッシュボード', - 'nav.agent': 'エージェント', - 'nav.tools': 'ツール', - 'nav.cron': 'スケジュール', - 'nav.integrations': '連携', - 'nav.memory': 'メモリ', - 'nav.config': '設定', - 'nav.cost': 'コスト', - 'nav.logs': 'ログ', - 'nav.doctor': '診断', - 'dashboard.hero_title': 'エレクトリック・ランタイム・ダッシュボード', - 'dashboard.live_gateway': 'ライブゲートウェイ', - 'dashboard.unpaired': '未ペア', - 'agent.title': 'エージェントチャット', - 'agent.placeholder': 'メッセージを入力…', - 'agent.connecting': '接続中…', - 'agent.connected': '接続済み', - 'agent.disconnected': '切断済み', - 'tools.search': 'ツールを検索…', - 'tools.agent_tools': 'エージェントツール', - 'tools.cli_tools': 'CLI ツール', - 'cron.add': 'ジョブを追加', - 'cron.scheduled_tasks': 'スケジュールされたジョブ', - 'integrations.title': '連携', - 'memory.add_memory': 'メモリを追加', - 'memory.search_entries': 'メモリエントリを検索…', - 'config.save': '保存', - 'config.saving': '保存中…', - 'cost.session': 'セッションコスト', - 'cost.daily': '日次コスト', - 'cost.monthly': '月次コスト', - 'logs.title': 'ライブログ', - 'logs.pause': '一時停止', - 'logs.resume': '再開', - 'doctor.title': 'システム診断', - 'doctor.run': '診断を実行', - 'doctor.running_short': '実行中…', - 'auth.pair_button': 'ペアリング', - 'auth.enter_code': '端末のワンタイムペアリングコードを入力してください', - 'auth.code_placeholder': '6桁のコード', - 'auth.pairing_progress': 'ペアリング中…', - 'auth.logout': 'ログアウト', - 'common.languages': '言語', - 'common.select_language': '言語を選択', - 'header.dashboard_tagline': 'ZeroClaw ダッシュボード', -}; - -const ru = { - ...en, - 'nav.dashboard': 'Панель', - 'nav.agent': 'Агент', - 'nav.tools': 'Инструменты', - 'nav.cron': 'Задания', - 'nav.integrations': 'Интеграции', - 'nav.memory': 'Память', - 'nav.config': 'Конфигурация', - 'nav.cost': 'Расходы', - 'nav.logs': 'Логи', - 'nav.doctor': 'Диагностика', - 'dashboard.hero_title': 'Панель электрического рантайма', - 'dashboard.live_gateway': 'Живой шлюз', - 'dashboard.unpaired': 'Не сопряжено', - 'agent.title': 'Чат агента', - 'agent.placeholder': 'Введите сообщение…', - 'agent.connecting': 'Подключение…', - 'agent.connected': 'Подключено', - 'agent.disconnected': 'Отключено', - 'tools.search': 'Поиск инструментов…', - 'tools.agent_tools': 'Инструменты агента', - 'tools.cli_tools': 'CLI-инструменты', - 'cron.add': 'Добавить задачу', - 'cron.scheduled_tasks': 'Запланированные задания', - 'integrations.title': 'Интеграции', - 'memory.add_memory': 'Добавить память', - 'memory.search_entries': 'Искать записи памяти…', - 'config.save': 'Сохранить', - 'config.saving': 'Сохранение…', - 'cost.session': 'Стоимость сессии', - 'cost.daily': 'Стоимость за день', - 'cost.monthly': 'Стоимость за месяц', - 'logs.title': 'Живые логи', - 'logs.pause': 'Пауза', - 'logs.resume': 'Продолжить', - 'doctor.title': 'Диагностика системы', - 'doctor.run': 'Запустить диагностику', - 'doctor.running_short': 'Выполняется…', - 'auth.pair_button': 'Сопрячь', - 'auth.enter_code': 'Введите одноразовый код сопряжения из терминала', - 'auth.code_placeholder': '6-значный код', - 'auth.pairing_progress': 'Сопряжение…', - 'auth.logout': 'Выйти', - 'common.languages': 'Языки', - 'common.select_language': 'Выберите язык', - 'header.dashboard_tagline': 'Панель ZeroClaw', -}; - -const fr = { - ...en, - 'nav.dashboard': 'Tableau de bord', - 'nav.agent': 'Agent', - 'nav.tools': 'Outils', - 'nav.cron': 'Tâches planifiées', - 'nav.integrations': 'Intégrations', - 'nav.memory': 'Mémoire', - 'nav.config': 'Configuration', - 'nav.cost': 'Coûts', - 'nav.logs': 'Journaux', - 'nav.doctor': 'Diagnostic', - 'dashboard.hero_title': 'Tableau de bord runtime électrique', - 'dashboard.live_gateway': 'Passerelle active', - 'dashboard.unpaired': 'Non appairé', - 'agent.title': 'Chat agent', - 'agent.placeholder': 'Saisissez un message…', - 'agent.connecting': 'Connexion…', - 'agent.connected': 'Connecté', - 'agent.disconnected': 'Déconnecté', - 'tools.search': 'Rechercher des outils…', - 'tools.agent_tools': 'Outils agent', - 'tools.cli_tools': 'Outils CLI', - 'cron.add': 'Ajouter une tâche', - 'cron.scheduled_tasks': 'Tâches planifiées', - 'integrations.title': 'Intégrations', - 'memory.add_memory': 'Ajouter une mémoire', - 'memory.search_entries': 'Rechercher dans la mémoire…', - 'config.save': 'Enregistrer', - 'config.saving': 'Enregistrement…', - 'cost.session': 'Coût de session', - 'cost.daily': 'Coût journalier', - 'cost.monthly': 'Coût mensuel', - 'logs.title': 'Journaux en direct', - 'logs.pause': 'Pause', - 'logs.resume': 'Reprendre', - 'doctor.title': 'Diagnostic système', - 'doctor.run': 'Lancer le diagnostic', - 'doctor.running_short': 'Exécution…', - 'auth.pair_button': 'Associer', - 'auth.enter_code': 'Entrez le code d’appairage à usage unique affiché dans le terminal', - 'auth.code_placeholder': 'Code à 6 chiffres', - 'auth.pairing_progress': 'Appairage…', - 'auth.logout': 'Déconnexion', - 'common.languages': 'Langues', - 'common.select_language': 'Choisir la langue', - 'header.dashboard_tagline': 'Tableau de bord ZeroClaw', -}; - -const vi = { - ...en, - 'nav.dashboard': 'Bảng điều khiển', - 'nav.agent': 'Tác tử', - 'nav.tools': 'Công cụ', - 'nav.cron': 'Lịch tác vụ', - 'nav.integrations': 'Tích hợp', - 'nav.memory': 'Bộ nhớ', - 'nav.config': 'Cấu hình', - 'nav.cost': 'Chi phí', - 'nav.logs': 'Nhật ký', - 'nav.doctor': 'Chẩn đoán', - 'dashboard.hero_title': 'Bảng điều khiển runtime điện xanh', - 'dashboard.live_gateway': 'Cổng hoạt động', - 'dashboard.unpaired': 'Chưa ghép đôi', - 'agent.title': 'Trò chuyện với tác tử', - 'agent.placeholder': 'Nhập tin nhắn…', - 'agent.connecting': 'Đang kết nối…', - 'agent.connected': 'Đã kết nối', - 'agent.disconnected': 'Đã ngắt kết nối', - 'tools.search': 'Tìm công cụ…', - 'tools.agent_tools': 'Công cụ tác tử', - 'tools.cli_tools': 'Công cụ CLI', - 'cron.add': 'Thêm tác vụ', - 'cron.scheduled_tasks': 'Tác vụ đã lên lịch', - 'integrations.title': 'Tích hợp', - 'memory.add_memory': 'Thêm bộ nhớ', - 'memory.search_entries': 'Tìm trong bộ nhớ…', - 'config.save': 'Lưu', - 'config.saving': 'Đang lưu…', - 'cost.session': 'Chi phí phiên', - 'cost.daily': 'Chi phí ngày', - 'cost.monthly': 'Chi phí tháng', - 'logs.title': 'Nhật ký trực tiếp', - 'logs.pause': 'Tạm dừng', - 'logs.resume': 'Tiếp tục', - 'doctor.title': 'Chẩn đoán hệ thống', - 'doctor.run': 'Chạy chẩn đoán', - 'doctor.running_short': 'Đang chạy…', - 'auth.pair_button': 'Ghép đôi', - 'auth.enter_code': 'Nhập mã ghép đôi một lần từ terminal', - 'auth.code_placeholder': 'Mã 6 chữ số', - 'auth.pairing_progress': 'Đang ghép đôi…', - 'auth.logout': 'Đăng xuất', - 'common.languages': 'Ngôn ngữ', - 'common.select_language': 'Chọn ngôn ngữ', - 'header.dashboard_tagline': 'Bảng điều khiển ZeroClaw', -}; - - -const createLocale = (overrides: Record) => ({ - ...en, - ...overrides, -}); - -const ko = createLocale({ - 'nav.dashboard': '대시보드', - 'nav.agent': '에이전트', - 'nav.tools': '도구', - 'nav.cron': '예약 작업', - 'nav.integrations': '통합', - 'nav.memory': '메모리', - 'nav.config': '설정', - 'nav.cost': '비용 추적', - 'nav.logs': '로그', - 'nav.doctor': '진단', - 'dashboard.hero_title': '전기 런타임 대시보드', - 'agent.placeholder': '메시지를 입력하세요…', - 'tools.search': '도구 검색…', - 'cron.add': '작업 추가', - 'memory.add_memory': '메모리 추가', - 'config.save': '저장', - 'cost.token_statistics': '토큰 통계', - 'logs.title': '실시간 로그', - 'doctor.title': '시스템 진단', - 'auth.pair_button': '페어링', - 'auth.enter_code': '터미널에 표시된 일회용 페어링 코드를 입력하세요', - 'auth.code_placeholder': '6자리 코드', - 'auth.pairing_progress': '페어링 중…', - 'auth.logout': '로그아웃', - 'common.languages': '언어', - 'common.select_language': '언어 선택', - 'header.dashboard_tagline': 'ZeroClaw 대시보드', -}); - -const tl = createLocale({ - 'nav.dashboard': 'Dashboard', - 'nav.agent': 'Ahente', - 'nav.tools': 'Mga Tool', - 'nav.cron': 'Naka-iskedyul na Trabaho', - 'nav.integrations': 'Mga Integrasyon', - 'nav.memory': 'Alaala', - 'nav.config': 'Konpigurasyon', - 'nav.cost': 'Pagsubaybay sa Gastos', - 'nav.logs': 'Mga Log', - 'nav.doctor': 'Diyagnostiko', - 'dashboard.hero_title': 'Elektrikong Dashboard ng Runtime', - 'agent.placeholder': 'Mag-type ng mensahe…', - 'tools.search': 'Maghanap ng tool…', - 'cron.add': 'Magdagdag ng gawain', - 'memory.add_memory': 'Magdagdag ng alaala', - 'config.save': 'I-save', - 'cost.token_statistics': 'Estadistika ng Token', - 'logs.title': 'Mga Live Log', - 'doctor.title': 'Diyagnostiko ng System', - 'auth.pair_button': 'Ipares', - 'auth.enter_code': 'Ilagay ang isang beses na pairing code mula sa terminal', - 'auth.code_placeholder': '6-digit na code', - 'auth.pairing_progress': 'Pinapares…', - 'auth.logout': 'Mag-logout', - 'common.languages': 'Mga Wika', - 'common.select_language': 'Piliin ang wika', - 'header.dashboard_tagline': 'Dashboard ng ZeroClaw', -}); - -const es = createLocale({ - 'nav.dashboard': 'Panel', - 'nav.agent': 'Agente', - 'nav.tools': 'Herramientas', - 'nav.cron': 'Tareas programadas', - 'nav.integrations': 'Integraciones', - 'nav.memory': 'Memoria', - 'nav.config': 'Configuración', - 'nav.cost': 'Costos', - 'nav.logs': 'Registros', - 'nav.doctor': 'Diagnóstico', - 'dashboard.hero_title': 'Panel eléctrico del runtime', - 'agent.placeholder': 'Escribe un mensaje…', - 'tools.search': 'Buscar herramientas…', - 'cron.add': 'Agregar tarea', - 'memory.add_memory': 'Agregar memoria', - 'config.save': 'Guardar', - 'cost.token_statistics': 'Estadísticas de tokens', - 'logs.title': 'Registros en vivo', - 'doctor.title': 'Diagnóstico del sistema', - 'auth.pair_button': 'Vincular', - 'auth.enter_code': 'Introduce el código de vinculación de un solo uso del terminal', - 'auth.code_placeholder': 'Código de 6 dígitos', - 'auth.pairing_progress': 'Vinculando…', - 'auth.logout': 'Cerrar sesión', - 'common.languages': 'Idiomas', - 'common.select_language': 'Elegir idioma', - 'header.dashboard_tagline': 'Panel de ZeroClaw', -}); - -const pt = createLocale({ - 'nav.dashboard': 'Painel', - 'nav.agent': 'Agente', - 'nav.tools': 'Ferramentas', - 'nav.cron': 'Tarefas agendadas', - 'nav.integrations': 'Integrações', - 'nav.memory': 'Memória', - 'nav.config': 'Configuração', - 'nav.cost': 'Custos', - 'nav.logs': 'Logs', - 'nav.doctor': 'Diagnóstico', - 'dashboard.hero_title': 'Painel elétrico do runtime', - 'agent.placeholder': 'Digite uma mensagem…', - 'tools.search': 'Buscar ferramentas…', - 'cron.add': 'Adicionar tarefa', - 'memory.add_memory': 'Adicionar memória', - 'config.save': 'Salvar', - 'cost.token_statistics': 'Estatísticas de tokens', - 'logs.title': 'Logs ao vivo', - 'doctor.title': 'Diagnóstico do sistema', - 'auth.pair_button': 'Parear', - 'auth.enter_code': 'Digite o código único de pareamento mostrado no terminal', - 'auth.code_placeholder': 'Código de 6 dígitos', - 'auth.pairing_progress': 'Pareando…', - 'auth.logout': 'Sair', - 'common.languages': 'Idiomas', - 'common.select_language': 'Escolher idioma', - 'header.dashboard_tagline': 'Painel do ZeroClaw', -}); - -const it = createLocale({ - 'nav.dashboard': 'Dashboard', - 'nav.agent': 'Agente', - 'nav.tools': 'Strumenti', - 'nav.cron': 'Attività pianificate', - 'nav.integrations': 'Integrazioni', - 'nav.memory': 'Memoria', - 'nav.config': 'Configurazione', - 'nav.cost': 'Costi', - 'nav.logs': 'Log', - 'nav.doctor': 'Diagnostica', - 'dashboard.hero_title': 'Dashboard runtime elettrica', - 'agent.placeholder': 'Scrivi un messaggio…', - 'tools.search': 'Cerca strumenti…', - 'cron.add': 'Aggiungi attività', - 'memory.add_memory': 'Aggiungi memoria', - 'config.save': 'Salva', - 'cost.token_statistics': 'Statistiche token', - 'logs.title': 'Log in tempo reale', - 'doctor.title': 'Diagnostica di sistema', - 'auth.pair_button': 'Associa', - 'auth.enter_code': 'Inserisci il codice di associazione monouso dal terminale', - 'auth.code_placeholder': 'Codice a 6 cifre', - 'auth.pairing_progress': 'Associazione…', - 'auth.logout': 'Disconnetti', - 'common.languages': 'Lingue', - 'common.select_language': 'Scegli lingua', - 'header.dashboard_tagline': 'Dashboard di ZeroClaw', -}); - -const de = createLocale({ - 'nav.dashboard': 'Dashboard', - 'nav.agent': 'Agent', - 'nav.tools': 'Werkzeuge', - 'nav.cron': 'Geplante Aufgaben', - 'nav.integrations': 'Integrationen', - 'nav.memory': 'Speicher', - 'nav.config': 'Konfiguration', - 'nav.cost': 'Kosten', - 'nav.logs': 'Protokolle', - 'nav.doctor': 'Diagnose', - 'dashboard.hero_title': 'Elektrisches Runtime-Dashboard', - 'agent.placeholder': 'Nachricht eingeben…', - 'tools.search': 'Werkzeuge suchen…', - 'cron.add': 'Aufgabe hinzufügen', - 'memory.add_memory': 'Speicher hinzufügen', - 'config.save': 'Speichern', - 'cost.token_statistics': 'Token-Statistiken', - 'logs.title': 'Live-Protokolle', - 'doctor.title': 'Systemdiagnose', - 'auth.pair_button': 'Koppeln', - 'auth.enter_code': 'Geben Sie den einmaligen Kopplungscode aus dem Terminal ein', - 'auth.code_placeholder': '6-stelliger Code', - 'auth.pairing_progress': 'Kopplung…', - 'auth.logout': 'Abmelden', - 'common.languages': 'Sprachen', - 'common.select_language': 'Sprache auswählen', - 'header.dashboard_tagline': 'ZeroClaw-Dashboard', -}); - -const ar = createLocale({ - 'nav.dashboard': 'لوحة التحكم', - 'nav.agent': 'الوكيل', - 'nav.tools': 'الأدوات', - 'nav.cron': 'المهام المجدولة', - 'nav.integrations': 'التكاملات', - 'nav.memory': 'الذاكرة', - 'nav.config': 'الإعدادات', - 'nav.cost': 'تتبع التكلفة', - 'nav.logs': 'السجلات', - 'nav.doctor': 'التشخيص', - 'dashboard.hero_title': 'لوحة تشغيل كهربائية', - 'agent.placeholder': 'اكتب رسالة…', - 'tools.search': 'ابحث في الأدوات…', - 'cron.add': 'إضافة مهمة', - 'memory.add_memory': 'إضافة ذاكرة', - 'config.save': 'حفظ', - 'cost.token_statistics': 'إحصاءات الرموز', - 'logs.title': 'السجلات المباشرة', - 'doctor.title': 'تشخيص النظام', - 'auth.pair_button': 'اقتران', - 'auth.enter_code': 'أدخل رمز الاقتران لمرة واحدة من الطرفية', - 'auth.code_placeholder': 'رمز من 6 أرقام', - 'auth.pairing_progress': 'جارٍ الاقتران…', - 'auth.logout': 'تسجيل الخروج', - 'common.languages': 'اللغات', - 'common.select_language': 'اختر اللغة', - 'header.dashboard_tagline': 'لوحة ZeroClaw', -}); - -const hi = createLocale({ - 'nav.dashboard': 'डैशबोर्ड', - 'nav.agent': 'एजेंट', - 'nav.tools': 'टूल्स', - 'nav.cron': 'निर्धारित कार्य', - 'nav.integrations': 'इंटीग्रेशन', - 'nav.memory': 'मेमोरी', - 'nav.config': 'कॉन्फ़िगरेशन', - 'nav.cost': 'लागत ट्रैकर', - 'nav.logs': 'लॉग्स', - 'nav.doctor': 'जाँच', - 'dashboard.hero_title': 'इलेक्ट्रिक रनटाइम डैशबोर्ड', - 'agent.placeholder': 'संदेश लिखें…', - 'tools.search': 'टूल खोजें…', - 'cron.add': 'कार्य जोड़ें', - 'memory.add_memory': 'मेमोरी जोड़ें', - 'config.save': 'सहेजें', - 'cost.token_statistics': 'टोकन आँकड़े', - 'logs.title': 'लाइव लॉग्स', - 'doctor.title': 'सिस्टम जाँच', - 'auth.pair_button': 'पेयर करें', - 'auth.enter_code': 'टर्मिनल से एक-बार वाला पेयरिंग कोड दर्ज करें', - 'auth.code_placeholder': '6-अंकों का कोड', - 'auth.pairing_progress': 'पेयर किया जा रहा है…', - 'auth.logout': 'लॉग आउट', - 'common.languages': 'भाषाएँ', - 'common.select_language': 'भाषा चुनें', - 'header.dashboard_tagline': 'ZeroClaw डैशबोर्ड', -}); - -const bn = createLocale({ - 'nav.dashboard': 'ড্যাশবোর্ড', - 'nav.agent': 'এজেন্ট', - 'nav.tools': 'টুলস', - 'nav.cron': 'নির্ধারিত কাজ', - 'nav.integrations': 'ইন্টিগ্রেশন', - 'nav.memory': 'মেমরি', - 'nav.config': 'কনফিগারেশন', - 'nav.cost': 'খরচ ট্র্যাকার', - 'nav.logs': 'লগ', - 'nav.doctor': 'ডায়াগনস্টিক', - 'dashboard.hero_title': 'ইলেকট্রিক রানটাইম ড্যাশবোর্ড', - 'agent.placeholder': 'একটি বার্তা লিখুন…', - 'tools.search': 'টুল খুঁজুন…', - 'cron.add': 'কাজ যোগ করুন', - 'memory.add_memory': 'মেমরি যোগ করুন', - 'config.save': 'সংরক্ষণ করুন', - 'cost.token_statistics': 'টোকেন পরিসংখ্যান', - 'logs.title': 'লাইভ লগ', - 'doctor.title': 'সিস্টেম ডায়াগনস্টিক', - 'auth.pair_button': 'পেয়ার করুন', - 'auth.enter_code': 'টার্মিনাল থেকে একবারের পেয়ারিং কোড লিখুন', - 'auth.code_placeholder': '৬-সংখ্যার কোড', - 'auth.pairing_progress': 'পেয়ার করা হচ্ছে…', - 'auth.logout': 'লগ আউট', - 'common.languages': 'ভাষাসমূহ', - 'common.select_language': 'ভাষা বেছে নিন', - 'header.dashboard_tagline': 'ZeroClaw ড্যাশবোর্ড', -}); - -const he = createLocale({ - 'nav.dashboard': 'לוח מחוונים', - 'nav.agent': 'סוכן', - 'nav.tools': 'כלים', - 'nav.cron': 'משימות מתוזמנות', - 'nav.integrations': 'אינטגרציות', - 'nav.memory': 'זיכרון', - 'nav.config': 'תצורה', - 'nav.cost': 'מעקב עלויות', - 'nav.logs': 'יומנים', - 'nav.doctor': 'אבחון', - 'dashboard.hero_title': 'לוח מחוונים חשמלי של זמן הריצה', - 'agent.placeholder': 'הקלד הודעה…', - 'tools.search': 'חפש כלים…', - 'cron.add': 'הוסף משימה', - 'memory.add_memory': 'הוסף זיכרון', - 'config.save': 'שמור', - 'cost.token_statistics': 'סטטיסטיקות אסימונים', - 'logs.title': 'יומנים חיים', - 'doctor.title': 'אבחון מערכת', - 'auth.pair_button': 'התאמה', - 'auth.enter_code': 'הזן את קוד ההתאמה החד-פעמי מהמסוף', - 'auth.code_placeholder': 'קוד בן 6 ספרות', - 'auth.pairing_progress': 'מתבצעת התאמה…', - 'auth.logout': 'התנתק', - 'common.languages': 'שפות', - 'common.select_language': 'בחר שפה', - 'header.dashboard_tagline': 'לוח המחוונים של ZeroClaw', -}); - -const pl = createLocale({ - 'nav.dashboard': 'Pulpit', - 'nav.agent': 'Agent', - 'nav.tools': 'Narzędzia', - 'nav.cron': 'Zaplanowane zadania', - 'nav.integrations': 'Integracje', - 'nav.memory': 'Pamięć', - 'nav.config': 'Konfiguracja', - 'nav.cost': 'Koszty', - 'nav.logs': 'Logi', - 'nav.doctor': 'Diagnostyka', - 'dashboard.hero_title': 'Elektryczny pulpit runtime', - 'agent.placeholder': 'Wpisz wiadomość…', - 'tools.search': 'Szukaj narzędzi…', - 'cron.add': 'Dodaj zadanie', - 'memory.add_memory': 'Dodaj pamięć', - 'config.save': 'Zapisz', - 'cost.token_statistics': 'Statystyki tokenów', - 'logs.title': 'Logi na żywo', - 'doctor.title': 'Diagnostyka systemu', - 'auth.pair_button': 'Sparuj', - 'auth.enter_code': 'Wprowadź jednorazowy kod parowania z terminala', - 'auth.code_placeholder': '6-cyfrowy kod', - 'auth.pairing_progress': 'Parowanie…', - 'auth.logout': 'Wyloguj', - 'common.languages': 'Języki', - 'common.select_language': 'Wybierz język', - 'header.dashboard_tagline': 'Pulpit ZeroClaw', -}); - -const cs = createLocale({ - 'nav.dashboard': 'Nástěnka', - 'nav.agent': 'Agent', - 'nav.tools': 'Nástroje', - 'nav.cron': 'Plánované úlohy', - 'nav.integrations': 'Integrace', - 'nav.memory': 'Paměť', - 'nav.config': 'Konfigurace', - 'nav.cost': 'Náklady', - 'nav.logs': 'Logy', - 'nav.doctor': 'Diagnostika', - 'dashboard.hero_title': 'Elektrický runtime panel', - 'agent.placeholder': 'Napište zprávu…', - 'tools.search': 'Hledat nástroje…', - 'cron.add': 'Přidat úlohu', - 'memory.add_memory': 'Přidat paměť', - 'config.save': 'Uložit', - 'cost.token_statistics': 'Statistiky tokenů', - 'logs.title': 'Živé logy', - 'doctor.title': 'Diagnostika systému', - 'auth.pair_button': 'Spárovat', - 'auth.enter_code': 'Zadejte jednorázový párovací kód z terminálu', - 'auth.code_placeholder': '6místný kód', - 'auth.pairing_progress': 'Párování…', - 'auth.logout': 'Odhlásit se', - 'common.languages': 'Jazyky', - 'common.select_language': 'Vyberte jazyk', - 'header.dashboard_tagline': 'Panel ZeroClaw', -}); - -const nl = createLocale({ - 'nav.dashboard': 'Dashboard', - 'nav.agent': 'Agent', - 'nav.tools': 'Tools', - 'nav.cron': 'Geplande taken', - 'nav.integrations': 'Integraties', - 'nav.memory': 'Geheugen', - 'nav.config': 'Configuratie', - 'nav.cost': 'Kosten', - 'nav.logs': 'Logs', - 'nav.doctor': 'Diagnose', - 'dashboard.hero_title': 'Elektrisch runtime-dashboard', - 'agent.placeholder': 'Typ een bericht…', - 'tools.search': 'Tools zoeken…', - 'cron.add': 'Taak toevoegen', - 'memory.add_memory': 'Geheugen toevoegen', - 'config.save': 'Opslaan', - 'cost.token_statistics': 'Tokenstatistieken', - 'logs.title': 'Live-logs', - 'doctor.title': 'Systeemdiagnose', - 'auth.pair_button': 'Koppelen', - 'auth.enter_code': 'Voer de eenmalige koppelcode uit de terminal in', - 'auth.code_placeholder': '6-cijferige code', - 'auth.pairing_progress': 'Koppelen…', - 'auth.logout': 'Afmelden', - 'common.languages': 'Talen', - 'common.select_language': 'Kies taal', - 'header.dashboard_tagline': 'ZeroClaw-dashboard', -}); - -const uk = createLocale({ - 'nav.dashboard': 'Панель', - 'nav.agent': 'Агент', - 'nav.tools': 'Інструменти', - 'nav.cron': 'Заплановані завдання', - 'nav.integrations': 'Інтеграції', - 'nav.memory': 'Пам’ять', - 'nav.config': 'Конфігурація', - 'nav.cost': 'Витрати', - 'nav.logs': 'Журнали', - 'nav.doctor': 'Діагностика', - 'dashboard.hero_title': 'Електрична панель runtime', - 'agent.placeholder': 'Введіть повідомлення…', - 'tools.search': 'Пошук інструментів…', - 'cron.add': 'Додати завдання', - 'memory.add_memory': 'Додати пам’ять', - 'config.save': 'Зберегти', - 'cost.token_statistics': 'Статистика токенів', - 'logs.title': 'Живі журнали', - 'doctor.title': 'Діагностика системи', - 'auth.pair_button': 'З’єднати', - 'auth.enter_code': 'Введіть одноразовий код з’єднання з термінала', - 'auth.code_placeholder': '6-значний код', - 'auth.pairing_progress': 'З’єднання…', - 'auth.logout': 'Вийти', - 'common.languages': 'Мови', - 'common.select_language': 'Оберіть мову', - 'header.dashboard_tagline': 'Панель ZeroClaw', -}); - -const id = createLocale({ - 'nav.dashboard': 'Dasbor', - 'nav.agent': 'Agen', - 'nav.tools': 'Alat', - 'nav.cron': 'Tugas terjadwal', - 'nav.integrations': 'Integrasi', - 'nav.memory': 'Memori', - 'nav.config': 'Konfigurasi', - 'nav.cost': 'Biaya', - 'nav.logs': 'Log', - 'nav.doctor': 'Diagnosis', - 'dashboard.hero_title': 'Dasbor runtime elektrik', - 'agent.placeholder': 'Tulis pesan…', - 'tools.search': 'Cari alat…', - 'cron.add': 'Tambah tugas', - 'memory.add_memory': 'Tambah memori', - 'config.save': 'Simpan', - 'cost.token_statistics': 'Statistik token', - 'logs.title': 'Log langsung', - 'doctor.title': 'Diagnosis sistem', - 'auth.pair_button': 'Pasangkan', - 'auth.enter_code': 'Masukkan kode pairing sekali pakai dari terminal', - 'auth.code_placeholder': 'Kode 6 digit', - 'auth.pairing_progress': 'Sedang memasangkan…', - 'auth.logout': 'Keluar', - 'common.languages': 'Bahasa', - 'common.select_language': 'Pilih bahasa', - 'header.dashboard_tagline': 'Dasbor ZeroClaw', -}); - -const th = createLocale({ - 'nav.dashboard': 'แดชบอร์ด', - 'nav.agent': 'เอเจนต์', - 'nav.tools': 'เครื่องมือ', - 'nav.cron': 'งานที่ตั้งเวลา', - 'nav.integrations': 'การเชื่อมต่อ', - 'nav.memory': 'หน่วยความจำ', - 'nav.config': 'การกำหนดค่า', - 'nav.cost': 'ต้นทุน', - 'nav.logs': 'บันทึก', - 'nav.doctor': 'วินิจฉัย', - 'dashboard.hero_title': 'แดชบอร์ดรันไทม์ไฟฟ้า', - 'agent.placeholder': 'พิมพ์ข้อความ…', - 'tools.search': 'ค้นหาเครื่องมือ…', - 'cron.add': 'เพิ่มงาน', - 'memory.add_memory': 'เพิ่มหน่วยความจำ', - 'config.save': 'บันทึก', - 'cost.token_statistics': 'สถิติโทเค็น', - 'logs.title': 'บันทึกสด', - 'doctor.title': 'วินิจฉัยระบบ', - 'auth.pair_button': 'จับคู่', - 'auth.enter_code': 'ป้อนรหัสจับคู่แบบใช้ครั้งเดียวจากเทอร์มินัล', - 'auth.code_placeholder': 'รหัส 6 หลัก', - 'auth.pairing_progress': 'กำลังจับคู่…', - 'auth.logout': 'ออกจากระบบ', - 'common.languages': 'ภาษา', - 'common.select_language': 'เลือกภาษา', - 'header.dashboard_tagline': 'แดชบอร์ด ZeroClaw', -}); - -const ur = createLocale({ - 'nav.dashboard': 'ڈیش بورڈ', - 'nav.agent': 'ایجنٹ', - 'nav.tools': 'ٹولز', - 'nav.cron': 'شیڈول شدہ کام', - 'nav.integrations': 'انضمامات', - 'nav.memory': 'میموری', - 'nav.config': 'ترتیبات', - 'nav.cost': 'لاگت', - 'nav.logs': 'لاگز', - 'nav.doctor': 'تشخیص', - 'dashboard.hero_title': 'الیکٹرک رن ٹائم ڈیش بورڈ', - 'agent.placeholder': 'پیغام لکھیں…', - 'tools.search': 'ٹولز تلاش کریں…', - 'cron.add': 'کام شامل کریں', - 'memory.add_memory': 'میموری شامل کریں', - 'config.save': 'محفوظ کریں', - 'cost.token_statistics': 'ٹوکن کے اعدادوشمار', - 'logs.title': 'لائیو لاگز', - 'doctor.title': 'سسٹم تشخیص', - 'auth.pair_button': 'جوڑیں', - 'auth.enter_code': 'ٹرمینل سے ایک بار استعمال ہونے والا پیئرنگ کوڈ درج کریں', - 'auth.code_placeholder': '6 ہندسوں کا کوڈ', - 'auth.pairing_progress': 'جوڑا جا رہا ہے…', - 'auth.logout': 'لاگ آؤٹ', - 'common.languages': 'زبانیں', - 'common.select_language': 'زبان منتخب کریں', - 'header.dashboard_tagline': 'ZeroClaw ڈیش بورڈ', -}); - -const ro = createLocale({ - 'nav.dashboard': 'Tablou de bord', - 'nav.agent': 'Agent', - 'nav.tools': 'Unelte', - 'nav.cron': 'Sarcini programate', - 'nav.integrations': 'Integrări', - 'nav.memory': 'Memorie', - 'nav.config': 'Configurație', - 'nav.cost': 'Costuri', - 'nav.logs': 'Jurnale', - 'nav.doctor': 'Diagnostic', - 'dashboard.hero_title': 'Tablou de bord runtime electric', - 'agent.placeholder': 'Scrie un mesaj…', - 'tools.search': 'Caută unelte…', - 'cron.add': 'Adaugă sarcină', - 'memory.add_memory': 'Adaugă memorie', - 'config.save': 'Salvează', - 'cost.token_statistics': 'Statistici tokenuri', - 'logs.title': 'Jurnale live', - 'doctor.title': 'Diagnostic sistem', - 'auth.pair_button': 'Asociază', - 'auth.enter_code': 'Introdu codul unic de asociere din terminal', - 'auth.code_placeholder': 'Cod din 6 cifre', - 'auth.pairing_progress': 'Asociere…', - 'auth.logout': 'Deconectare', - 'common.languages': 'Limbi', - 'common.select_language': 'Alege limba', - 'header.dashboard_tagline': 'Tabloul ZeroClaw', -}); - -const sv = createLocale({ - 'nav.dashboard': 'Instrumentpanel', - 'nav.agent': 'Agent', - 'nav.tools': 'Verktyg', - 'nav.cron': 'Schemalagda jobb', - 'nav.integrations': 'Integrationer', - 'nav.memory': 'Minne', - 'nav.config': 'Konfiguration', - 'nav.cost': 'Kostnader', - 'nav.logs': 'Loggar', - 'nav.doctor': 'Diagnostik', - 'dashboard.hero_title': 'Elektrisk runtimepanel', - 'agent.placeholder': 'Skriv ett meddelande…', - 'tools.search': 'Sök verktyg…', - 'cron.add': 'Lägg till jobb', - 'memory.add_memory': 'Lägg till minne', - 'config.save': 'Spara', - 'cost.token_statistics': 'Tokenstatistik', - 'logs.title': 'Live-loggar', - 'doctor.title': 'Systemdiagnostik', - 'auth.pair_button': 'Para', - 'auth.enter_code': 'Ange engångskoden från terminalen', - 'auth.code_placeholder': '6-siffrig kod', - 'auth.pairing_progress': 'Parar…', - 'auth.logout': 'Logga ut', - 'common.languages': 'Språk', - 'common.select_language': 'Välj språk', - 'header.dashboard_tagline': 'ZeroClaw-panel', -}); - -const el = createLocale({ - 'nav.dashboard': 'Πίνακας ελέγχου', - 'nav.agent': 'Πράκτορας', - 'nav.tools': 'Εργαλεία', - 'nav.cron': 'Προγραμματισμένες εργασίες', - 'nav.integrations': 'Ενσωματώσεις', - 'nav.memory': 'Μνήμη', - 'nav.config': 'Ρυθμίσεις', - 'nav.cost': 'Κόστος', - 'nav.logs': 'Αρχεία καταγραφής', - 'nav.doctor': 'Διάγνωση', - 'dashboard.hero_title': 'Ηλεκτρικός πίνακας runtime', - 'agent.placeholder': 'Πληκτρολογήστε μήνυμα…', - 'tools.search': 'Αναζήτηση εργαλείων…', - 'cron.add': 'Προσθήκη εργασίας', - 'memory.add_memory': 'Προσθήκη μνήμης', - 'config.save': 'Αποθήκευση', - 'cost.token_statistics': 'Στατιστικά token', - 'logs.title': 'Ζωντανά αρχεία καταγραφής', - 'doctor.title': 'Διάγνωση συστήματος', - 'auth.pair_button': 'Σύζευξη', - 'auth.enter_code': 'Εισαγάγετε τον εφάπαξ κωδικό σύζευξης από το terminal', - 'auth.code_placeholder': '6ψήφιος κωδικός', - 'auth.pairing_progress': 'Σύζευξη…', - 'auth.logout': 'Αποσύνδεση', - 'common.languages': 'Γλώσσες', - 'common.select_language': 'Επιλέξτε γλώσσα', - 'header.dashboard_tagline': 'Πίνακας ZeroClaw', -}); - -const hu = createLocale({ - 'nav.dashboard': 'Irányítópult', - 'nav.agent': 'Ügynök', - 'nav.tools': 'Eszközök', - 'nav.cron': 'Ütemezett feladatok', - 'nav.integrations': 'Integrációk', - 'nav.memory': 'Memória', - 'nav.config': 'Konfiguráció', - 'nav.cost': 'Költségek', - 'nav.logs': 'Naplók', - 'nav.doctor': 'Diagnosztika', - 'dashboard.hero_title': 'Elektromos runtime irányítópult', - 'agent.placeholder': 'Írjon üzenetet…', - 'tools.search': 'Eszközök keresése…', - 'cron.add': 'Feladat hozzáadása', - 'memory.add_memory': 'Memória hozzáadása', - 'config.save': 'Mentés', - 'cost.token_statistics': 'Tokenstatisztika', - 'logs.title': 'Élő naplók', - 'doctor.title': 'Rendszerdiagnosztika', - 'auth.pair_button': 'Párosítás', - 'auth.enter_code': 'Adja meg a terminál egyszer használatos párosítási kódját', - 'auth.code_placeholder': '6 számjegyű kód', - 'auth.pairing_progress': 'Párosítás…', - 'auth.logout': 'Kijelentkezés', - 'common.languages': 'Nyelvek', - 'common.select_language': 'Nyelv kiválasztása', - 'header.dashboard_tagline': 'ZeroClaw irányítópult', -}); - -const fi = createLocale({ - 'nav.dashboard': 'Hallintapaneeli', - 'nav.agent': 'Agentti', - 'nav.tools': 'Työkalut', - 'nav.cron': 'Ajastetut tehtävät', - 'nav.integrations': 'Integraatiot', - 'nav.memory': 'Muisti', - 'nav.config': 'Asetukset', - 'nav.cost': 'Kustannukset', - 'nav.logs': 'Lokit', - 'nav.doctor': 'Diagnostiikka', - 'dashboard.hero_title': 'Sähköinen runtime-hallintapaneeli', - 'agent.placeholder': 'Kirjoita viesti…', - 'tools.search': 'Etsi työkaluja…', - 'cron.add': 'Lisää tehtävä', - 'memory.add_memory': 'Lisää muisti', - 'config.save': 'Tallenna', - 'cost.token_statistics': 'Token-tilastot', - 'logs.title': 'Live-lokit', - 'doctor.title': 'Järjestelmädiagnostiikka', - 'auth.pair_button': 'Yhdistä', - 'auth.enter_code': 'Syötä terminaalin kertakäyttöinen parituskoodi', - 'auth.code_placeholder': '6-numeroinen koodi', - 'auth.pairing_progress': 'Yhdistetään…', - 'auth.logout': 'Kirjaudu ulos', - 'common.languages': 'Kielet', - 'common.select_language': 'Valitse kieli', - 'header.dashboard_tagline': 'ZeroClaw-hallintapaneeli', -}); - -const da = createLocale({ - 'nav.dashboard': 'Kontrolpanel', - 'nav.agent': 'Agent', - 'nav.tools': 'Værktøjer', - 'nav.cron': 'Planlagte job', - 'nav.integrations': 'Integrationer', - 'nav.memory': 'Hukommelse', - 'nav.config': 'Konfiguration', - 'nav.cost': 'Omkostninger', - 'nav.logs': 'Logge', - 'nav.doctor': 'Diagnostik', - 'dashboard.hero_title': 'Elektrisk runtime-kontrolpanel', - 'agent.placeholder': 'Skriv en besked…', - 'tools.search': 'Søg værktøjer…', - 'cron.add': 'Tilføj job', - 'memory.add_memory': 'Tilføj hukommelse', - 'config.save': 'Gem', - 'cost.token_statistics': 'Tokenstatistik', - 'logs.title': 'Live-logge', - 'doctor.title': 'Systemdiagnostik', - 'auth.pair_button': 'Par', - 'auth.enter_code': 'Indtast engangskoden fra terminalen', - 'auth.code_placeholder': '6-cifret kode', - 'auth.pairing_progress': 'Parrer…', - 'auth.logout': 'Log ud', - 'common.languages': 'Sprog', - 'common.select_language': 'Vælg sprog', - 'header.dashboard_tagline': 'ZeroClaw-kontrolpanel', -}); - -const nb = createLocale({ - 'nav.dashboard': 'Kontrollpanel', - 'nav.agent': 'Agent', - 'nav.tools': 'Verktøy', - 'nav.cron': 'Planlagte jobber', - 'nav.integrations': 'Integrasjoner', - 'nav.memory': 'Minne', - 'nav.config': 'Konfigurasjon', - 'nav.cost': 'Kostnader', - 'nav.logs': 'Logger', - 'nav.doctor': 'Diagnostikk', - 'dashboard.hero_title': 'Elektrisk runtime-kontrollpanel', - 'agent.placeholder': 'Skriv en melding…', - 'tools.search': 'Søk etter verktøy…', - 'cron.add': 'Legg til jobb', - 'memory.add_memory': 'Legg til minne', - 'config.save': 'Lagre', - 'cost.token_statistics': 'Tokenstatistikk', - 'logs.title': 'Live-logger', - 'doctor.title': 'Systemdiagnostikk', - 'auth.pair_button': 'Koble til', - 'auth.enter_code': 'Skriv inn engangskoden fra terminalen', - 'auth.code_placeholder': '6-sifret kode', - 'auth.pairing_progress': 'Kobler til…', - 'auth.logout': 'Logg ut', - 'common.languages': 'Språk', - 'common.select_language': 'Velg språk', - 'header.dashboard_tagline': 'ZeroClaw-kontrollpanel', -}); - - -const translations: Record> = { - en, - 'zh-CN': zhCn, - ja, - ko, - vi, - tl, - es, - pt, - it, - de, - fr, - ar, - hi, - ru, - bn, - he, - pl, - cs, - nl, - tr, - uk, - id, - th, - ur, - ro, - sv, - el, - hu, - fi, - da, - nb, -}; - -let currentLocale: Locale = 'en'; - -export function getLocale(): Locale { - return currentLocale; -} - -export function setLocale(locale: Locale): void { - currentLocale = locale; -} - -export function coerceLocale(locale: string | undefined): Locale { - if (!locale) return 'en'; - const normalized = locale.toLowerCase(); - if (normalized.startsWith('zh')) return 'zh-CN'; - if (normalized.startsWith('ja')) return 'ja'; - if (normalized.startsWith('ko')) return 'ko'; - if (normalized.startsWith('vi')) return 'vi'; - if (normalized.startsWith('tl')) return 'tl'; - if (normalized.startsWith('es')) return 'es'; - if (normalized.startsWith('pt')) return 'pt'; - if (normalized.startsWith('it')) return 'it'; - if (normalized.startsWith('de')) return 'de'; - if (normalized.startsWith('fr')) return 'fr'; - if (normalized.startsWith('ar')) return 'ar'; - if (normalized.startsWith('hi')) return 'hi'; - if (normalized.startsWith('ru')) return 'ru'; - if (normalized.startsWith('bn')) return 'bn'; - if (normalized.startsWith('iw') || normalized.startsWith('he')) return 'he'; - if (normalized.startsWith('pl')) return 'pl'; - if (normalized.startsWith('cs')) return 'cs'; - if (normalized.startsWith('nl')) return 'nl'; - if (normalized.startsWith('tr')) return 'tr'; - if (normalized.startsWith('uk')) return 'uk'; - if (normalized.startsWith('id')) return 'id'; - if (normalized.startsWith('th')) return 'th'; - if (normalized.startsWith('ur')) return 'ur'; - if (normalized.startsWith('ro')) return 'ro'; - if (normalized.startsWith('sv')) return 'sv'; - if (normalized.startsWith('el')) return 'el'; - if (normalized.startsWith('hu')) return 'hu'; - if (normalized.startsWith('fi')) return 'fi'; - if (normalized.startsWith('da')) return 'da'; - if (normalized.startsWith('nb') || normalized.startsWith('no')) return 'nb'; - return 'en'; -} - -export function t(key: string): string { - return translations[currentLocale]?.[key] ?? translations.en[key] ?? key; -} - -export function tLocale(key: string, locale: Locale): string { - return translations[locale]?.[key] ?? translations.en[key] ?? key; -} - -export function useLocale(): { locale: Locale; t: (key: string) => string } { - const [locale, setLocaleState] = useState(currentLocale); - - useEffect(() => { - let cancelled = false; - - getStatus() - .then((status) => { - if (cancelled) return; - const detected = coerceLocale(status.locale); - setLocale(detected); - setLocaleState(detected); - }) - .catch(() => { - // Keep default locale on error - }); - - return () => { - cancelled = true; - }; - }, []); - - return { - locale, - t: (key: string) => tLocale(key, locale), - }; -} diff --git a/web/src/lib/i18n.test.ts b/web/src/lib/i18n/index.test.ts similarity index 95% rename from web/src/lib/i18n.test.ts rename to web/src/lib/i18n/index.test.ts index d760fd3ea..88edf1e9c 100644 --- a/web/src/lib/i18n.test.ts +++ b/web/src/lib/i18n/index.test.ts @@ -3,11 +3,10 @@ import { applyLocaleToDocument, coerceLocale, getLanguageOption, - getLanguageOptionLabel, getLocaleDirection, LANGUAGE_OPTIONS, LANGUAGE_SWITCH_ORDER, -} from './i18n'; +} from '.'; describe('language metadata', () => { it('keeps language options aligned with switch order', () => { @@ -18,7 +17,7 @@ describe('language metadata', () => { it('provides a flag-backed label for every locale', () => { for (const option of LANGUAGE_OPTIONS) { expect(getLanguageOption(option.value)).toEqual(option); - expect(getLanguageOptionLabel(option)).toBe(option.label); + expect(option.label.length).toBeGreaterThan(0); expect(option.flag.length).toBeGreaterThan(0); } }); diff --git a/web/src/lib/i18n/index.ts b/web/src/lib/i18n/index.ts new file mode 100644 index 000000000..e4d2eb2e0 --- /dev/null +++ b/web/src/lib/i18n/index.ts @@ -0,0 +1,4 @@ +export type { Locale, LocaleDirection, LanguageOption, LocaleDocumentTarget } from './types'; +export { LANGUAGE_OPTIONS, LANGUAGE_SWITCH_ORDER, getLocaleDirection, getLanguageOption } from './languages'; +export { coerceLocale, getLocale, setLocale, t, tLocale, applyLocaleToDocument } from './translate'; +export { translations } from './locales'; diff --git a/web/src/lib/i18n/languages.ts b/web/src/lib/i18n/languages.ts new file mode 100644 index 000000000..b6d1b20bc --- /dev/null +++ b/web/src/lib/i18n/languages.ts @@ -0,0 +1,58 @@ +import type { LanguageOption, Locale, LocaleDirection } from './types'; + +export const LANGUAGE_OPTIONS: ReadonlyArray = [ + { value: 'en', label: 'English', flag: '🇺🇸', direction: 'ltr' }, + { value: 'zh-CN', label: '简体中文', flag: '🇨🇳', direction: 'ltr' }, + { value: 'ja', label: '日本語', flag: '🇯🇵', direction: 'ltr' }, + { value: 'ko', label: '한국어', flag: '🇰🇷', direction: 'ltr' }, + { value: 'vi', label: 'Tiếng Việt', flag: '🇻🇳', direction: 'ltr' }, + { value: 'tl', label: 'Tagalog', flag: '🇵🇭', direction: 'ltr' }, + { value: 'es', label: 'Español', flag: '🇪🇸', direction: 'ltr' }, + { value: 'pt', label: 'Português', flag: '🇵🇹', direction: 'ltr' }, + { value: 'it', label: 'Italiano', flag: '🇮🇹', direction: 'ltr' }, + { value: 'de', label: 'Deutsch', flag: '🇩🇪', direction: 'ltr' }, + { value: 'fr', label: 'Français', flag: '🇫🇷', direction: 'ltr' }, + { value: 'ar', label: 'العربية', flag: '🇸🇦', direction: 'rtl' }, + { value: 'hi', label: 'हिन्दी', flag: '🇮🇳', direction: 'ltr' }, + { value: 'ru', label: 'Русский', flag: '🇷🇺', direction: 'ltr' }, + { value: 'bn', label: 'বাংলা', flag: '🇧🇩', direction: 'ltr' }, + { value: 'he', label: 'עברית', flag: '🇮🇱', direction: 'rtl' }, + { value: 'pl', label: 'Polski', flag: '🇵🇱', direction: 'ltr' }, + { value: 'cs', label: 'Čeština', flag: '🇨🇿', direction: 'ltr' }, + { value: 'nl', label: 'Nederlands', flag: '🇳🇱', direction: 'ltr' }, + { value: 'tr', label: 'Türkçe', flag: '🇹🇷', direction: 'ltr' }, + { value: 'uk', label: 'Українська', flag: '🇺🇦', direction: 'ltr' }, + { value: 'id', label: 'Bahasa Indonesia', flag: '🇮🇩', direction: 'ltr' }, + { value: 'th', label: 'ไทย', flag: '🇹🇭', direction: 'ltr' }, + { value: 'ur', label: 'اردو', flag: '🇵🇰', direction: 'rtl' }, + { value: 'ro', label: 'Română', flag: '🇷🇴', direction: 'ltr' }, + { value: 'sv', label: 'Svenska', flag: '🇸🇪', direction: 'ltr' }, + { value: 'el', label: 'Ελληνικά', flag: '🇬🇷', direction: 'ltr' }, + { value: 'hu', label: 'Magyar', flag: '🇭🇺', direction: 'ltr' }, + { value: 'fi', label: 'Suomi', flag: '🇫🇮', direction: 'ltr' }, + { value: 'da', label: 'Dansk', flag: '🇩🇰', direction: 'ltr' }, + { value: 'nb', label: 'Norsk Bokmål', flag: '🇳🇴', direction: 'ltr' }, +]; + +export const LANGUAGE_SWITCH_ORDER: ReadonlyArray = + LANGUAGE_OPTIONS.map((option) => option.value); + +const RTL_LOCALES = new Set(['ar', 'he', 'ur']); + +export function getLocaleDirection(locale: Locale): LocaleDirection { + return RTL_LOCALES.has(locale) ? 'rtl' : 'ltr'; +} + +export function getLanguageOption(locale: Locale): LanguageOption { + const matched = LANGUAGE_OPTIONS.find((option) => option.value === locale); + if (matched) { + return matched; + } + + const fallback = LANGUAGE_OPTIONS.find((option) => option.value === 'en'); + if (!fallback) { + throw new Error('English locale metadata is missing.'); + } + + return fallback; +} diff --git a/web/src/lib/i18n/locales/ar.ts b/web/src/lib/i18n/locales/ar.ts new file mode 100644 index 000000000..da191039e --- /dev/null +++ b/web/src/lib/i18n/locales/ar.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const ar: Partial = { + 'nav.dashboard': 'لوحة التحكم', + 'nav.agent': 'الوكيل', + 'nav.tools': 'الأدوات', + 'nav.cron': 'المهام المجدولة', + 'nav.integrations': 'التكاملات', + 'nav.memory': 'الذاكرة', + 'nav.config': 'الإعدادات', + 'nav.cost': 'تتبع التكلفة', + 'nav.logs': 'السجلات', + 'nav.doctor': 'التشخيص', + 'dashboard.hero_title': 'لوحة تشغيل كهربائية', + 'agent.placeholder': 'اكتب رسالة…', + 'tools.search': 'ابحث في الأدوات…', + 'cron.add': 'إضافة مهمة', + 'memory.add_memory': 'إضافة ذاكرة', + 'config.save': 'حفظ', + 'cost.token_statistics': 'إحصاءات الرموز', + 'logs.title': 'السجلات المباشرة', + 'doctor.title': 'تشخيص النظام', + 'auth.pair_button': 'اقتران', + 'auth.enter_code': 'أدخل رمز الاقتران لمرة واحدة من الطرفية', + 'auth.code_placeholder': 'رمز من 6 أرقام', + 'auth.pairing_progress': 'جارٍ الاقتران…', + 'auth.logout': 'تسجيل الخروج', + 'common.languages': 'اللغات', + 'common.select_language': 'اختر اللغة', + 'header.dashboard_tagline': 'لوحة ZeroClaw', +}; + +export default ar; diff --git a/web/src/lib/i18n/locales/bn.ts b/web/src/lib/i18n/locales/bn.ts new file mode 100644 index 000000000..464fb9493 --- /dev/null +++ b/web/src/lib/i18n/locales/bn.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const bn: Partial = { + 'nav.dashboard': 'ড্যাশবোর্ড', + 'nav.agent': 'এজেন্ট', + 'nav.tools': 'টুলস', + 'nav.cron': 'নির্ধারিত কাজ', + 'nav.integrations': 'ইন্টিগ্রেশন', + 'nav.memory': 'মেমরি', + 'nav.config': 'কনফিগারেশন', + 'nav.cost': 'খরচ ট্র্যাকার', + 'nav.logs': 'লগ', + 'nav.doctor': 'ডায়াগনস্টিক', + 'dashboard.hero_title': 'ইলেকট্রিক রানটাইম ড্যাশবোর্ড', + 'agent.placeholder': 'একটি বার্তা লিখুন…', + 'tools.search': 'টুল খুঁজুন…', + 'cron.add': 'কাজ যোগ করুন', + 'memory.add_memory': 'মেমরি যোগ করুন', + 'config.save': 'সংরক্ষণ করুন', + 'cost.token_statistics': 'টোকেন পরিসংখ্যান', + 'logs.title': 'লাইভ লগ', + 'doctor.title': 'সিস্টেম ডায়াগনস্টিক', + 'auth.pair_button': 'পেয়ার করুন', + 'auth.enter_code': 'টার্মিনাল থেকে একবারের পেয়ারিং কোড লিখুন', + 'auth.code_placeholder': '৬-সংখ্যার কোড', + 'auth.pairing_progress': 'পেয়ার করা হচ্ছে…', + 'auth.logout': 'লগ আউট', + 'common.languages': 'ভাষাসমূহ', + 'common.select_language': 'ভাষা বেছে নিন', + 'header.dashboard_tagline': 'ZeroClaw ড্যাশবোর্ড', +}; + +export default bn; diff --git a/web/src/lib/i18n/locales/cs.ts b/web/src/lib/i18n/locales/cs.ts new file mode 100644 index 000000000..fbf488aa1 --- /dev/null +++ b/web/src/lib/i18n/locales/cs.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const cs: Partial = { + 'nav.dashboard': 'Nástěnka', + 'nav.agent': 'Agent', + 'nav.tools': 'Nástroje', + 'nav.cron': 'Plánované úlohy', + 'nav.integrations': 'Integrace', + 'nav.memory': 'Paměť', + 'nav.config': 'Konfigurace', + 'nav.cost': 'Náklady', + 'nav.logs': 'Logy', + 'nav.doctor': 'Diagnostika', + 'dashboard.hero_title': 'Elektrický runtime panel', + 'agent.placeholder': 'Napište zprávu…', + 'tools.search': 'Hledat nástroje…', + 'cron.add': 'Přidat úlohu', + 'memory.add_memory': 'Přidat paměť', + 'config.save': 'Uložit', + 'cost.token_statistics': 'Statistiky tokenů', + 'logs.title': 'Živé logy', + 'doctor.title': 'Diagnostika systému', + 'auth.pair_button': 'Spárovat', + 'auth.enter_code': 'Zadejte jednorázový párovací kód z terminálu', + 'auth.code_placeholder': '6místný kód', + 'auth.pairing_progress': 'Párování…', + 'auth.logout': 'Odhlásit se', + 'common.languages': 'Jazyky', + 'common.select_language': 'Vyberte jazyk', + 'header.dashboard_tagline': 'Panel ZeroClaw', +}; + +export default cs; diff --git a/web/src/lib/i18n/locales/da.ts b/web/src/lib/i18n/locales/da.ts new file mode 100644 index 000000000..dc1d7976b --- /dev/null +++ b/web/src/lib/i18n/locales/da.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const da: Partial = { + 'nav.dashboard': 'Kontrolpanel', + 'nav.agent': 'Agent', + 'nav.tools': 'Værktøjer', + 'nav.cron': 'Planlagte job', + 'nav.integrations': 'Integrationer', + 'nav.memory': 'Hukommelse', + 'nav.config': 'Konfiguration', + 'nav.cost': 'Omkostninger', + 'nav.logs': 'Logge', + 'nav.doctor': 'Diagnostik', + 'dashboard.hero_title': 'Elektrisk runtime-kontrolpanel', + 'agent.placeholder': 'Skriv en besked…', + 'tools.search': 'Søg værktøjer…', + 'cron.add': 'Tilføj job', + 'memory.add_memory': 'Tilføj hukommelse', + 'config.save': 'Gem', + 'cost.token_statistics': 'Tokenstatistik', + 'logs.title': 'Live-logge', + 'doctor.title': 'Systemdiagnostik', + 'auth.pair_button': 'Par', + 'auth.enter_code': 'Indtast engangskoden fra terminalen', + 'auth.code_placeholder': '6-cifret kode', + 'auth.pairing_progress': 'Parrer…', + 'auth.logout': 'Log ud', + 'common.languages': 'Sprog', + 'common.select_language': 'Vælg sprog', + 'header.dashboard_tagline': 'ZeroClaw-kontrolpanel', +}; + +export default da; diff --git a/web/src/lib/i18n/locales/de.ts b/web/src/lib/i18n/locales/de.ts new file mode 100644 index 000000000..e96481aa3 --- /dev/null +++ b/web/src/lib/i18n/locales/de.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const de: Partial = { + 'nav.dashboard': 'Dashboard', + 'nav.agent': 'Agent', + 'nav.tools': 'Werkzeuge', + 'nav.cron': 'Geplante Aufgaben', + 'nav.integrations': 'Integrationen', + 'nav.memory': 'Speicher', + 'nav.config': 'Konfiguration', + 'nav.cost': 'Kosten', + 'nav.logs': 'Protokolle', + 'nav.doctor': 'Diagnose', + 'dashboard.hero_title': 'Elektrisches Runtime-Dashboard', + 'agent.placeholder': 'Nachricht eingeben…', + 'tools.search': 'Werkzeuge suchen…', + 'cron.add': 'Aufgabe hinzufügen', + 'memory.add_memory': 'Speicher hinzufügen', + 'config.save': 'Speichern', + 'cost.token_statistics': 'Token-Statistiken', + 'logs.title': 'Live-Protokolle', + 'doctor.title': 'Systemdiagnose', + 'auth.pair_button': 'Koppeln', + 'auth.enter_code': 'Geben Sie den einmaligen Kopplungscode aus dem Terminal ein', + 'auth.code_placeholder': '6-stelliger Code', + 'auth.pairing_progress': 'Kopplung…', + 'auth.logout': 'Abmelden', + 'common.languages': 'Sprachen', + 'common.select_language': 'Sprache auswählen', + 'header.dashboard_tagline': 'ZeroClaw-Dashboard', +}; + +export default de; diff --git a/web/src/lib/i18n/locales/el.ts b/web/src/lib/i18n/locales/el.ts new file mode 100644 index 000000000..6cd023b8c --- /dev/null +++ b/web/src/lib/i18n/locales/el.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const el: Partial = { + 'nav.dashboard': 'Πίνακας ελέγχου', + 'nav.agent': 'Πράκτορας', + 'nav.tools': 'Εργαλεία', + 'nav.cron': 'Προγραμματισμένες εργασίες', + 'nav.integrations': 'Ενσωματώσεις', + 'nav.memory': 'Μνήμη', + 'nav.config': 'Ρυθμίσεις', + 'nav.cost': 'Κόστος', + 'nav.logs': 'Αρχεία καταγραφής', + 'nav.doctor': 'Διάγνωση', + 'dashboard.hero_title': 'Ηλεκτρικός πίνακας runtime', + 'agent.placeholder': 'Πληκτρολογήστε μήνυμα…', + 'tools.search': 'Αναζήτηση εργαλείων…', + 'cron.add': 'Προσθήκη εργασίας', + 'memory.add_memory': 'Προσθήκη μνήμης', + 'config.save': 'Αποθήκευση', + 'cost.token_statistics': 'Στατιστικά token', + 'logs.title': 'Ζωντανά αρχεία καταγραφής', + 'doctor.title': 'Διάγνωση συστήματος', + 'auth.pair_button': 'Σύζευξη', + 'auth.enter_code': 'Εισαγάγετε τον εφάπαξ κωδικό σύζευξης από το terminal', + 'auth.code_placeholder': '6ψήφιος κωδικός', + 'auth.pairing_progress': 'Σύζευξη…', + 'auth.logout': 'Αποσύνδεση', + 'common.languages': 'Γλώσσες', + 'common.select_language': 'Επιλέξτε γλώσσα', + 'header.dashboard_tagline': 'Πίνακας ZeroClaw', +}; + +export default el; diff --git a/web/src/lib/i18n/locales/en.ts b/web/src/lib/i18n/locales/en.ts new file mode 100644 index 000000000..f16e28229 --- /dev/null +++ b/web/src/lib/i18n/locales/en.ts @@ -0,0 +1,273 @@ +const en = { + 'nav.dashboard': 'Dashboard', + 'nav.agent': 'Agent', + 'nav.tools': 'Tools', + 'nav.cron': 'Scheduled Jobs', + 'nav.integrations': 'Integrations', + 'nav.memory': 'Memory', + 'nav.config': 'Configuration', + 'nav.cost': 'Cost Tracker', + 'nav.logs': 'Logs', + 'nav.doctor': 'Doctor', + + 'dashboard.title': 'Dashboard', + 'dashboard.provider': 'Provider', + 'dashboard.model': 'Model', + 'dashboard.uptime': 'Uptime', + 'dashboard.temperature': 'Temperature', + 'dashboard.gateway_port': 'Gateway Port', + 'dashboard.locale': 'Locale', + 'dashboard.memory_backend': 'Memory Backend', + 'dashboard.paired': 'Paired', + 'dashboard.channels': 'Channels', + 'dashboard.health': 'Health', + 'dashboard.status': 'Status', + 'dashboard.overview': 'Overview', + 'dashboard.system_info': 'System Information', + 'dashboard.quick_actions': 'Quick Actions', + 'dashboard.load_failed': 'Dashboard load failed', + 'dashboard.load_unknown_error': 'Unknown dashboard load error', + 'dashboard.hero_eyebrow': 'ZeroClaw Command Deck', + 'dashboard.hero_title': 'Electric Runtime Dashboard', + 'dashboard.hero_subtitle': 'Real-time telemetry, cost pulse, and operations status in a single collapsible surface.', + 'dashboard.live_gateway': 'Live Gateway', + 'dashboard.unpaired': 'Unpaired', + 'dashboard.provider_model': 'Provider / Model', + 'dashboard.since_last_restart': 'Since last restart', + 'dashboard.pairing_active': 'Pairing active', + 'dashboard.no_paired_devices': 'No paired devices', + 'dashboard.cost_pulse': 'Cost Pulse', + 'dashboard.cost_subtitle': 'Session, daily, and monthly runtime spend', + 'dashboard.session': 'Session', + 'dashboard.daily': 'Daily', + 'dashboard.monthly': 'Monthly', + 'dashboard.channel_activity': 'Channel Activity', + 'dashboard.channel_subtitle': 'Live integrations and route connectivity', + 'dashboard.no_channels': 'No channels configured.', + 'dashboard.active': 'Active', + 'dashboard.inactive': 'Inactive', + 'dashboard.component_health': 'Component Health', + 'dashboard.component_subtitle': 'Runtime heartbeat and restart awareness', + 'dashboard.no_component_health': 'No component health is currently available.', + 'dashboard.restarts': 'Restarts', + 'dashboard.unknown_provider': 'Unknown', + + 'agent.title': 'Agent Chat', + 'agent.send': 'Send', + 'agent.placeholder': 'Type a message...', + 'agent.connecting': 'Connecting...', + 'agent.connected': 'Connected', + 'agent.disconnected': 'Disconnected', + 'agent.reconnecting': 'Reconnecting...', + 'agent.thinking': 'Thinking...', + 'agent.tool_call': 'Tool Call', + 'agent.tool_result': 'Tool Result', + 'agent.connection_error': 'Connection error. Attempting to reconnect...', + 'agent.failed_send': 'Failed to send message. Please try again.', + 'agent.empty_title': 'ZeroClaw Agent', + 'agent.empty_subtitle': 'Send a message to start the conversation', + 'agent.unknown_error': 'Unknown error', + + 'tools.title': 'Available Tools', + 'tools.name': 'Name', + 'tools.description': 'Description', + 'tools.parameters': 'Parameters', + 'tools.search': 'Search tools...', + 'tools.empty': 'No tools available.', + 'tools.count': 'Total tools', + 'tools.agent_tools': 'Agent Tools', + 'tools.cli_tools': 'CLI Tools', + 'tools.no_search_results': 'No tools match your search.', + 'tools.parameter_schema': 'Parameter Schema', + 'tools.path': 'Path', + 'tools.version': 'Version', + 'tools.load_failed': 'Failed to load tools', + + 'cron.title': 'Scheduled Jobs', + 'cron.add': 'Add Job', + 'cron.delete': 'Delete', + 'cron.enable': 'Enable', + 'cron.disable': 'Disable', + 'cron.name': 'Name', + 'cron.command': 'Command', + 'cron.schedule': 'Schedule', + 'cron.next_run': 'Next Run', + 'cron.last_run': 'Last Run', + 'cron.last_status': 'Last Status', + 'cron.enabled': 'Enabled', + 'cron.empty': 'No scheduled jobs.', + 'cron.confirm_delete': 'Are you sure you want to delete this job?', + 'cron.scheduled_tasks': 'Scheduled Tasks', + 'cron.add_cron_job': 'Add Cron Job', + 'cron.name_optional': 'Name (optional)', + 'cron.schedule_required_command_required': 'Schedule and command are required.', + 'cron.adding': 'Adding...', + 'cron.no_tasks_configured': 'No scheduled tasks configured.', + 'cron.load_failed': 'Failed to load cron jobs', + 'cron.failed_add': 'Failed to add job', + 'cron.failed_delete': 'Failed to delete job', + 'cron.delete_prompt': 'Delete?', + 'cron.id': 'ID', + 'cron.disabled': 'Disabled', + + 'integrations.title': 'Integrations', + 'integrations.available': 'Available', + 'integrations.active': 'Active', + 'integrations.coming_soon': 'Coming Soon', + 'integrations.category': 'Category', + 'integrations.status': 'Status', + 'integrations.search': 'Search integrations...', + 'integrations.empty': 'No integrations found.', + 'integrations.activate': 'Activate', + 'integrations.deactivate': 'Deactivate', + 'integrations.load_failed': 'Failed to load integrations', + 'integrations.all': 'all', + + 'memory.title': 'Memory Store', + 'memory.search': 'Search memory...', + 'memory.add': 'Store Memory', + 'memory.delete': 'Delete', + 'memory.key': 'Key', + 'memory.content': 'Content', + 'memory.category': 'Category', + 'memory.timestamp': 'Timestamp', + 'memory.session': 'Session', + 'memory.score': 'Score', + 'memory.empty': 'No memory entries found.', + 'memory.confirm_delete': 'Are you sure you want to delete this memory entry?', + 'memory.all_categories': 'All Categories', + 'memory.add_memory': 'Add Memory', + 'memory.search_entries': 'Search memory entries...', + 'memory.load_failed': 'Failed to load memory', + 'memory.key_content_required': 'Key and content are required.', + 'memory.failed_store': 'Failed to store memory', + 'memory.failed_delete': 'Failed to delete memory', + 'memory.category_optional': 'Category (optional)', + 'memory.key_placeholder': 'e.g. user_preferences', + 'memory.content_placeholder': 'Memory content...', + 'memory.category_placeholder': 'e.g. preferences, context, facts', + 'memory.search_button': 'Search', + 'memory.saving': 'Saving...', + 'memory.delete_prompt': 'Delete?', + + 'config.title': 'Configuration', + 'config.save': 'Save', + 'config.reset': 'Reset', + 'config.saved': 'Configuration saved successfully.', + 'config.error': 'Failed to save configuration.', + 'config.loading': 'Loading configuration...', + 'config.editor_placeholder': 'TOML configuration...', + 'config.saving': 'Saving...', + 'config.masked_title': 'Sensitive fields are masked', + 'config.masked_description': 'API keys, tokens, and passwords are hidden for security. To update a masked field, replace the entire masked value with your new value.', + 'config.toml_configuration': 'TOML Configuration', + 'config.lines': 'lines', + + 'cost.title': 'Cost Tracker', + 'cost.session': 'Session Cost', + 'cost.daily': 'Daily Cost', + 'cost.monthly': 'Monthly Cost', + 'cost.total_tokens': 'Total Tokens', + 'cost.request_count': 'Requests', + 'cost.by_model': 'Cost by Model', + 'cost.model': 'Model', + 'cost.tokens': 'Tokens', + 'cost.requests': 'Requests', + 'cost.usd': 'Cost (USD)', + 'cost.total_requests': 'Total Requests', + 'cost.token_statistics': 'Token Statistics', + 'cost.avg_tokens_per_request': 'Avg Tokens / Request', + 'cost.cost_per_1k_tokens': 'Cost per 1K Tokens', + 'cost.model_breakdown': 'Model Breakdown', + 'cost.no_model_data': 'No model data available.', + 'cost.share': 'Share', + 'cost.load_failed': 'Failed to load cost data', + + 'logs.title': 'Live Logs', + 'logs.clear': 'Clear', + 'logs.pause': 'Pause', + 'logs.resume': 'Resume', + 'logs.filter': 'Filter logs...', + 'logs.empty': 'No log entries.', + 'logs.connected': 'Connected to event stream.', + 'logs.disconnected': 'Disconnected from event stream.', + 'logs.events': 'events', + 'logs.jump_to_bottom': 'Jump to bottom', + 'logs.filter_label': 'Filter:', + 'logs.paused_stream': 'Log streaming is paused.', + 'logs.waiting_for_events': 'Waiting for events...', + + 'doctor.title': 'System Diagnostics', + 'doctor.run': 'Run Diagnostics', + 'doctor.running': 'Running diagnostics...', + 'doctor.ok': 'OK', + 'doctor.warn': 'Warning', + 'doctor.error': 'Error', + 'doctor.severity': 'Severity', + 'doctor.category': 'Category', + 'doctor.message': 'Message', + 'doctor.empty': 'No diagnostics have been run yet.', + 'doctor.summary': 'Diagnostic Summary', + 'doctor.running_short': 'Running...', + 'doctor.running_hint': 'This may take a few seconds.', + 'doctor.issues_found': 'Issues Found', + 'doctor.warnings': 'Warnings', + 'doctor.all_clear': 'All Clear', + 'doctor.instructions': 'Click "Run Diagnostics" to check your ZeroClaw installation.', + + 'auth.pair': 'Pair Device', + 'auth.pairing_code': 'Pairing Code', + 'auth.pair_button': 'Pair', + 'auth.logout': 'Logout', + 'auth.pairing_success': 'Pairing successful!', + 'auth.pairing_failed': 'Pairing failed. Please try again.', + 'auth.enter_code': 'Enter the one-time pairing code from your terminal', + 'auth.code_placeholder': '6-digit code', + 'auth.pairing_progress': 'Pairing...', + + 'common.loading': 'Loading...', + 'common.error': 'An error occurred.', + 'common.retry': 'Retry', + 'common.cancel': 'Cancel', + 'common.confirm': 'Confirm', + 'common.save': 'Save', + 'common.delete': 'Delete', + 'common.edit': 'Edit', + 'common.close': 'Close', + 'common.yes': 'Yes', + 'common.no': 'No', + 'common.search': 'Search...', + 'common.no_data': 'No data available.', + 'common.refresh': 'Refresh', + 'common.back': 'Back', + 'common.actions': 'Actions', + 'common.name': 'Name', + 'common.description': 'Description', + 'common.status': 'Status', + 'common.created': 'Created', + 'common.updated': 'Updated', + 'common.languages': 'Languages', + 'common.select_language': 'Select language', + 'common.connecting': 'Connecting...', + + 'health.title': 'System Health', + 'health.component': 'Component', + 'health.status': 'Status', + 'health.last_ok': 'Last OK', + 'health.last_error': 'Last Error', + 'health.restart_count': 'Restart Count', + 'health.pid': 'Process ID', + 'health.uptime': 'Uptime', + 'health.updated_at': 'Updated At', + + 'header.dashboard_tagline': 'ZeroClaw dashboard', + 'sidebar.gateway_dashboard': 'Gateway + Dashboard', + 'sidebar.runtime_mode': 'Runtime Mode', + 'navigation.open': 'Open navigation', + 'navigation.close': 'Close navigation', + 'navigation.expand': 'Expand navigation', + 'navigation.collapse': 'Collapse navigation', +} satisfies Record; + +export type TranslationKeys = typeof en; +export default en; diff --git a/web/src/lib/i18n/locales/es.ts b/web/src/lib/i18n/locales/es.ts new file mode 100644 index 000000000..5dc1be139 --- /dev/null +++ b/web/src/lib/i18n/locales/es.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const es: Partial = { + 'nav.dashboard': 'Panel', + 'nav.agent': 'Agente', + 'nav.tools': 'Herramientas', + 'nav.cron': 'Tareas programadas', + 'nav.integrations': 'Integraciones', + 'nav.memory': 'Memoria', + 'nav.config': 'Configuración', + 'nav.cost': 'Costos', + 'nav.logs': 'Registros', + 'nav.doctor': 'Diagnóstico', + 'dashboard.hero_title': 'Panel eléctrico del runtime', + 'agent.placeholder': 'Escribe un mensaje…', + 'tools.search': 'Buscar herramientas…', + 'cron.add': 'Agregar tarea', + 'memory.add_memory': 'Agregar memoria', + 'config.save': 'Guardar', + 'cost.token_statistics': 'Estadísticas de tokens', + 'logs.title': 'Registros en vivo', + 'doctor.title': 'Diagnóstico del sistema', + 'auth.pair_button': 'Vincular', + 'auth.enter_code': 'Introduce el código de vinculación de un solo uso del terminal', + 'auth.code_placeholder': 'Código de 6 dígitos', + 'auth.pairing_progress': 'Vinculando…', + 'auth.logout': 'Cerrar sesión', + 'common.languages': 'Idiomas', + 'common.select_language': 'Elegir idioma', + 'header.dashboard_tagline': 'Panel de ZeroClaw', +}; + +export default es; diff --git a/web/src/lib/i18n/locales/fi.ts b/web/src/lib/i18n/locales/fi.ts new file mode 100644 index 000000000..f1605f39a --- /dev/null +++ b/web/src/lib/i18n/locales/fi.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const fi: Partial = { + 'nav.dashboard': 'Hallintapaneeli', + 'nav.agent': 'Agentti', + 'nav.tools': 'Työkalut', + 'nav.cron': 'Ajastetut tehtävät', + 'nav.integrations': 'Integraatiot', + 'nav.memory': 'Muisti', + 'nav.config': 'Asetukset', + 'nav.cost': 'Kustannukset', + 'nav.logs': 'Lokit', + 'nav.doctor': 'Diagnostiikka', + 'dashboard.hero_title': 'Sähköinen runtime-hallintapaneeli', + 'agent.placeholder': 'Kirjoita viesti…', + 'tools.search': 'Etsi työkaluja…', + 'cron.add': 'Lisää tehtävä', + 'memory.add_memory': 'Lisää muisti', + 'config.save': 'Tallenna', + 'cost.token_statistics': 'Token-tilastot', + 'logs.title': 'Live-lokit', + 'doctor.title': 'Järjestelmädiagnostiikka', + 'auth.pair_button': 'Yhdistä', + 'auth.enter_code': 'Syötä terminaalin kertakäyttöinen parituskoodi', + 'auth.code_placeholder': '6-numeroinen koodi', + 'auth.pairing_progress': 'Yhdistetään…', + 'auth.logout': 'Kirjaudu ulos', + 'common.languages': 'Kielet', + 'common.select_language': 'Valitse kieli', + 'header.dashboard_tagline': 'ZeroClaw-hallintapaneeli', +}; + +export default fi; diff --git a/web/src/lib/i18n/locales/fr.ts b/web/src/lib/i18n/locales/fr.ts new file mode 100644 index 000000000..33478ee8b --- /dev/null +++ b/web/src/lib/i18n/locales/fr.ts @@ -0,0 +1,51 @@ +import type { TranslationKeys } from './en'; + +const fr: Partial = { + 'nav.dashboard': 'Tableau de bord', + 'nav.agent': 'Agent', + 'nav.tools': 'Outils', + 'nav.cron': 'Tâches planifiées', + 'nav.integrations': 'Intégrations', + 'nav.memory': 'Mémoire', + 'nav.config': 'Configuration', + 'nav.cost': 'Coûts', + 'nav.logs': 'Journaux', + 'nav.doctor': 'Diagnostic', + 'dashboard.hero_title': 'Tableau de bord runtime électrique', + 'dashboard.live_gateway': 'Passerelle active', + 'dashboard.unpaired': 'Non appairé', + 'agent.title': 'Chat agent', + 'agent.placeholder': 'Saisissez un message…', + 'agent.connecting': 'Connexion…', + 'agent.connected': 'Connecté', + 'agent.disconnected': 'Déconnecté', + 'tools.search': 'Rechercher des outils…', + 'tools.agent_tools': 'Outils agent', + 'tools.cli_tools': 'Outils CLI', + 'cron.add': 'Ajouter une tâche', + 'cron.scheduled_tasks': 'Tâches planifiées', + 'integrations.title': 'Intégrations', + 'memory.add_memory': 'Ajouter une mémoire', + 'memory.search_entries': 'Rechercher dans la mémoire…', + 'config.save': 'Enregistrer', + 'config.saving': 'Enregistrement…', + 'cost.session': 'Coût de session', + 'cost.daily': 'Coût journalier', + 'cost.monthly': 'Coût mensuel', + 'logs.title': 'Journaux en direct', + 'logs.pause': 'Pause', + 'logs.resume': 'Reprendre', + 'doctor.title': 'Diagnostic système', + 'doctor.run': 'Lancer le diagnostic', + 'doctor.running_short': 'Exécution…', + 'auth.pair_button': 'Associer', + 'auth.enter_code': 'Entrez le code d\u2019appairage à usage unique affiché dans le terminal', + 'auth.code_placeholder': 'Code à 6 chiffres', + 'auth.pairing_progress': 'Appairage…', + 'auth.logout': 'Déconnexion', + 'common.languages': 'Langues', + 'common.select_language': 'Choisir la langue', + 'header.dashboard_tagline': 'Tableau de bord ZeroClaw', +}; + +export default fr; diff --git a/web/src/lib/i18n/locales/he.ts b/web/src/lib/i18n/locales/he.ts new file mode 100644 index 000000000..304576148 --- /dev/null +++ b/web/src/lib/i18n/locales/he.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const he: Partial = { + 'nav.dashboard': 'לוח מחוונים', + 'nav.agent': 'סוכן', + 'nav.tools': 'כלים', + 'nav.cron': 'משימות מתוזמנות', + 'nav.integrations': 'אינטגרציות', + 'nav.memory': 'זיכרון', + 'nav.config': 'תצורה', + 'nav.cost': 'מעקב עלויות', + 'nav.logs': 'יומנים', + 'nav.doctor': 'אבחון', + 'dashboard.hero_title': 'לוח מחוונים חשמלי של זמן הריצה', + 'agent.placeholder': 'הקלד הודעה…', + 'tools.search': 'חפש כלים…', + 'cron.add': 'הוסף משימה', + 'memory.add_memory': 'הוסף זיכרון', + 'config.save': 'שמור', + 'cost.token_statistics': 'סטטיסטיקות אסימונים', + 'logs.title': 'יומנים חיים', + 'doctor.title': 'אבחון מערכת', + 'auth.pair_button': 'התאמה', + 'auth.enter_code': 'הזן את קוד ההתאמה החד-פעמי מהמסוף', + 'auth.code_placeholder': 'קוד בן 6 ספרות', + 'auth.pairing_progress': 'מתבצעת התאמה…', + 'auth.logout': 'התנתק', + 'common.languages': 'שפות', + 'common.select_language': 'בחר שפה', + 'header.dashboard_tagline': 'לוח המחוונים של ZeroClaw', +}; + +export default he; diff --git a/web/src/lib/i18n/locales/hi.ts b/web/src/lib/i18n/locales/hi.ts new file mode 100644 index 000000000..271f70e5d --- /dev/null +++ b/web/src/lib/i18n/locales/hi.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const hi: Partial = { + 'nav.dashboard': 'डैशबोर्ड', + 'nav.agent': 'एजेंट', + 'nav.tools': 'टूल्स', + 'nav.cron': 'निर्धारित कार्य', + 'nav.integrations': 'इंटीग्रेशन', + 'nav.memory': 'मेमोरी', + 'nav.config': 'कॉन्फ़िगरेशन', + 'nav.cost': 'लागत ट्रैकर', + 'nav.logs': 'लॉग्स', + 'nav.doctor': 'जाँच', + 'dashboard.hero_title': 'इलेक्ट्रिक रनटाइम डैशबोर्ड', + 'agent.placeholder': 'संदेश लिखें…', + 'tools.search': 'टूल खोजें…', + 'cron.add': 'कार्य जोड़ें', + 'memory.add_memory': 'मेमोरी जोड़ें', + 'config.save': 'सहेजें', + 'cost.token_statistics': 'टोकन आँकड़े', + 'logs.title': 'लाइव लॉग्स', + 'doctor.title': 'सिस्टम जाँच', + 'auth.pair_button': 'पेयर करें', + 'auth.enter_code': 'टर्मिनल से एक-बार वाला पेयरिंग कोड दर्ज करें', + 'auth.code_placeholder': '6-अंकों का कोड', + 'auth.pairing_progress': 'पेयर किया जा रहा है…', + 'auth.logout': 'लॉग आउट', + 'common.languages': 'भाषाएँ', + 'common.select_language': 'भाषा चुनें', + 'header.dashboard_tagline': 'ZeroClaw डैशबोर्ड', +}; + +export default hi; diff --git a/web/src/lib/i18n/locales/hu.ts b/web/src/lib/i18n/locales/hu.ts new file mode 100644 index 000000000..40bb464c9 --- /dev/null +++ b/web/src/lib/i18n/locales/hu.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const hu: Partial = { + 'nav.dashboard': 'Irányítópult', + 'nav.agent': 'Ügynök', + 'nav.tools': 'Eszközök', + 'nav.cron': 'Ütemezett feladatok', + 'nav.integrations': 'Integrációk', + 'nav.memory': 'Memória', + 'nav.config': 'Konfiguráció', + 'nav.cost': 'Költségek', + 'nav.logs': 'Naplók', + 'nav.doctor': 'Diagnosztika', + 'dashboard.hero_title': 'Elektromos runtime irányítópult', + 'agent.placeholder': 'Írjon üzenetet…', + 'tools.search': 'Eszközök keresése…', + 'cron.add': 'Feladat hozzáadása', + 'memory.add_memory': 'Memória hozzáadása', + 'config.save': 'Mentés', + 'cost.token_statistics': 'Tokenstatisztika', + 'logs.title': 'Élő naplók', + 'doctor.title': 'Rendszerdiagnosztika', + 'auth.pair_button': 'Párosítás', + 'auth.enter_code': 'Adja meg a terminál egyszer használatos párosítási kódját', + 'auth.code_placeholder': '6 számjegyű kód', + 'auth.pairing_progress': 'Párosítás…', + 'auth.logout': 'Kijelentkezés', + 'common.languages': 'Nyelvek', + 'common.select_language': 'Nyelv kiválasztása', + 'header.dashboard_tagline': 'ZeroClaw irányítópult', +}; + +export default hu; diff --git a/web/src/lib/i18n/locales/id.ts b/web/src/lib/i18n/locales/id.ts new file mode 100644 index 000000000..7c179bdab --- /dev/null +++ b/web/src/lib/i18n/locales/id.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const id: Partial = { + 'nav.dashboard': 'Dasbor', + 'nav.agent': 'Agen', + 'nav.tools': 'Alat', + 'nav.cron': 'Tugas terjadwal', + 'nav.integrations': 'Integrasi', + 'nav.memory': 'Memori', + 'nav.config': 'Konfigurasi', + 'nav.cost': 'Biaya', + 'nav.logs': 'Log', + 'nav.doctor': 'Diagnosis', + 'dashboard.hero_title': 'Dasbor runtime elektrik', + 'agent.placeholder': 'Tulis pesan…', + 'tools.search': 'Cari alat…', + 'cron.add': 'Tambah tugas', + 'memory.add_memory': 'Tambah memori', + 'config.save': 'Simpan', + 'cost.token_statistics': 'Statistik token', + 'logs.title': 'Log langsung', + 'doctor.title': 'Diagnosis sistem', + 'auth.pair_button': 'Pasangkan', + 'auth.enter_code': 'Masukkan kode pairing sekali pakai dari terminal', + 'auth.code_placeholder': 'Kode 6 digit', + 'auth.pairing_progress': 'Sedang memasangkan…', + 'auth.logout': 'Keluar', + 'common.languages': 'Bahasa', + 'common.select_language': 'Pilih bahasa', + 'header.dashboard_tagline': 'Dasbor ZeroClaw', +}; + +export default id; diff --git a/web/src/lib/i18n/locales/index.ts b/web/src/lib/i18n/locales/index.ts new file mode 100644 index 000000000..f65eb25a7 --- /dev/null +++ b/web/src/lib/i18n/locales/index.ts @@ -0,0 +1,70 @@ +import type { Locale } from '../types'; +import en from './en'; +import zhCN from './zh-CN'; +import ja from './ja'; +import ko from './ko'; +import vi from './vi'; +import tl from './tl'; +import es from './es'; +import pt from './pt'; +import it from './it'; +import de from './de'; +import fr from './fr'; +import ar from './ar'; +import hi from './hi'; +import ru from './ru'; +import bn from './bn'; +import he from './he'; +import pl from './pl'; +import cs from './cs'; +import nl from './nl'; +import tr from './tr'; +import uk from './uk'; +import id from './id'; +import th from './th'; +import ur from './ur'; +import ro from './ro'; +import sv from './sv'; +import el from './el'; +import hu from './hu'; +import fi from './fi'; +import da from './da'; +import nb from './nb'; + +function merge(overrides: Partial): Record { + return { ...en, ...overrides }; +} + +export const translations: Record> = { + en, + 'zh-CN': merge(zhCN), + ja: merge(ja), + ko: merge(ko), + vi: merge(vi), + tl: merge(tl), + es: merge(es), + pt: merge(pt), + it: merge(it), + de: merge(de), + fr: merge(fr), + ar: merge(ar), + hi: merge(hi), + ru: merge(ru), + bn: merge(bn), + he: merge(he), + pl: merge(pl), + cs: merge(cs), + nl: merge(nl), + tr: merge(tr), + uk: merge(uk), + id: merge(id), + th: merge(th), + ur: merge(ur), + ro: merge(ro), + sv: merge(sv), + el: merge(el), + hu: merge(hu), + fi: merge(fi), + da: merge(da), + nb: merge(nb), +}; diff --git a/web/src/lib/i18n/locales/it.ts b/web/src/lib/i18n/locales/it.ts new file mode 100644 index 000000000..0c6d9f8dd --- /dev/null +++ b/web/src/lib/i18n/locales/it.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const it: Partial = { + 'nav.dashboard': 'Dashboard', + 'nav.agent': 'Agente', + 'nav.tools': 'Strumenti', + 'nav.cron': 'Attività pianificate', + 'nav.integrations': 'Integrazioni', + 'nav.memory': 'Memoria', + 'nav.config': 'Configurazione', + 'nav.cost': 'Costi', + 'nav.logs': 'Log', + 'nav.doctor': 'Diagnostica', + 'dashboard.hero_title': 'Dashboard runtime elettrica', + 'agent.placeholder': 'Scrivi un messaggio…', + 'tools.search': 'Cerca strumenti…', + 'cron.add': 'Aggiungi attività', + 'memory.add_memory': 'Aggiungi memoria', + 'config.save': 'Salva', + 'cost.token_statistics': 'Statistiche token', + 'logs.title': 'Log in tempo reale', + 'doctor.title': 'Diagnostica di sistema', + 'auth.pair_button': 'Associa', + 'auth.enter_code': 'Inserisci il codice di associazione monouso dal terminale', + 'auth.code_placeholder': 'Codice a 6 cifre', + 'auth.pairing_progress': 'Associazione…', + 'auth.logout': 'Disconnetti', + 'common.languages': 'Lingue', + 'common.select_language': 'Scegli lingua', + 'header.dashboard_tagline': 'Dashboard di ZeroClaw', +}; + +export default it; diff --git a/web/src/lib/i18n/locales/ja.ts b/web/src/lib/i18n/locales/ja.ts new file mode 100644 index 000000000..338c053e2 --- /dev/null +++ b/web/src/lib/i18n/locales/ja.ts @@ -0,0 +1,51 @@ +import type { TranslationKeys } from './en'; + +const ja: Partial = { + 'nav.dashboard': 'ダッシュボード', + 'nav.agent': 'エージェント', + 'nav.tools': 'ツール', + 'nav.cron': 'スケジュール', + 'nav.integrations': '連携', + 'nav.memory': 'メモリ', + 'nav.config': '設定', + 'nav.cost': 'コスト', + 'nav.logs': 'ログ', + 'nav.doctor': '診断', + 'dashboard.hero_title': 'エレクトリック・ランタイム・ダッシュボード', + 'dashboard.live_gateway': 'ライブゲートウェイ', + 'dashboard.unpaired': '未ペア', + 'agent.title': 'エージェントチャット', + 'agent.placeholder': 'メッセージを入力…', + 'agent.connecting': '接続中…', + 'agent.connected': '接続済み', + 'agent.disconnected': '切断済み', + 'tools.search': 'ツールを検索…', + 'tools.agent_tools': 'エージェントツール', + 'tools.cli_tools': 'CLI ツール', + 'cron.add': 'ジョブを追加', + 'cron.scheduled_tasks': 'スケジュールされたジョブ', + 'integrations.title': '連携', + 'memory.add_memory': 'メモリを追加', + 'memory.search_entries': 'メモリエントリを検索…', + 'config.save': '保存', + 'config.saving': '保存中…', + 'cost.session': 'セッションコスト', + 'cost.daily': '日次コスト', + 'cost.monthly': '月次コスト', + 'logs.title': 'ライブログ', + 'logs.pause': '一時停止', + 'logs.resume': '再開', + 'doctor.title': 'システム診断', + 'doctor.run': '診断を実行', + 'doctor.running_short': '実行中…', + 'auth.pair_button': 'ペアリング', + 'auth.enter_code': '端末のワンタイムペアリングコードを入力してください', + 'auth.code_placeholder': '6桁のコード', + 'auth.pairing_progress': 'ペアリング中…', + 'auth.logout': 'ログアウト', + 'common.languages': '言語', + 'common.select_language': '言語を選択', + 'header.dashboard_tagline': 'ZeroClaw ダッシュボード', +}; + +export default ja; diff --git a/web/src/lib/i18n/locales/ko.ts b/web/src/lib/i18n/locales/ko.ts new file mode 100644 index 000000000..e9e772813 --- /dev/null +++ b/web/src/lib/i18n/locales/ko.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const ko: Partial = { + 'nav.dashboard': '대시보드', + 'nav.agent': '에이전트', + 'nav.tools': '도구', + 'nav.cron': '예약 작업', + 'nav.integrations': '통합', + 'nav.memory': '메모리', + 'nav.config': '설정', + 'nav.cost': '비용 추적', + 'nav.logs': '로그', + 'nav.doctor': '진단', + 'dashboard.hero_title': '전기 런타임 대시보드', + 'agent.placeholder': '메시지를 입력하세요…', + 'tools.search': '도구 검색…', + 'cron.add': '작업 추가', + 'memory.add_memory': '메모리 추가', + 'config.save': '저장', + 'cost.token_statistics': '토큰 통계', + 'logs.title': '실시간 로그', + 'doctor.title': '시스템 진단', + 'auth.pair_button': '페어링', + 'auth.enter_code': '터미널에 표시된 일회용 페어링 코드를 입력하세요', + 'auth.code_placeholder': '6자리 코드', + 'auth.pairing_progress': '페어링 중…', + 'auth.logout': '로그아웃', + 'common.languages': '언어', + 'common.select_language': '언어 선택', + 'header.dashboard_tagline': 'ZeroClaw 대시보드', +}; + +export default ko; diff --git a/web/src/lib/i18n/locales/nb.ts b/web/src/lib/i18n/locales/nb.ts new file mode 100644 index 000000000..d1e7a19e8 --- /dev/null +++ b/web/src/lib/i18n/locales/nb.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const nb: Partial = { + 'nav.dashboard': 'Kontrollpanel', + 'nav.agent': 'Agent', + 'nav.tools': 'Verktøy', + 'nav.cron': 'Planlagte jobber', + 'nav.integrations': 'Integrasjoner', + 'nav.memory': 'Minne', + 'nav.config': 'Konfigurasjon', + 'nav.cost': 'Kostnader', + 'nav.logs': 'Logger', + 'nav.doctor': 'Diagnostikk', + 'dashboard.hero_title': 'Elektrisk runtime-kontrollpanel', + 'agent.placeholder': 'Skriv en melding…', + 'tools.search': 'Søk etter verktøy…', + 'cron.add': 'Legg til jobb', + 'memory.add_memory': 'Legg til minne', + 'config.save': 'Lagre', + 'cost.token_statistics': 'Tokenstatistikk', + 'logs.title': 'Live-logger', + 'doctor.title': 'Systemdiagnostikk', + 'auth.pair_button': 'Koble til', + 'auth.enter_code': 'Skriv inn engangskoden fra terminalen', + 'auth.code_placeholder': '6-sifret kode', + 'auth.pairing_progress': 'Kobler til…', + 'auth.logout': 'Logg ut', + 'common.languages': 'Språk', + 'common.select_language': 'Velg språk', + 'header.dashboard_tagline': 'ZeroClaw-kontrollpanel', +}; + +export default nb; diff --git a/web/src/lib/i18n/locales/nl.ts b/web/src/lib/i18n/locales/nl.ts new file mode 100644 index 000000000..2dd62390c --- /dev/null +++ b/web/src/lib/i18n/locales/nl.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const nl: Partial = { + 'nav.dashboard': 'Dashboard', + 'nav.agent': 'Agent', + 'nav.tools': 'Tools', + 'nav.cron': 'Geplande taken', + 'nav.integrations': 'Integraties', + 'nav.memory': 'Geheugen', + 'nav.config': 'Configuratie', + 'nav.cost': 'Kosten', + 'nav.logs': 'Logs', + 'nav.doctor': 'Diagnose', + 'dashboard.hero_title': 'Elektrisch runtime-dashboard', + 'agent.placeholder': 'Typ een bericht…', + 'tools.search': 'Tools zoeken…', + 'cron.add': 'Taak toevoegen', + 'memory.add_memory': 'Geheugen toevoegen', + 'config.save': 'Opslaan', + 'cost.token_statistics': 'Tokenstatistieken', + 'logs.title': 'Live-logs', + 'doctor.title': 'Systeemdiagnose', + 'auth.pair_button': 'Koppelen', + 'auth.enter_code': 'Voer de eenmalige koppelcode uit de terminal in', + 'auth.code_placeholder': '6-cijferige code', + 'auth.pairing_progress': 'Koppelen…', + 'auth.logout': 'Afmelden', + 'common.languages': 'Talen', + 'common.select_language': 'Kies taal', + 'header.dashboard_tagline': 'ZeroClaw-dashboard', +}; + +export default nl; diff --git a/web/src/lib/i18n/locales/pl.ts b/web/src/lib/i18n/locales/pl.ts new file mode 100644 index 000000000..521b17db6 --- /dev/null +++ b/web/src/lib/i18n/locales/pl.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const pl: Partial = { + 'nav.dashboard': 'Pulpit', + 'nav.agent': 'Agent', + 'nav.tools': 'Narzędzia', + 'nav.cron': 'Zaplanowane zadania', + 'nav.integrations': 'Integracje', + 'nav.memory': 'Pamięć', + 'nav.config': 'Konfiguracja', + 'nav.cost': 'Koszty', + 'nav.logs': 'Logi', + 'nav.doctor': 'Diagnostyka', + 'dashboard.hero_title': 'Elektryczny pulpit runtime', + 'agent.placeholder': 'Wpisz wiadomość…', + 'tools.search': 'Szukaj narzędzi…', + 'cron.add': 'Dodaj zadanie', + 'memory.add_memory': 'Dodaj pamięć', + 'config.save': 'Zapisz', + 'cost.token_statistics': 'Statystyki tokenów', + 'logs.title': 'Logi na żywo', + 'doctor.title': 'Diagnostyka systemu', + 'auth.pair_button': 'Sparuj', + 'auth.enter_code': 'Wprowadź jednorazowy kod parowania z terminala', + 'auth.code_placeholder': '6-cyfrowy kod', + 'auth.pairing_progress': 'Parowanie…', + 'auth.logout': 'Wyloguj', + 'common.languages': 'Języki', + 'common.select_language': 'Wybierz język', + 'header.dashboard_tagline': 'Pulpit ZeroClaw', +}; + +export default pl; diff --git a/web/src/lib/i18n/locales/pt.ts b/web/src/lib/i18n/locales/pt.ts new file mode 100644 index 000000000..2f0d255d9 --- /dev/null +++ b/web/src/lib/i18n/locales/pt.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const pt: Partial = { + 'nav.dashboard': 'Painel', + 'nav.agent': 'Agente', + 'nav.tools': 'Ferramentas', + 'nav.cron': 'Tarefas agendadas', + 'nav.integrations': 'Integrações', + 'nav.memory': 'Memória', + 'nav.config': 'Configuração', + 'nav.cost': 'Custos', + 'nav.logs': 'Logs', + 'nav.doctor': 'Diagnóstico', + 'dashboard.hero_title': 'Painel elétrico do runtime', + 'agent.placeholder': 'Digite uma mensagem…', + 'tools.search': 'Buscar ferramentas…', + 'cron.add': 'Adicionar tarefa', + 'memory.add_memory': 'Adicionar memória', + 'config.save': 'Salvar', + 'cost.token_statistics': 'Estatísticas de tokens', + 'logs.title': 'Logs ao vivo', + 'doctor.title': 'Diagnóstico do sistema', + 'auth.pair_button': 'Parear', + 'auth.enter_code': 'Digite o código único de pareamento mostrado no terminal', + 'auth.code_placeholder': 'Código de 6 dígitos', + 'auth.pairing_progress': 'Pareando…', + 'auth.logout': 'Sair', + 'common.languages': 'Idiomas', + 'common.select_language': 'Escolher idioma', + 'header.dashboard_tagline': 'Painel do ZeroClaw', +}; + +export default pt; diff --git a/web/src/lib/i18n/locales/ro.ts b/web/src/lib/i18n/locales/ro.ts new file mode 100644 index 000000000..3db6359c2 --- /dev/null +++ b/web/src/lib/i18n/locales/ro.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const ro: Partial = { + 'nav.dashboard': 'Tablou de bord', + 'nav.agent': 'Agent', + 'nav.tools': 'Unelte', + 'nav.cron': 'Sarcini programate', + 'nav.integrations': 'Integrări', + 'nav.memory': 'Memorie', + 'nav.config': 'Configurație', + 'nav.cost': 'Costuri', + 'nav.logs': 'Jurnale', + 'nav.doctor': 'Diagnostic', + 'dashboard.hero_title': 'Tablou de bord runtime electric', + 'agent.placeholder': 'Scrie un mesaj…', + 'tools.search': 'Caută unelte…', + 'cron.add': 'Adaugă sarcină', + 'memory.add_memory': 'Adaugă memorie', + 'config.save': 'Salvează', + 'cost.token_statistics': 'Statistici tokenuri', + 'logs.title': 'Jurnale live', + 'doctor.title': 'Diagnostic sistem', + 'auth.pair_button': 'Asociază', + 'auth.enter_code': 'Introdu codul unic de asociere din terminal', + 'auth.code_placeholder': 'Cod din 6 cifre', + 'auth.pairing_progress': 'Asociere…', + 'auth.logout': 'Deconectare', + 'common.languages': 'Limbi', + 'common.select_language': 'Alege limba', + 'header.dashboard_tagline': 'Tabloul ZeroClaw', +}; + +export default ro; diff --git a/web/src/lib/i18n/locales/ru.ts b/web/src/lib/i18n/locales/ru.ts new file mode 100644 index 000000000..a6a3bb44f --- /dev/null +++ b/web/src/lib/i18n/locales/ru.ts @@ -0,0 +1,51 @@ +import type { TranslationKeys } from './en'; + +const ru: Partial = { + 'nav.dashboard': 'Панель', + 'nav.agent': 'Агент', + 'nav.tools': 'Инструменты', + 'nav.cron': 'Задания', + 'nav.integrations': 'Интеграции', + 'nav.memory': 'Память', + 'nav.config': 'Конфигурация', + 'nav.cost': 'Расходы', + 'nav.logs': 'Логи', + 'nav.doctor': 'Диагностика', + 'dashboard.hero_title': 'Панель электрического рантайма', + 'dashboard.live_gateway': 'Живой шлюз', + 'dashboard.unpaired': 'Не сопряжено', + 'agent.title': 'Чат агента', + 'agent.placeholder': 'Введите сообщение…', + 'agent.connecting': 'Подключение…', + 'agent.connected': 'Подключено', + 'agent.disconnected': 'Отключено', + 'tools.search': 'Поиск инструментов…', + 'tools.agent_tools': 'Инструменты агента', + 'tools.cli_tools': 'CLI-инструменты', + 'cron.add': 'Добавить задачу', + 'cron.scheduled_tasks': 'Запланированные задания', + 'integrations.title': 'Интеграции', + 'memory.add_memory': 'Добавить память', + 'memory.search_entries': 'Искать записи памяти…', + 'config.save': 'Сохранить', + 'config.saving': 'Сохранение…', + 'cost.session': 'Стоимость сессии', + 'cost.daily': 'Стоимость за день', + 'cost.monthly': 'Стоимость за месяц', + 'logs.title': 'Живые логи', + 'logs.pause': 'Пауза', + 'logs.resume': 'Продолжить', + 'doctor.title': 'Диагностика системы', + 'doctor.run': 'Запустить диагностику', + 'doctor.running_short': 'Выполняется…', + 'auth.pair_button': 'Сопрячь', + 'auth.enter_code': 'Введите одноразовый код сопряжения из терминала', + 'auth.code_placeholder': '6-значный код', + 'auth.pairing_progress': 'Сопряжение…', + 'auth.logout': 'Выйти', + 'common.languages': 'Языки', + 'common.select_language': 'Выберите язык', + 'header.dashboard_tagline': 'Панель ZeroClaw', +}; + +export default ru; diff --git a/web/src/lib/i18n/locales/sv.ts b/web/src/lib/i18n/locales/sv.ts new file mode 100644 index 000000000..48ee8d9e1 --- /dev/null +++ b/web/src/lib/i18n/locales/sv.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const sv: Partial = { + 'nav.dashboard': 'Instrumentpanel', + 'nav.agent': 'Agent', + 'nav.tools': 'Verktyg', + 'nav.cron': 'Schemalagda jobb', + 'nav.integrations': 'Integrationer', + 'nav.memory': 'Minne', + 'nav.config': 'Konfiguration', + 'nav.cost': 'Kostnader', + 'nav.logs': 'Loggar', + 'nav.doctor': 'Diagnostik', + 'dashboard.hero_title': 'Elektrisk runtimepanel', + 'agent.placeholder': 'Skriv ett meddelande…', + 'tools.search': 'Sök verktyg…', + 'cron.add': 'Lägg till jobb', + 'memory.add_memory': 'Lägg till minne', + 'config.save': 'Spara', + 'cost.token_statistics': 'Tokenstatistik', + 'logs.title': 'Live-loggar', + 'doctor.title': 'Systemdiagnostik', + 'auth.pair_button': 'Para', + 'auth.enter_code': 'Ange engångskoden från terminalen', + 'auth.code_placeholder': '6-siffrig kod', + 'auth.pairing_progress': 'Parar…', + 'auth.logout': 'Logga ut', + 'common.languages': 'Språk', + 'common.select_language': 'Välj språk', + 'header.dashboard_tagline': 'ZeroClaw-panel', +}; + +export default sv; diff --git a/web/src/lib/i18n/locales/th.ts b/web/src/lib/i18n/locales/th.ts new file mode 100644 index 000000000..d09c182c9 --- /dev/null +++ b/web/src/lib/i18n/locales/th.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const th: Partial = { + 'nav.dashboard': 'แดชบอร์ด', + 'nav.agent': 'เอเจนต์', + 'nav.tools': 'เครื่องมือ', + 'nav.cron': 'งานที่ตั้งเวลา', + 'nav.integrations': 'การเชื่อมต่อ', + 'nav.memory': 'หน่วยความจำ', + 'nav.config': 'การกำหนดค่า', + 'nav.cost': 'ต้นทุน', + 'nav.logs': 'บันทึก', + 'nav.doctor': 'วินิจฉัย', + 'dashboard.hero_title': 'แดชบอร์ดรันไทม์ไฟฟ้า', + 'agent.placeholder': 'พิมพ์ข้อความ…', + 'tools.search': 'ค้นหาเครื่องมือ…', + 'cron.add': 'เพิ่มงาน', + 'memory.add_memory': 'เพิ่มหน่วยความจำ', + 'config.save': 'บันทึก', + 'cost.token_statistics': 'สถิติโทเค็น', + 'logs.title': 'บันทึกสด', + 'doctor.title': 'วินิจฉัยระบบ', + 'auth.pair_button': 'จับคู่', + 'auth.enter_code': 'ป้อนรหัสจับคู่แบบใช้ครั้งเดียวจากเทอร์มินัล', + 'auth.code_placeholder': 'รหัส 6 หลัก', + 'auth.pairing_progress': 'กำลังจับคู่…', + 'auth.logout': 'ออกจากระบบ', + 'common.languages': 'ภาษา', + 'common.select_language': 'เลือกภาษา', + 'header.dashboard_tagline': 'แดชบอร์ด ZeroClaw', +}; + +export default th; diff --git a/web/src/lib/i18n/locales/tl.ts b/web/src/lib/i18n/locales/tl.ts new file mode 100644 index 000000000..acd9f428d --- /dev/null +++ b/web/src/lib/i18n/locales/tl.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const tl: Partial = { + 'nav.dashboard': 'Dashboard', + 'nav.agent': 'Ahente', + 'nav.tools': 'Mga Tool', + 'nav.cron': 'Naka-iskedyul na Trabaho', + 'nav.integrations': 'Mga Integrasyon', + 'nav.memory': 'Alaala', + 'nav.config': 'Konpigurasyon', + 'nav.cost': 'Pagsubaybay sa Gastos', + 'nav.logs': 'Mga Log', + 'nav.doctor': 'Diyagnostiko', + 'dashboard.hero_title': 'Elektrikong Dashboard ng Runtime', + 'agent.placeholder': 'Mag-type ng mensahe…', + 'tools.search': 'Maghanap ng tool…', + 'cron.add': 'Magdagdag ng gawain', + 'memory.add_memory': 'Magdagdag ng alaala', + 'config.save': 'I-save', + 'cost.token_statistics': 'Estadistika ng Token', + 'logs.title': 'Mga Live Log', + 'doctor.title': 'Diyagnostiko ng System', + 'auth.pair_button': 'Ipares', + 'auth.enter_code': 'Ilagay ang isang beses na pairing code mula sa terminal', + 'auth.code_placeholder': '6-digit na code', + 'auth.pairing_progress': 'Pinapares…', + 'auth.logout': 'Mag-logout', + 'common.languages': 'Mga Wika', + 'common.select_language': 'Piliin ang wika', + 'header.dashboard_tagline': 'Dashboard ng ZeroClaw', +}; + +export default tl; diff --git a/web/src/lib/i18n/locales/tr.ts b/web/src/lib/i18n/locales/tr.ts new file mode 100644 index 000000000..6abd0aca8 --- /dev/null +++ b/web/src/lib/i18n/locales/tr.ts @@ -0,0 +1,157 @@ +import type { TranslationKeys } from './en'; + +const tr: Partial = { + 'nav.dashboard': 'Kontrol Paneli', + 'nav.agent': 'Ajan', + 'nav.tools': 'Araçlar', + 'nav.cron': 'Zamanlanmış Görevler', + 'nav.integrations': 'Entegrasyonlar', + 'nav.memory': 'Hafıza', + 'nav.config': 'Yapılandırma', + 'nav.cost': 'Maliyet Takibi', + 'nav.logs': 'Kayıtlar', + 'nav.doctor': 'Doktor', + 'agent.title': 'Ajan Sohbeti', + 'agent.send': 'Gönder', + 'agent.placeholder': 'Bir mesaj yazın...', + 'agent.connecting': 'Bağlanıyor...', + 'agent.connected': 'Bağlı', + 'agent.disconnected': 'Bağlantı Kesildi', + 'agent.reconnecting': 'Yeniden bağlanıyor...', + 'agent.thinking': 'Düşünüyor...', + 'agent.tool_call': 'Araç Çağrısı', + 'agent.tool_result': 'Araç Sonucu', + 'agent.connection_error': 'Bağlantı hatası. Yeniden bağlanmaya çalışılıyor...', + 'agent.failed_send': 'Mesaj gönderilemedi. Lütfen tekrar deneyin.', + 'agent.empty_title': 'ZeroClaw Ajanı', + 'agent.empty_subtitle': 'Konuşmayı başlatmak için bir mesaj gönderin', + 'dashboard.title': 'Kontrol Paneli', + 'dashboard.provider': 'Sağlayıcı', + 'dashboard.model': 'Model', + 'dashboard.uptime': 'Çalışma Süresi', + 'dashboard.temperature': 'Sıcaklık', + 'dashboard.gateway_port': 'Ağ Geçidi Portu', + 'dashboard.locale': 'Yerel Ayar', + 'dashboard.memory_backend': 'Hafıza Arka Ucu', + 'dashboard.hero_eyebrow': 'ZeroClaw Komuta Güvertesi', + 'dashboard.hero_title': 'Elektrik Çalışma Zamanı Paneli', + 'dashboard.hero_subtitle': 'Gerçek zamanlı telemetri, maliyet akışı ve operasyon durumunu tek bir daraltılabilir yüzeyde görün.', + 'dashboard.live_gateway': 'Canlı Ağ Geçidi', + 'dashboard.unpaired': 'Eşleşmemiş', + 'dashboard.provider_model': 'Sağlayıcı / Model', + 'dashboard.since_last_restart': 'Son yeniden başlatmadan beri', + 'dashboard.pairing_active': 'Eşleştirme etkin', + 'dashboard.no_paired_devices': 'Eşleşmiş cihaz yok', + 'dashboard.cost_pulse': 'Maliyet Nabzı', + 'dashboard.cost_subtitle': 'Oturum, günlük ve aylık çalışma zamanı harcaması', + 'dashboard.session': 'Oturum', + 'dashboard.daily': 'Günlük', + 'dashboard.monthly': 'Aylık', + 'dashboard.channel_activity': 'Kanal Etkinliği', + 'dashboard.channel_subtitle': 'Canlı entegrasyonlar ve rota bağlantısı', + 'dashboard.no_channels': 'Hiç kanal yapılandırılmamış.', + 'dashboard.active': 'Aktif', + 'dashboard.inactive': 'Pasif', + 'dashboard.component_health': 'Bileşen Sağlığı', + 'dashboard.component_subtitle': 'Çalışma zamanı nabzı ve yeniden başlatma farkındalığı', + 'dashboard.no_component_health': 'Şu anda bileşen sağlığı bilgisi yok.', + 'dashboard.restarts': 'Yeniden Başlatmalar', + 'tools.title': 'Mevcut Araçlar', + 'tools.search': 'Araç ara...', + 'tools.agent_tools': 'Ajan Araçları', + 'tools.cli_tools': 'CLI Araçları', + 'tools.no_search_results': 'Aramanızla eşleşen araç yok.', + 'tools.parameter_schema': 'Parametre Şeması', + 'tools.path': 'Yol', + 'tools.version': 'Sürüm', + 'cron.title': 'Zamanlanmış Görevler', + 'cron.add': 'Görev Ekle', + 'cron.scheduled_tasks': 'Zamanlanmış Görevler', + 'cron.add_cron_job': 'Cron Görevi Ekle', + 'cron.name_optional': 'Ad (isteğe bağlı)', + 'cron.schedule_required_command_required': 'Zamanlama ve komut gereklidir.', + 'cron.adding': 'Ekleniyor...', + 'cron.no_tasks_configured': 'Zamanlanmış görev yapılandırılmamış.', + 'cron.load_failed': 'Cron görevleri yüklenemedi', + 'cron.failed_add': 'Görev eklenemedi', + 'cron.failed_delete': 'Görev silinemedi', + 'cron.delete_prompt': 'Silinsin mi?', + 'cron.disabled': 'Devre Dışı', + 'integrations.title': 'Entegrasyonlar', + 'integrations.available': 'Mevcut', + 'integrations.active': 'Aktif', + 'integrations.coming_soon': 'Yakında', + 'integrations.empty': 'Entegrasyon bulunamadı.', + 'integrations.load_failed': 'Entegrasyonlar yüklenemedi', + 'memory.title': 'Hafıza Deposu', + 'memory.add_memory': 'Hafıza Ekle', + 'memory.search_entries': 'Hafıza girdilerinde ara...', + 'memory.all_categories': 'Tüm Kategoriler', + 'memory.search_button': 'Ara', + 'memory.load_failed': 'Hafıza yüklenemedi', + 'memory.key_content_required': 'Anahtar ve içerik gereklidir.', + 'memory.failed_store': 'Hafıza kaydedilemedi', + 'memory.failed_delete': 'Hafıza silinemedi', + 'memory.category_optional': 'Kategori (isteğe bağlı)', + 'memory.key_placeholder': 'örn. kullanici_tercihleri', + 'memory.content_placeholder': 'Hafıza içeriği...', + 'memory.category_placeholder': 'örn. tercihler, bağlam, gerçekler', + 'memory.saving': 'Kaydediliyor...', + 'memory.delete_prompt': 'Silinsin mi?', + 'config.title': 'Yapılandırma', + 'config.save': 'Kaydet', + 'config.saved': 'Yapılandırma başarıyla kaydedildi.', + 'config.saving': 'Kaydediliyor...', + 'config.masked_title': 'Hassas alanlar maskelendi', + 'config.masked_description': 'Güvenlik için API anahtarları, belirteçler ve parolalar gizlenir. Maskelenmiş bir alanı güncellemek için tüm maskeli değeri yeni değerinizle değiştirin.', + 'config.toml_configuration': 'TOML Yapılandırması', + 'config.lines': 'satır', + 'cost.title': 'Maliyet Takibi', + 'cost.session': 'Oturum Maliyeti', + 'cost.daily': 'Günlük Maliyet', + 'cost.monthly': 'Aylık Maliyet', + 'cost.total_requests': 'Toplam İstek', + 'cost.token_statistics': 'Belirteç İstatistikleri', + 'cost.avg_tokens_per_request': 'İstek Başına Ort. Belirteç', + 'cost.cost_per_1k_tokens': '1K Belirteç Başına Maliyet', + 'cost.model_breakdown': 'Model Dağılımı', + 'cost.no_model_data': 'Model verisi yok.', + 'cost.share': 'Pay', + 'cost.load_failed': 'Maliyet verisi yüklenemedi', + 'logs.title': 'Canlı Kayıtlar', + 'logs.pause': 'Duraklat', + 'logs.resume': 'Sürdür', + 'logs.events': 'olay', + 'logs.jump_to_bottom': 'Alta git', + 'logs.filter_label': 'Filtre:', + 'logs.paused_stream': 'Kayıt akışı duraklatıldı.', + 'logs.waiting_for_events': 'Olaylar bekleniyor...', + 'doctor.title': 'Sistem Teşhisleri', + 'doctor.run': 'Teşhisleri Çalıştır', + 'doctor.running': 'Teşhisler çalıştırılıyor...', + 'doctor.running_short': 'Çalışıyor...', + 'doctor.running_hint': 'Bu birkaç saniye sürebilir.', + 'doctor.warn': 'Uyarı', + 'doctor.issues_found': 'Sorunlar Bulundu', + 'doctor.warnings': 'Uyarılar', + 'doctor.all_clear': 'Temiz', + 'doctor.instructions': 'ZeroClaw kurulumunuzu kontrol etmek için "Teşhisleri Çalıştır" düğmesine tıklayın.', + 'auth.pair': 'Cihazı Eşle', + 'auth.pair_button': 'Eşle', + 'auth.logout': 'Çıkış Yap', + 'auth.enter_code': 'Terminalinizdeki tek kullanımlık eşleştirme kodunu girin', + 'auth.code_placeholder': '6 haneli kod', + 'auth.pairing_progress': 'Eşleştiriliyor...', + 'common.languages': 'Diller', + 'common.select_language': 'Dil seçin', + 'common.connecting': 'Bağlanıyor...', + 'header.dashboard_tagline': 'ZeroClaw paneli', + 'sidebar.gateway_dashboard': 'Ağ Geçidi + Panel', + 'sidebar.runtime_mode': 'Çalışma Modu', + 'navigation.open': 'Gezinmeyi aç', + 'navigation.close': 'Gezinmeyi kapat', + 'navigation.expand': 'Gezinmeyi genişlet', + 'navigation.collapse': 'Gezinmeyi daralt', +}; + +export default tr; diff --git a/web/src/lib/i18n/locales/uk.ts b/web/src/lib/i18n/locales/uk.ts new file mode 100644 index 000000000..9da36ebe9 --- /dev/null +++ b/web/src/lib/i18n/locales/uk.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const uk: Partial = { + 'nav.dashboard': 'Панель', + 'nav.agent': 'Агент', + 'nav.tools': 'Інструменти', + 'nav.cron': 'Заплановані завдання', + 'nav.integrations': 'Інтеграції', + 'nav.memory': 'Пам\u2019ять', + 'nav.config': 'Конфігурація', + 'nav.cost': 'Витрати', + 'nav.logs': 'Журнали', + 'nav.doctor': 'Діагностика', + 'dashboard.hero_title': 'Електрична панель runtime', + 'agent.placeholder': 'Введіть повідомлення…', + 'tools.search': 'Пошук інструментів…', + 'cron.add': 'Додати завдання', + 'memory.add_memory': 'Додати пам\u2019ять', + 'config.save': 'Зберегти', + 'cost.token_statistics': 'Статистика токенів', + 'logs.title': 'Живі журнали', + 'doctor.title': 'Діагностика системи', + 'auth.pair_button': 'З\u2019єднати', + 'auth.enter_code': 'Введіть одноразовий код з\u2019єднання з термінала', + 'auth.code_placeholder': '6-значний код', + 'auth.pairing_progress': 'З\u2019єднання…', + 'auth.logout': 'Вийти', + 'common.languages': 'Мови', + 'common.select_language': 'Оберіть мову', + 'header.dashboard_tagline': 'Панель ZeroClaw', +}; + +export default uk; diff --git a/web/src/lib/i18n/locales/ur.ts b/web/src/lib/i18n/locales/ur.ts new file mode 100644 index 000000000..541625e50 --- /dev/null +++ b/web/src/lib/i18n/locales/ur.ts @@ -0,0 +1,33 @@ +import type { TranslationKeys } from './en'; + +const ur: Partial = { + 'nav.dashboard': 'ڈیش بورڈ', + 'nav.agent': 'ایجنٹ', + 'nav.tools': 'ٹولز', + 'nav.cron': 'شیڈول شدہ کام', + 'nav.integrations': 'انضمامات', + 'nav.memory': 'میموری', + 'nav.config': 'ترتیبات', + 'nav.cost': 'لاگت', + 'nav.logs': 'لاگز', + 'nav.doctor': 'تشخیص', + 'dashboard.hero_title': 'الیکٹرک رن ٹائم ڈیش بورڈ', + 'agent.placeholder': 'پیغام لکھیں…', + 'tools.search': 'ٹولز تلاش کریں…', + 'cron.add': 'کام شامل کریں', + 'memory.add_memory': 'میموری شامل کریں', + 'config.save': 'محفوظ کریں', + 'cost.token_statistics': 'ٹوکن کے اعدادوشمار', + 'logs.title': 'لائیو لاگز', + 'doctor.title': 'سسٹم تشخیص', + 'auth.pair_button': 'جوڑیں', + 'auth.enter_code': 'ٹرمینل سے ایک بار استعمال ہونے والا پیئرنگ کوڈ درج کریں', + 'auth.code_placeholder': '6 ہندسوں کا کوڈ', + 'auth.pairing_progress': 'جوڑا جا رہا ہے…', + 'auth.logout': 'لاگ آؤٹ', + 'common.languages': 'زبانیں', + 'common.select_language': 'زبان منتخب کریں', + 'header.dashboard_tagline': 'ZeroClaw ڈیش بورڈ', +}; + +export default ur; diff --git a/web/src/lib/i18n/locales/vi.ts b/web/src/lib/i18n/locales/vi.ts new file mode 100644 index 000000000..63b8140e5 --- /dev/null +++ b/web/src/lib/i18n/locales/vi.ts @@ -0,0 +1,51 @@ +import type { TranslationKeys } from './en'; + +const vi: Partial = { + 'nav.dashboard': 'Bảng điều khiển', + 'nav.agent': 'Tác tử', + 'nav.tools': 'Công cụ', + 'nav.cron': 'Lịch tác vụ', + 'nav.integrations': 'Tích hợp', + 'nav.memory': 'Bộ nhớ', + 'nav.config': 'Cấu hình', + 'nav.cost': 'Chi phí', + 'nav.logs': 'Nhật ký', + 'nav.doctor': 'Chẩn đoán', + 'dashboard.hero_title': 'Bảng điều khiển runtime điện xanh', + 'dashboard.live_gateway': 'Cổng hoạt động', + 'dashboard.unpaired': 'Chưa ghép đôi', + 'agent.title': 'Trò chuyện với tác tử', + 'agent.placeholder': 'Nhập tin nhắn…', + 'agent.connecting': 'Đang kết nối…', + 'agent.connected': 'Đã kết nối', + 'agent.disconnected': 'Đã ngắt kết nối', + 'tools.search': 'Tìm công cụ…', + 'tools.agent_tools': 'Công cụ tác tử', + 'tools.cli_tools': 'Công cụ CLI', + 'cron.add': 'Thêm tác vụ', + 'cron.scheduled_tasks': 'Tác vụ đã lên lịch', + 'integrations.title': 'Tích hợp', + 'memory.add_memory': 'Thêm bộ nhớ', + 'memory.search_entries': 'Tìm trong bộ nhớ…', + 'config.save': 'Lưu', + 'config.saving': 'Đang lưu…', + 'cost.session': 'Chi phí phiên', + 'cost.daily': 'Chi phí ngày', + 'cost.monthly': 'Chi phí tháng', + 'logs.title': 'Nhật ký trực tiếp', + 'logs.pause': 'Tạm dừng', + 'logs.resume': 'Tiếp tục', + 'doctor.title': 'Chẩn đoán hệ thống', + 'doctor.run': 'Chạy chẩn đoán', + 'doctor.running_short': 'Đang chạy…', + 'auth.pair_button': 'Ghép đôi', + 'auth.enter_code': 'Nhập mã ghép đôi một lần từ terminal', + 'auth.code_placeholder': 'Mã 6 chữ số', + 'auth.pairing_progress': 'Đang ghép đôi…', + 'auth.logout': 'Đăng xuất', + 'common.languages': 'Ngôn ngữ', + 'common.select_language': 'Chọn ngôn ngữ', + 'header.dashboard_tagline': 'Bảng điều khiển ZeroClaw', +}; + +export default vi; diff --git a/web/src/lib/i18n/locales/zh-CN.ts b/web/src/lib/i18n/locales/zh-CN.ts new file mode 100644 index 000000000..f4dfff9d2 --- /dev/null +++ b/web/src/lib/i18n/locales/zh-CN.ts @@ -0,0 +1,51 @@ +import type { TranslationKeys } from './en'; + +const zhCN: Partial = { + 'nav.dashboard': '仪表盘', + 'nav.agent': '代理', + 'nav.tools': '工具', + 'nav.cron': '定时任务', + 'nav.integrations': '集成', + 'nav.memory': '记忆', + 'nav.config': '配置', + 'nav.cost': '成本跟踪', + 'nav.logs': '日志', + 'nav.doctor': '诊断', + 'dashboard.hero_title': '电光运行仪表盘', + 'dashboard.live_gateway': '在线网关', + 'dashboard.unpaired': '未配对', + 'agent.title': '代理聊天', + 'agent.placeholder': '输入消息…', + 'agent.connecting': '正在连接…', + 'agent.connected': '已连接', + 'agent.disconnected': '已断开', + 'tools.search': '搜索工具…', + 'tools.agent_tools': '代理工具', + 'tools.cli_tools': 'CLI 工具', + 'cron.add': '添加任务', + 'cron.scheduled_tasks': '定时任务', + 'integrations.title': '集成', + 'memory.add_memory': '添加记忆', + 'memory.search_entries': '搜索记忆条目…', + 'config.save': '保存', + 'config.saving': '正在保存…', + 'cost.session': '会话成本', + 'cost.daily': '每日成本', + 'cost.monthly': '每月成本', + 'logs.title': '实时日志', + 'logs.pause': '暂停', + 'logs.resume': '继续', + 'doctor.title': '系统诊断', + 'doctor.run': '运行诊断', + 'doctor.running_short': '运行中…', + 'auth.pair_button': '配对', + 'auth.enter_code': '输入终端中的一次性配对码', + 'auth.code_placeholder': '6 位代码', + 'auth.pairing_progress': '正在配对…', + 'auth.logout': '退出', + 'common.languages': '语言', + 'common.select_language': '选择语言', + 'header.dashboard_tagline': 'ZeroClaw 仪表盘', +}; + +export default zhCN; diff --git a/web/src/lib/i18n/translate.ts b/web/src/lib/i18n/translate.ts new file mode 100644 index 000000000..2aa7c9ee4 --- /dev/null +++ b/web/src/lib/i18n/translate.ts @@ -0,0 +1,75 @@ +import type { Locale, LocaleDocumentTarget } from './types'; +import { getLocaleDirection } from './languages'; +import { translations } from './locales'; + +const LOCALE_PREFIX_MAP = new Map([ + ['zh', 'zh-CN'], + ['ja', 'ja'], + ['ko', 'ko'], + ['vi', 'vi'], + ['tl', 'tl'], + ['es', 'es'], + ['pt', 'pt'], + ['it', 'it'], + ['de', 'de'], + ['fr', 'fr'], + ['ar', 'ar'], + ['hi', 'hi'], + ['ru', 'ru'], + ['bn', 'bn'], + ['iw', 'he'], + ['he', 'he'], + ['pl', 'pl'], + ['cs', 'cs'], + ['nl', 'nl'], + ['tr', 'tr'], + ['uk', 'uk'], + ['id', 'id'], + ['th', 'th'], + ['ur', 'ur'], + ['ro', 'ro'], + ['sv', 'sv'], + ['el', 'el'], + ['hu', 'hu'], + ['fi', 'fi'], + ['da', 'da'], + ['nb', 'nb'], + ['no', 'nb'], +]); + +export function coerceLocale(locale: string | undefined): Locale { + if (!locale) return 'en'; + const prefix = locale.toLowerCase().split(/[-_]/)[0]; + return LOCALE_PREFIX_MAP.get(prefix) ?? 'en'; +} + +let currentLocale: Locale = 'en'; + +export function getLocale(): Locale { + return currentLocale; +} + +export function setLocale(locale: Locale): void { + currentLocale = locale; +} + +export function t(key: string): string { + return translations[currentLocale]?.[key] ?? translations.en[key] ?? key; +} + +export function tLocale(key: string, locale: Locale): string { + return translations[locale]?.[key] ?? translations.en[key] ?? key; +} + +export function applyLocaleToDocument(locale: Locale, target: LocaleDocumentTarget): void { + const direction = getLocaleDirection(locale); + + if (target.documentElement) { + target.documentElement.lang = locale; + target.documentElement.dir = direction; + } + + if (target.body) { + target.body.dir = direction; + } +} diff --git a/web/src/lib/i18n/types.ts b/web/src/lib/i18n/types.ts new file mode 100644 index 000000000..6c5284087 --- /dev/null +++ b/web/src/lib/i18n/types.ts @@ -0,0 +1,46 @@ +export type Locale = + | 'en' + | 'zh-CN' + | 'ja' + | 'ko' + | 'vi' + | 'tl' + | 'es' + | 'pt' + | 'it' + | 'de' + | 'fr' + | 'ar' + | 'hi' + | 'ru' + | 'bn' + | 'he' + | 'pl' + | 'cs' + | 'nl' + | 'tr' + | 'uk' + | 'id' + | 'th' + | 'ur' + | 'ro' + | 'sv' + | 'el' + | 'hu' + | 'fi' + | 'da' + | 'nb'; + +export type LocaleDirection = 'ltr' | 'rtl'; + +export interface LanguageOption { + value: Locale; + label: string; + flag: string; + direction: LocaleDirection; +} + +export interface LocaleDocumentTarget { + documentElement?: { lang?: string; dir?: string }; + body?: { dir?: string } | null; +}