- DeepSeek/MiMo/Agnes 移除 supportsThinking 元信息硬门控:思考参数完全遵循用户配置 (事故复盘中 vision-exp 元信息标注不支持思考、实际产生了 8189 token 推理内容, 元信息不可靠;预算耗尽由引擎降级重试兜底,元信息不符仅告警不拦截) - Ollama 保留 /api/show 能力探测门控(服务端硬协议约束:向不支持思考的模型发 think 每次请求 400,属协议正确性而非意图覆盖),探测失败 fail-open - LLM 设置提示文案修订:元信息不符仍按用户配置发送,降级重试自动兜底 - 测试契约反向钉住:vision-exp + 用户开启→照发 enabled+reasoning_effort; 关闭/未配置→显式 disabled;Ollama 探测 false→不发 think / null→fail-open - 补录 docs/v0.8.0-迭代实施清单.md(含逐项验证记录与本次修订记录; 首次提交时该文件因故未入库,本次补齐) - 验证:typecheck 0 错误 / lint 0 问题 / 系统 Node 2146 通过 / thinking 矩阵 101 用例全绿
1446 lines
75 KiB
TypeScript
1446 lines
75 KiB
TypeScript
/**
|
||
* 集中文案字典(v0.6.4 P3-5 第一轮 → v0.7.2 P4-15 第二阶段 → v0.7.4 P3-1 收口)
|
||
*
|
||
* 目标:把散落在数据层与核心组件的硬编码文案收敛为稳定 key。
|
||
* 第三阶段(v0.7.4 P3-1)覆盖渲染层全量迁移:CommandPalette / ContextMenu /
|
||
* 聊天组件(AssistantMessage、ChatInput、MessageList、StreamingIndicator、ThoughtBlock、
|
||
* ToolCallCard、ToolResultBlock、UserMessage)/ ErrorBoundary / DetailPanel / Header /
|
||
* 各设置 Tab(Agent、Appearance、Logs、MCP、SearXNG、SettingsModal、Tools、Workspace)/
|
||
* TaskList / Trace(TokenUsage、TraceStep、TraceViewer)/ WorkspaceViewer / useConfig。
|
||
* 组件层按此模式渐进迁移 —— 每迁一处,删一处字面量。
|
||
*/
|
||
|
||
import { registerTranslations } from './i18n';
|
||
|
||
registerTranslations('zh-CN', {
|
||
// ===== 会话终止(useAgentStream done 分支)=====
|
||
'agent.terminated.max_iterations': '⏹ 已达到最大迭代轮次上限',
|
||
'agent.terminated.timeout': '⏹ 任务执行超时',
|
||
'agent.terminated.error': '执行出错',
|
||
// ===== 确认/中断 =====
|
||
'agent.system.stopped': '⏹ 会话已停止:{{reason}}',
|
||
'agent.error.generic': '错误: {{message}}',
|
||
'agent.error.content_filtered': '⚠️ {{message}}',
|
||
// v0.8.0 P2-4: @ 文件提及
|
||
'input.mention.failed': '@{{path}} 读取失败:{{reason}}',
|
||
|
||
// ===== v0.8.0 P0-2/P0-4: 流结束契约提示 =====
|
||
'agent.terminated.output_truncated':
|
||
'⚠️ 回答可能因输出上限被截断(finish_reason=length)。可在 设置 → LLM 配置 中提高"最大输出上限",或降低思考强度',
|
||
'agent.error.output_length_exceeded':
|
||
'⚠️ 模型的思考内容耗尽了输出 token 预算,未能产出回答(finish_reason=length)。建议:提高"最大输出上限" / 关闭思考模式或降低思考强度 / 更换输出预算更大的模型',
|
||
'agent.error.empty_response':
|
||
'⚠️ 模型未返回任何内容(含重试)。可能为上游中断或输出上限截断,请重试或调整输出上限/思考设置',
|
||
'agent.system.empty_completed': '⚠️ 模型未返回内容。请重试,或检查输出上限与思考模式设置',
|
||
'agent.system.finalize_missing':
|
||
'⚠️ 会话已结束但未收到正常收尾事件,已恢复输入(结果以数据库内容为准)',
|
||
'agent.system.abort_failed': '⚠️ 中断请求失败,Agent 可能仍在运行;已恢复实时显示',
|
||
'agent.system.replay_truncated': '(提示:后台运行内容较多,仅恢复了最近部分事件)',
|
||
'agent.system.tool_interrupted': '已中断',
|
||
|
||
// ===== 通用 =====
|
||
'common.cancel': '取消',
|
||
'common.delete': '删除',
|
||
'common.refresh': '刷新',
|
||
'common.close': '关闭',
|
||
// v0.8.0 P2-2: 会话回放
|
||
'replay.title': '会话回放',
|
||
'replay.file': '选择录制文件',
|
||
'replay.play': '播放',
|
||
'replay.pause': '暂停',
|
||
'replay.stepBack': '上一步',
|
||
'replay.stepForward': '下一步',
|
||
'replay.speed': '播放速度',
|
||
'replay.loadFailed': '加载录制失败',
|
||
'replay.noRecordings': '该会话还没有 TRACE 录制文件(logs/session_*.jsonl)',
|
||
'replay.skippedLines': '{{count}} 行损坏/截断被跳过',
|
||
'replay.event.iterationStart': '▶ 第 {{iteration}} 轮开始',
|
||
'replay.event.iterationEnd': '■ 第 {{iteration}} 轮结束({{duration}})',
|
||
'replay.event.sessionEnd': '会话结束:{{reason}}({{iterations}} 轮)',
|
||
|
||
// ===== 工具确认弹框(ConfirmationDialog)=====
|
||
'confirm.title': '工具执行确认',
|
||
'confirm.parallelSuffix': '({{count}} 个并行请求)',
|
||
'confirm.refreshList': '刷新 pending 列表',
|
||
'confirm.batchReason':
|
||
'检测到 {{count}} 个并行工具调用请求确认(涉及 {{groups}} 个不同工具)。综合最高风险:{{risk}}',
|
||
'confirm.defaultReason': 'Agent 正在请求执行工具',
|
||
'confirm.rememberedDenials': '本会话中已记住拒绝的工具({{minutes}} 分钟后自动恢复询问):',
|
||
'confirm.askAgain': '重新询问',
|
||
'confirm.earliestExpiry': '最早过期 ',
|
||
'confirm.remaining': '剩余 ',
|
||
'confirm.selectAll': '全选',
|
||
'confirm.deselectAll': '全不选',
|
||
'confirm.selectedCount': '已选 {{selected}} / {{total}}',
|
||
'confirm.noArgs': '(无参数)',
|
||
'confirm.rememberSession': '在本次会话中记住此决定(同工具不再询问)',
|
||
'confirm.autoExecuteLabel': '永久自动执行选中工具(跨会话不再询问,可在设置中关闭)',
|
||
'confirm.autoExecuteApplies': '· 将应用到 {{count}} 个工具',
|
||
'confirm.autoExecConfirmTitle': '确认永久自动执行?',
|
||
'confirm.autoExecConfirmBody':
|
||
'勾选后,选中的工具将永久自动执行(跨会话不再询问),包括未来的潜在危险操作。此设置可在「设置 → 工具管理」中关闭。',
|
||
'confirm.autoExecConfirmQuestion': '确定要启用吗?',
|
||
'confirm.autoExecConfirmYes': '确认自动执行',
|
||
'confirm.denyAll': '拒绝全部 ({{count}})',
|
||
'confirm.denyAllTitle': '拒绝全部请求',
|
||
'confirm.denyAllExpiredTitle': '已超时,点击立即清理全部请求',
|
||
'confirm.approveAll': '批准全部',
|
||
'confirm.approveAllTitle': '批准全部请求',
|
||
'confirm.approveAllDisabledTitle': '已全部选中,请使用"批准选中"',
|
||
'confirm.approveAllExpiredTitle': '已超时(批准不再生效)',
|
||
'confirm.approveSelected': '批准选中 ({{count}})',
|
||
'confirm.confirmExecution': '确认执行 ({{count}})',
|
||
'confirm.expired': '已超时',
|
||
'confirm.expiredHint': '已超时,将自动拒绝;如需重新触发请等待 Agent 重试',
|
||
|
||
// ===== 侧边栏(Sidebar)=====
|
||
'sidebar.newSession': '新建会话',
|
||
'sidebar.searchPlaceholder': '搜索会话标题与内容...',
|
||
'sidebar.noMatch': '无匹配结果',
|
||
'sidebar.empty': '暂无会话',
|
||
'sidebar.archived': '已归档',
|
||
// v0.8.0 P2-1: 回收站
|
||
'sidebar.trash': '回收站(30 天后自动清理)',
|
||
'sidebar.trash.empty': '回收站为空',
|
||
'sidebar.trash.purge': '彻底删除',
|
||
'sidebar.trash.purgeTitle': '彻底删除会话?',
|
||
'sidebar.trash.purgeBody': '「{{title}}」及其全部消息将被永久删除,此操作不可恢复。',
|
||
'sidebar.count': '{{count}} 个',
|
||
'sidebar.restore': '恢复',
|
||
'sidebar.deleteTitle': '删除会话',
|
||
'sidebar.deleteBody': '确定删除会话「{{title}}」?此操作不可恢复。',
|
||
'sidebar.deleteSessionAria': '删除会话 {{title}}',
|
||
'sidebar.messageCount': '{{count}} 条',
|
||
'sidebar.matchCount': '({{count}} 处) ',
|
||
'sidebar.toolManager': '工具管理',
|
||
'sidebar.toolsReady': '{{count}} 就绪',
|
||
'sidebar.toast.createFailed': '创建会话失败,请检查数据库状态',
|
||
'sidebar.toast.bridgeUnavailable': 'IPC 桥不可用:无法创建会话',
|
||
'sidebar.toast.deleteFailed': '删除会话失败,请重试',
|
||
'sidebar.toast.restoreFailed': '恢复失败',
|
||
'sidebar.toast.toolsLoadFailed': '加载工具列表失败',
|
||
|
||
// ===== 状态栏(StatusBar)=====
|
||
'status.checkUpdate': '点击检查更新(当前 {{version}})',
|
||
'status.checking': '检查中…',
|
||
'status.newVersion': '发现新版本 {{version}},点击此通知或设置中打开下载页',
|
||
'status.upToDate': '已是最新版本',
|
||
'status.settings': '设置 (Ctrl+,)',
|
||
'status.agent.idle': '空闲',
|
||
'status.agent.thinking': '思考中...',
|
||
'status.agent.executing': '执行中...',
|
||
'status.agent.error': '错误',
|
||
|
||
// ===== Agent 状态监视(AgentMonitor)=====
|
||
'monitor.agentStatus': 'Agent 状态',
|
||
'monitor.subAgentTasks': 'SubAgent 任务',
|
||
'monitor.count': '{{count}} 个',
|
||
'monitor.provider': 'Provider',
|
||
'monitor.model': '模型',
|
||
'monitor.iteration': '迭代',
|
||
'monitor.totalDuration': '总耗时',
|
||
'monitor.sub.delegated': '已委派',
|
||
'monitor.sub.running': '运行中',
|
||
'monitor.sub.completed': '已完成',
|
||
'monitor.sub.error': '失败',
|
||
|
||
// ===== 输入框(ChatInput)—— v0.7.3 P4-3 =====
|
||
'input.placeholder.ready': '输入消息... (Cmd/Ctrl+Enter 发送, Cmd/Ctrl+Shift+Enter 换行, / 命令)',
|
||
'input.placeholder.toolsLoading': '工具加载中...',
|
||
'input.placeholder.configLoading': '正在加载配置...',
|
||
'input.send': '发送',
|
||
'input.abort': '中断',
|
||
'input.attach.image': '附加文件(图片/文本/代码)',
|
||
'input.attach.textOnly.model': '附加文件(文本/代码)— 当前模型不支持图片',
|
||
'input.attach.textOnly.toggle': '附加文件(文本/代码)— 多模态未开启(设置 → LLM 配置)',
|
||
'input.image.skipped.model':
|
||
'当前模型不支持图片({{provider}} 需多模态模型),已跳过 {{count}} 个图片文件',
|
||
'input.image.skipped.toggle': '多模态未开启(设置 → LLM 配置),已跳过 {{count}} 个图片文件',
|
||
'input.image.skipped.probe': '当前模型不支持图片(能力探测),已跳过 {{count}} 个图片文件',
|
||
'input.file.readFailed': '文件读取失败,请检查文件是否损坏或被锁定',
|
||
'input.file.partialFailed': '{{count}} 个文件读取失败,已跳过',
|
||
'input.text.truncated': '文本附件 "{{name}}" 超过 512KB,已截断为前 512KB',
|
||
'input.text.truncatedNote':
|
||
'\n\n[... 文件内容已截断:原始大小 {{size}},仅包含前 {{limit}}。如需完整内容请分段处理 ...]',
|
||
'input.toast.toolsLoading': '工具正在加载中,请稍候...',
|
||
'input.slash.tool': '选择工具',
|
||
'input.slash.memory': '搜索记忆',
|
||
'input.slash.clear': '清空会话',
|
||
'input.slash.export': '导出 Markdown',
|
||
|
||
// ===== LLM 配置(LLMSettings)—— v0.7.3 P4-3 =====
|
||
'llm.title': 'LLM 配置',
|
||
'llm.loading': '加载中...',
|
||
'llm.provider.label': 'Provider',
|
||
'llm.baseURL': 'API Base URL',
|
||
'llm.baseURL.error': '需以 http:// 或 https:// 开头',
|
||
'llm.model.label': '模型名称',
|
||
'llm.model.placeholder': '如 deepseek-v4-pro、gpt-4o、claude-sonnet-4-5',
|
||
'llm.model.space': '模型名称不能包含空格',
|
||
'llm.models.load': '获取模型列表',
|
||
'llm.models.hint': '基于「已保存」的配置查询(修改后请先保存)',
|
||
'llm.models.hint.unloaded': '可手动输入,或点击下方按钮获取模型列表',
|
||
'llm.models.failed': '获取模型列表失败',
|
||
'llm.multimodal.label': '启用多模态(图片输入)',
|
||
'llm.multimodal.helper':
|
||
'开启后可在输入框上传图片;DeepSeek 需 vision 系列模型。历史会话图片会随上下文回传(最近 10 张)',
|
||
'llm.apiKey.label': 'API Key',
|
||
'llm.apiKey.required': '必填,未填 {{provider}} 的 API Key 会 401',
|
||
'llm.numCtx.label': '上下文长度 (num_ctx)',
|
||
'llm.numCtx.placeholder': '默认由模型决定(如 2048、4096、128000)',
|
||
'llm.numCtx.error': '最小值为 512',
|
||
'llm.ctxWindow.label': '上下文窗口 (contextWindow)',
|
||
'llm.ctxWindow.placeholder': '如 64000、128000、1000000',
|
||
'llm.ctxWindow.minError': '最小值为 4096',
|
||
'llm.ctxWindow.helper': '用于上下文压缩判断,不传给 API',
|
||
'llm.ctxWindow.mimoHelper': '默认 1000000(1M),用于上下文压缩判断',
|
||
'llm.ctxWindow.oaHelper': 'gpt-4o 默认 128K,gpt-4.1 默认 1M',
|
||
'llm.ctxWindow.anthropicHelper': 'Claude 默认 200K',
|
||
// v0.8.0 FEAT-1: 最大输出上限(llm.maxTokens,按请求传给 API)
|
||
'llm.maxTokens.label': '最大输出上限 (tokens)',
|
||
'llm.maxTokens.helper': '单次回复(含思考内容)的最大 token 数;思考会占用此预算',
|
||
'llm.maxTokens.minError': '最小值为 256',
|
||
'llm.maxTokens.exceedCap': '当前模型输出上限为 {{cap}},保存后将按模型上限生效(配置值被钳制)',
|
||
'llm.maxTokens.capInfo': '当前模型输出上限:{{cap}} tokens',
|
||
'llm.thinking.unsupported':
|
||
'当前模型元信息标注不支持思考:仍按你的配置发送思考参数;若思考耗尽输出预算,会自动关闭思考重试一次',
|
||
'llm.pull.title': '下载 Ollama 模型',
|
||
'llm.pull.placeholder': '模型名,如 qwen3:8b',
|
||
'llm.pull.download': '下载',
|
||
'llm.pull.cancel': '取消',
|
||
'llm.pull.helper':
|
||
'从 Ollama 服务拉取模型(大模型下载耗时取决于网络,可随时取消);完成后获取模型列表即可见',
|
||
'llm.pull.done': '模型 {{name}} 下载完成',
|
||
'llm.pull.failed': '模型下载失败:{{message}}',
|
||
'llm.balance.label': '账户余额',
|
||
'llm.balance.querying': '查询中...',
|
||
'llm.balance.unqueried': '未查询(需已保存 API Key)',
|
||
'llm.balance.granted': '(赠送 {{granted}} + 充值 {{topped}})',
|
||
'llm.balance.queryFailed': '查询失败',
|
||
'llm.fallback.title': '故障转移(可选)',
|
||
'llm.fallback.helper':
|
||
'主 Provider 请求失败(重试耗尽或密钥失效)时自动切换到备用 Provider 重发。留空禁用。',
|
||
'llm.fallback.provider': '备用 Provider',
|
||
'llm.fallback.disabled': '禁用',
|
||
'llm.fallback.baseURL': '备用 Base URL',
|
||
'llm.fallback.model': '备用模型名称',
|
||
'llm.fallback.apiKey': '备用 API Key',
|
||
'llm.save': '保存配置',
|
||
'llm.saving': '保存中...',
|
||
'llm.save.blocked': '请修正表单错误后再保存',
|
||
'llm.save.blockedToast': '请修正表单中的错误后再保存',
|
||
'llm.save.success': '配置已保存',
|
||
'llm.save.failed': '保存失败:{{message}}',
|
||
'llm.api.unavailable': '配置 API 不可用',
|
||
'llm.save.failed.generic': '配置保存失败',
|
||
|
||
// ===== 记忆库(MemoryViewer)—— v0.7.3 P4-3 =====
|
||
'memory.search.title': '记忆搜索',
|
||
'memory.list.title': '记忆库',
|
||
'memory.results': '{{count}} 条结果',
|
||
'memory.total': '{{count}} 条',
|
||
'memory.search.placeholder': '搜索记忆...',
|
||
'memory.search.clear': '清除',
|
||
'memory.searching': '搜索中...',
|
||
'memory.search.empty': '无匹配结果',
|
||
'memory.empty': '暂无记忆数据',
|
||
'memory.loadFailed': '加载记忆失败',
|
||
'memory.deleteFailed': '删除失败',
|
||
'memory.type.episodic': '情景记忆',
|
||
'memory.type.semantic': '语义记忆',
|
||
'memory.type.working': '工作记忆',
|
||
|
||
// ===== 引导向导(OnboardingWizard)—— v0.7.3 P4-3 =====
|
||
'onboarding.step.welcome': '欢迎',
|
||
'onboarding.step.llm': '配置 LLM',
|
||
'onboarding.step.agent': '自定义 Agent',
|
||
'onboarding.step.workspace': '工作空间',
|
||
'onboarding.step.done': '开始使用',
|
||
'onboarding.prev': '上一步',
|
||
'onboarding.next': '下一步',
|
||
'onboarding.finish': '开始使用',
|
||
'onboarding.welcome.title': '欢迎使用 MetonaAI Desktop',
|
||
'onboarding.welcome.body':
|
||
'生产级通用 AI Agent 智能体桌面应用,支持多轮对话、工具调用、记忆系统和 MCP 协议集成。',
|
||
'onboarding.welcome.hint': '让我们花 1 分钟完成初始配置。',
|
||
'onboarding.llm.title': '配置 LLM Provider',
|
||
'onboarding.llm.body': '选择 Provider 并填写 API 信息。Base URL 和模型名称支持任意输入。',
|
||
'onboarding.llm.multimodal.label': '启用多模态(图片输入)',
|
||
'onboarding.llm.multimodal.helper': '开启后可在输入框上传图片;DeepSeek 需 vision 系列模型',
|
||
'onboarding.llm.apiKey.placeholder': 'sk-...(本地模型可留空)',
|
||
'onboarding.llm.ctx.ollama': '上下文长度 (num_ctx)',
|
||
'onboarding.llm.ctx.window': '上下文窗口 (contextWindow)',
|
||
'onboarding.llm.ctx.ollamaPlaceholder': '默认由模型决定(如 2048、4096、128000)',
|
||
'onboarding.llm.ctx.placeholder': '如 64000、128000、1000000',
|
||
'onboarding.llm.ctx.helper': '用于上下文压缩判断,不传给 API',
|
||
'onboarding.llm.ctx.minError': '最小值为 {{min}}',
|
||
'onboarding.agent.title': '自定义 Agent',
|
||
'onboarding.agent.body': '编辑工作空间中的 SOUL.md 文件来定义 Agent 的身份和性格。',
|
||
'onboarding.agent.soulLabel': 'SOUL.md — 定义 Agent 的身份、性格、核心价值观',
|
||
'onboarding.agent.soulHint': '此步骤可稍后在工作空间目录中完成。',
|
||
'onboarding.workspace.title': '工作空间',
|
||
'onboarding.workspace.body': '选择工作空间目录,或使用默认路径。',
|
||
'onboarding.workspace.pick': '选择文件夹',
|
||
'onboarding.workspace.placeholder': '~/MetonaWorkspaces/default/',
|
||
'onboarding.workspace.helper': '包含 SOUL.md、MEMORY.md 两个必需文件,首次打开时自动创建。',
|
||
'onboarding.done.title': '配置完成!',
|
||
'onboarding.done.body': 'MetonaAI Desktop 已准备就绪。开始与你的 AI Agent 对话吧!',
|
||
'onboarding.done.hint': '按 Ctrl+Enter 发送消息,输入 / 查看命令列表',
|
||
'onboarding.toast.saveFailed': '配置保存失败,请重试',
|
||
'onboarding.toast.saveFailedWithReason': '保存配置失败:{{message}}',
|
||
'onboarding.toast.folderFailed': '选择文件夹失败',
|
||
|
||
// ===== 通用(v0.7.4 P3-1 补充)=====
|
||
'common.loading': '加载中...',
|
||
|
||
// ===== 命令面板(CommandPalette)=====
|
||
'command.newSession': '新建会话',
|
||
'command.newSessionDesc': '创建一个新的对话会话',
|
||
'command.createFailed': '创建会话失败',
|
||
'command.clearSession': '清空当前会话',
|
||
'command.openSettings': '打开设置',
|
||
'command.messageCount': '{{count}} 条消息',
|
||
'command.searchPlaceholder': '搜索会话、命令...',
|
||
'command.noMatch': '无匹配结果',
|
||
'command.navHint': '↑↓ 导航',
|
||
'command.selectHint': '↵ 选择',
|
||
'command.closeHint': 'Esc 关闭',
|
||
|
||
// ===== 右键菜单(ContextMenu)=====
|
||
'contextMenu.confirm': '确认',
|
||
'contextMenu.prompt': '输入',
|
||
'contextMenu.ok': '确定',
|
||
'contextMenu.toast.copyFailed': '复制失败',
|
||
'contextMenu.copy': '复制',
|
||
'contextMenu.quote': '引用回复',
|
||
'contextMenu.regenerate': '重新生成',
|
||
'contextMenu.rename': '重命名',
|
||
'contextMenu.renamePromptLabel': '新会话名称',
|
||
'contextMenu.renamePromptTitle': '重命名会话',
|
||
'contextMenu.toast.renameFailed': '重命名失败',
|
||
'contextMenu.pin': '置顶',
|
||
'contextMenu.unpin': '取消置顶',
|
||
'contextMenu.toast.pinFailed': '置顶失败',
|
||
'contextMenu.archive': '归档',
|
||
'contextMenu.unarchive': '取消归档',
|
||
'contextMenu.toast.archiveFailed': '归档失败',
|
||
'contextMenu.exportJson': '导出 JSON',
|
||
'contextMenu.exportMarkdown': '导出 Markdown',
|
||
'contextMenu.sessionExportTitle': '会话导出',
|
||
'contextMenu.toast.exportFailed': '导出失败',
|
||
'contextMenu.deleteConfirmBody': '确定删除此会话?此操作不可撤销。',
|
||
'contextMenu.toast.deleteFailed': '删除失败',
|
||
|
||
// ===== 聊天(chat / assistant / messageList / streaming / thought / toolCall / toolResult / userMessage)=====
|
||
'chat.export.title': '会话导出',
|
||
'assistant.thinking': '正在思考...',
|
||
'assistant.thinkingLabel': '思考过程',
|
||
'assistant.generating': '正在生成回复...',
|
||
'assistant.toolCalls': '工具调用',
|
||
'assistant.reply': '回复',
|
||
'assistant.copy': '复制',
|
||
'assistant.copied': '已复制',
|
||
'messageList.subtitle': '生产级通用 AI Agent 智能体桌面应用',
|
||
'messageList.emptyHint': 'Agent 就绪 · 选择一个 Provider 开始对话',
|
||
'messageList.ariaLabel': '聊天消息列表',
|
||
'streaming.connecting': '正在连接 AI...',
|
||
'thought.thinkingLabel': '思考过程',
|
||
'toolCall.status.pending': '等待中',
|
||
'toolCall.status.executing': '执行中',
|
||
'toolCall.status.success': '成功',
|
||
'toolCall.status.error': '失败',
|
||
'toolCall.status.blocked': '已阻止',
|
||
'toolResult.title': '{{name}} 结果',
|
||
'userMessage.saveOnly': '仅保存',
|
||
'userMessage.saveAndResend': '保存并重发',
|
||
'userMessage.resendHint': '重发将删除此消息之后的所有消息 · Ctrl+Enter',
|
||
|
||
// ===== 错误边界(ErrorBoundary)=====
|
||
'errorBoundary.renderFailed': '组件渲染失败',
|
||
'errorBoundary.unknownError': '未知错误',
|
||
'errorBoundary.retry': '重试',
|
||
|
||
// ===== 详情面板(DetailPanel)=====
|
||
'detailPanel.error.trace': 'Trace 渲染失败',
|
||
'detailPanel.error.memory': 'Memory 渲染失败',
|
||
'detailPanel.error.tasks': 'Tasks 渲染失败',
|
||
'detailPanel.error.workspace': 'Workspace 渲染失败',
|
||
|
||
// ===== 顶栏(Header)=====
|
||
'header.theme.light': '浅色主题',
|
||
'header.theme.dark': '深色主题',
|
||
'header.theme.auto': '跟随系统',
|
||
'header.hideSidebar': '隐藏侧边栏',
|
||
'header.showSidebar': '显示侧边栏',
|
||
'header.hideDetail': '隐藏详情面板',
|
||
'header.showDetail': '显示详情面板',
|
||
'header.exitFocus': '退出专注模式',
|
||
'header.enterFocus': '进入专注模式',
|
||
'header.settings': '设置',
|
||
|
||
// ===== Agent 监视(AgentMonitor 补充)=====
|
||
'monitor.iterations': ' · {{count}} 轮',
|
||
|
||
// ===== Agent 配置(AgentSettings)=====
|
||
'settings.agent.title': 'Agent 配置',
|
||
'settings.agent.maxIterations': '最大迭代次数',
|
||
'settings.agent.totalTimeout': '总超时(秒)',
|
||
'settings.agent.toolExecTimeout': '工具执行超时(秒)',
|
||
'settings.agent.toolExecTimeoutHelper':
|
||
'单个工具执行的最大时长,超时自动终止(最低 10 秒,无上限)',
|
||
'settings.agent.confirmTimeout': '工具确认超时(秒)',
|
||
'settings.agent.confirmTimeoutHelper': '用户未响应工具确认时,超时自动视为拒绝(30~600 秒)',
|
||
'settings.agent.enableThinking': '启用思考模式',
|
||
'settings.agent.thinkingEffort': '思考强度',
|
||
'settings.agent.enableReflection': '启用反思阶段(REFLECTING)',
|
||
'settings.agent.enableReflectionHelper':
|
||
'每轮工具执行后进入反思状态,存在失败结果时记录告警(不阻断执行)',
|
||
|
||
// ===== 外观设置(AppearanceSettings)=====
|
||
'settings.appearance.title': '外观',
|
||
'settings.appearance.theme': '主题',
|
||
'settings.appearance.dark': '深色',
|
||
'settings.appearance.light': '浅色',
|
||
'settings.appearance.auto': '跟随系统',
|
||
'settings.appearance.locale': '界面语言',
|
||
'settings.appearance.localeZhCN': '简体中文',
|
||
'settings.appearance.localeEnUS': 'English',
|
||
'settings.appearance.localeHelper':
|
||
'切换即时生效;已迁移的界面(系统消息 / 工具确认弹框 / 侧边栏 / 状态栏 / Agent 状态区)将跟随所选语言显示',
|
||
|
||
// ===== 日志与数据(LogsSettings)=====
|
||
'settings.logs.title': '日志与数据',
|
||
'settings.logs.logLevel': '日志级别',
|
||
'settings.logs.logFile': '日志文件',
|
||
'settings.logs.pathLoading': '正在获取路径...',
|
||
'settings.logs.pathUnavailable': '路径不可用',
|
||
'settings.logs.openLogFolder': '打开日志文件夹',
|
||
'settings.logs.copied': '已复制',
|
||
'settings.logs.copyPath': '复制路径',
|
||
'settings.logs.copyFailed': '复制失败',
|
||
'settings.logs.openFailed': '打开失败: {{message}}',
|
||
'settings.logs.logLevelHelper':
|
||
'日志级别变更重启后生效。日志文件按日期滚动,旧日志保留在 logs 目录下。',
|
||
'settings.logs.dataManagement': '数据管理',
|
||
'settings.logs.exportAllData': '📦 导出全部数据(JSON)',
|
||
'settings.logs.exportFailed': '导出失败: {{message}}',
|
||
'settings.logs.exporting': '导出中...',
|
||
'settings.logs.exportAuditJsonl': '📋 导出审计 (JSONL)',
|
||
'settings.logs.exportAuditCsv': '📊 导出审计 (CSV)',
|
||
'settings.logs.auditExported': '已导出 {{count}} 条审计记录',
|
||
'settings.logs.auditExportFailed': '审计导出失败: {{message}}',
|
||
'settings.logs.clearing': '清理中...',
|
||
'settings.logs.clearSessions': '🗑️ 清理所有会话',
|
||
'settings.logs.clearMemories': '🗑️ 清理所有记忆',
|
||
'settings.logs.clearAuditLogs': '🗑️ 清理审计日志',
|
||
'settings.logs.clear': '清理',
|
||
'settings.logs.clearFailed': '失败: {{message}}',
|
||
'settings.logs.confirmClearTitle': '确认清理',
|
||
'settings.logs.confirmClearBody': '确定清理{{label}}?此操作不可撤销。',
|
||
'settings.logs.cleared': '{{label}}已清理',
|
||
'settings.logs.data.sessions': '所有会话',
|
||
'settings.logs.data.memories': '所有记忆',
|
||
'settings.logs.data.auditLogs': '审计日志',
|
||
'settings.logs.traceFilesTitle': '会话录制文件(TRACE JSONL)',
|
||
// v0.8.0 P2-3: 检查更新 / 下载安装
|
||
'settings.logs.update.title': '应用更新',
|
||
'settings.logs.update.check': '检查更新',
|
||
'settings.logs.update.checking': '检查中…',
|
||
'settings.logs.update.downloadInstall': '下载并安装',
|
||
'settings.logs.update.installing': '准备安装…',
|
||
'settings.logs.update.available': '新版本 {{version}} 可用,点击"下载并安装"升级',
|
||
'settings.logs.update.upToDate': '已是最新版本({{version}})',
|
||
'settings.logs.update.disabled': '未配置更新源(app.updateFeedUrl)',
|
||
'settings.logs.update.error': '更新失败:{{message}}',
|
||
'settings.logs.update.downloaded': '下载完成,即将重启安装…',
|
||
'settings.logs.traceStats':
|
||
'{{count}} 个文件 · 共 {{size}}(保留策略:最近 200 个,启动时自动清理)',
|
||
'settings.logs.statsLoading': '统计中...',
|
||
'settings.logs.refreshStats': '刷新统计',
|
||
'settings.logs.pruneOldFiles': '清理旧录制文件',
|
||
'settings.logs.pruneDone': '已清理 {{count}} 个旧录制文件(保留最近 200 个)',
|
||
'settings.logs.pruneFailed': '清理失败:{{message}}',
|
||
'settings.logs.healthTitle': '运行健康(SLO / 健康检查)',
|
||
'settings.logs.noSnapshot': '暂无快照',
|
||
'settings.logs.health.errorRate': '请求错误率(5 分钟窗口)',
|
||
'settings.logs.health.errorRateValue': '{{pct}}({{count}} 次请求)',
|
||
'settings.logs.health.latency': '延迟 P50 / P95 / P99',
|
||
'settings.logs.health.burnRate': 'SLO 燃烧速率(目标 99.9%)',
|
||
'settings.logs.health.check': '健康检查',
|
||
'settings.logs.health.allPassed': '全部通过',
|
||
'settings.logs.health.abnormal': '异常:{{checks}}',
|
||
'settings.logs.health.notRunYet': '启动后尚未执行(周期 60s)',
|
||
'settings.logs.health.chainVerify': '审计日志链校验',
|
||
'settings.logs.health.chainValid': '通过({{verified}}/{{total}} 条)',
|
||
'settings.logs.health.chainTampered': '已篡改!首个异常记录 #{{index}}',
|
||
'settings.logs.health.verifyChainBtn': '校验审计日志链',
|
||
'settings.logs.verifyFailed': '校验失败:{{message}}',
|
||
|
||
// ===== MCP 服务(MCPSettings)=====
|
||
'settings.mcp.title': 'MCP 服务',
|
||
'settings.mcp.empty': '暂无 MCP 服务',
|
||
'settings.mcp.toolCount': '{{count}} 工具',
|
||
'settings.mcp.connect': '连接',
|
||
'settings.mcp.disconnect': '断开',
|
||
'settings.mcp.remove': '移除',
|
||
'settings.mcp.add': '添加',
|
||
'settings.mcp.addServer': '+ 添加 MCP 服务',
|
||
'settings.mcp.serverName': '服务名称',
|
||
'settings.mcp.localStdio': '本地 (stdio)',
|
||
'settings.mcp.remoteHttp': '远程 (HTTP)',
|
||
'settings.mcp.commandPlaceholder': '命令路径(如 npx / node / python)',
|
||
'settings.mcp.argsPlaceholder': '参数 (空格分隔)',
|
||
'settings.mcp.urlPlaceholder': 'Streamable HTTP URL(如 https://example.com/mcp)',
|
||
'settings.mcp.headersPlaceholder':
|
||
'自定义请求头 (JSON,可选),如 {"Authorization": "Bearer xxx"}',
|
||
'settings.mcp.headersInvalid':
|
||
'自定义请求头需为合法 JSON 对象,如 {"Authorization": "Bearer xxx"}',
|
||
'settings.mcp.addFailed': '添加 MCP 服务失败',
|
||
'settings.mcp.addFailedMsg': '添加 MCP 服务失败:{{message}}',
|
||
'settings.mcp.removeFailed': '移除失败',
|
||
// v0.8.0 P2-5: MCP Resources / Prompts 发现
|
||
'settings.mcp.contents.show': '查看资源与提示词',
|
||
'settings.mcp.contents.hide': '收起资源与提示词',
|
||
'settings.mcp.contents.empty': '该 Server 未声明 Resources / Prompts 能力',
|
||
'settings.mcp.removeFailedMsg': '移除失败:{{message}}',
|
||
'settings.mcp.toggleFailed': '操作失败',
|
||
'settings.mcp.toggleFailedMsg': '操作失败:{{message}}',
|
||
'settings.mcp.removeConfirmTitle': '确认移除',
|
||
'settings.mcp.removeConfirmBody': '确定移除 MCP 服务 "{{name}}"?此操作不可撤销。',
|
||
|
||
// ===== SearXNG 配置(SearXNGSettings)=====
|
||
'settings.searxng.tabTitle': 'SearXNG',
|
||
'settings.searxng.title': 'SearXNG 元搜索',
|
||
'settings.searxng.description':
|
||
'SearXNG 是开源元搜索引擎,支持 70+ 搜索引擎聚合。启用后替代内置四引擎搜索通道,未启用时回退到 Bing + 百度 + 搜狗 + 360 搜索。',
|
||
'settings.searxng.enabled': '已启用',
|
||
'settings.searxng.disabled': '未启用',
|
||
'settings.searxng.enableAria': '启用 SearXNG',
|
||
'settings.searxng.enable': '启用 SearXNG',
|
||
'settings.searxng.urlLabel': 'API 地址',
|
||
'settings.searxng.urlPlaceholder': '如 https://searxng.example.com',
|
||
'settings.searxng.urlError': '需以 http:// 或 https:// 开头',
|
||
'settings.searxng.urlHelper': '实例根地址(不含 /search 路径)',
|
||
'settings.searxng.test': '测试连接',
|
||
'settings.searxng.testSuccess': '连接成功({{latency}}ms)',
|
||
'settings.searxng.testFailedHttp': '连接失败(HTTP {{code}})',
|
||
'settings.searxng.enginesLabel': '搜索引擎(逗号分隔)',
|
||
'settings.searxng.enginesPlaceholder': '如 google,bing,duckduckgo(留空使用实例默认)',
|
||
'settings.searxng.language': '语言',
|
||
'settings.searxng.langZhCN': '简体中文',
|
||
'settings.searxng.langZhTW': '繁體中文',
|
||
'settings.searxng.langAuto': '自动检测',
|
||
'settings.searxng.safesearch': '安全搜索',
|
||
'settings.searxng.safeOff': '关闭',
|
||
'settings.searxng.safeMedium': '中等',
|
||
'settings.searxng.safeStrict': '严格',
|
||
'settings.searxng.timeRange': '时间范围',
|
||
'settings.searxng.timeAny': '不限',
|
||
'settings.searxng.timeDay': '一天',
|
||
'settings.searxng.timeWeek': '一周',
|
||
'settings.searxng.timeMonth': '一月',
|
||
'settings.searxng.timeYear': '一年',
|
||
'settings.searxng.format': '返回格式',
|
||
'settings.searxng.formatJson': 'JSON(结构化解析)',
|
||
'settings.searxng.formatHtml': 'HTML(原始网页)',
|
||
'settings.searxng.maxResults': '最大结果数',
|
||
'settings.searxng.maxResultsPlaceholder': '0 表示使用默认',
|
||
'settings.searxng.fetchCount': '自动抓取条数',
|
||
'settings.searxng.fetchCountPlaceholder': '0 表示由 AI 决定',
|
||
'settings.searxng.fetchMode': '抓取类型',
|
||
'settings.searxng.fetchSequential': '顺序抓取',
|
||
'settings.searxng.fetchRandom': '随机抓取',
|
||
'settings.searxng.authTitle': '认证设置',
|
||
'settings.searxng.authType': '认证类型',
|
||
'settings.searxng.authToken': 'Token',
|
||
'settings.searxng.authUserPass': '用户名:密码',
|
||
'settings.searxng.authTokenPlaceholder': '访问令牌原值',
|
||
'settings.searxng.authUserPassPlaceholder': 'username:password',
|
||
'settings.searxng.hideKey': '隐藏密钥',
|
||
'settings.searxng.showKey': '显示密钥',
|
||
'settings.searxng.authBearerHelper':
|
||
'Bearer: 直接填写令牌原值,原样透传到 Authorization 头。建议配合 HTTPS 使用。',
|
||
'settings.searxng.authBasicHelper':
|
||
'Basic: 填写 username:password 明文串,系统自动 Base64 编码。必须配合 HTTPS 使用。',
|
||
'settings.searxng.saved': 'SearXNG 配置已保存',
|
||
'settings.searxng.saveFailed': '保存失败',
|
||
'settings.searxng.toggleFailed': '开关保存失败',
|
||
'settings.searxng.saving': '保存中...',
|
||
'settings.searxng.saveChanges': '保存更改',
|
||
'settings.searxng.dirty': '有未保存的修改',
|
||
'settings.searxng.savedNotice': '已保存',
|
||
'settings.searxng.loading': '正在读取配置...',
|
||
|
||
// ===== 设置弹窗(SettingsModal)=====
|
||
'settings.title': '设置',
|
||
'settings.tabs.workspace': '工作空间',
|
||
'settings.tabs.llm': 'LLM 配置',
|
||
'settings.tabs.agent': 'Agent 配置',
|
||
'settings.tabs.tools': '工具管理',
|
||
'settings.tabs.mcp': 'MCP 服务',
|
||
'settings.tabs.searxng': 'SearXNG',
|
||
'settings.tabs.appearance': '外观',
|
||
'settings.tabs.logs': '日志与数据',
|
||
'settings.error.workspace': '工作空间设置渲染失败',
|
||
'settings.error.llm': 'LLM 配置渲染失败',
|
||
'settings.error.agent': 'Agent 配置渲染失败',
|
||
'settings.error.tools': '工具管理渲染失败',
|
||
'settings.error.mcp': 'MCP 服务渲染失败',
|
||
'settings.error.searxng': 'SearXNG 渲染失败',
|
||
'settings.error.appearance': '外观设置渲染失败',
|
||
'settings.error.logs': '日志与数据渲染失败',
|
||
'settings.saveFailed': '配置保存失败',
|
||
|
||
// ===== 工具管理(ToolsSettings)=====
|
||
'settings.tools.title': '工具管理',
|
||
'settings.tools.toggleFailed': '切换工具失败',
|
||
'settings.tools.autoExecFailed': '设置自动执行失败',
|
||
'settings.tools.autoExecTitle': '自动执行工具',
|
||
'settings.tools.autoExecCount': '{{count}} 个',
|
||
'settings.tools.autoExecHelper':
|
||
'已设为自动执行的工具将跳过用户确认步骤,直接执行。此设置跨会话持久化。',
|
||
'settings.tools.noAutoExec': '暂无自动执行工具',
|
||
'settings.tools.autoChip': '自动',
|
||
'settings.tools.cancelAuto': '取消自动',
|
||
'settings.tools.availableAutoExec': '可设为自动执行(当前需要确认)',
|
||
'settings.tools.setAuto': '设为自动',
|
||
'settings.tools.proxyTitle': '网络代理',
|
||
'settings.tools.proxyLabel': '代理地址(可选)',
|
||
'settings.tools.proxyPlaceholder': 'http://127.0.0.1:7890 或 socks5://…(留空直连)',
|
||
'settings.tools.proxyError': '需以 http://、https://、socks5:// 或 socks4:// 开头',
|
||
'settings.tools.proxyHelper':
|
||
'应用于 Chromium 会话与主进程全部网络请求;未填时回退系统环境变量 HTTPS_PROXY。',
|
||
|
||
// ===== 工作空间设置(WorkspaceSettings)=====
|
||
'settings.workspace.title': '工作空间',
|
||
'settings.workspace.description':
|
||
'工作空间是 Metona 的组织核心,包含 SOUL.md、MEMORY.md 两个必需文件。',
|
||
'settings.workspace.placeholder': '~/MetonaWorkspaces/default/',
|
||
'settings.workspace.checking': '校验中...',
|
||
'settings.workspace.check': '校验',
|
||
'settings.workspace.checkingInProgress': '正在校验工作空间...',
|
||
'settings.workspace.invalidPath': '路径无效:{{reason}}',
|
||
'settings.workspace.openInFileManager': '📂 在文件管理器中打开',
|
||
'settings.workspace.openFolderFailed': '打开文件夹失败',
|
||
'settings.workspace.targetWorkspace': '目标工作空间:{{path}}',
|
||
'settings.workspace.newWorkspace':
|
||
'新工作空间 — 切换后将自动创建 2 个必需文件(SOUL.md、MEMORY.md)',
|
||
'settings.workspace.missingFiles':
|
||
'已有目录但缺少 {{count}} 个文件:{{files}}。缺失文件将自动创建。',
|
||
'settings.workspace.existingWorkspace':
|
||
'已有工作空间 — 2 个必需文件均已就绪,将直接加载现有配置。',
|
||
'settings.workspace.inheritFromCurrent': '从当前工作空间继承:',
|
||
'settings.workspace.inheritSoul': 'SOUL.md(身份与角色定义)',
|
||
'settings.workspace.inheritDatabase': '数据库 agent.db(会话/消息/记忆/Trace 历史记录)',
|
||
'settings.workspace.inheritDatabaseHelper':
|
||
'勾选后将复制当前工作空间的全部历史数据到新工作空间(通过 SQLite backup API 原子性导出)',
|
||
'settings.workspace.memoryNotInherited': 'MEMORY.md 不继承(记忆与工作空间项目上下文绑定)',
|
||
'settings.workspace.applying': '应用中...',
|
||
'settings.workspace.confirmSwitch': '确认切换',
|
||
'settings.workspace.restartHint': '修改工作空间路径后需重启应用生效。',
|
||
'settings.workspace.switchedTitle': '工作空间已切换',
|
||
'settings.workspace.switchedBody': '工作空间已更新为:',
|
||
'settings.workspace.restartQuestion': '需要重启应用以加载新工作空间的配置和文件。是否立即重启?',
|
||
'settings.workspace.restartLater': '稍后手动重启',
|
||
'settings.workspace.restartNow': '立即重启',
|
||
'settings.workspace.dbIntegrityFailed': '源数据库校验失败:{{message}}',
|
||
'settings.workspace.dbCorrupted': '源数据库损坏({{detail}}),无法继承',
|
||
'settings.workspace.dbIntegrityError': '源数据库校验异常:{{message}}',
|
||
'settings.workspace.inheritPartialFailed': '部分文件继承失败:{{message}},请手动检查',
|
||
'settings.workspace.switchFailed': '切换工作空间失败:{{message}}',
|
||
|
||
// ===== 任务列表(TaskList)=====
|
||
'taskList.title': '任务列表',
|
||
'taskList.count': '{{count}} 项',
|
||
'taskList.addTask': '新增任务',
|
||
'taskList.cancelAdd': '取消新增',
|
||
'taskList.titlePlaceholder': '任务标题...',
|
||
'taskList.creating': '...',
|
||
'taskList.create': '创建',
|
||
'taskList.cancelAddTask': '取消新增任务',
|
||
'taskList.selectSession': '请先选择或创建会话',
|
||
'taskList.titleRequired': '任务标题不能为空',
|
||
'taskList.createFailed': '创建任务失败',
|
||
'taskList.updateFailed': '更新任务失败',
|
||
'taskList.deleteFailed': '删除任务失败',
|
||
'taskList.loadFailed': '加载任务失败',
|
||
'taskList.selectSessionHint': '请先选择会话',
|
||
'taskList.empty': '暂无任务,点击 + 创建',
|
||
'taskList.noDescription': '无描述',
|
||
'taskList.status.pending': '待处理',
|
||
'taskList.status.inProgress': '进行中',
|
||
'taskList.status.completed': '已完成',
|
||
'taskList.status.blocked': '阻塞',
|
||
'taskList.status.cancelled': '已取消',
|
||
'taskList.priority.low': '低',
|
||
'taskList.priority.medium': '中',
|
||
'taskList.priority.high': '高',
|
||
'taskList.priority.critical': '紧急',
|
||
|
||
// ===== Token 统计(TokenUsage)=====
|
||
'trace.token.usage': 'Token 用量',
|
||
'trace.token.input': '输入',
|
||
'trace.token.output': '输出',
|
||
'trace.token.total': '累计消耗',
|
||
'trace.token.context': '上下文占用',
|
||
'trace.token.compressedSaved': '压缩节省',
|
||
|
||
// ===== Trace 步骤(TraceStep / constants)=====
|
||
'trace.step.toolCalls': '工具调用',
|
||
'trace.state.INIT': '初始化',
|
||
'trace.state.THINKING': '思考',
|
||
'trace.state.PARSING': '解析',
|
||
'trace.state.EXECUTING': '执行',
|
||
'trace.state.OBSERVING': '观察',
|
||
'trace.state.REFLECTING': '反思',
|
||
'trace.state.COMPRESSING': '压缩',
|
||
'trace.state.TERMINATED': '终止',
|
||
|
||
// ===== Trace 视图(TraceViewer)=====
|
||
'trace.viewer.rounds': '共 {{count}} 轮',
|
||
'trace.viewer.waiting': '等待 Agent 活动...',
|
||
'trace.viewer.roundNumber': '第 {{index}} 轮',
|
||
'trace.viewer.inProgress': '进行中',
|
||
'trace.viewer.completed': '已完成',
|
||
'trace.viewer.steps': '{{count}} 步',
|
||
|
||
// ===== 工作空间浏览器(WorkspaceViewer)=====
|
||
'workspace.currentWorkspace': '当前工作空间',
|
||
'workspace.openInFileManager': '在文件管理器中打开',
|
||
'workspace.showInFileManager': '在文件管理器中显示',
|
||
'workspace.coreFiles': '核心文件({{count}}/{{total}})',
|
||
'workspace.emptyFile': '(空文件)',
|
||
'workspace.fileMissing': '文件不存在',
|
||
'workspace.autoDirs': '自动目录',
|
||
'workspace.dirFileCount': '{{count}} 个文件',
|
||
'workspace.dirMissing': '不存在',
|
||
'workspace.noData': '无数据',
|
||
'workspace.loadFailed': '加载工作空间信息失败',
|
||
'workspace.openFailed': '打开文件夹失败',
|
||
});
|
||
|
||
registerTranslations('en-US', {
|
||
'agent.terminated.max_iterations': '⏹ Max iteration limit reached',
|
||
'agent.terminated.timeout': '⏹ Task timed out',
|
||
'agent.terminated.error': 'Execution error',
|
||
'agent.system.stopped': '⏹ Session stopped: {{reason}}',
|
||
'agent.error.generic': 'Error: {{message}}',
|
||
'agent.error.content_filtered': '⚠️ {{message}}',
|
||
// v0.8.0 P2-4: @ file mention
|
||
'input.mention.failed': '@{{path}} read failed: {{reason}}',
|
||
|
||
// ===== v0.8.0 P0-2/P0-4: stream-end contract notices =====
|
||
'agent.terminated.output_truncated':
|
||
'⚠️ The answer may have been truncated by the output token limit (finish_reason=length). Raise "Max Output Tokens" in Settings → LLM, or lower thinking effort',
|
||
'agent.error.output_length_exceeded':
|
||
'⚠️ The model consumed its entire output token budget on reasoning and produced no answer (finish_reason=length). Try: raise "Max Output Tokens" / disable or lower thinking / switch to a model with a larger output budget',
|
||
'agent.error.empty_response':
|
||
'⚠️ The model returned no content (after retries). This may be an upstream drop or output-limit cutoff — retry, or adjust output limit / thinking settings',
|
||
'agent.system.empty_completed':
|
||
'⚠️ The model returned no content. Please retry, or check the output limit / thinking settings',
|
||
'agent.system.finalize_missing':
|
||
'⚠️ The run ended without a normal completion event — input restored (results reflect the database)',
|
||
'agent.system.abort_failed':
|
||
'⚠️ Abort request failed — the agent may still be running; live display restored',
|
||
'agent.system.replay_truncated':
|
||
' (Note: many events occurred in the background; only the most recent were restored)',
|
||
'agent.system.tool_interrupted': 'Interrupted',
|
||
|
||
'common.cancel': 'Cancel',
|
||
'common.delete': 'Delete',
|
||
'common.refresh': 'Refresh',
|
||
'common.close': 'Close',
|
||
// v0.8.0 P2-2: Session replay
|
||
'replay.title': 'Session replay',
|
||
'replay.file': 'Select recording',
|
||
'replay.play': 'Play',
|
||
'replay.pause': 'Pause',
|
||
'replay.stepBack': 'Step back',
|
||
'replay.stepForward': 'Step forward',
|
||
'replay.speed': 'Playback speed',
|
||
'replay.loadFailed': 'Failed to load recording',
|
||
'replay.noRecordings': 'No TRACE recordings for this session yet (logs/session_*.jsonl)',
|
||
'replay.skippedLines': '{{count}} corrupt/truncated line(s) skipped',
|
||
'replay.event.iterationStart': '▶ Iteration {{iteration}} start',
|
||
'replay.event.iterationEnd': '■ Iteration {{iteration}} end ({{duration}})',
|
||
'replay.event.sessionEnd': 'Session ended: {{reason}} ({{iterations}} iterations)',
|
||
|
||
'confirm.title': 'Tool Execution Confirmation',
|
||
'confirm.parallelSuffix': ' ({{count}} parallel requests)',
|
||
'confirm.refreshList': 'Refresh pending list',
|
||
'confirm.batchReason':
|
||
'{{count}} parallel tool calls are requesting confirmation ({{groups}} distinct tools). Highest risk: {{risk}}',
|
||
'confirm.defaultReason': 'The agent is requesting to execute a tool',
|
||
'confirm.rememberedDenials':
|
||
'Tools remembered as denied in this session (asking again in {{minutes}} min):',
|
||
'confirm.askAgain': 'Ask again',
|
||
'confirm.earliestExpiry': 'Earliest expires in ',
|
||
'confirm.remaining': 'Remaining ',
|
||
'confirm.selectAll': 'Select all',
|
||
'confirm.deselectAll': 'Deselect all',
|
||
'confirm.selectedCount': 'Selected {{selected}} / {{total}}',
|
||
'confirm.noArgs': '(no arguments)',
|
||
'confirm.rememberSession': 'Remember this decision for this session (ask no more)',
|
||
'confirm.autoExecuteLabel':
|
||
'Always auto-execute selected tools (across sessions; disable in Settings)',
|
||
'confirm.autoExecuteApplies': '· Applies to {{count}} tool(s)',
|
||
'confirm.autoExecConfirmTitle': 'Enable permanent auto-execution?',
|
||
'confirm.autoExecConfirmBody':
|
||
'Once enabled, the selected tools will always run without asking — including potentially dangerous operations in the future. You can turn this off in Settings → Tools.',
|
||
'confirm.autoExecConfirmQuestion': 'Are you sure?',
|
||
'confirm.autoExecConfirmYes': 'Enable auto-execution',
|
||
'confirm.denyAll': 'Deny all ({{count}})',
|
||
'confirm.denyAllTitle': 'Deny all requests',
|
||
'confirm.denyAllExpiredTitle': 'Expired — click to clean up all requests now',
|
||
'confirm.approveAll': 'Approve all',
|
||
'confirm.approveAllTitle': 'Approve all requests',
|
||
'confirm.approveAllDisabledTitle': 'All selected — use "Approve selected" instead',
|
||
'confirm.approveAllExpiredTitle': 'Expired (approval no longer applies)',
|
||
'confirm.approveSelected': 'Approve selected ({{count}})',
|
||
'confirm.confirmExecution': 'Confirm execution ({{count}})',
|
||
'confirm.expired': 'Expired',
|
||
'confirm.expiredHint': 'Expired and will be auto-denied; wait for the agent to retry if needed',
|
||
|
||
'sidebar.newSession': 'New Session',
|
||
'sidebar.searchPlaceholder': 'Search session titles and content...',
|
||
'sidebar.noMatch': 'No matches',
|
||
'sidebar.empty': 'No sessions yet',
|
||
'sidebar.archived': 'Archived',
|
||
// v0.8.0 P2-1: Trash
|
||
'sidebar.trash': 'Trash (auto-purged after 30 days)',
|
||
'sidebar.trash.empty': 'Trash is empty',
|
||
'sidebar.trash.purge': 'Delete forever',
|
||
'sidebar.trash.purgeTitle': 'Delete session forever?',
|
||
'sidebar.trash.purgeBody':
|
||
'"{{title}}" and all of its messages will be permanently deleted. This cannot be undone.',
|
||
'sidebar.count': '{{count}}',
|
||
'sidebar.restore': 'Restore',
|
||
'sidebar.deleteTitle': 'Delete Session',
|
||
'sidebar.deleteBody': 'Delete session "{{title}}"? This cannot be undone.',
|
||
'sidebar.deleteSessionAria': 'Delete session {{title}}',
|
||
'sidebar.messageCount': '{{count}} msgs',
|
||
'sidebar.matchCount': '({{count}} hits) ',
|
||
'sidebar.toolManager': 'Tools',
|
||
'sidebar.toolsReady': '{{count}} ready',
|
||
'sidebar.toast.createFailed': 'Failed to create session — check database status',
|
||
'sidebar.toast.bridgeUnavailable': 'IPC bridge unavailable: cannot create session',
|
||
'sidebar.toast.deleteFailed': 'Failed to delete session — please retry',
|
||
'sidebar.toast.restoreFailed': 'Restore failed',
|
||
'sidebar.toast.toolsLoadFailed': 'Failed to load tool list',
|
||
|
||
'status.checkUpdate': 'Click to check for updates (current {{version}})',
|
||
'status.checking': 'Checking…',
|
||
'status.newVersion':
|
||
'New version {{version}} available — click this notification to open the download page',
|
||
'status.upToDate': 'Up to date',
|
||
'status.settings': 'Settings (Ctrl+,)',
|
||
'status.agent.idle': 'Idle',
|
||
'status.agent.thinking': 'Thinking...',
|
||
'status.agent.executing': 'Executing...',
|
||
'status.agent.error': 'Error',
|
||
|
||
'monitor.agentStatus': 'Agent Status',
|
||
'monitor.subAgentTasks': 'SubAgent Tasks',
|
||
'monitor.count': '{{count}}',
|
||
'monitor.provider': 'Provider',
|
||
'monitor.model': 'Model',
|
||
'monitor.iteration': 'Iteration',
|
||
'monitor.totalDuration': 'Total time',
|
||
'monitor.sub.delegated': 'Delegated',
|
||
'monitor.sub.running': 'Running',
|
||
'monitor.sub.completed': 'Completed',
|
||
'monitor.sub.error': 'Failed',
|
||
|
||
// ===== 输入框(ChatInput)=====
|
||
'input.placeholder.ready':
|
||
'Type a message... (Cmd/Ctrl+Enter to send, Cmd/Ctrl+Shift+Enter for newline, / for commands)',
|
||
'input.placeholder.toolsLoading': 'Loading tools...',
|
||
'input.placeholder.configLoading': 'Loading configuration...',
|
||
'input.send': 'Send',
|
||
'input.abort': 'Stop',
|
||
'input.attach.image': 'Attach files (images/text/code)',
|
||
'input.attach.textOnly.model': 'Attach files (text/code) — current model has no image support',
|
||
'input.attach.textOnly.toggle': 'Attach files (text/code) — multimodal disabled (Settings → LLM)',
|
||
'input.image.skipped.model':
|
||
'Current model has no image support ({{provider}} requires a multimodal model); {{count}} image file(s) skipped',
|
||
'input.image.skipped.toggle':
|
||
'Multimodal is disabled (Settings → LLM); {{count}} image file(s) skipped',
|
||
'input.image.skipped.probe':
|
||
'Current model has no image support (capability probe); {{count}} image file(s) skipped',
|
||
'input.file.readFailed': 'Failed to read files — check whether they are corrupted or locked',
|
||
'input.file.partialFailed': '{{count}} file(s) failed to read and were skipped',
|
||
'input.text.truncated':
|
||
'Text attachment "{{name}}" exceeds 512KB and was truncated to the first 512KB',
|
||
'input.text.truncatedNote':
|
||
'\n\n[... File content truncated: original size {{size}}, only the first {{limit}} included. Process in segments if you need the full content ...]',
|
||
'input.toast.toolsLoading': 'Tools are still loading, please wait...',
|
||
'input.slash.tool': 'Pick a tool',
|
||
'input.slash.memory': 'Search memory',
|
||
'input.slash.clear': 'Clear session',
|
||
'input.slash.export': 'Export Markdown',
|
||
|
||
// ===== LLM 配置(LLMSettings)=====
|
||
'llm.title': 'LLM Configuration',
|
||
'llm.loading': 'Loading...',
|
||
'llm.provider.label': 'Provider',
|
||
'llm.baseURL': 'API Base URL',
|
||
'llm.baseURL.error': 'Must start with http:// or https://',
|
||
'llm.model.label': 'Model Name',
|
||
'llm.model.placeholder': 'e.g. deepseek-v4-pro, gpt-4o, claude-sonnet-4-5',
|
||
'llm.model.space': 'Model name must not contain spaces',
|
||
'llm.models.load': 'Fetch model list',
|
||
'llm.models.hint': 'Queries the saved configuration (save changes first)',
|
||
'llm.models.hint.unloaded': 'Type manually, or fetch the model list below',
|
||
'llm.models.failed': 'Failed to fetch model list',
|
||
'llm.multimodal.label': 'Enable multimodal (image input)',
|
||
'llm.multimodal.helper':
|
||
'Allows uploading images; DeepSeek requires a vision model. Images from history are replayed (last 10)',
|
||
'llm.apiKey.label': 'API Key',
|
||
'llm.apiKey.required': 'Required — missing {{provider}} API Key will result in 401',
|
||
'llm.numCtx.label': 'Context length (num_ctx)',
|
||
'llm.numCtx.placeholder': 'Default decided by the model (e.g. 2048, 4096, 128000)',
|
||
'llm.numCtx.error': 'Minimum is 512',
|
||
'llm.ctxWindow.label': 'Context window (contextWindow)',
|
||
'llm.ctxWindow.placeholder': 'e.g. 64000, 128000, 1000000',
|
||
'llm.ctxWindow.minError': 'Minimum is 4096',
|
||
'llm.ctxWindow.helper': 'Used for context-compression decisions; not sent to the API',
|
||
'llm.ctxWindow.mimoHelper': 'Default 1000000 (1M), used for compression decisions',
|
||
'llm.ctxWindow.oaHelper': 'gpt-4o defaults to 128K, gpt-4.1 to 1M',
|
||
'llm.ctxWindow.anthropicHelper': 'Claude defaults to 200K',
|
||
// v0.8.0 FEAT-1: max output tokens (llm.maxTokens, sent per request)
|
||
'llm.maxTokens.label': 'Max output tokens',
|
||
'llm.maxTokens.helper':
|
||
'Maximum tokens per response (reasoning included); thinking consumes this budget',
|
||
'llm.maxTokens.minError': 'Minimum is 256',
|
||
'llm.maxTokens.exceedCap':
|
||
'This model caps output at {{cap}} — the saved value will be clamped to the model limit',
|
||
'llm.maxTokens.capInfo': 'Model output cap: {{cap}} tokens',
|
||
'llm.thinking.unsupported':
|
||
'Model metadata marks thinking as unsupported — your setting is still sent; if reasoning exhausts the output budget, one degraded retry (thinking off) runs automatically',
|
||
'llm.pull.title': 'Download Ollama model',
|
||
'llm.pull.placeholder': 'Model name, e.g. qwen3:8b',
|
||
'llm.pull.download': 'Download',
|
||
'llm.pull.cancel': 'Cancel',
|
||
'llm.pull.helper':
|
||
'Pull a model from the Ollama server (large downloads depend on network; cancellable). Fetch the list afterwards',
|
||
'llm.pull.done': 'Model {{name}} downloaded',
|
||
'llm.pull.failed': 'Model download failed: {{message}}',
|
||
'llm.balance.label': 'Account Balance',
|
||
'llm.balance.querying': 'Querying...',
|
||
'llm.balance.unqueried': 'Not queried (requires a saved API Key)',
|
||
'llm.balance.granted': '(granted {{granted}} + topped up {{topped}})',
|
||
'llm.balance.queryFailed': 'Query failed',
|
||
'llm.fallback.title': 'Failover (optional)',
|
||
'llm.fallback.helper':
|
||
'Switch to the fallback provider when the primary fails (retries exhausted or invalid key). Leave empty to disable.',
|
||
'llm.fallback.provider': 'Fallback Provider',
|
||
'llm.fallback.disabled': 'Disabled',
|
||
'llm.fallback.baseURL': 'Fallback Base URL',
|
||
'llm.fallback.model': 'Fallback Model Name',
|
||
'llm.fallback.apiKey': 'Fallback API Key',
|
||
'llm.save': 'Save Configuration',
|
||
'llm.saving': 'Saving...',
|
||
'llm.save.blocked': 'Fix form errors before saving',
|
||
'llm.save.blockedToast': 'Please fix the form errors before saving',
|
||
'llm.save.success': 'Configuration saved',
|
||
'llm.save.failed': 'Save failed: {{message}}',
|
||
'llm.api.unavailable': 'Configuration API unavailable',
|
||
'llm.save.failed.generic': 'Failed to save configuration',
|
||
|
||
// ===== 记忆库(MemoryViewer)=====
|
||
'memory.search.title': 'Memory Search',
|
||
'memory.list.title': 'Memory Store',
|
||
'memory.results': '{{count}} results',
|
||
'memory.total': '{{count}} items',
|
||
'memory.search.placeholder': 'Search memories...',
|
||
'memory.search.clear': 'Clear',
|
||
'memory.searching': 'Searching...',
|
||
'memory.search.empty': 'No matches',
|
||
'memory.empty': 'No memories yet',
|
||
'memory.loadFailed': 'Failed to load memories',
|
||
'memory.deleteFailed': 'Delete failed',
|
||
'memory.type.episodic': 'Episodic',
|
||
'memory.type.semantic': 'Semantic',
|
||
'memory.type.working': 'Working',
|
||
|
||
// ===== 引导向导(OnboardingWizard)=====
|
||
'onboarding.step.welcome': 'Welcome',
|
||
'onboarding.step.llm': 'Configure LLM',
|
||
'onboarding.step.agent': 'Customize Agent',
|
||
'onboarding.step.workspace': 'Workspace',
|
||
'onboarding.step.done': 'Get Started',
|
||
'onboarding.prev': 'Back',
|
||
'onboarding.next': 'Next',
|
||
'onboarding.finish': 'Get Started',
|
||
'onboarding.welcome.title': 'Welcome to MetonaAI Desktop',
|
||
'onboarding.welcome.body':
|
||
'A production-grade AI Agent desktop app with multi-turn chat, tool calling, memory, and MCP integration.',
|
||
'onboarding.welcome.hint': "Let's spend 1 minute on initial setup.",
|
||
'onboarding.llm.title': 'Configure LLM Provider',
|
||
'onboarding.llm.body':
|
||
'Pick a provider and fill in API details. Base URL and model accept any input.',
|
||
'onboarding.llm.multimodal.label': 'Enable multimodal (image input)',
|
||
'onboarding.llm.multimodal.helper': 'Allows uploading images; DeepSeek requires a vision model',
|
||
'onboarding.llm.apiKey.placeholder': 'sk-... (leave empty for local models)',
|
||
'onboarding.llm.ctx.ollama': 'Context length (num_ctx)',
|
||
'onboarding.llm.ctx.window': 'Context window (contextWindow)',
|
||
'onboarding.llm.ctx.ollamaPlaceholder': 'Default decided by the model (e.g. 2048, 4096, 128000)',
|
||
'onboarding.llm.ctx.placeholder': 'e.g. 64000, 128000, 1000000',
|
||
'onboarding.llm.ctx.helper': 'Used for context-compression decisions; not sent to the API',
|
||
'onboarding.llm.ctx.minError': 'Minimum is {{min}}',
|
||
'onboarding.agent.title': 'Customize Agent',
|
||
'onboarding.agent.body':
|
||
'Edit SOUL.md in the workspace to define the agent identity and personality.',
|
||
'onboarding.agent.soulLabel': 'SOUL.md — define the agent identity, personality, and core values',
|
||
'onboarding.agent.soulHint': 'You can do this later in the workspace directory.',
|
||
'onboarding.workspace.title': 'Workspace',
|
||
'onboarding.workspace.body': 'Choose a workspace directory, or keep the default.',
|
||
'onboarding.workspace.pick': 'Choose Folder',
|
||
'onboarding.workspace.placeholder': '~/MetonaWorkspaces/default/',
|
||
'onboarding.workspace.helper':
|
||
'Contains the two required files SOUL.md and MEMORY.md, auto-created on first open.',
|
||
'onboarding.done.title': 'All set!',
|
||
'onboarding.done.body': 'MetonaAI Desktop is ready. Start chatting with your AI agent!',
|
||
'onboarding.done.hint': 'Press Ctrl+Enter to send; type / to see commands',
|
||
'onboarding.toast.saveFailed': 'Failed to save configuration, please retry',
|
||
'onboarding.toast.saveFailedWithReason': 'Failed to save configuration: {{message}}',
|
||
'onboarding.toast.folderFailed': 'Failed to choose folder',
|
||
|
||
// ===== Common =====
|
||
'common.loading': 'Loading...',
|
||
|
||
// ===== Command Palette =====
|
||
'command.newSession': 'New Session',
|
||
'command.newSessionDesc': 'Create a new chat session',
|
||
'command.createFailed': 'Failed to create session',
|
||
'command.clearSession': 'Clear current session',
|
||
'command.openSettings': 'Open Settings',
|
||
'command.messageCount': '{{count}} messages',
|
||
'command.searchPlaceholder': 'Search sessions and commands...',
|
||
'command.noMatch': 'No matches',
|
||
'command.navHint': '↑↓ Navigate',
|
||
'command.selectHint': '↵ Select',
|
||
'command.closeHint': 'Esc Close',
|
||
|
||
// ===== Context Menu =====
|
||
'contextMenu.confirm': 'Confirm',
|
||
'contextMenu.prompt': 'Input',
|
||
'contextMenu.ok': 'OK',
|
||
'contextMenu.toast.copyFailed': 'Copy failed',
|
||
'contextMenu.copy': 'Copy',
|
||
'contextMenu.quote': 'Quote reply',
|
||
'contextMenu.regenerate': 'Regenerate',
|
||
'contextMenu.rename': 'Rename',
|
||
'contextMenu.renamePromptLabel': 'New session name',
|
||
'contextMenu.renamePromptTitle': 'Rename Session',
|
||
'contextMenu.toast.renameFailed': 'Rename failed',
|
||
'contextMenu.pin': 'Pin',
|
||
'contextMenu.unpin': 'Unpin',
|
||
'contextMenu.toast.pinFailed': 'Pin failed',
|
||
'contextMenu.archive': 'Archive',
|
||
'contextMenu.unarchive': 'Unarchive',
|
||
'contextMenu.toast.archiveFailed': 'Archive failed',
|
||
'contextMenu.exportJson': 'Export JSON',
|
||
'contextMenu.exportMarkdown': 'Export Markdown',
|
||
'contextMenu.sessionExportTitle': 'Session Export',
|
||
'contextMenu.toast.exportFailed': 'Export failed',
|
||
'contextMenu.deleteConfirmBody': 'Delete this session? This cannot be undone.',
|
||
'contextMenu.toast.deleteFailed': 'Delete failed',
|
||
|
||
// ===== Chat / assistant / messageList / streaming / thought / toolCall / toolResult / userMessage =====
|
||
'chat.export.title': 'Session Export',
|
||
'assistant.thinking': 'Thinking...',
|
||
'assistant.thinkingLabel': 'Thought process',
|
||
'assistant.generating': 'Generating reply...',
|
||
'assistant.toolCalls': 'Tool calls',
|
||
'assistant.reply': 'Reply',
|
||
'assistant.copy': 'Copy',
|
||
'assistant.copied': 'Copied',
|
||
'messageList.subtitle': 'A production-grade AI Agent desktop app',
|
||
'messageList.emptyHint': 'Agent ready · pick a provider to start chatting',
|
||
'messageList.ariaLabel': 'Chat message list',
|
||
'streaming.connecting': 'Connecting to AI...',
|
||
'thought.thinkingLabel': 'Thought process',
|
||
'toolCall.status.pending': 'Waiting',
|
||
'toolCall.status.executing': 'Executing',
|
||
'toolCall.status.success': 'Success',
|
||
'toolCall.status.error': 'Failed',
|
||
'toolCall.status.blocked': 'Blocked',
|
||
'toolResult.title': '{{name}} result',
|
||
'userMessage.saveOnly': 'Save only',
|
||
'userMessage.saveAndResend': 'Save & resend',
|
||
'userMessage.resendHint': 'Resending deletes all messages after this one · Ctrl+Enter',
|
||
|
||
// ===== Error Boundary =====
|
||
'errorBoundary.renderFailed': 'Component render failed',
|
||
'errorBoundary.unknownError': 'Unknown error',
|
||
'errorBoundary.retry': 'Retry',
|
||
|
||
// ===== Detail Panel =====
|
||
'detailPanel.error.trace': 'Failed to render Trace',
|
||
'detailPanel.error.memory': 'Failed to render Memory',
|
||
'detailPanel.error.tasks': 'Failed to render Tasks',
|
||
'detailPanel.error.workspace': 'Failed to render Workspace',
|
||
|
||
// ===== Header =====
|
||
'header.theme.light': 'Light theme',
|
||
'header.theme.dark': 'Dark theme',
|
||
'header.theme.auto': 'System theme',
|
||
'header.hideSidebar': 'Hide sidebar',
|
||
'header.showSidebar': 'Show sidebar',
|
||
'header.hideDetail': 'Hide detail panel',
|
||
'header.showDetail': 'Show detail panel',
|
||
'header.exitFocus': 'Exit focus mode',
|
||
'header.enterFocus': 'Enter focus mode',
|
||
'header.settings': 'Settings',
|
||
|
||
// ===== Agent Monitor (supplement) =====
|
||
'monitor.iterations': ' · {{count}} round(s)',
|
||
|
||
// ===== Agent Settings =====
|
||
'settings.agent.title': 'Agent Configuration',
|
||
'settings.agent.maxIterations': 'Max iterations',
|
||
'settings.agent.totalTimeout': 'Total timeout (seconds)',
|
||
'settings.agent.toolExecTimeout': 'Tool execution timeout (seconds)',
|
||
'settings.agent.toolExecTimeoutHelper':
|
||
'Maximum duration for a single tool call; auto-terminated on timeout (min 10s, no upper limit)',
|
||
'settings.agent.confirmTimeout': 'Tool confirmation timeout (seconds)',
|
||
'settings.agent.confirmTimeoutHelper':
|
||
'If the user does not respond to a tool confirmation, it is auto-denied after the timeout (30–600s)',
|
||
'settings.agent.enableThinking': 'Enable thinking mode',
|
||
'settings.agent.thinkingEffort': 'Thinking effort',
|
||
'settings.agent.enableReflection': 'Enable reflection phase (REFLECTING)',
|
||
'settings.agent.enableReflectionHelper':
|
||
'Enters a reflection state after each round of tool execution; logs warnings on failed results (does not block execution)',
|
||
|
||
// ===== Appearance Settings =====
|
||
'settings.appearance.title': 'Appearance',
|
||
'settings.appearance.theme': 'Theme',
|
||
'settings.appearance.dark': 'Dark',
|
||
'settings.appearance.light': 'Light',
|
||
'settings.appearance.auto': 'System',
|
||
'settings.appearance.locale': 'Interface language',
|
||
'settings.appearance.localeZhCN': '简体中文',
|
||
'settings.appearance.localeEnUS': 'English',
|
||
'settings.appearance.localeHelper':
|
||
'Takes effect immediately; migrated UI (system messages / tool confirmation dialog / sidebar / status bar / agent status) follows the selected language',
|
||
|
||
// ===== Logs & Data Settings =====
|
||
'settings.logs.title': 'Logs & Data',
|
||
'settings.logs.logLevel': 'Log level',
|
||
'settings.logs.logFile': 'Log file',
|
||
'settings.logs.pathLoading': 'Fetching path...',
|
||
'settings.logs.pathUnavailable': 'Path unavailable',
|
||
'settings.logs.openLogFolder': 'Open log folder',
|
||
'settings.logs.copied': 'Copied',
|
||
'settings.logs.copyPath': 'Copy path',
|
||
'settings.logs.copyFailed': 'Copy failed',
|
||
'settings.logs.openFailed': 'Failed to open: {{message}}',
|
||
'settings.logs.logLevelHelper':
|
||
'Log level changes take effect after restart. Log files rotate by date; old logs are kept in the logs directory.',
|
||
'settings.logs.dataManagement': 'Data management',
|
||
'settings.logs.exportAllData': '📦 Export all data (JSON)',
|
||
'settings.logs.exportFailed': 'Export failed: {{message}}',
|
||
'settings.logs.exporting': 'Exporting...',
|
||
'settings.logs.exportAuditJsonl': '📋 Export audit (JSONL)',
|
||
'settings.logs.exportAuditCsv': '📊 Export audit (CSV)',
|
||
'settings.logs.auditExported': 'Exported {{count}} audit record(s)',
|
||
'settings.logs.auditExportFailed': 'Audit export failed: {{message}}',
|
||
'settings.logs.clearing': 'Clearing...',
|
||
'settings.logs.clearSessions': '🗑️ Clear all sessions',
|
||
'settings.logs.clearMemories': '🗑️ Clear all memories',
|
||
'settings.logs.clearAuditLogs': '🗑️ Clear audit logs',
|
||
'settings.logs.clear': 'Clear',
|
||
'settings.logs.clearFailed': 'Failed: {{message}}',
|
||
'settings.logs.confirmClearTitle': 'Confirm clear',
|
||
'settings.logs.confirmClearBody': 'Clear {{label}}? This cannot be undone.',
|
||
'settings.logs.cleared': '{{label}} cleared',
|
||
'settings.logs.data.sessions': 'all sessions',
|
||
'settings.logs.data.memories': 'all memories',
|
||
'settings.logs.data.auditLogs': 'audit logs',
|
||
'settings.logs.traceFilesTitle': 'Session recording files (TRACE JSONL)',
|
||
// v0.8.0 P2-3: App update
|
||
'settings.logs.update.title': 'App update',
|
||
'settings.logs.update.check': 'Check for updates',
|
||
'settings.logs.update.checking': 'Checking…',
|
||
'settings.logs.update.downloadInstall': 'Download & install',
|
||
'settings.logs.update.installing': 'Preparing to install…',
|
||
'settings.logs.update.available':
|
||
'Version {{version}} is available — click "Download & install" to upgrade',
|
||
'settings.logs.update.upToDate': 'Up to date ({{version}})',
|
||
'settings.logs.update.disabled': 'No update feed configured (app.updateFeedUrl)',
|
||
'settings.logs.update.error': 'Update failed: {{message}}',
|
||
'settings.logs.update.downloaded': 'Download complete — restarting to install…',
|
||
'settings.logs.traceStats':
|
||
'{{count}} file(s) · {{size}} total (retention: last 200, auto-cleaned on startup)',
|
||
'settings.logs.statsLoading': 'Computing...',
|
||
'settings.logs.refreshStats': 'Refresh stats',
|
||
'settings.logs.pruneOldFiles': 'Clear old recordings',
|
||
'settings.logs.pruneDone': 'Cleared {{count}} old recording file(s) (keeping the last 200)',
|
||
'settings.logs.pruneFailed': 'Clear failed: {{message}}',
|
||
'settings.logs.healthTitle': 'Runtime health (SLO / health checks)',
|
||
'settings.logs.noSnapshot': 'No snapshot yet',
|
||
'settings.logs.health.errorRate': 'Request error rate (5-min window)',
|
||
'settings.logs.health.errorRateValue': '{{pct}} ({{count}} requests)',
|
||
'settings.logs.health.latency': 'Latency P50 / P95 / P99',
|
||
'settings.logs.health.burnRate': 'SLO burn rate (target 99.9%)',
|
||
'settings.logs.health.check': 'Health checks',
|
||
'settings.logs.health.allPassed': 'All passed',
|
||
'settings.logs.health.abnormal': 'Abnormal: {{checks}}',
|
||
'settings.logs.health.notRunYet': 'Not run since startup (interval 60s)',
|
||
'settings.logs.health.chainVerify': 'Audit log chain verification',
|
||
'settings.logs.health.chainValid': 'Passed ({{verified}}/{{total}})',
|
||
'settings.logs.health.chainTampered': 'Tampered! First anomaly at record #{{index}}',
|
||
'settings.logs.health.verifyChainBtn': 'Verify audit chain',
|
||
'settings.logs.verifyFailed': 'Verification failed: {{message}}',
|
||
|
||
// ===== MCP Settings =====
|
||
'settings.mcp.title': 'MCP Services',
|
||
'settings.mcp.empty': 'No MCP servers yet',
|
||
'settings.mcp.toolCount': '{{count}} tools',
|
||
'settings.mcp.connect': 'Connect',
|
||
'settings.mcp.disconnect': 'Disconnect',
|
||
'settings.mcp.remove': 'Remove',
|
||
'settings.mcp.add': 'Add',
|
||
'settings.mcp.addServer': '+ Add MCP server',
|
||
'settings.mcp.serverName': 'Server name',
|
||
'settings.mcp.localStdio': 'Local (stdio)',
|
||
'settings.mcp.remoteHttp': 'Remote (HTTP)',
|
||
'settings.mcp.commandPlaceholder': 'Command path (e.g. npx / node / python)',
|
||
'settings.mcp.argsPlaceholder': 'Arguments (space-separated)',
|
||
'settings.mcp.urlPlaceholder': 'Streamable HTTP URL (e.g. https://example.com/mcp)',
|
||
'settings.mcp.headersPlaceholder':
|
||
'Custom headers (JSON, optional), e.g. {"Authorization": "Bearer xxx"}',
|
||
'settings.mcp.headersInvalid':
|
||
'Custom headers must be a valid JSON object, e.g. {"Authorization": "Bearer xxx"}',
|
||
'settings.mcp.addFailed': 'Failed to add MCP server',
|
||
'settings.mcp.addFailedMsg': 'Failed to add MCP server: {{message}}',
|
||
'settings.mcp.removeFailed': 'Remove failed',
|
||
// v0.8.0 P2-5: MCP discovery
|
||
'settings.mcp.contents.show': 'Show resources & prompts',
|
||
'settings.mcp.contents.hide': 'Hide resources & prompts',
|
||
'settings.mcp.contents.empty': 'This server does not declare Resources / Prompts capabilities',
|
||
'settings.mcp.removeFailedMsg': 'Remove failed: {{message}}',
|
||
'settings.mcp.toggleFailed': 'Operation failed',
|
||
'settings.mcp.toggleFailedMsg': 'Operation failed: {{message}}',
|
||
'settings.mcp.removeConfirmTitle': 'Confirm removal',
|
||
'settings.mcp.removeConfirmBody': 'Remove MCP server "{{name}}"? This cannot be undone.',
|
||
|
||
// ===== SearXNG Settings =====
|
||
'settings.searxng.tabTitle': 'SearXNG',
|
||
'settings.searxng.title': 'SearXNG Meta Search',
|
||
'settings.searxng.description':
|
||
'SearXNG is an open-source metasearch engine aggregating 70+ search engines. When enabled it replaces the built-in four-engine channel; otherwise it falls back to Bing + Baidu + Sogou + 360.',
|
||
'settings.searxng.enabled': 'Enabled',
|
||
'settings.searxng.disabled': 'Disabled',
|
||
'settings.searxng.enableAria': 'Enable SearXNG',
|
||
'settings.searxng.enable': 'Enable SearXNG',
|
||
'settings.searxng.urlLabel': 'API URL',
|
||
'settings.searxng.urlPlaceholder': 'e.g. https://searxng.example.com',
|
||
'settings.searxng.urlError': 'Must start with http:// or https://',
|
||
'settings.searxng.urlHelper': 'Instance root URL (without the /search path)',
|
||
'settings.searxng.test': 'Test connection',
|
||
'settings.searxng.testSuccess': 'Connection successful ({{latency}}ms)',
|
||
'settings.searxng.testFailedHttp': 'Connection failed (HTTP {{code}})',
|
||
'settings.searxng.enginesLabel': 'Search engines (comma-separated)',
|
||
'settings.searxng.enginesPlaceholder':
|
||
'e.g. google,bing,duckduckgo (empty uses instance default)',
|
||
'settings.searxng.language': 'Language',
|
||
'settings.searxng.langZhCN': '简体中文',
|
||
'settings.searxng.langZhTW': '繁體中文',
|
||
'settings.searxng.langAuto': 'Auto-detect',
|
||
'settings.searxng.safesearch': 'Safe search',
|
||
'settings.searxng.safeOff': 'Off',
|
||
'settings.searxng.safeMedium': 'Moderate',
|
||
'settings.searxng.safeStrict': 'Strict',
|
||
'settings.searxng.timeRange': 'Time range',
|
||
'settings.searxng.timeAny': 'Any',
|
||
'settings.searxng.timeDay': 'A day',
|
||
'settings.searxng.timeWeek': 'A week',
|
||
'settings.searxng.timeMonth': 'A month',
|
||
'settings.searxng.timeYear': 'A year',
|
||
'settings.searxng.format': 'Result format',
|
||
'settings.searxng.formatJson': 'JSON (structured parsing)',
|
||
'settings.searxng.formatHtml': 'HTML (raw page)',
|
||
'settings.searxng.maxResults': 'Max results',
|
||
'settings.searxng.maxResultsPlaceholder': '0 uses the default',
|
||
'settings.searxng.fetchCount': 'Auto-fetch count',
|
||
'settings.searxng.fetchCountPlaceholder': '0 lets the AI decide',
|
||
'settings.searxng.fetchMode': 'Fetch mode',
|
||
'settings.searxng.fetchSequential': 'Sequential fetch',
|
||
'settings.searxng.fetchRandom': 'Random fetch',
|
||
'settings.searxng.authTitle': 'Authentication',
|
||
'settings.searxng.authType': 'Auth type',
|
||
'settings.searxng.authToken': 'Token',
|
||
'settings.searxng.authUserPass': 'Username:password',
|
||
'settings.searxng.authTokenPlaceholder': 'Raw access token',
|
||
'settings.searxng.authUserPassPlaceholder': 'username:password',
|
||
'settings.searxng.hideKey': 'Hide key',
|
||
'settings.searxng.showKey': 'Show key',
|
||
'settings.searxng.authBearerHelper':
|
||
'Bearer: paste the raw token; it is passed through to the Authorization header. Recommended with HTTPS.',
|
||
'settings.searxng.authBasicHelper':
|
||
'Basic: enter a plaintext username:password pair; the app Base64-encodes it. HTTPS is required.',
|
||
'settings.searxng.saved': 'SearXNG configuration saved',
|
||
'settings.searxng.saveFailed': 'Save failed',
|
||
'settings.searxng.toggleFailed': 'Failed to save the toggle',
|
||
'settings.searxng.saving': 'Saving...',
|
||
'settings.searxng.saveChanges': 'Save changes',
|
||
'settings.searxng.dirty': 'You have unsaved changes',
|
||
'settings.searxng.savedNotice': 'Saved',
|
||
'settings.searxng.loading': 'Loading configuration...',
|
||
|
||
// ===== Settings Modal =====
|
||
'settings.title': 'Settings',
|
||
'settings.tabs.workspace': 'Workspace',
|
||
'settings.tabs.llm': 'LLM Configuration',
|
||
'settings.tabs.agent': 'Agent Configuration',
|
||
'settings.tabs.tools': 'Tools',
|
||
'settings.tabs.mcp': 'MCP Services',
|
||
'settings.tabs.searxng': 'SearXNG',
|
||
'settings.tabs.appearance': 'Appearance',
|
||
'settings.tabs.logs': 'Logs & Data',
|
||
'settings.error.workspace': 'Failed to render workspace settings',
|
||
'settings.error.llm': 'Failed to render LLM settings',
|
||
'settings.error.agent': 'Failed to render agent settings',
|
||
'settings.error.tools': 'Failed to render tool settings',
|
||
'settings.error.mcp': 'Failed to render MCP settings',
|
||
'settings.error.searxng': 'Failed to render SearXNG settings',
|
||
'settings.error.appearance': 'Failed to render appearance settings',
|
||
'settings.error.logs': 'Failed to render logs & data settings',
|
||
'settings.saveFailed': 'Failed to save configuration',
|
||
|
||
// ===== Tools Settings =====
|
||
'settings.tools.title': 'Tools',
|
||
'settings.tools.toggleFailed': 'Failed to toggle tool',
|
||
'settings.tools.autoExecFailed': 'Failed to set auto-execute',
|
||
'settings.tools.autoExecTitle': 'Auto-execute tools',
|
||
'settings.tools.autoExecCount': '{{count}}',
|
||
'settings.tools.autoExecHelper':
|
||
'Tools set to auto-execute skip the user confirmation step and run directly. This setting persists across sessions.',
|
||
'settings.tools.noAutoExec': 'No auto-execute tools yet',
|
||
'settings.tools.autoChip': 'Auto',
|
||
'settings.tools.cancelAuto': 'Cancel auto',
|
||
'settings.tools.availableAutoExec':
|
||
'Available for auto-execute (currently requires confirmation)',
|
||
'settings.tools.setAuto': 'Set auto',
|
||
'settings.tools.proxyTitle': 'Network proxy',
|
||
'settings.tools.proxyLabel': 'Proxy URL (optional)',
|
||
'settings.tools.proxyPlaceholder': 'http://127.0.0.1:7890 or socks5://… (empty = direct)',
|
||
'settings.tools.proxyError': 'Must start with http://, https://, socks5:// or socks4://',
|
||
'settings.tools.proxyHelper':
|
||
'Applies to all network requests from the Chromium session and the main process; falls back to the HTTPS_PROXY environment variable when empty.',
|
||
|
||
// ===== Workspace Settings =====
|
||
'settings.workspace.title': 'Workspace',
|
||
'settings.workspace.description':
|
||
"The workspace is Metona's organizational core, containing the two required files SOUL.md and MEMORY.md.",
|
||
'settings.workspace.placeholder': '~/MetonaWorkspaces/default/',
|
||
'settings.workspace.checking': 'Checking...',
|
||
'settings.workspace.check': 'Check',
|
||
'settings.workspace.checkingInProgress': 'Checking workspace...',
|
||
'settings.workspace.invalidPath': 'Invalid path: {{reason}}',
|
||
'settings.workspace.openInFileManager': '📂 Open in file manager',
|
||
'settings.workspace.openFolderFailed': 'Failed to open folder',
|
||
'settings.workspace.targetWorkspace': 'Target workspace: {{path}}',
|
||
'settings.workspace.newWorkspace':
|
||
'New workspace — the 2 required files (SOUL.md, MEMORY.md) will be auto-created on switch',
|
||
'settings.workspace.missingFiles':
|
||
'Directory exists but {{count}} file(s) are missing: {{files}}. Missing files will be auto-created.',
|
||
'settings.workspace.existingWorkspace':
|
||
'Existing workspace — the 2 required files are ready; existing configuration will be loaded.',
|
||
'settings.workspace.inheritFromCurrent': 'Inherit from the current workspace:',
|
||
'settings.workspace.inheritSoul': 'SOUL.md (identity & role definition)',
|
||
'settings.workspace.inheritDatabase':
|
||
'Database agent.db (sessions/messages/memories/Trace history)',
|
||
'settings.workspace.inheritDatabaseHelper':
|
||
'When checked, all history from the current workspace is copied to the new one (exported atomically via the SQLite backup API)',
|
||
'settings.workspace.memoryNotInherited':
|
||
'MEMORY.md is not inherited (memories are bound to the workspace project context)',
|
||
'settings.workspace.applying': 'Applying...',
|
||
'settings.workspace.confirmSwitch': 'Confirm switch',
|
||
'settings.workspace.restartHint':
|
||
'Changing the workspace path requires an app restart to take effect.',
|
||
'settings.workspace.switchedTitle': 'Workspace switched',
|
||
'settings.workspace.switchedBody': 'The workspace has been updated to:',
|
||
'settings.workspace.restartQuestion':
|
||
'An app restart is required to load the new workspace configuration and files. Restart now?',
|
||
'settings.workspace.restartLater': 'Restart later',
|
||
'settings.workspace.restartNow': 'Restart now',
|
||
'settings.workspace.dbIntegrityFailed': 'Source database verification failed: {{message}}',
|
||
'settings.workspace.dbCorrupted': 'Source database is corrupted ({{detail}}); cannot inherit',
|
||
'settings.workspace.dbIntegrityError': 'Source database verification error: {{message}}',
|
||
'settings.workspace.inheritPartialFailed':
|
||
'Some files failed to inherit: {{message}} — check manually',
|
||
'settings.workspace.switchFailed': 'Failed to switch workspace: {{message}}',
|
||
|
||
// ===== Task List =====
|
||
'taskList.title': 'Tasks',
|
||
'taskList.count': '{{count}} item(s)',
|
||
'taskList.addTask': 'Add task',
|
||
'taskList.cancelAdd': 'Cancel add',
|
||
'taskList.titlePlaceholder': 'Task title...',
|
||
'taskList.creating': '...',
|
||
'taskList.create': 'Create',
|
||
'taskList.cancelAddTask': 'Cancel adding task',
|
||
'taskList.selectSession': 'Select or create a session first',
|
||
'taskList.titleRequired': 'Task title cannot be empty',
|
||
'taskList.createFailed': 'Failed to create task',
|
||
'taskList.updateFailed': 'Failed to update task',
|
||
'taskList.deleteFailed': 'Failed to delete task',
|
||
'taskList.loadFailed': 'Failed to load tasks',
|
||
'taskList.selectSessionHint': 'Select a session first',
|
||
'taskList.empty': 'No tasks yet — click + to create',
|
||
'taskList.noDescription': 'No description',
|
||
'taskList.status.pending': 'Pending',
|
||
'taskList.status.inProgress': 'In progress',
|
||
'taskList.status.completed': 'Completed',
|
||
'taskList.status.blocked': 'Blocked',
|
||
'taskList.status.cancelled': 'Cancelled',
|
||
'taskList.priority.low': 'Low',
|
||
'taskList.priority.medium': 'Medium',
|
||
'taskList.priority.high': 'High',
|
||
'taskList.priority.critical': 'Critical',
|
||
|
||
// ===== Token Usage =====
|
||
'trace.token.usage': 'Token Usage',
|
||
'trace.token.input': 'Input',
|
||
'trace.token.output': 'Output',
|
||
'trace.token.total': 'Total usage',
|
||
'trace.token.context': 'Context usage',
|
||
'trace.token.compressedSaved': 'Saved by compression',
|
||
|
||
// ===== Trace Step (TraceStep / constants) =====
|
||
'trace.step.toolCalls': 'Tool calls',
|
||
'trace.state.INIT': 'Initializing',
|
||
'trace.state.THINKING': 'Thinking',
|
||
'trace.state.PARSING': 'Parsing',
|
||
'trace.state.EXECUTING': 'Executing',
|
||
'trace.state.OBSERVING': 'Observing',
|
||
'trace.state.REFLECTING': 'Reflecting',
|
||
'trace.state.COMPRESSING': 'Compressing',
|
||
'trace.state.TERMINATED': 'Terminated',
|
||
|
||
// ===== Trace Viewer =====
|
||
'trace.viewer.rounds': '{{count}} round(s)',
|
||
'trace.viewer.waiting': 'Waiting for agent activity...',
|
||
'trace.viewer.roundNumber': 'Round {{index}}',
|
||
'trace.viewer.inProgress': 'In progress',
|
||
'trace.viewer.completed': 'Completed',
|
||
'trace.viewer.steps': '{{count}} step(s)',
|
||
|
||
// ===== Workspace Viewer =====
|
||
'workspace.currentWorkspace': 'Current workspace',
|
||
'workspace.openInFileManager': 'Open in file manager',
|
||
'workspace.showInFileManager': 'Show in file manager',
|
||
'workspace.coreFiles': 'Core files ({{count}}/{{total}})',
|
||
'workspace.emptyFile': '(empty file)',
|
||
'workspace.fileMissing': 'File does not exist',
|
||
'workspace.autoDirs': 'Auto directories',
|
||
'workspace.dirFileCount': '{{count}} files',
|
||
'workspace.dirMissing': 'Does not exist',
|
||
'workspace.noData': 'No data',
|
||
'workspace.loadFailed': 'Failed to load workspace info',
|
||
'workspace.openFailed': 'Failed to open folder',
|
||
});
|