/**
 * Lightweight frontend i18n for Cognithor Control Center.
 *
 * Usage:
 *   import { t, setLocale, getLocale } from "../utils/i18n";
 *   t("chat.placeholder")  // → "Type a message..."
 *   setLocale("de")        // switches all strings
 *
 * The locale is kept in sync with the backend config.language setting.
 * Components re-render via a simple event emitter pattern.
 */

// ── Translation packs ────────────────────────────────────────────────────

const packs = {
  en: {
    // Sidebar navigation
    "nav.chat": "Chat",
    "nav.general": "General",
    "nav.language": "Language",
    "nav.providers": "LLM Providers",
    "nav.models": "Models",
    "nav.planner": "PGE Trinity",
    "nav.executor": "Executor",
    "nav.memory": "Memory",
    "nav.channels": "Channels",
    "nav.security": "Security",
    "nav.web": "Web Tools",
    "nav.mcp": "Integrations",
    "nav.cron": "Cron & Heartbeat",
    "nav.database": "Database",
    "nav.logging": "Logging",
    "nav.prompts": "Prompts & Policies",
    "nav.agents": "Agents",
    "nav.bindings": "Bindings",
    "nav.workflows": "Workflows",
    "nav.knowledge_graph": "Knowledge Graph",
    "nav.system": "System",

    // Chat
    "chat.title": "Chat with Jarvis",
    "chat.placeholder": "Type a message...",
    "chat.empty": "Hello! Ask me anything...",
    "chat.send": "Send (Enter)",
    "chat.attach": "Attach file",
    "chat.voice": "Voice",
    "chat.voice_on": "Voice On",
    "chat.clear": "Clear",
    "chat.canvas": "Canvas",
    "chat.canvas_active": "Canvas active",
    "chat.canvas_close": "Close canvas",
    "chat.canvas_title": "Jarvis Canvas",
    "chat.stop_recording": "Stop recording",
    "chat.voice_message": "Voice message",

    // Voice
    "voice.wake": 'Say "Jarvis"...',
    "voice.listening": 'Listening... (say "Jarvis stop" to end)',
    "voice.processing": "Processing...",
    "voice.speaking": "Speaking...",

    // Language settings
    "lang.title": "Language Settings",
    "lang.subtitle": "System language, locale selection, and prompt translation",
    "lang.active": "Active Language",
    "lang.system": "System language",
    "lang.system_desc": "Controls UI messages, error texts, and status outputs. Changing this triggers a prompt translation offer below.",
    "lang.packs_info": "Installed language packs: {packs} \u00b7 Prompt presets available for: {presets}",
    "lang.translate_title": "System Prompt Translation",
    "lang.translate_desc": "You changed the language to {lang}.",
    "lang.translate_question": "Would you like to translate the system prompts?",
    "lang.method_label": "Translation method",
    "lang.method_preset": "Use curated preset (instant, recommended)",
    "lang.method_ollama": "Translate via Ollama (slower, custom)",
    "lang.desc_preset": "Pre-verified translations — instant, no LLM needed. Available for:",
    "lang.desc_ollama": "Uses your configured planner model to translate prompts on-the-fly. May take 30-60 seconds.",
    "lang.translate_btn": "Translate Prompts",
    "lang.translating": "Translating...",
    "lang.skip": "Skip \u2014 keep current prompts",
    "lang.preview_title": "Translation Preview",
    "lang.preview_desc": "Review the translated prompts below. Click Accept & Apply to write them, or Discard to keep the originals.",
    "lang.accept": "Accept & Apply",
    "lang.discard": "Discard",
    "lang.planner_prompt": "Planner System-Prompt",
    "lang.replan_prompt": "Replan-Prompt",
    "lang.escalation_prompt": "Escalation-Prompt",

    // Header / Power
    "header.power_on": "Power On",
    "header.power_off": "Power Off",
    "header.version": "Control Center v{version}",
    "header.backend_stopped": "Backend not started. Click \"Power On\" above to launch Cognithor.",
    "header.backend_error": "Backend unreachable \u2014 is Cognithor running?",
    "header.starting": "Starting...",
    "header.stopping": "Stopping...",

    // Prompts & Policies page
    "prompts.title": "Prompts & Policies",
    "prompts.subtitle": "View and customize system prompts, gatekeeper policies, CORE.md, HEARTBEAT.md",
    "prompts.core_title": "CORE.md \u2014 System Personality",
    "prompts.core_desc": "Core Memory (Markdown)",
    "prompts.core_hint": "Personality, rules and preferences of Jarvis",
    "prompts.planner": "Planner System-Prompt",
    "prompts.replan": "Replan-Prompt",
    "prompts.escalation": "Escalation-Prompt",
    "prompts.gatekeeper": "Gatekeeper-Policies (YAML)",
    "prompts.heartbeat": "HEARTBEAT.md \u2014 Heartbeat Checklist",
    "prompts.reset": "Reset",

    // Common
    "common.save": "Save",
    "common.cancel": "Cancel",
    "common.loading": "Loading...",
    "common.error": "Error",
    "common.search": "Search...",

    // Save bar
    "save.unsaved": "Unsaved changes",
    "save.discard": "Discard",
    "save.saving": "Saving...",
    "save.saved": "Saved!",
    "save.save": "Save changes",

    // Spinner
    "common.loading_config": "Loading configuration...",

    // General page
    "gen.title": "General",
    "gen.desc": "Identity, operation mode and cost tracking",
    "gen.identity": "Identity",
    "gen.owner": "Owner name",
    "gen.owner_desc": "Used in prompts and CORE.md",
    "gen.owner_required": "Required",
    "gen.mode": "Operation mode",
    "gen.mode_desc": "Auto detects the mode based on available API keys",
    "gen.version": "Version",
    "gen.version_desc": "System version (read-only)",
    "gen.cost": "Cost Tracking",
    "gen.cost_enabled": "Cost tracking enabled",
    "gen.daily_limit": "Daily limit (USD)",
    "gen.monthly_limit": "Monthly limit (USD)",
    "gen.no_limit": "0 = no limit",

    // Prompt Evolution
    "evo.title": "Prompt Evolution (A/B)",
    "evo.enabled": "Prompt evolution enabled",
    "evo.active_version": "Active version",
    "evo.versions": "Versions",
    "evo.total_sessions": "Total sessions",
    "evo.running_tests": "Running tests",
    "evo.completed_tests": "Completed tests",
    "evo.evolving": "Evolving...",
    "evo.evolve_now": "Evolve now",
    "evo.new_version": "New version: {id}",
    "evo.no_data": "No evolution (not enough data yet)",

    // Providers page
    "prov.title": "LLM Providers",
    "prov.desc": "15 backends — API keys, endpoints, backend selection",
    "prov.active": "Active Backend",
    "prov.backend": "LLM Backend",
    "prov.backend_desc": "All models use this backend",
    "prov.filter": "Filter providers...",
    "prov.no_match": "No provider found for",
    "prov.base_url": "Base URL",
    "prov.timeout": "Timeout (sec)",
    "prov.keep_alive": "Keep-Alive",
    "prov.keep_alive_desc": "How long models stay in VRAM (e.g. 30m)",
    "prov.api_key": "API Key",
    "prov.max_tokens": "Max Output Tokens",
    "prov.openai_url_desc": "Also for Together, Groq, vLLM, LM Studio",

    // Models page
    "models.title": "Models",
    "models.desc": "Model assignment per role, vision models, skill overrides. Each role can use its own API provider.",
    "models.name": "Model name",
    "models.backend": "Backend / Provider",
    "models.backend_desc": "Custom provider for this role (empty = global backend)",
    "models.context": "Context Window",
    "models.vram": "VRAM (GB)",
    "models.temp": "Temperature",
    "models.temp_desc": "Creativity (0=deterministic, 2=wild)",
    "models.top_p": "Top P",
    "models.top_p_desc": "Nucleus Sampling",
    "models.strengths": "Strengths",
    "models.vision": "Vision Models",
    "models.vision_standard": "Standard Vision",
    "models.vision_standard_desc": "Fast vision model",
    "models.vision_detail": "Detail Vision",
    "models.vision_detail_desc": "Highest quality",
    "models.skill_overrides": "Skill Overrides",
    "models.skill_overrides_desc": "Per-skill model assignment (JSON key-value)",
    "models.global": "Global (Standard)",

    // PGE Trinity page
    "pge.title": "PGE Trinity",
    "pge.desc": "Planner, Gatekeeper, Executor — core engine",
    "pge.planner": "Planner (Thinker)",
    "pge.max_iter": "Max iterations",
    "pge.max_iter_desc": "Max agent loop cycles per request",
    "pge.escalation": "Escalation after",
    "pge.escalation_desc": "Inform user after X steps",
    "pge.temp": "Temperature",
    "pge.temp_desc": "Creativity (0=deterministic, 2=wild)",
    "pge.token_budget": "Response Token Budget",
    "pge.gatekeeper": "Gatekeeper (Guardian)",
    "pge.policies_dir": "Policies directory",
    "pge.policies_desc": "Relative to jarvis_home",
    "pge.risk_level": "Default risk level",
    "pge.max_retries": "Max blocked retries",
    "pge.sandbox": "Sandbox (Executor)",
    "pge.sandbox_level": "Sandbox level",
    "pge.sandbox_level_desc": "Code execution isolation level",
    "pge.sandbox_timeout": "Timeout (sec)",
    "pge.sandbox_memory": "Max memory (MB)",
    "pge.sandbox_cpu": "Max CPU (sec)",
    "pge.network": "Network access",
    "pge.allowed_paths": "Allowed paths",
    "pge.env_vars": "Environment variables (JSON)",

    // Memory page
    "mem.title": "Memory System",
    "mem.desc": "5-tier memory: indexing, hybrid search, recency, compaction",
    "mem.indexing": "Indexing",
    "mem.chunk_size": "Chunk Size (Tokens)",
    "mem.chunk_overlap": "Chunk Overlap",
    "mem.top_k": "Search Top-K",
    "mem.search": "Hybrid Search Weighting",
    "mem.sum": "Sum:",
    "mem.perfect": "Perfect",
    "mem.normalized": "Will be normalized",
    "mem.below": "Below 1.0",
    "mem.vector": "Vector (Embedding)",
    "mem.bm25": "BM25 (Keyword)",
    "mem.graph": "Graph (Knowledge)",
    "mem.dynamic": "Dynamic weighting",
    "mem.dynamic_desc": "Automatically adjust weights based on query type",
    "mem.recency": "Recency & Compaction",
    "mem.half_life": "Recency half-life (days)",
    "mem.compact_thresh": "Compaction threshold",
    "mem.keep_last": "Keep last N",
    "mem.retention": "Episodic retention (days)",
    "mem.retention_desc": "How many days of daily logs to keep",

    // Channels page
    "ch.title": "Channels",
    "ch.desc": "17 communication channels — enable and configure",
    "ch.enable": "Enable {name}",
    "ch.voice_config": "Voice Configuration",
    "ch.voice_enabled": "Voice enabled",
    "ch.voice_enabled_desc": "Enable voice control in chat",
    "ch.tts_backend": "TTS Backend",
    "ch.tts_backend_desc": "Text-to-speech engine",
    "ch.piper_voice": "Piper voice",
    "ch.piper_voice_desc": "Downloaded automatically on first use",
    "ch.speech_rate": "Speech rate",
    "ch.speech_rate_desc": "1.0 = normal, lower = faster",
    "ch.elevenlabs_key": "ElevenLabs API Key",
    "ch.elevenlabs_voice": "ElevenLabs Voice ID",
    "ch.elevenlabs_model": "ElevenLabs Model",
    "ch.wake_word_enabled": "Wake word enabled",
    "ch.wake_word_enabled_desc": "Trigger voice command by wake word",
    "ch.wake_word": "Wake word",
    "ch.wake_word_desc": "Default: jarvis",
    "ch.wake_word_backend": "Wake word backend",
    "ch.wake_word_backend_desc": "browser = Web Speech API (no setup needed)",
    "ch.talk_mode": "Talk mode",
    "ch.talk_mode_desc": "Continuous listening in chat",
    "ch.auto_listen": "Auto-listen",
    "ch.auto_listen_desc": "Automatically listen again after response",

    // Security page
    "sec.title": "Security",
    "sec.desc": "Iteration limits, paths, blocked commands, credential patterns",
    "sec.limits": "Gatekeeper Limits",
    "sec.max_iter": "Max iterations",
    "sec.max_iter_desc": "Infinite loop protection",
    "sec.max_depth": "Max sub-agent depth",
    "sec.max_depth_desc": "Maximum recursion depth for sub-agent delegations",
    "sec.filesystem": "Gatekeeper Filesystem",
    "sec.allowed_paths": "Allowed paths",
    "sec.blocked": "Gatekeeper Blocked Commands (Regex)",
    "sec.blocked_patterns": "Patterns",
    "sec.credentials": "Gatekeeper Credential Detection (Regex)",
    "sec.cred_patterns": "Patterns",

    // Executor page
    "exec.title": "Executor",
    "exec.desc": "Tool execution: timeouts, retries, parallelism",
    "exec.general": "General",
    "exec.llm_timeout": "LLM timeout (seconds)",
    "exec.llm_timeout_desc": "Timeout for LLM requests (Planner/Executor). Applies to all backends (Ollama, OpenAI, etc.)",
    "exec.default_timeout": "Default timeout (seconds)",
    "exec.default_timeout_desc": "Timeout for individual tool calls",
    "exec.max_output": "Max output (chars)",
    "exec.max_output_desc": "Tool output is truncated after this length",
    "exec.max_retries": "Max retries",
    "exec.max_retries_desc": "Retry attempts for transient errors",
    "exec.backoff": "Backoff base (seconds)",
    "exec.backoff_desc": "Base delay for exponential backoff",
    "exec.dag": "DAG Parallelism",
    "exec.max_parallel": "Max parallel tools",
    "exec.max_parallel_desc": "Maximum number of simultaneously executed tools (DAG-based)",
    "exec.tool_timeouts": "Tool-specific Timeouts",
    "exec.image_timeout": "Image analysis (seconds)",
    "exec.image_timeout_desc": "Vision models need more time (20+ GB VRAM)",
    "exec.audio_timeout": "Audio transcription (seconds)",
    "exec.text_timeout": "Text extraction (seconds)",
    "exec.tts_timeout": "Text-to-speech (seconds)",
    "exec.python_timeout": "Python execution (seconds)",

    // Web Tools page
    "web.title": "Web Tools",
    "web.desc": "Search backends, limits, rate limiting, HTTP requests",
    "web.searxng": "SearXNG (Self-hosted)",
    "web.searxng_url": "SearXNG URL",
    "web.searxng_desc": "Highest priority",
    "web.brave": "Brave Search",
    "web.brave_key": "API Key",
    "web.brave_desc": "2000 requests/month free",
    "web.google": "Google Custom Search Engine",
    "web.google_key": "API Key",
    "web.google_desc": "100 requests/day free",
    "web.google_cx": "Search Engine ID (cx)",
    "web.jina": "Jina AI Reader",
    "web.jina_key": "API Key",
    "web.jina_desc": "Optional — free tier works without key",
    "web.ddg": "DuckDuckGo",
    "web.ddg_enabled": "DuckDuckGo enabled",
    "web.ddg_enabled_desc": "Free fallback",
    "web.ddg_delay": "Min delay (seconds)",
    "web.ddg_delay_desc": "Rate limiting between DuckDuckGo searches",
    "web.ddg_wait": "Rate limit wait (seconds)",
    "web.ddg_wait_desc": "Wait time on 429 error",
    "web.ddg_cache": "Cache TTL (seconds)",
    "web.ddg_cache_desc": "How long search results are cached",
    "web.fetch_limits": "Fetch Limits",
    "web.max_fetch": "Max fetch size (bytes)",
    "web.max_fetch_desc": "Maximum response size for URL fetch",
    "web.max_text": "Max text chars",
    "web.max_text_desc": "Maximum character count of extracted text",
    "web.fetch_timeout": "Fetch timeout (seconds)",
    "web.search_timeout": "Search timeout (seconds)",
    "web.max_results": "Max search results",
    "web.sar_chars": "search_and_read max chars/page",
    "web.http": "HTTP Request Tool",
    "web.http_body": "Max body size (bytes)",
    "web.http_body_desc": "Maximum request body size",
    "web.http_timeout": "Default timeout (seconds)",
    "web.http_rate": "Rate limit (seconds)",
    "web.http_rate_desc": "Minimum interval between requests. 0 = no limit.",
    "web.domain_filter": "Domain Filter",
    "web.blocklist": "Blocklist",
    "web.blocklist_desc": "These domains are blocked during fetch",
    "web.allowlist": "Allowlist",
    "web.allowlist_desc": "If not empty: ONLY these domains are allowed (whitelist)",

    // MCP / Integrations page
    "mcp.title": "Integrations",
    "mcp.desc": "Model Context Protocol (MCP) Server + Agent-to-Agent Communication (A2A)",
    "mcp.server_mode": "MCP Server Mode",
    "mcp.mode": "Mode",
    "mcp.mode_desc": "Expose Jarvis as MCP server",
    "mcp.http_host": "HTTP Host",
    "mcp.http_port": "HTTP Port",
    "mcp.server_name": "Server-Name",
    "mcp.auth_required": "Auth required",
    "mcp.auth_token": "Auth Token",
    "mcp.expose_tools": "Expose tools",
    "mcp.expose_resources": "Expose resources",
    "mcp.expose_prompts": "Expose prompts",
    "mcp.sampling": "Sampling enabled",
    "mcp.external": "External MCP Servers",
    "mcp.external_desc": "Connected external MCP servers (tools & resources)",
    "mcp.srv_name": "Server Name",
    "mcp.command": "Command",
    "mcp.arguments": "Arguments",
    "mcp.env_vars": "Environment Variables (JSON)",
    "mcp.always_allow": "Always Allow (Tools)",
    "mcp.disabled": "Disabled",
    "mcp.delete": "Delete",
    "mcp.add_server": "+ Add server",
    "mcp.a2a": "A2A Protocol",
    "mcp.a2a_enabled": "A2A enabled",
    "mcp.a2a_desc": "Agent-to-agent communication (Linux Foundation A2A RC v1.0)",
    "mcp.a2a_host": "Host",
    "mcp.a2a_port": "Port",
    "mcp.a2a_name": "Agent Name",
    "mcp.a2a_description": "Description",
    "mcp.a2a_max_tasks": "Max Tasks",
    "mcp.a2a_task_timeout": "Task Timeout (sec)",
    "mcp.a2a_streaming": "Streaming",
    "mcp.a2a_push": "Push Notifications",
    "mcp.a2a_remotes": "Remotes (JSON Array)",
    "mcp.a2a_remotes_desc": "List of remote agents: [{\"endpoint\": \"http://...\", \"auth_token\": \"\"}]",

    // Cron & Heartbeat page
    "cron.title": "Cron & Heartbeat",
    "cron.desc": "Periodic tasks, heartbeat checklist, plugins",
    "cron.heartbeat": "Heartbeat",
    "cron.hb_enabled": "Heartbeat enabled",
    "cron.hb_enabled_desc": "Periodic system checks",
    "cron.hb_interval": "Interval (min)",
    "cron.hb_file": "Checklist file",
    "cron.hb_file_desc": "Relative to jarvis_home",
    "cron.hb_channel": "Channel",
    "cron.hb_model": "Model",
    "cron.jobs": "Cron-Jobs",
    "cron.name": "Name",
    "cron.schedule": "Schedule (Cron)",
    "cron.prompt": "Prompt",
    "cron.channel": "Channel",
    "cron.model": "Model",
    "cron.agent": "Agent",
    "cron.agent_placeholder": "(empty = default routing)",
    "cron.delete_job": "Delete job",
    "cron.add_job": "Add new job",
    "cron.plugins": "Plugins",
    "cron.skills_dir": "Skills directory",
    "cron.skills_desc": "Relative to jarvis_home",
    "cron.auto_update": "Auto-update",
    "cron.auto_update_desc": "Automatic plugin updates on startup",

    // Logging page
    "log.title": "Logging",
    "log.desc": "Logging and debugging",
    "log.general": "General",
    "log.level": "Log level",
    "log.json": "JSON logs",
    "log.json_desc": "Structured JSON logs for external tools",
    "log.console": "Console output",
    "log.console_desc": "Output logs to console",

    // Database page
    "db.title": "Database",
    "db.desc": "Storage backend for memory, logs and state",
    "db.connection": "Connection",
    "db.backend": "Backend",
    "db.host": "Host",
    "db.port": "Port",
    "db.database": "Database",
    "db.user": "User",
    "db.password": "Password",
    "db.pool": "Connection Pool",
    "db.pool_min": "Pool Min",
    "db.pool_max": "Pool Max",
    "db.encryption": "Encryption",
    "db.encryption_enabled": "SQLite encryption (SQLCipher)",
    "db.encryption_desc": "Encrypts all SQLite databases with SQLCipher. The key is stored securely in the OS keyring.",
    "db.encryption_info": "The encryption key is managed automatically in the system keyring (Windows Credential Locker / macOS Keychain / Linux SecretService). A new key is generated on first activation.",
    "db.encryption_prereq": "Prerequisite:",

    // Agents page
    "agents.title": "Agents",
    "agents.desc": "Manage multi-agent profiles — routing, models, permissions",
    "agents.name_id": "Name (ID)",
    "agents.required": "Required",
    "agents.display_name": "Display name",
    "agents.description": "Description",
    "agents.system_prompt": "System-Prompt",
    "agents.language": "Language",
    "agents.priority": "Priority",
    "agents.preferred_model": "Preferred model",
    "agents.temperature": "Temperature",
    "agents.trigger_keywords": "Trigger Keywords",
    "agents.blocked_tools": "Blocked tools",
    "agents.enabled": "Enabled",
    "agents.delete": "Delete agent",
    "agents.create": "Create new agent",

    // Bindings page
    "bind.title": "Bindings",
    "bind.desc": "Routing rules: which message goes to which agent?",
    "bind.name": "Name",
    "bind.required": "Required",
    "bind.target": "Target agent",
    "bind.priority": "Priority",
    "bind.description": "Description",
    "bind.channels": "Channels",
    "bind.prefixes": "Command Prefixes",
    "bind.patterns": "Message Patterns (Regex)",
    "bind.enabled": "Enabled",
    "bind.delete": "Delete binding",
    "bind.create": "New binding",

    // System page
    "sys.title": "System",
    "sys.desc": "Restart, export/import, factory reset",
    "sys.restart": "Restart Cognithor",
    "sys.restart_desc": "Cleanly shuts down Cognithor (save sessions, stop channels, flush memory) and restarts with the current configuration.",
    "sys.restarting": "Restarting...",
    "sys.restarted": "Restarted!",
    "sys.restart_btn": "Restart Cognithor",
    "sys.export_import": "Export & Import",
    "sys.export": "Export configuration",
    "sys.import": "Import configuration",
    "sys.factory_reset": "Factory Reset",
    "sys.factory_desc": "Resets all configuration settings to defaults. API keys and stored data (memory, skills, workflows) are preserved.",
    "sys.factory_btn": "Reset all settings",
    "sys.info": "System Info",
    "sys.info_version": "Version",
    "sys.info_backend": "Backend",
    "sys.info_owner": "Owner",
    "sys.info_mode": "Mode",

    // Global Search
    "search.hint": "Search...",
    "search.placeholder": "Search settings...",
    "search.no_results": "No results for \"{query}\"",

    // Knowledge Graph
    "kg.title": "Knowledge Graph",
    "kg.loading": "Loading knowledge graph...",
    "kg.entities": "Entities",
    "kg.relationships": "Relationships",
    "kg.empty_title": "No entities in knowledge graph",
    "kg.empty_desc": "Entities are automatically extracted from conversations.",
    "kg.search_placeholder": "Search entity...",
    "kg.all_types": "All types",
    "kg.visible": "{count} visible",
    "kg.type_label": "Type:",
    "kg.confidence_label": "Confidence:",
    "kg.attributes_label": "Attributes:",
    "kg.relationships_label": "Relationships ({count}):",
    "kg.id_label": "ID:",

    // Workflow Graph
    "wf.title": "Workflow Execution Graph",
    "wf.loading": "Loading workflows...",
    "wf.templates": "Templates",
    "wf.instances": "Instances",
    "wf.dag_runs": "DAG Runs",
    "wf.active": "active",
    "wf.completed": "completed",
    "wf.start": "Start",
    "wf.back": "\u2190 Back",
    "wf.no_templates": "No workflow templates available",
    "wf.no_instances": "No running workflows",
    "wf.no_dag_runs": "No DAG runs available",
    "wf.no_nodes": "No nodes",
    "wf.steps": "steps",
    "wf.min": "min",
    "wf.type_tool": "Tool",
    "wf.type_llm": "LLM",
    "wf.type_condition": "IF",
    "wf.type_approval": "Approval",
    "wf.nodes": "nodes",
    "wf.detail_type": "Type:",
    "wf.detail_status": "Status:",
    "wf.detail_output": "Output:",
    "wf.detail_error": "Error:",
    "wf.detail_duration": "Duration:",
    "wf.detail_retries": "Retries:",
    "wf.detail_depends": "Depends on:",
  },

  de: {
    "nav.chat": "Chat",
    "nav.general": "Allgemein",
    "nav.language": "Sprache",
    "nav.providers": "LLM-Anbieter",
    "nav.models": "Modelle",
    "nav.planner": "PGE Trinity",
    "nav.executor": "Executor",
    "nav.memory": "Speicher",
    "nav.channels": "Kan\u00e4le",
    "nav.security": "Sicherheit",
    "nav.web": "Web-Tools",
    "nav.mcp": "Integrationen",
    "nav.cron": "Cron & Heartbeat",
    "nav.database": "Datenbank",
    "nav.logging": "Logging",
    "nav.prompts": "Prompts & Richtlinien",
    "nav.agents": "Agenten",
    "nav.bindings": "Bindings",
    "nav.workflows": "Workflows",
    "nav.knowledge_graph": "Wissensgraph",
    "nav.system": "System",

    "chat.title": "Chat mit Jarvis",
    "chat.placeholder": "Nachricht eingeben...",
    "chat.empty": "Hallo! Frag mich etwas...",
    "chat.send": "Senden (Enter)",
    "chat.attach": "Datei anh\u00e4ngen",
    "chat.voice": "Sprache",
    "chat.voice_on": "Sprache An",
    "chat.clear": "Leeren",
    "chat.canvas": "Canvas",
    "chat.canvas_active": "Canvas aktiv",
    "chat.canvas_close": "Canvas schlie\u00dfen",
    "chat.canvas_title": "Jarvis Canvas",
    "chat.stop_recording": "Aufnahme stoppen",
    "chat.voice_message": "Sprachnachricht",

    "voice.wake": "Sag \"Jarvis\"...",
    "voice.listening": "H\u00f6re zu... (sag \"Jarvis stop\" zum Beenden)",
    "voice.processing": "Verarbeite...",
    "voice.speaking": "Spreche...",

    "lang.title": "Spracheinstellungen",
    "lang.subtitle": "Systemsprache, Sprachpaket-Auswahl und Prompt-\u00dcbersetzung",
    "lang.active": "Aktive Sprache",
    "lang.system": "Systemsprache",
    "lang.system_desc": "Steuert UI-Nachrichten, Fehlertexte und Statusausgaben. Eine \u00c4nderung l\u00f6st ein \u00dcbersetzungsangebot f\u00fcr die Prompts aus.",
    "lang.packs_info": "Installierte Sprachpakete: {packs} \u00b7 Prompt-Presets verf\u00fcgbar f\u00fcr: {presets}",
    "lang.translate_title": "System-Prompt-\u00dcbersetzung",
    "lang.translate_desc": "Du hast die Sprache auf {lang} ge\u00e4ndert.",
    "lang.translate_question": "M\u00f6chtest du die System-Prompts \u00fcbersetzen?",
    "lang.method_label": "\u00dcbersetzungsmethode",
    "lang.method_preset": "Kuratiertes Preset verwenden (sofort, empfohlen)",
    "lang.method_ollama": "Via Ollama \u00fcbersetzen (langsamer, individuell)",
    "lang.desc_preset": "Vorab gepr\u00fcfte \u00dcbersetzungen — sofort, kein LLM n\u00f6tig. Verf\u00fcgbar f\u00fcr:",
    "lang.desc_ollama": "Nutzt das konfigurierte Planner-Modell zur Echtzeit-\u00dcbersetzung. Kann 30\u201360 Sekunden dauern.",
    "lang.translate_btn": "Prompts \u00fcbersetzen",
    "lang.translating": "\u00dcbersetze...",
    "lang.skip": "\u00dcberspringen \u2014 aktuelle Prompts behalten",
    "lang.preview_title": "\u00dcbersetzungsvorschau",
    "lang.preview_desc": "Pr\u00fcfe die \u00fcbersetzten Prompts. Klicke \u00dcbernehmen zum Speichern, oder Verwerfen f\u00fcr die Originale.",
    "lang.accept": "\u00dcbernehmen",
    "lang.discard": "Verwerfen",
    "lang.planner_prompt": "Planner System-Prompt",
    "lang.replan_prompt": "Replan-Prompt",
    "lang.escalation_prompt": "Eskalations-Prompt",

    "header.power_on": "Einschalten",
    "header.power_off": "Ausschalten",
    "header.version": "Control Center v{version}",
    "header.backend_stopped": "Backend nicht gestartet. Klicke oben auf \"Einschalten\" um Cognithor zu starten.",
    "header.backend_error": "Backend nicht erreichbar \u2014 l\u00e4uft Cognithor?",
    "header.starting": "Startet...",
    "header.stopping": "Stoppt...",

    "prompts.title": "Prompts & Richtlinien",
    "prompts.subtitle": "System-Prompts, Gatekeeper-Richtlinien, CORE.md und HEARTBEAT.md anzeigen und bearbeiten",
    "prompts.core_title": "CORE.md \u2014 System-Pers\u00f6nlichkeit",
    "prompts.core_desc": "Kern-Ged\u00e4chtnis (Markdown)",
    "prompts.core_hint": "Pers\u00f6nlichkeit, Regeln und Pr\u00e4ferenzen von Jarvis",
    "prompts.planner": "Planner System-Prompt",
    "prompts.replan": "Replan-Prompt",
    "prompts.escalation": "Eskalations-Prompt",
    "prompts.gatekeeper": "Gatekeeper-Richtlinien (YAML)",
    "prompts.heartbeat": "HEARTBEAT.md \u2014 Heartbeat-Checkliste",
    "prompts.reset": "Zur\u00fccksetzen",

    "common.save": "Speichern",
    "common.cancel": "Abbrechen",
    "common.loading": "Laden...",
    "common.error": "Fehler",
    "common.search": "Suchen...",

    // Save bar
    "save.unsaved": "Ungespeicherte \u00c4nderungen",
    "save.discard": "Verwerfen",
    "save.saving": "Speichere...",
    "save.saved": "Gespeichert!",
    "save.save": "\u00c4nderungen speichern",

    // Spinner
    "common.loading_config": "Konfiguration wird geladen...",

    // General page
    "gen.title": "Allgemein",
    "gen.desc": "Identit\u00e4t, Betriebsmodus und Kostenerfassung",
    "gen.identity": "Identit\u00e4t",
    "gen.owner": "Besitzername",
    "gen.owner_desc": "Wird in Prompts und CORE.md verwendet",
    "gen.owner_required": "Erforderlich",
    "gen.mode": "Betriebsmodus",
    "gen.mode_desc": "Erkennt den Modus automatisch anhand verf\u00fcgbarer API-Schl\u00fcssel",
    "gen.version": "Version",
    "gen.version_desc": "Systemversion (schreibgesch\u00fctzt)",
    "gen.cost": "Kostenerfassung",
    "gen.cost_enabled": "Kostenerfassung aktiviert",
    "gen.daily_limit": "Tageslimit (USD)",
    "gen.monthly_limit": "Monatslimit (USD)",
    "gen.no_limit": "0 = kein Limit",

    // Prompt Evolution
    "evo.title": "Prompt-Evolution (A/B)",
    "evo.enabled": "Prompt-Evolution aktiviert",
    "evo.active_version": "Aktive Version",
    "evo.versions": "Versionen",
    "evo.total_sessions": "Gesamte Sitzungen",
    "evo.running_tests": "Laufende Tests",
    "evo.completed_tests": "Abgeschlossene Tests",
    "evo.evolving": "Evolviere...",
    "evo.evolve_now": "Jetzt evolvieren",
    "evo.new_version": "Neue Version: {id}",
    "evo.no_data": "Keine Evolution (noch nicht gen\u00fcgend Daten)",

    // Providers page
    "prov.title": "LLM-Anbieter",
    "prov.desc": "15 Backends \u2014 API-Schl\u00fcssel, Endpunkte, Backend-Auswahl",
    "prov.active": "Aktives Backend",
    "prov.backend": "LLM-Backend",
    "prov.backend_desc": "Alle Modelle nutzen dieses Backend",
    "prov.filter": "Anbieter filtern...",
    "prov.no_match": "Kein Anbieter gefunden f\u00fcr",
    "prov.base_url": "Basis-URL",
    "prov.timeout": "Timeout (Sek.)",
    "prov.keep_alive": "Keep-Alive",
    "prov.keep_alive_desc": "Wie lange Modelle im VRAM bleiben (z.B. 30m)",
    "prov.api_key": "API-Schl\u00fcssel",
    "prov.max_tokens": "Max. Ausgabe-Tokens",
    "prov.openai_url_desc": "Auch f\u00fcr Together, Groq, vLLM, LM Studio",

    // Models page
    "models.title": "Modelle",
    "models.desc": "Modellzuweisung pro Rolle, Vision-Modelle, Skill-\u00dcberschreibungen. Jede Rolle kann einen eigenen API-Anbieter nutzen.",
    "models.name": "Modellname",
    "models.backend": "Backend / Anbieter",
    "models.backend_desc": "Eigener Anbieter f\u00fcr diese Rolle (leer = globales Backend)",
    "models.context": "Kontextfenster",
    "models.vram": "VRAM (GB)",
    "models.temp": "Temperatur",
    "models.temp_desc": "Kreativit\u00e4t (0=deterministisch, 2=wild)",
    "models.top_p": "Top P",
    "models.top_p_desc": "Nucleus Sampling",
    "models.strengths": "St\u00e4rken",
    "models.vision": "Vision-Modelle",
    "models.vision_standard": "Standard-Vision",
    "models.vision_standard_desc": "Schnelles Vision-Modell",
    "models.vision_detail": "Detail-Vision",
    "models.vision_detail_desc": "H\u00f6chste Qualit\u00e4t",
    "models.skill_overrides": "Skill-\u00dcberschreibungen",
    "models.skill_overrides_desc": "Modellzuweisung pro Skill (JSON Schl\u00fcssel-Wert)",
    "models.global": "Global (Standard)",

    // PGE Trinity page
    "pge.title": "PGE Trinity",
    "pge.desc": "Planner, Gatekeeper, Executor \u2014 Kern-Engine",
    "pge.planner": "Planner (Denker)",
    "pge.max_iter": "Max. Iterationen",
    "pge.max_iter_desc": "Max. Agentenschleifen-Zyklen pro Anfrage",
    "pge.escalation": "Eskalation nach",
    "pge.escalation_desc": "Benutzer nach X Schritten informieren",
    "pge.temp": "Temperatur",
    "pge.temp_desc": "Kreativit\u00e4t (0=deterministisch, 2=wild)",
    "pge.token_budget": "Antwort-Token-Budget",
    "pge.gatekeeper": "Gatekeeper (W\u00e4chter)",
    "pge.policies_dir": "Richtlinien-Verzeichnis",
    "pge.policies_desc": "Relativ zu jarvis_home",
    "pge.risk_level": "Standard-Risikostufe",
    "pge.max_retries": "Max. blockierte Wiederholungen",
    "pge.sandbox": "Sandbox (Executor)",
    "pge.sandbox_level": "Sandbox-Stufe",
    "pge.sandbox_level_desc": "Isolationsstufe f\u00fcr Code-Ausf\u00fchrung",
    "pge.sandbox_timeout": "Timeout (Sek.)",
    "pge.sandbox_memory": "Max. Speicher (MB)",
    "pge.sandbox_cpu": "Max. CPU (Sek.)",
    "pge.network": "Netzwerkzugriff",
    "pge.allowed_paths": "Erlaubte Pfade",
    "pge.env_vars": "Umgebungsvariablen (JSON)",

    // Memory page
    "mem.title": "Speichersystem",
    "mem.desc": "5-stufiger Speicher: Indexierung, hybride Suche, Aktualit\u00e4t, Komprimierung",
    "mem.indexing": "Indexierung",
    "mem.chunk_size": "Chunk-Gr\u00f6\u00dfe (Tokens)",
    "mem.chunk_overlap": "Chunk-\u00dcberlappung",
    "mem.top_k": "Suche Top-K",
    "mem.search": "Hybride Suchgewichtung",
    "mem.sum": "Summe:",
    "mem.perfect": "Perfekt",
    "mem.normalized": "Wird normalisiert",
    "mem.below": "Unter 1.0",
    "mem.vector": "Vektor (Embedding)",
    "mem.bm25": "BM25 (Stichwort)",
    "mem.graph": "Graph (Wissen)",
    "mem.dynamic": "Dynamische Gewichtung",
    "mem.dynamic_desc": "Gewichte automatisch basierend auf Abfragetyp anpassen",
    "mem.recency": "Aktualit\u00e4t & Komprimierung",
    "mem.half_life": "Aktualit\u00e4ts-Halbwertszeit (Tage)",
    "mem.compact_thresh": "Komprimierungsschwelle",
    "mem.keep_last": "Letzte N behalten",
    "mem.retention": "Episodische Aufbewahrung (Tage)",
    "mem.retention_desc": "Wie viele Tage t\u00e4gliche Protokolle aufbewahrt werden",

    // Channels page
    "ch.title": "Kan\u00e4le",
    "ch.desc": "17 Kommunikationskan\u00e4le \u2014 aktivieren und konfigurieren",
    "ch.enable": "{name} aktivieren",
    "ch.voice_config": "Sprachkonfiguration",
    "ch.voice_enabled": "Sprache aktiviert",
    "ch.voice_enabled_desc": "Sprachsteuerung im Chat aktivieren",
    "ch.tts_backend": "TTS-Backend",
    "ch.tts_backend_desc": "Text-to-Speech-Engine",
    "ch.piper_voice": "Piper-Stimme",
    "ch.piper_voice_desc": "Wird beim ersten Gebrauch automatisch heruntergeladen",
    "ch.speech_rate": "Sprechgeschwindigkeit",
    "ch.speech_rate_desc": "1.0 = normal, kleiner = schneller",
    "ch.elevenlabs_key": "ElevenLabs API-Schl\u00fcssel",
    "ch.elevenlabs_voice": "ElevenLabs Voice-ID",
    "ch.elevenlabs_model": "ElevenLabs Modell",
    "ch.wake_word_enabled": "Aktivierungswort aktiviert",
    "ch.wake_word_enabled_desc": "Sprachbefehl per Aktivierungswort ausl\u00f6sen",
    "ch.wake_word": "Aktivierungswort",
    "ch.wake_word_desc": "Standard: jarvis",
    "ch.wake_word_backend": "Aktivierungswort-Backend",
    "ch.wake_word_backend_desc": "browser = Web Speech API (kein Setup n\u00f6tig)",
    "ch.talk_mode": "Sprechmodus",
    "ch.talk_mode_desc": "Dauerhaftes Zuh\u00f6ren im Chat",
    "ch.auto_listen": "Auto-Zuh\u00f6ren",
    "ch.auto_listen_desc": "Nach Antwort automatisch wieder zuh\u00f6ren",

    // Security page
    "sec.title": "Sicherheit",
    "sec.desc": "Iterationslimits, Pfade, blockierte Befehle, Credential-Muster",
    "sec.limits": "Gatekeeper-Limits",
    "sec.max_iter": "Max. Iterationen",
    "sec.max_iter_desc": "Endlosschleifen-Schutz",
    "sec.max_depth": "Max. Sub-Agent-Tiefe",
    "sec.max_depth_desc": "Maximale Rekursionstiefe f\u00fcr Sub-Agent-Delegierungen",
    "sec.filesystem": "Gatekeeper-Dateisystem",
    "sec.allowed_paths": "Erlaubte Pfade",
    "sec.blocked": "Gatekeeper blockierte Befehle (Regex)",
    "sec.blocked_patterns": "Muster",
    "sec.credentials": "Gatekeeper Credential-Erkennung (Regex)",
    "sec.cred_patterns": "Muster",

    // Executor page
    "exec.title": "Executor",
    "exec.desc": "Tool-Ausf\u00fchrung: Timeouts, Wiederholungen, Parallelit\u00e4t",
    "exec.general": "Allgemein",
    "exec.llm_timeout": "LLM-Timeout (Sekunden)",
    "exec.llm_timeout_desc": "Timeout f\u00fcr LLM-Anfragen (Planner/Executor). Gilt f\u00fcr alle Backends (Ollama, OpenAI, etc.)",
    "exec.default_timeout": "Standard-Timeout (Sekunden)",
    "exec.default_timeout_desc": "Timeout f\u00fcr einzelne Tool-Aufrufe",
    "exec.max_output": "Max. Ausgabe (Zeichen)",
    "exec.max_output_desc": "Tool-Ausgabe wird nach dieser L\u00e4nge abgeschnitten",
    "exec.max_retries": "Max. Wiederholungen",
    "exec.max_retries_desc": "Wiederholungsversuche bei vor\u00fcbergehenden Fehlern",
    "exec.backoff": "Backoff-Basis (Sekunden)",
    "exec.backoff_desc": "Basisverz\u00f6gerung f\u00fcr exponentiellen Backoff",
    "exec.dag": "DAG-Parallelit\u00e4t",
    "exec.max_parallel": "Max. parallele Tools",
    "exec.max_parallel_desc": "Maximale Anzahl gleichzeitig ausgef\u00fchrter Tools (DAG-basiert)",
    "exec.tool_timeouts": "Tool-spezifische Timeouts",
    "exec.image_timeout": "Bildanalyse (Sekunden)",
    "exec.image_timeout_desc": "Vision-Modelle brauchen mehr Zeit (20+ GB VRAM)",
    "exec.audio_timeout": "Audio-Transkription (Sekunden)",
    "exec.text_timeout": "Textextraktion (Sekunden)",
    "exec.tts_timeout": "Text-to-Speech (Sekunden)",
    "exec.python_timeout": "Python-Ausf\u00fchrung (Sekunden)",

    // Web Tools page
    "web.title": "Web-Tools",
    "web.desc": "Such-Backends, Limits, Rate-Limiting, HTTP-Anfragen",
    "web.searxng": "SearXNG (Selbst-gehostet)",
    "web.searxng_url": "SearXNG-URL",
    "web.searxng_desc": "H\u00f6chste Priorit\u00e4t",
    "web.brave": "Brave-Suche",
    "web.brave_key": "API-Schl\u00fcssel",
    "web.brave_desc": "2000 Anfragen/Monat kostenlos",
    "web.google": "Google Custom Search Engine",
    "web.google_key": "API-Schl\u00fcssel",
    "web.google_desc": "100 Anfragen/Tag kostenlos",
    "web.google_cx": "Suchmaschinen-ID (cx)",
    "web.jina": "Jina AI Reader",
    "web.jina_key": "API-Schl\u00fcssel",
    "web.jina_desc": "Optional \u2014 kostenlose Stufe funktioniert ohne Schl\u00fcssel",
    "web.ddg": "DuckDuckGo",
    "web.ddg_enabled": "DuckDuckGo aktiviert",
    "web.ddg_enabled_desc": "Kostenloser Fallback",
    "web.ddg_delay": "Min. Verz\u00f6gerung (Sekunden)",
    "web.ddg_delay_desc": "Rate-Limiting zwischen DuckDuckGo-Suchen",
    "web.ddg_wait": "Rate-Limit-Wartezeit (Sekunden)",
    "web.ddg_wait_desc": "Wartezeit bei 429-Fehler",
    "web.ddg_cache": "Cache-TTL (Sekunden)",
    "web.ddg_cache_desc": "Wie lange Suchergebnisse gecacht werden",
    "web.fetch_limits": "Abruf-Limits",
    "web.max_fetch": "Max. Abrufgr\u00f6\u00dfe (Bytes)",
    "web.max_fetch_desc": "Maximale Antwortgr\u00f6\u00dfe beim URL-Abruf",
    "web.max_text": "Max. Textzeichen",
    "web.max_text_desc": "Maximale Zeichenanzahl des extrahierten Textes",
    "web.fetch_timeout": "Abruf-Timeout (Sekunden)",
    "web.search_timeout": "Such-Timeout (Sekunden)",
    "web.max_results": "Max. Suchergebnisse",
    "web.sar_chars": "search_and_read max Zeichen/Seite",
    "web.http": "HTTP-Anfrage-Tool",
    "web.http_body": "Max. Body-Gr\u00f6\u00dfe (Bytes)",
    "web.http_body_desc": "Maximale Anfrage-Body-Gr\u00f6\u00dfe",
    "web.http_timeout": "Standard-Timeout (Sekunden)",
    "web.http_rate": "Rate-Limit (Sekunden)",
    "web.http_rate_desc": "Mindestintervall zwischen Anfragen. 0 = kein Limit.",
    "web.domain_filter": "Domain-Filter",
    "web.blocklist": "Blockliste",
    "web.blocklist_desc": "Diese Domains werden beim Abruf blockiert",
    "web.allowlist": "Erlaubnisliste",
    "web.allowlist_desc": "Falls nicht leer: NUR diese Domains sind erlaubt (Whitelist)",

    // MCP / Integrations page
    "mcp.title": "Integrationen",
    "mcp.desc": "Model Context Protocol (MCP) Server + Agent-zu-Agent-Kommunikation (A2A)",
    "mcp.server_mode": "MCP-Servermodus",
    "mcp.mode": "Modus",
    "mcp.mode_desc": "Jarvis als MCP-Server bereitstellen",
    "mcp.http_host": "HTTP-Host",
    "mcp.http_port": "HTTP-Port",
    "mcp.server_name": "Servername",
    "mcp.auth_required": "Auth erforderlich",
    "mcp.auth_token": "Auth-Token",
    "mcp.expose_tools": "Tools bereitstellen",
    "mcp.expose_resources": "Ressourcen bereitstellen",
    "mcp.expose_prompts": "Prompts bereitstellen",
    "mcp.sampling": "Sampling aktiviert",
    "mcp.external": "Externe MCP-Server",
    "mcp.external_desc": "Verbundene externe MCP-Server (Tools & Ressourcen)",
    "mcp.srv_name": "Servername",
    "mcp.command": "Befehl",
    "mcp.arguments": "Argumente",
    "mcp.env_vars": "Umgebungsvariablen (JSON)",
    "mcp.always_allow": "Immer erlauben (Tools)",
    "mcp.disabled": "Deaktiviert",
    "mcp.delete": "L\u00f6schen",
    "mcp.add_server": "+ Server hinzuf\u00fcgen",
    "mcp.a2a": "A2A-Protokoll",
    "mcp.a2a_enabled": "A2A aktiviert",
    "mcp.a2a_desc": "Agent-zu-Agent-Kommunikation (Linux Foundation A2A RC v1.0)",
    "mcp.a2a_host": "Host",
    "mcp.a2a_port": "Port",
    "mcp.a2a_name": "Agentenname",
    "mcp.a2a_description": "Beschreibung",
    "mcp.a2a_max_tasks": "Max. Aufgaben",
    "mcp.a2a_task_timeout": "Aufgaben-Timeout (Sek.)",
    "mcp.a2a_streaming": "Streaming",
    "mcp.a2a_push": "Push-Benachrichtigungen",
    "mcp.a2a_remotes": "Remotes (JSON-Array)",
    "mcp.a2a_remotes_desc": "Liste entfernter Agenten: [{\"endpoint\": \"http://...\", \"auth_token\": \"\"}]",

    // Cron & Heartbeat page
    "cron.title": "Cron & Heartbeat",
    "cron.desc": "Periodische Aufgaben, Heartbeat-Checkliste, Plugins",
    "cron.heartbeat": "Heartbeat",
    "cron.hb_enabled": "Heartbeat aktiviert",
    "cron.hb_enabled_desc": "Periodische Systempr\u00fcfungen",
    "cron.hb_interval": "Intervall (Min.)",
    "cron.hb_file": "Checklisten-Datei",
    "cron.hb_file_desc": "Relativ zu jarvis_home",
    "cron.hb_channel": "Kanal",
    "cron.hb_model": "Modell",
    "cron.jobs": "Cron-Jobs",
    "cron.name": "Name",
    "cron.schedule": "Zeitplan (Cron)",
    "cron.prompt": "Prompt",
    "cron.channel": "Kanal",
    "cron.model": "Modell",
    "cron.agent": "Agent",
    "cron.agent_placeholder": "(leer = Standard-Routing)",
    "cron.delete_job": "Job l\u00f6schen",
    "cron.add_job": "Neuen Job hinzuf\u00fcgen",
    "cron.plugins": "Plugins",
    "cron.skills_dir": "Skills-Verzeichnis",
    "cron.skills_desc": "Relativ zu jarvis_home",
    "cron.auto_update": "Auto-Update",
    "cron.auto_update_desc": "Automatische Plugin-Updates beim Start",

    // Logging page
    "log.title": "Logging",
    "log.desc": "Protokollierung und Debugging",
    "log.general": "Allgemein",
    "log.level": "Log-Stufe",
    "log.json": "JSON-Logs",
    "log.json_desc": "Strukturierte JSON-Logs f\u00fcr externe Tools",
    "log.console": "Konsolenausgabe",
    "log.console_desc": "Logs in Konsole ausgeben",

    // Database page
    "db.title": "Datenbank",
    "db.desc": "Speicher-Backend f\u00fcr Ged\u00e4chtnis, Logs und Zustand",
    "db.connection": "Verbindung",
    "db.backend": "Backend",
    "db.host": "Host",
    "db.port": "Port",
    "db.database": "Datenbank",
    "db.user": "Benutzer",
    "db.password": "Passwort",
    "db.pool": "Verbindungspool",
    "db.pool_min": "Pool Min",
    "db.pool_max": "Pool Max",
    "db.encryption": "Verschl\u00fcsselung",
    "db.encryption_enabled": "SQLite-Verschl\u00fcsselung (SQLCipher)",
    "db.encryption_desc": "Verschl\u00fcsselt alle SQLite-Datenbanken mit SQLCipher. Der Schl\u00fcssel wird sicher im OS-Keyring gespeichert.",
    "db.encryption_info": "Der Verschl\u00fcsselungsschl\u00fcssel wird automatisch im System-Keyring verwaltet (Windows Credential Locker / macOS Keychain / Linux SecretService). Ein neuer Schl\u00fcssel wird bei Erstaktivierung generiert.",
    "db.encryption_prereq": "Voraussetzung:",

    // Agents page
    "agents.title": "Agenten",
    "agents.desc": "Multi-Agent-Profile verwalten \u2014 Routing, Modelle, Berechtigungen",
    "agents.name_id": "Name (ID)",
    "agents.required": "Erforderlich",
    "agents.display_name": "Anzeigename",
    "agents.description": "Beschreibung",
    "agents.system_prompt": "System-Prompt",
    "agents.language": "Sprache",
    "agents.priority": "Priorit\u00e4t",
    "agents.preferred_model": "Bevorzugtes Modell",
    "agents.temperature": "Temperatur",
    "agents.trigger_keywords": "Ausl\u00f6se-Schl\u00fcsselw\u00f6rter",
    "agents.blocked_tools": "Blockierte Tools",
    "agents.enabled": "Aktiviert",
    "agents.delete": "Agent l\u00f6schen",
    "agents.create": "Neuen Agent erstellen",

    // Bindings page
    "bind.title": "Bindings",
    "bind.desc": "Routing-Regeln: Welche Nachricht geht an welchen Agent?",
    "bind.name": "Name",
    "bind.required": "Erforderlich",
    "bind.target": "Ziel-Agent",
    "bind.priority": "Priorit\u00e4t",
    "bind.description": "Beschreibung",
    "bind.channels": "Kan\u00e4le",
    "bind.prefixes": "Befehlspr\u00e4fixe",
    "bind.patterns": "Nachrichtenmuster (Regex)",
    "bind.enabled": "Aktiviert",
    "bind.delete": "Binding l\u00f6schen",
    "bind.create": "Neues Binding",

    // System page
    "sys.title": "System",
    "sys.desc": "Neustart, Export/Import, Werksreset",
    "sys.restart": "Cognithor neu starten",
    "sys.restart_desc": "F\u00e4hrt Cognithor sauber herunter (Sitzungen speichern, Kan\u00e4le stoppen, Speicher leeren) und startet mit der aktuellen Konfiguration neu.",
    "sys.restarting": "Startet neu...",
    "sys.restarted": "Neugestartet!",
    "sys.restart_btn": "Cognithor neu starten",
    "sys.export_import": "Export & Import",
    "sys.export": "Konfiguration exportieren",
    "sys.import": "Konfiguration importieren",
    "sys.factory_reset": "Werksreset",
    "sys.factory_desc": "Setzt alle Konfigurationseinstellungen auf Standardwerte zur\u00fcck. API-Schl\u00fcssel und gespeicherte Daten (Ged\u00e4chtnis, Skills, Workflows) bleiben erhalten.",
    "sys.factory_btn": "Alle Einstellungen zur\u00fccksetzen",
    "sys.info": "Systeminformationen",
    "sys.info_version": "Version",
    "sys.info_backend": "Backend",
    "sys.info_owner": "Besitzer",
    "sys.info_mode": "Modus",

    // Global Search
    "search.hint": "Suchen...",
    "search.placeholder": "Einstellungen durchsuchen...",
    "search.no_results": "Keine Ergebnisse f\u00fcr \u201e{query}\u201c",

    // Knowledge Graph
    "kg.title": "Wissensgraph",
    "kg.loading": "Wissensgraph wird geladen...",
    "kg.entities": "Entit\u00e4ten",
    "kg.relationships": "Beziehungen",
    "kg.empty_title": "Keine Entit\u00e4ten im Wissensgraph",
    "kg.empty_desc": "Entit\u00e4ten werden automatisch aus Gespr\u00e4chen extrahiert.",
    "kg.search_placeholder": "Entit\u00e4t suchen...",
    "kg.all_types": "Alle Typen",
    "kg.visible": "{count} sichtbar",
    "kg.type_label": "Typ:",
    "kg.confidence_label": "Konfidenz:",
    "kg.attributes_label": "Attribute:",
    "kg.relationships_label": "Beziehungen ({count}):",
    "kg.id_label": "ID:",

    // Workflow Graph
    "wf.title": "Workflow-Ausf\u00fchrungsgraph",
    "wf.loading": "Workflows werden geladen...",
    "wf.templates": "Vorlagen",
    "wf.instances": "Instanzen",
    "wf.dag_runs": "DAG-L\u00e4ufe",
    "wf.active": "aktiv",
    "wf.completed": "abgeschlossen",
    "wf.start": "Starten",
    "wf.back": "\u2190 Zur\u00fcck",
    "wf.no_templates": "Keine Workflow-Vorlagen verf\u00fcgbar",
    "wf.no_instances": "Keine laufenden Workflows",
    "wf.no_dag_runs": "Keine DAG-L\u00e4ufe verf\u00fcgbar",
    "wf.no_nodes": "Keine Knoten",
    "wf.steps": "Schritte",
    "wf.min": "Min.",
    "wf.type_tool": "Tool",
    "wf.type_llm": "LLM",
    "wf.type_condition": "WENN",
    "wf.type_approval": "Genehmigung",
    "wf.nodes": "Knoten",
    "wf.detail_type": "Typ:",
    "wf.detail_status": "Status:",
    "wf.detail_output": "Ausgabe:",
    "wf.detail_error": "Fehler:",
    "wf.detail_duration": "Dauer:",
    "wf.detail_retries": "Wiederholungen:",
    "wf.detail_depends": "Abh\u00e4ngig von:",
  },

  zh: {
    "nav.chat": "\u5bf9\u8bdd",
    "nav.general": "\u901a\u7528\u8bbe\u7f6e",
    "nav.language": "\u8bed\u8a00",
    "nav.providers": "LLM \u670d\u52a1\u5546",
    "nav.models": "\u6a21\u578b",
    "nav.planner": "PGE Trinity",
    "nav.executor": "\u6267\u884c\u5668",
    "nav.memory": "\u8bb0\u5fc6",
    "nav.channels": "\u901a\u9053",
    "nav.security": "\u5b89\u5168",
    "nav.web": "Web \u5de5\u5177",
    "nav.mcp": "\u96c6\u6210",
    "nav.cron": "\u5b9a\u65f6 & \u5fc3\u8df3",
    "nav.database": "\u6570\u636e\u5e93",
    "nav.logging": "\u65e5\u5fd7",
    "nav.prompts": "\u63d0\u793a\u8bcd & \u7b56\u7565",
    "nav.agents": "\u667a\u80fd\u4f53",
    "nav.bindings": "\u7ed1\u5b9a",
    "nav.workflows": "\u5de5\u4f5c\u6d41",
    "nav.knowledge_graph": "\u77e5\u8bc6\u56fe\u8c31",
    "nav.system": "\u7cfb\u7edf",

    "chat.title": "\u4e0e Jarvis \u5bf9\u8bdd",
    "chat.placeholder": "\u8f93\u5165\u6d88\u606f...",
    "chat.empty": "\u4f60\u597d\uff01\u8bf7\u95ee\u6211\u4efb\u4f55\u95ee\u9898...",
    "chat.send": "\u53d1\u9001 (Enter)",
    "chat.attach": "\u6dfb\u52a0\u9644\u4ef6",
    "chat.voice": "\u8bed\u97f3",
    "chat.voice_on": "\u8bed\u97f3\u5f00\u542f",
    "chat.clear": "\u6e05\u9664",
    "chat.canvas": "\u753b\u5e03",
    "chat.canvas_active": "\u753b\u5e03\u5df2\u6fc0\u6d3b",
    "chat.canvas_close": "\u5173\u95ed\u753b\u5e03",
    "chat.canvas_title": "Jarvis \u753b\u5e03",
    "chat.stop_recording": "\u505c\u6b62\u5f55\u97f3",
    "chat.voice_message": "\u8bed\u97f3\u6d88\u606f",

    "voice.wake": "\u8bf4 \"Jarvis\"...",
    "voice.listening": "\u8046\u542c\u4e2d...\uff08\u8bf4 \"Jarvis stop\" \u7ed3\u675f\uff09",
    "voice.processing": "\u5904\u7406\u4e2d...",
    "voice.speaking": "\u64ad\u653e\u4e2d...",

    "lang.title": "\u8bed\u8a00\u8bbe\u7f6e",
    "lang.subtitle": "\u7cfb\u7edf\u8bed\u8a00\u3001\u8bed\u8a00\u5305\u9009\u62e9\u548c\u63d0\u793a\u8bcd\u7ffb\u8bd1",
    "lang.active": "\u5f53\u524d\u8bed\u8a00",
    "lang.system": "\u7cfb\u7edf\u8bed\u8a00",
    "lang.system_desc": "\u63a7\u5236\u754c\u9762\u6d88\u606f\u3001\u9519\u8bef\u6587\u672c\u548c\u72b6\u6001\u8f93\u51fa\u3002\u66f4\u6539\u540e\u5c06\u63d0\u4f9b\u63d0\u793a\u8bcd\u7ffb\u8bd1\u9009\u9879\u3002",
    "lang.packs_info": "\u5df2\u5b89\u88c5\u8bed\u8a00\u5305\uff1a{packs} \u00b7 \u53ef\u7528\u63d0\u793a\u8bcd\u9884\u8bbe\uff1a{presets}",
    "lang.translate_title": "\u7cfb\u7edf\u63d0\u793a\u8bcd\u7ffb\u8bd1",
    "lang.translate_desc": "\u4f60\u5df2\u5c06\u8bed\u8a00\u66f4\u6539\u4e3a {lang}\u3002",
    "lang.translate_question": "\u662f\u5426\u8981\u7ffb\u8bd1\u7cfb\u7edf\u63d0\u793a\u8bcd\uff1f",
    "lang.method_label": "\u7ffb\u8bd1\u65b9\u5f0f",
    "lang.method_preset": "\u4f7f\u7528\u7cbe\u9009\u9884\u8bbe\uff08\u5373\u65f6\uff0c\u63a8\u8350\uff09",
    "lang.method_ollama": "\u901a\u8fc7 Ollama \u7ffb\u8bd1\uff08\u8f83\u6162\uff0c\u81ea\u5b9a\u4e49\uff09",
    "lang.desc_preset": "\u9884\u5148\u9a8c\u8bc1\u7684\u7ffb\u8bd1 \u2014 \u5373\u65f6\uff0c\u65e0\u9700 LLM\u3002\u53ef\u7528\u4e8e\uff1a",
    "lang.desc_ollama": "\u4f7f\u7528\u914d\u7f6e\u7684\u89c4\u5212\u6a21\u578b\u5b9e\u65f6\u7ffb\u8bd1\u63d0\u793a\u8bcd\u3002\u53ef\u80fd\u9700\u8981 30\u201360 \u79d2\u3002",
    "lang.translate_btn": "\u7ffb\u8bd1\u63d0\u793a\u8bcd",
    "lang.translating": "\u7ffb\u8bd1\u4e2d...",
    "lang.skip": "\u8df3\u8fc7 \u2014 \u4fdd\u7559\u5f53\u524d\u63d0\u793a\u8bcd",
    "lang.preview_title": "\u7ffb\u8bd1\u9884\u89c8",
    "lang.preview_desc": "\u8bf7\u67e5\u770b\u4ee5\u4e0b\u7ffb\u8bd1\u7684\u63d0\u793a\u8bcd\u3002\u70b9\u51fb\u201c\u5e94\u7528\u201d\u5199\u5165\uff0c\u6216\u201c\u653e\u5f03\u201d\u4fdd\u7559\u539f\u6587\u3002",
    "lang.accept": "\u5e94\u7528",
    "lang.discard": "\u653e\u5f03",
    "lang.planner_prompt": "Planner \u7cfb\u7edf\u63d0\u793a\u8bcd",
    "lang.replan_prompt": "\u91cd\u89c4\u5212\u63d0\u793a\u8bcd",
    "lang.escalation_prompt": "\u5347\u7ea7\u63d0\u793a\u8bcd",

    "header.power_on": "\u542f\u52a8",
    "header.power_off": "\u5173\u95ed",
    "header.version": "\u63a7\u5236\u4e2d\u5fc3 v{version}",
    "header.backend_stopped": "\u540e\u7aef\u672a\u542f\u52a8\u3002\u70b9\u51fb\u4e0a\u65b9\u201c\u542f\u52a8\u201d\u6309\u94ae\u6765\u542f\u52a8 Cognithor\u3002",
    "header.backend_error": "\u540e\u7aef\u4e0d\u53ef\u8fbe \u2014 Cognithor \u662f\u5426\u5728\u8fd0\u884c\uff1f",
    "header.starting": "\u542f\u52a8\u4e2d...",
    "header.stopping": "\u505c\u6b62\u4e2d...",

    "prompts.title": "\u63d0\u793a\u8bcd & \u7b56\u7565",
    "prompts.subtitle": "\u67e5\u770b\u548c\u81ea\u5b9a\u4e49\u7cfb\u7edf\u63d0\u793a\u8bcd\u3001\u5b88\u95e8\u4eba\u7b56\u7565\u3001CORE.md \u548c HEARTBEAT.md",
    "prompts.core_title": "CORE.md \u2014 \u7cfb\u7edf\u4e2a\u6027",
    "prompts.core_desc": "\u6838\u5fc3\u8bb0\u5fc6\uff08Markdown\uff09",
    "prompts.core_hint": "Jarvis \u7684\u4e2a\u6027\u3001\u89c4\u5219\u548c\u504f\u597d",
    "prompts.planner": "Planner \u7cfb\u7edf\u63d0\u793a\u8bcd",
    "prompts.replan": "\u91cd\u89c4\u5212\u63d0\u793a\u8bcd",
    "prompts.escalation": "\u5347\u7ea7\u63d0\u793a\u8bcd",
    "prompts.gatekeeper": "\u5b88\u95e8\u4eba\u7b56\u7565\uff08YAML\uff09",
    "prompts.heartbeat": "HEARTBEAT.md \u2014 \u5fc3\u8df3\u68c0\u67e5\u6e05\u5355",
    "prompts.reset": "\u91cd\u7f6e",

    "common.save": "\u4fdd\u5b58",
    "common.cancel": "\u53d6\u6d88",
    "common.loading": "\u52a0\u8f7d\u4e2d...",
    "common.error": "\u9519\u8bef",
    "common.search": "\u641c\u7d22...",

    // Save bar
    "save.unsaved": "\u672a\u4fdd\u5b58\u7684\u66f4\u6539",
    "save.discard": "\u653e\u5f03",
    "save.saving": "\u4fdd\u5b58\u4e2d...",
    "save.saved": "\u5df2\u4fdd\u5b58!",
    "save.save": "\u4fdd\u5b58\u66f4\u6539",

    // Spinner
    "common.loading_config": "\u6b63\u5728\u52a0\u8f7d\u914d\u7f6e...",

    // General page
    "gen.title": "\u901a\u7528\u8bbe\u7f6e",
    "gen.desc": "\u8eab\u4efd\u3001\u8fd0\u884c\u6a21\u5f0f\u548c\u8d39\u7528\u8ddf\u8e2a",
    "gen.identity": "\u8eab\u4efd",
    "gen.owner": "\u6240\u6709\u8005\u540d\u79f0",
    "gen.owner_desc": "\u7528\u4e8e\u63d0\u793a\u8bcd\u548c CORE.md",
    "gen.owner_required": "\u5fc5\u586b",
    "gen.mode": "\u8fd0\u884c\u6a21\u5f0f",
    "gen.mode_desc": "\u6839\u636e\u53ef\u7528\u7684 API \u5bc6\u94a5\u81ea\u52a8\u68c0\u6d4b\u6a21\u5f0f",
    "gen.version": "\u7248\u672c",
    "gen.version_desc": "\u7cfb\u7edf\u7248\u672c\uff08\u53ea\u8bfb\uff09",
    "gen.cost": "\u8d39\u7528\u8ddf\u8e2a",
    "gen.cost_enabled": "\u8d39\u7528\u8ddf\u8e2a\u5df2\u542f\u7528",
    "gen.daily_limit": "\u6bcf\u65e5\u9650\u989d\uff08USD\uff09",
    "gen.monthly_limit": "\u6bcf\u6708\u9650\u989d\uff08USD\uff09",
    "gen.no_limit": "0 = \u65e0\u9650\u5236",

    // Prompt Evolution
    "evo.title": "\u63d0\u793a\u8bcd\u8fdb\u5316 (A/B)",
    "evo.enabled": "\u63d0\u793a\u8bcd\u8fdb\u5316\u5df2\u542f\u7528",
    "evo.active_version": "\u6d3b\u8dc3\u7248\u672c",
    "evo.versions": "\u7248\u672c",
    "evo.total_sessions": "\u603b\u4f1a\u8bdd\u6570",
    "evo.running_tests": "\u8fd0\u884c\u4e2d\u7684\u6d4b\u8bd5",
    "evo.completed_tests": "\u5df2\u5b8c\u6210\u7684\u6d4b\u8bd5",
    "evo.evolving": "\u8fdb\u5316\u4e2d...",
    "evo.evolve_now": "\u7acb\u5373\u8fdb\u5316",
    "evo.new_version": "\u65b0\u7248\u672c: {id}",
    "evo.no_data": "\u65e0\u8fdb\u5316\uff08\u6570\u636e\u4e0d\u8db3\uff09",

    // Providers page
    "prov.title": "LLM \u670d\u52a1\u5546",
    "prov.desc": "15 \u4e2a\u540e\u7aef \u2014 API \u5bc6\u94a5\u3001\u7aef\u70b9\u3001\u540e\u7aef\u9009\u62e9",
    "prov.active": "\u6d3b\u8dc3\u540e\u7aef",
    "prov.backend": "LLM \u540e\u7aef",
    "prov.backend_desc": "\u6240\u6709\u6a21\u578b\u4f7f\u7528\u6b64\u540e\u7aef",
    "prov.filter": "\u7b5b\u9009\u670d\u52a1\u5546...",
    "prov.no_match": "\u672a\u627e\u5230\u5339\u914d\u7684\u670d\u52a1\u5546",
    "prov.base_url": "\u57fa\u7840 URL",
    "prov.timeout": "\u8d85\u65f6\uff08\u79d2\uff09",
    "prov.keep_alive": "Keep-Alive",
    "prov.keep_alive_desc": "\u6a21\u578b\u5728 VRAM \u4e2d\u4fdd\u7559\u7684\u65f6\u95f4\uff08\u4f8b\u5982 30m\uff09",
    "prov.api_key": "API \u5bc6\u94a5",
    "prov.max_tokens": "\u6700\u5927\u8f93\u51fa Token \u6570",
    "prov.openai_url_desc": "\u4e5f\u9002\u7528\u4e8e Together\u3001Groq\u3001vLLM\u3001LM Studio",

    // Models page
    "models.title": "\u6a21\u578b",
    "models.desc": "\u6309\u89d2\u8272\u5206\u914d\u6a21\u578b\u3001\u89c6\u89c9\u6a21\u578b\u3001\u6280\u80fd\u8986\u76d6\u3002\u6bcf\u4e2a\u89d2\u8272\u53ef\u4ee5\u4f7f\u7528\u81ea\u5df1\u7684 API \u670d\u52a1\u5546\u3002",
    "models.name": "\u6a21\u578b\u540d\u79f0",
    "models.backend": "\u540e\u7aef / \u670d\u52a1\u5546",
    "models.backend_desc": "\u6b64\u89d2\u8272\u7684\u81ea\u5b9a\u4e49\u670d\u52a1\u5546\uff08\u7a7a = \u5168\u5c40\u540e\u7aef\uff09",
    "models.context": "\u4e0a\u4e0b\u6587\u7a97\u53e3",
    "models.vram": "VRAM (GB)",
    "models.temp": "\u6e29\u5ea6",
    "models.temp_desc": "\u521b\u9020\u529b\uff080=\u786e\u5b9a\u6027\uff0c2=\u72c2\u91ce\uff09",
    "models.top_p": "Top P",
    "models.top_p_desc": "\u6838\u91c7\u6837",
    "models.strengths": "\u4f18\u52bf",
    "models.vision": "\u89c6\u89c9\u6a21\u578b",
    "models.vision_standard": "\u6807\u51c6\u89c6\u89c9",
    "models.vision_standard_desc": "\u5feb\u901f\u89c6\u89c9\u6a21\u578b",
    "models.vision_detail": "\u7ec6\u8282\u89c6\u89c9",
    "models.vision_detail_desc": "\u6700\u9ad8\u8d28\u91cf",
    "models.skill_overrides": "\u6280\u80fd\u8986\u76d6",
    "models.skill_overrides_desc": "\u6309\u6280\u80fd\u5206\u914d\u6a21\u578b\uff08JSON \u952e\u503c\u5bf9\uff09",
    "models.global": "\u5168\u5c40\uff08\u6807\u51c6\uff09",

    // PGE Trinity page
    "pge.title": "PGE Trinity",
    "pge.desc": "Planner\u3001Gatekeeper\u3001Executor \u2014 \u6838\u5fc3\u5f15\u64ce",
    "pge.planner": "Planner\uff08\u601d\u8003\u8005\uff09",
    "pge.max_iter": "\u6700\u5927\u8fed\u4ee3\u6b21\u6570",
    "pge.max_iter_desc": "\u6bcf\u6b21\u8bf7\u6c42\u7684\u6700\u5927\u4ee3\u7406\u5faa\u73af\u6b21\u6570",
    "pge.escalation": "\u5347\u7ea7\u4e8e",
    "pge.escalation_desc": "X \u6b65\u540e\u901a\u77e5\u7528\u6237",
    "pge.temp": "\u6e29\u5ea6",
    "pge.temp_desc": "\u521b\u9020\u529b\uff080=\u786e\u5b9a\u6027\uff0c2=\u72c2\u91ce\uff09",
    "pge.token_budget": "\u54cd\u5e94 Token \u9884\u7b97",
    "pge.gatekeeper": "Gatekeeper\uff08\u5b88\u62a4\u8005\uff09",
    "pge.policies_dir": "\u7b56\u7565\u76ee\u5f55",
    "pge.policies_desc": "\u76f8\u5bf9\u4e8e jarvis_home",
    "pge.risk_level": "\u9ed8\u8ba4\u98ce\u9669\u7b49\u7ea7",
    "pge.max_retries": "\u6700\u5927\u963b\u6b62\u91cd\u8bd5\u6b21\u6570",
    "pge.sandbox": "\u6c99\u7bb1\uff08\u6267\u884c\u5668\uff09",
    "pge.sandbox_level": "\u6c99\u7bb1\u7b49\u7ea7",
    "pge.sandbox_level_desc": "\u4ee3\u7801\u6267\u884c\u9694\u79bb\u7b49\u7ea7",
    "pge.sandbox_timeout": "\u8d85\u65f6\uff08\u79d2\uff09",
    "pge.sandbox_memory": "\u6700\u5927\u5185\u5b58\uff08MB\uff09",
    "pge.sandbox_cpu": "\u6700\u5927 CPU\uff08\u79d2\uff09",
    "pge.network": "\u7f51\u7edc\u8bbf\u95ee",
    "pge.allowed_paths": "\u5141\u8bb8\u7684\u8def\u5f84",
    "pge.env_vars": "\u73af\u5883\u53d8\u91cf\uff08JSON\uff09",

    // Memory page
    "mem.title": "\u8bb0\u5fc6\u7cfb\u7edf",
    "mem.desc": "5\u5c42\u8bb0\u5fc6\uff1a\u7d22\u5f15\u3001\u6df7\u5408\u641c\u7d22\u3001\u65f6\u6548\u6027\u3001\u538b\u7f29",
    "mem.indexing": "\u7d22\u5f15",
    "mem.chunk_size": "\u5206\u5757\u5927\u5c0f\uff08Token\uff09",
    "mem.chunk_overlap": "\u5206\u5757\u91cd\u53e0",
    "mem.top_k": "\u641c\u7d22 Top-K",
    "mem.search": "\u6df7\u5408\u641c\u7d22\u6743\u91cd",
    "mem.sum": "\u603b\u548c\uff1a",
    "mem.perfect": "\u5b8c\u7f8e",
    "mem.normalized": "\u5c06\u88ab\u5f52\u4e00\u5316",
    "mem.below": "\u4f4e\u4e8e 1.0",
    "mem.vector": "\u5411\u91cf\uff08Embedding\uff09",
    "mem.bm25": "BM25\uff08\u5173\u952e\u8bcd\uff09",
    "mem.graph": "\u56fe\u8c31\uff08\u77e5\u8bc6\uff09",
    "mem.dynamic": "\u52a8\u6001\u6743\u91cd",
    "mem.dynamic_desc": "\u6839\u636e\u67e5\u8be2\u7c7b\u578b\u81ea\u52a8\u8c03\u6574\u6743\u91cd",
    "mem.recency": "\u65f6\u6548\u6027\u4e0e\u538b\u7f29",
    "mem.half_life": "\u65f6\u6548\u534a\u8870\u671f\uff08\u5929\uff09",
    "mem.compact_thresh": "\u538b\u7f29\u9608\u503c",
    "mem.keep_last": "\u4fdd\u7559\u6700\u540e N \u6761",
    "mem.retention": "\u60c5\u666f\u4fdd\u7559\u671f\uff08\u5929\uff09",
    "mem.retention_desc": "\u4fdd\u7559\u591a\u5c11\u5929\u7684\u6bcf\u65e5\u65e5\u5fd7",

    // Channels page
    "ch.title": "\u901a\u9053",
    "ch.desc": "17 \u4e2a\u901a\u4fe1\u901a\u9053 \u2014 \u542f\u7528\u548c\u914d\u7f6e",
    "ch.enable": "\u542f\u7528 {name}",
    "ch.voice_config": "\u8bed\u97f3\u914d\u7f6e",
    "ch.voice_enabled": "\u8bed\u97f3\u5df2\u542f\u7528",
    "ch.voice_enabled_desc": "\u5728\u804a\u5929\u4e2d\u542f\u7528\u8bed\u97f3\u63a7\u5236",
    "ch.tts_backend": "TTS \u540e\u7aef",
    "ch.tts_backend_desc": "\u6587\u672c\u8f6c\u8bed\u97f3\u5f15\u64ce",
    "ch.piper_voice": "Piper \u8bed\u97f3",
    "ch.piper_voice_desc": "\u9996\u6b21\u4f7f\u7528\u65f6\u81ea\u52a8\u4e0b\u8f7d",
    "ch.speech_rate": "\u8bed\u901f",
    "ch.speech_rate_desc": "1.0 = \u6b63\u5e38\uff0c\u8f83\u5c0f = \u8f83\u5feb",
    "ch.elevenlabs_key": "ElevenLabs API \u5bc6\u94a5",
    "ch.elevenlabs_voice": "ElevenLabs \u8bed\u97f3 ID",
    "ch.elevenlabs_model": "ElevenLabs \u6a21\u578b",
    "ch.wake_word_enabled": "\u5524\u9192\u8bcd\u5df2\u542f\u7528",
    "ch.wake_word_enabled_desc": "\u901a\u8fc7\u5524\u9192\u8bcd\u89e6\u53d1\u8bed\u97f3\u547d\u4ee4",
    "ch.wake_word": "\u5524\u9192\u8bcd",
    "ch.wake_word_desc": "\u9ed8\u8ba4\uff1ajarvis",
    "ch.wake_word_backend": "\u5524\u9192\u8bcd\u540e\u7aef",
    "ch.wake_word_backend_desc": "browser = Web Speech API\uff08\u65e0\u9700\u8bbe\u7f6e\uff09",
    "ch.talk_mode": "\u5bf9\u8bdd\u6a21\u5f0f",
    "ch.talk_mode_desc": "\u804a\u5929\u4e2d\u6301\u7eed\u76d1\u542c",
    "ch.auto_listen": "\u81ea\u52a8\u76d1\u542c",
    "ch.auto_listen_desc": "\u54cd\u5e94\u540e\u81ea\u52a8\u91cd\u65b0\u76d1\u542c",

    // Security page
    "sec.title": "\u5b89\u5168",
    "sec.desc": "\u8fed\u4ee3\u9650\u5236\u3001\u8def\u5f84\u3001\u963b\u6b62\u7684\u547d\u4ee4\u3001\u51ed\u8bc1\u6a21\u5f0f",
    "sec.limits": "Gatekeeper \u9650\u5236",
    "sec.max_iter": "\u6700\u5927\u8fed\u4ee3\u6b21\u6570",
    "sec.max_iter_desc": "\u65e0\u9650\u5faa\u73af\u4fdd\u62a4",
    "sec.max_depth": "\u6700\u5927\u5b50\u4ee3\u7406\u6df1\u5ea6",
    "sec.max_depth_desc": "\u5b50\u4ee3\u7406\u59d4\u6d3e\u7684\u6700\u5927\u9012\u5f52\u6df1\u5ea6",
    "sec.filesystem": "Gatekeeper \u6587\u4ef6\u7cfb\u7edf",
    "sec.allowed_paths": "\u5141\u8bb8\u7684\u8def\u5f84",
    "sec.blocked": "Gatekeeper \u963b\u6b62\u7684\u547d\u4ee4\uff08\u6b63\u5219\uff09",
    "sec.blocked_patterns": "\u6a21\u5f0f",
    "sec.credentials": "Gatekeeper \u51ed\u8bc1\u68c0\u6d4b\uff08\u6b63\u5219\uff09",
    "sec.cred_patterns": "\u6a21\u5f0f",

    // Executor page
    "exec.title": "\u6267\u884c\u5668",
    "exec.desc": "\u5de5\u5177\u6267\u884c\uff1a\u8d85\u65f6\u3001\u91cd\u8bd5\u3001\u5e76\u884c\u5ea6",
    "exec.general": "\u5e38\u89c4",
    "exec.llm_timeout": "LLM \u8d85\u65f6\uff08\u79d2\uff09",
    "exec.llm_timeout_desc": "LLM \u8bf7\u6c42\u8d85\u65f6\uff08Planner/Executor\uff09\u3002\u9002\u7528\u4e8e\u6240\u6709\u540e\u7aef\uff08Ollama\u3001OpenAI \u7b49\uff09",
    "exec.default_timeout": "\u9ed8\u8ba4\u8d85\u65f6\uff08\u79d2\uff09",
    "exec.default_timeout_desc": "\u5355\u4e2a\u5de5\u5177\u8c03\u7528\u7684\u8d85\u65f6\u65f6\u95f4",
    "exec.max_output": "\u6700\u5927\u8f93\u51fa\uff08\u5b57\u7b26\uff09",
    "exec.max_output_desc": "\u5de5\u5177\u8f93\u51fa\u8d85\u8fc7\u6b64\u957f\u5ea6\u540e\u622a\u65ad",
    "exec.max_retries": "\u6700\u5927\u91cd\u8bd5\u6b21\u6570",
    "exec.max_retries_desc": "\u77ac\u65f6\u9519\u8bef\u7684\u91cd\u8bd5\u6b21\u6570",
    "exec.backoff": "\u9000\u907f\u57fa\u6570\uff08\u79d2\uff09",
    "exec.backoff_desc": "\u6307\u6570\u9000\u907f\u7684\u57fa\u7840\u5ef6\u8fdf",
    "exec.dag": "DAG \u5e76\u884c\u5ea6",
    "exec.max_parallel": "\u6700\u5927\u5e76\u884c\u5de5\u5177\u6570",
    "exec.max_parallel_desc": "\u540c\u65f6\u6267\u884c\u7684\u6700\u5927\u5de5\u5177\u6570\uff08\u57fa\u4e8e DAG\uff09",
    "exec.tool_timeouts": "\u5de5\u5177\u7279\u5b9a\u8d85\u65f6",
    "exec.image_timeout": "\u56fe\u50cf\u5206\u6790\uff08\u79d2\uff09",
    "exec.image_timeout_desc": "\u89c6\u89c9\u6a21\u578b\u9700\u8981\u66f4\u591a\u65f6\u95f4\uff0820+ GB VRAM\uff09",
    "exec.audio_timeout": "\u97f3\u9891\u8f6c\u5f55\uff08\u79d2\uff09",
    "exec.text_timeout": "\u6587\u672c\u63d0\u53d6\uff08\u79d2\uff09",
    "exec.tts_timeout": "\u6587\u672c\u8f6c\u8bed\u97f3\uff08\u79d2\uff09",
    "exec.python_timeout": "Python \u6267\u884c\uff08\u79d2\uff09",

    // Web Tools page
    "web.title": "Web \u5de5\u5177",
    "web.desc": "\u641c\u7d22\u540e\u7aef\u3001\u9650\u5236\u3001\u901f\u7387\u9650\u5236\u3001HTTP \u8bf7\u6c42",
    "web.searxng": "SearXNG\uff08\u81ea\u6258\u7ba1\uff09",
    "web.searxng_url": "SearXNG URL",
    "web.searxng_desc": "\u6700\u9ad8\u4f18\u5148\u7ea7",
    "web.brave": "Brave \u641c\u7d22",
    "web.brave_key": "API \u5bc6\u94a5",
    "web.brave_desc": "\u6bcf\u6708 2000 \u6b21\u514d\u8d39\u8bf7\u6c42",
    "web.google": "Google \u81ea\u5b9a\u4e49\u641c\u7d22\u5f15\u64ce",
    "web.google_key": "API \u5bc6\u94a5",
    "web.google_desc": "\u6bcf\u5929 100 \u6b21\u514d\u8d39\u8bf7\u6c42",
    "web.google_cx": "\u641c\u7d22\u5f15\u64ce ID (cx)",
    "web.jina": "Jina AI Reader",
    "web.jina_key": "API \u5bc6\u94a5",
    "web.jina_desc": "\u53ef\u9009 \u2014 \u514d\u8d39\u5c42\u65e0\u9700\u5bc6\u94a5",
    "web.ddg": "DuckDuckGo",
    "web.ddg_enabled": "DuckDuckGo \u5df2\u542f\u7528",
    "web.ddg_enabled_desc": "\u514d\u8d39\u5907\u7528",
    "web.ddg_delay": "\u6700\u5c0f\u5ef6\u8fdf\uff08\u79d2\uff09",
    "web.ddg_delay_desc": "DuckDuckGo \u641c\u7d22\u4e4b\u95f4\u7684\u901f\u7387\u9650\u5236",
    "web.ddg_wait": "\u901f\u7387\u9650\u5236\u7b49\u5f85\uff08\u79d2\uff09",
    "web.ddg_wait_desc": "429 \u9519\u8bef\u65f6\u7684\u7b49\u5f85\u65f6\u95f4",
    "web.ddg_cache": "\u7f13\u5b58 TTL\uff08\u79d2\uff09",
    "web.ddg_cache_desc": "\u641c\u7d22\u7ed3\u679c\u7f13\u5b58\u65f6\u95f4",
    "web.fetch_limits": "\u83b7\u53d6\u9650\u5236",
    "web.max_fetch": "\u6700\u5927\u83b7\u53d6\u5927\u5c0f\uff08\u5b57\u8282\uff09",
    "web.max_fetch_desc": "URL \u83b7\u53d6\u7684\u6700\u5927\u54cd\u5e94\u5927\u5c0f",
    "web.max_text": "\u6700\u5927\u6587\u672c\u5b57\u7b26\u6570",
    "web.max_text_desc": "\u63d0\u53d6\u6587\u672c\u7684\u6700\u5927\u5b57\u7b26\u6570",
    "web.fetch_timeout": "\u83b7\u53d6\u8d85\u65f6\uff08\u79d2\uff09",
    "web.search_timeout": "\u641c\u7d22\u8d85\u65f6\uff08\u79d2\uff09",
    "web.max_results": "\u6700\u5927\u641c\u7d22\u7ed3\u679c\u6570",
    "web.sar_chars": "search_and_read \u6bcf\u9875\u6700\u5927\u5b57\u7b26\u6570",
    "web.http": "HTTP \u8bf7\u6c42\u5de5\u5177",
    "web.http_body": "\u6700\u5927 Body \u5927\u5c0f\uff08\u5b57\u8282\uff09",
    "web.http_body_desc": "\u6700\u5927\u8bf7\u6c42 Body \u5927\u5c0f",
    "web.http_timeout": "\u9ed8\u8ba4\u8d85\u65f6\uff08\u79d2\uff09",
    "web.http_rate": "\u901f\u7387\u9650\u5236\uff08\u79d2\uff09",
    "web.http_rate_desc": "\u8bf7\u6c42\u4e4b\u95f4\u7684\u6700\u5c0f\u95f4\u9694\u30020 = \u65e0\u9650\u5236\u3002",
    "web.domain_filter": "\u57df\u540d\u8fc7\u6ee4",
    "web.blocklist": "\u9ed1\u540d\u5355",
    "web.blocklist_desc": "\u8fd9\u4e9b\u57df\u540d\u5728\u83b7\u53d6\u65f6\u88ab\u963b\u6b62",
    "web.allowlist": "\u767d\u540d\u5355",
    "web.allowlist_desc": "\u5982\u679c\u4e0d\u4e3a\u7a7a\uff1a\u4ec5\u5141\u8bb8\u8fd9\u4e9b\u57df\u540d\uff08\u767d\u540d\u5355\uff09",

    // MCP / Integrations page
    "mcp.title": "\u96c6\u6210",
    "mcp.desc": "\u6a21\u578b\u4e0a\u4e0b\u6587\u534f\u8bae (MCP) \u670d\u52a1\u5668 + \u4ee3\u7406\u95f4\u901a\u4fe1 (A2A)",
    "mcp.server_mode": "MCP \u670d\u52a1\u5668\u6a21\u5f0f",
    "mcp.mode": "\u6a21\u5f0f",
    "mcp.mode_desc": "\u5c06 Jarvis \u4f5c\u4e3a MCP \u670d\u52a1\u5668\u66b4\u9732",
    "mcp.http_host": "HTTP \u4e3b\u673a",
    "mcp.http_port": "HTTP \u7aef\u53e3",
    "mcp.server_name": "\u670d\u52a1\u5668\u540d\u79f0",
    "mcp.auth_required": "\u9700\u8981\u8ba4\u8bc1",
    "mcp.auth_token": "\u8ba4\u8bc1\u4ee4\u724c",
    "mcp.expose_tools": "\u66b4\u9732\u5de5\u5177",
    "mcp.expose_resources": "\u66b4\u9732\u8d44\u6e90",
    "mcp.expose_prompts": "\u66b4\u9732\u63d0\u793a\u8bcd",
    "mcp.sampling": "\u91c7\u6837\u5df2\u542f\u7528",
    "mcp.external": "\u5916\u90e8 MCP \u670d\u52a1\u5668",
    "mcp.external_desc": "\u5df2\u8fde\u63a5\u7684\u5916\u90e8 MCP \u670d\u52a1\u5668\uff08\u5de5\u5177\u548c\u8d44\u6e90\uff09",
    "mcp.srv_name": "\u670d\u52a1\u5668\u540d\u79f0",
    "mcp.command": "\u547d\u4ee4",
    "mcp.arguments": "\u53c2\u6570",
    "mcp.env_vars": "\u73af\u5883\u53d8\u91cf\uff08JSON\uff09",
    "mcp.always_allow": "\u59cb\u7ec8\u5141\u8bb8\uff08\u5de5\u5177\uff09",
    "mcp.disabled": "\u5df2\u7981\u7528",
    "mcp.delete": "\u5220\u9664",
    "mcp.add_server": "+ \u6dfb\u52a0\u670d\u52a1\u5668",
    "mcp.a2a": "A2A \u534f\u8bae",
    "mcp.a2a_enabled": "A2A \u5df2\u542f\u7528",
    "mcp.a2a_desc": "\u4ee3\u7406\u95f4\u901a\u4fe1\uff08Linux Foundation A2A RC v1.0\uff09",
    "mcp.a2a_host": "\u4e3b\u673a",
    "mcp.a2a_port": "\u7aef\u53e3",
    "mcp.a2a_name": "\u4ee3\u7406\u540d\u79f0",
    "mcp.a2a_description": "\u63cf\u8ff0",
    "mcp.a2a_max_tasks": "\u6700\u5927\u4efb\u52a1\u6570",
    "mcp.a2a_task_timeout": "\u4efb\u52a1\u8d85\u65f6\uff08\u79d2\uff09",
    "mcp.a2a_streaming": "\u6d41\u5f0f\u4f20\u8f93",
    "mcp.a2a_push": "\u63a8\u9001\u901a\u77e5",
    "mcp.a2a_remotes": "\u8fdc\u7a0b\u4ee3\u7406\uff08JSON \u6570\u7ec4\uff09",
    "mcp.a2a_remotes_desc": "\u8fdc\u7a0b\u4ee3\u7406\u5217\u8868: [{\"endpoint\": \"http://...\", \"auth_token\": \"\"}]",

    // Cron & Heartbeat page
    "cron.title": "\u5b9a\u65f6\u4efb\u52a1 & \u5fc3\u8df3",
    "cron.desc": "\u5468\u671f\u6027\u4efb\u52a1\u3001\u5fc3\u8df3\u68c0\u67e5\u6e05\u5355\u3001\u63d2\u4ef6",
    "cron.heartbeat": "\u5fc3\u8df3",
    "cron.hb_enabled": "\u5fc3\u8df3\u5df2\u542f\u7528",
    "cron.hb_enabled_desc": "\u5468\u671f\u6027\u7cfb\u7edf\u68c0\u67e5",
    "cron.hb_interval": "\u95f4\u9694\uff08\u5206\u949f\uff09",
    "cron.hb_file": "\u68c0\u67e5\u6e05\u5355\u6587\u4ef6",
    "cron.hb_file_desc": "\u76f8\u5bf9\u4e8e jarvis_home",
    "cron.hb_channel": "\u901a\u9053",
    "cron.hb_model": "\u6a21\u578b",
    "cron.jobs": "\u5b9a\u65f6\u4efb\u52a1",
    "cron.name": "\u540d\u79f0",
    "cron.schedule": "\u8c03\u5ea6\uff08Cron\uff09",
    "cron.prompt": "\u63d0\u793a\u8bcd",
    "cron.channel": "\u901a\u9053",
    "cron.model": "\u6a21\u578b",
    "cron.agent": "\u4ee3\u7406",
    "cron.agent_placeholder": "\uff08\u7a7a = \u9ed8\u8ba4\u8def\u7531\uff09",
    "cron.delete_job": "\u5220\u9664\u4efb\u52a1",
    "cron.add_job": "\u6dfb\u52a0\u65b0\u4efb\u52a1",
    "cron.plugins": "\u63d2\u4ef6",
    "cron.skills_dir": "\u6280\u80fd\u76ee\u5f55",
    "cron.skills_desc": "\u76f8\u5bf9\u4e8e jarvis_home",
    "cron.auto_update": "\u81ea\u52a8\u66f4\u65b0",
    "cron.auto_update_desc": "\u542f\u52a8\u65f6\u81ea\u52a8\u66f4\u65b0\u63d2\u4ef6",

    // Logging page
    "log.title": "\u65e5\u5fd7",
    "log.desc": "\u65e5\u5fd7\u8bb0\u5f55\u548c\u8c03\u8bd5",
    "log.general": "\u5e38\u89c4",
    "log.level": "\u65e5\u5fd7\u7ea7\u522b",
    "log.json": "JSON \u65e5\u5fd7",
    "log.json_desc": "\u7528\u4e8e\u5916\u90e8\u5de5\u5177\u7684\u7ed3\u6784\u5316 JSON \u65e5\u5fd7",
    "log.console": "\u63a7\u5236\u53f0\u8f93\u51fa",
    "log.console_desc": "\u5c06\u65e5\u5fd7\u8f93\u51fa\u5230\u63a7\u5236\u53f0",

    // Database page
    "db.title": "\u6570\u636e\u5e93",
    "db.desc": "\u8bb0\u5fc6\u3001\u65e5\u5fd7\u548c\u72b6\u6001\u7684\u5b58\u50a8\u540e\u7aef",
    "db.connection": "\u8fde\u63a5",
    "db.backend": "\u540e\u7aef",
    "db.host": "\u4e3b\u673a",
    "db.port": "\u7aef\u53e3",
    "db.database": "\u6570\u636e\u5e93",
    "db.user": "\u7528\u6237",
    "db.password": "\u5bc6\u7801",
    "db.pool": "\u8fde\u63a5\u6c60",
    "db.pool_min": "\u6c60\u6700\u5c0f\u503c",
    "db.pool_max": "\u6c60\u6700\u5927\u503c",
    "db.encryption": "\u52a0\u5bc6",
    "db.encryption_enabled": "SQLite \u52a0\u5bc6 (SQLCipher)",
    "db.encryption_desc": "\u4f7f\u7528 SQLCipher \u52a0\u5bc6\u6240\u6709 SQLite \u6570\u636e\u5e93\u3002\u5bc6\u94a5\u5b89\u5168\u5b58\u50a8\u5728\u64cd\u4f5c\u7cfb\u7edf\u5bc6\u94a5\u73af\u4e2d\u3002",
    "db.encryption_info": "\u52a0\u5bc6\u5bc6\u94a5\u5728\u7cfb\u7edf\u5bc6\u94a5\u73af\u4e2d\u81ea\u52a8\u7ba1\u7406\uff08Windows Credential Locker / macOS Keychain / Linux SecretService\uff09\u3002\u9996\u6b21\u6fc0\u6d3b\u65f6\u751f\u6210\u65b0\u5bc6\u94a5\u3002",
    "db.encryption_prereq": "\u524d\u7f6e\u6761\u4ef6\uff1a",

    // Agents page
    "agents.title": "\u667a\u80fd\u4f53",
    "agents.desc": "\u7ba1\u7406\u591a\u4ee3\u7406\u914d\u7f6e \u2014 \u8def\u7531\u3001\u6a21\u578b\u3001\u6743\u9650",
    "agents.name_id": "\u540d\u79f0 (ID)",
    "agents.required": "\u5fc5\u586b",
    "agents.display_name": "\u663e\u793a\u540d\u79f0",
    "agents.description": "\u63cf\u8ff0",
    "agents.system_prompt": "\u7cfb\u7edf\u63d0\u793a\u8bcd",
    "agents.language": "\u8bed\u8a00",
    "agents.priority": "\u4f18\u5148\u7ea7",
    "agents.preferred_model": "\u9996\u9009\u6a21\u578b",
    "agents.temperature": "\u6e29\u5ea6",
    "agents.trigger_keywords": "\u89e6\u53d1\u5173\u952e\u8bcd",
    "agents.blocked_tools": "\u963b\u6b62\u7684\u5de5\u5177",
    "agents.enabled": "\u5df2\u542f\u7528",
    "agents.delete": "\u5220\u9664\u4ee3\u7406",
    "agents.create": "\u521b\u5efa\u65b0\u4ee3\u7406",

    // Bindings page
    "bind.title": "\u7ed1\u5b9a",
    "bind.desc": "\u8def\u7531\u89c4\u5219\uff1a\u54ea\u6761\u6d88\u606f\u53d1\u9001\u7ed9\u54ea\u4e2a\u4ee3\u7406\uff1f",
    "bind.name": "\u540d\u79f0",
    "bind.required": "\u5fc5\u586b",
    "bind.target": "\u76ee\u6807\u4ee3\u7406",
    "bind.priority": "\u4f18\u5148\u7ea7",
    "bind.description": "\u63cf\u8ff0",
    "bind.channels": "\u901a\u9053",
    "bind.prefixes": "\u547d\u4ee4\u524d\u7f00",
    "bind.patterns": "\u6d88\u606f\u6a21\u5f0f\uff08\u6b63\u5219\uff09",
    "bind.enabled": "\u5df2\u542f\u7528",
    "bind.delete": "\u5220\u9664\u7ed1\u5b9a",
    "bind.create": "\u65b0\u5efa\u7ed1\u5b9a",

    // System page
    "sys.title": "\u7cfb\u7edf",
    "sys.desc": "\u91cd\u542f\u3001\u5bfc\u51fa/\u5bfc\u5165\u3001\u6062\u590d\u51fa\u5382\u8bbe\u7f6e",
    "sys.restart": "\u91cd\u542f Cognithor",
    "sys.restart_desc": "\u5e72\u51c0\u5730\u5173\u95ed Cognithor\uff08\u4fdd\u5b58\u4f1a\u8bdd\u3001\u505c\u6b62\u901a\u9053\u3001\u5237\u65b0\u8bb0\u5fc6\uff09\u5e76\u4f7f\u7528\u5f53\u524d\u914d\u7f6e\u91cd\u65b0\u542f\u52a8\u3002",
    "sys.restarting": "\u91cd\u542f\u4e2d...",
    "sys.restarted": "\u5df2\u91cd\u542f\uff01",
    "sys.restart_btn": "\u91cd\u542f Cognithor",
    "sys.export_import": "\u5bfc\u51fa & \u5bfc\u5165",
    "sys.export": "\u5bfc\u51fa\u914d\u7f6e",
    "sys.import": "\u5bfc\u5165\u914d\u7f6e",
    "sys.factory_reset": "\u6062\u590d\u51fa\u5382\u8bbe\u7f6e",
    "sys.factory_desc": "\u5c06\u6240\u6709\u914d\u7f6e\u91cd\u7f6e\u4e3a\u9ed8\u8ba4\u503c\u3002API \u5bc6\u94a5\u548c\u5b58\u50a8\u7684\u6570\u636e\uff08\u8bb0\u5fc6\u3001\u6280\u80fd\u3001\u5de5\u4f5c\u6d41\uff09\u5c06\u88ab\u4fdd\u7559\u3002",
    "sys.factory_btn": "\u91cd\u7f6e\u6240\u6709\u8bbe\u7f6e",
    "sys.info": "\u7cfb\u7edf\u4fe1\u606f",
    "sys.info_version": "\u7248\u672c",
    "sys.info_backend": "\u540e\u7aef",
    "sys.info_owner": "\u6240\u6709\u8005",
    "sys.info_mode": "\u6a21\u5f0f",

    // Global Search
    "search.hint": "\u641c\u7d22...",
    "search.placeholder": "\u641c\u7d22\u8bbe\u7f6e...",
    "search.no_results": "\u201c{query}\u201d \u65e0\u7ed3\u679c",

    // Knowledge Graph
    "kg.title": "\u77e5\u8bc6\u56fe\u8c31",
    "kg.loading": "\u6b63\u5728\u52a0\u8f7d\u77e5\u8bc6\u56fe\u8c31...",
    "kg.entities": "\u5b9e\u4f53",
    "kg.relationships": "\u5173\u7cfb",
    "kg.empty_title": "\u77e5\u8bc6\u56fe\u8c31\u4e2d\u65e0\u5b9e\u4f53",
    "kg.empty_desc": "\u5b9e\u4f53\u4f1a\u81ea\u52a8\u4ece\u5bf9\u8bdd\u4e2d\u63d0\u53d6\u3002",
    "kg.search_placeholder": "\u641c\u7d22\u5b9e\u4f53...",
    "kg.all_types": "\u6240\u6709\u7c7b\u578b",
    "kg.visible": "{count} \u53ef\u89c1",
    "kg.type_label": "\u7c7b\u578b\uff1a",
    "kg.confidence_label": "\u7f6e\u4fe1\u5ea6\uff1a",
    "kg.attributes_label": "\u5c5e\u6027\uff1a",
    "kg.relationships_label": "\u5173\u7cfb ({count})\uff1a",
    "kg.id_label": "ID\uff1a",

    // Workflow Graph
    "wf.title": "\u5de5\u4f5c\u6d41\u6267\u884c\u56fe",
    "wf.loading": "\u6b63\u5728\u52a0\u8f7d\u5de5\u4f5c\u6d41...",
    "wf.templates": "\u6a21\u677f",
    "wf.instances": "\u5b9e\u4f8b",
    "wf.dag_runs": "DAG \u8fd0\u884c",
    "wf.active": "\u6d3b\u52a8",
    "wf.completed": "\u5df2\u5b8c\u6210",
    "wf.start": "\u542f\u52a8",
    "wf.back": "\u2190 \u8fd4\u56de",
    "wf.no_templates": "\u6ca1\u6709\u53ef\u7528\u7684\u5de5\u4f5c\u6d41\u6a21\u677f",
    "wf.no_instances": "\u6ca1\u6709\u8fd0\u884c\u4e2d\u7684\u5de5\u4f5c\u6d41",
    "wf.no_dag_runs": "\u6ca1\u6709\u53ef\u7528\u7684 DAG \u8fd0\u884c",
    "wf.no_nodes": "\u65e0\u8282\u70b9",
    "wf.steps": "\u6b65\u9aa4",
    "wf.min": "\u5206\u949f",
    "wf.type_tool": "\u5de5\u5177",
    "wf.type_llm": "LLM",
    "wf.type_condition": "\u6761\u4ef6",
    "wf.type_approval": "\u5ba1\u6279",
    "wf.nodes": "\u8282\u70b9",
    "wf.detail_type": "\u7c7b\u578b\uff1a",
    "wf.detail_status": "\u72b6\u6001\uff1a",
    "wf.detail_output": "\u8f93\u51fa\uff1a",
    "wf.detail_error": "\u9519\u8bef\uff1a",
    "wf.detail_duration": "\u65f6\u957f\uff1a",
    "wf.detail_retries": "\u91cd\u8bd5\uff1a",
    "wf.detail_depends": "\u4f9d\u8d56\uff1a",
  },
};

// ── State ────────────────────────────────────────────────────────────────

let _locale = "en";
const _listeners = new Set();

/**
 * Translate a key, with optional {placeholder} interpolation.
 * Falls back to English, then to the raw key.
 */
export function t(key, params) {
  const pack = packs[_locale] || packs.en;
  let text = pack[key] || packs.en[key] || key;
  if (params) {
    for (const [k, v] of Object.entries(params)) {
      text = text.replace(`{${k}}`, v);
    }
  }
  return text;
}

/**
 * Translate a key using a specific locale (without changing the global locale).
 * Used by the language settings popup to preview text in the selected language (#32).
 */
export function tLocale(locale, key, params) {
  const pack = packs[locale] || packs.en;
  let text = pack[key] || packs.en[key] || key;
  if (params) {
    for (const [k, v] of Object.entries(params)) {
      text = text.replace(`{${k}}`, v);
    }
  }
  return text;
}

/** Get the current locale. */
export function getLocale() {
  return _locale;
}

/** Set locale and notify all listeners. */
export function setLocale(locale) {
  if (!packs[locale] && locale !== _locale) {
    // Unknown locale — fall back to en
    locale = "en";
  }
  if (locale === _locale) return;
  _locale = locale;
  for (const fn of _listeners) {
    try { fn(locale); } catch { /* ignore */ }
  }
}

/** Subscribe to locale changes. Returns unsubscribe function. */
export function onLocaleChange(fn) {
  _listeners.add(fn);
  return () => _listeners.delete(fn);
}
