From fd66d80543702106a4ee45eebb3ad4e38cfea320 Mon Sep 17 00:00:00 2001 From: bowenliang123 Date: Sun, 11 Oct 2026 13:55:42 +0800 Subject: [PATCH] refactor(client): split the i18n dictionaries under the 1000-line cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i18n.ts had grown past the repo's 1000-line limit with the two dictionaries inline (the prefix/suffix keys pushed it further). zh — with DictKey, the key-set source of truth — and en, pinned to it at compile time, move to their own files; i18n.ts keeps the shared Translate type and re-exports. --- src/client/i18n.ts | 1086 +----------------------------------------- src/client/i18nEn.ts | 539 +++++++++++++++++++++ src/client/i18nZh.ts | 542 +++++++++++++++++++++ 3 files changed, 1086 insertions(+), 1081 deletions(-) create mode 100644 src/client/i18nEn.ts create mode 100644 src/client/i18nZh.ts diff --git a/src/client/i18n.ts b/src/client/i18n.ts index 7d2339c..b08337d 100644 --- a/src/client/i18n.ts +++ b/src/client/i18n.ts @@ -1,1086 +1,10 @@ -/** Bilingual dictionaries (zh/en) for every UI string; missing keys fall through the harness - * locale chain (active → en → common → the key). - * - * zh is the key-set source of truth, following the harness's own idiom — see - * `packages/client/ui-conversation/src/client/locales.ts` in deepseek-harness. */ +/** Locale registry for every UI string; missing keys fall through the harness + * locale chain (active → en → common → the key). The dictionaries live in + * `i18nZh.ts` (the key-set source of truth) and `i18nEn.ts`. */ /** Keyed `string`, not a {@link DictKey} union: call sites compose keys at runtime (`'form.' + form`, * a weekday template), and typing the union would mean a cast at each one. */ export type Translate = (key: string, params?: Record) => string -export const DICT_ZH = { - 'tab.context': '上下文', - 'tab.fleet': '编队', - 'sidebar.guideDescription': '查看上下文的构成、统计、演变。', - 'cat.system': '系统提示词', - 'cat.tools': '工具定义', - 'cat.user': '用户消息', - 'cat.inject': '注入内容', - 'cat.skill': '技能注入', - 'cat.assistant': '助手消息', - 'cat.tool': '工具结果', - 'overview.title': '当前上下文', - 'overview.estimate': 'tokens(估算)', - 'overview.free': '剩余窗口', - 'overview.used': '上下文已用', - 'overview.ofUsed': '占已用上下文', - 'overview.compactReserve': '自动压缩预留:占用达 {pct}% 窗口时触发压缩,此区域一般不实际占用', - 'stats.title': '上下文统计', - 'stats.session': '当前会话', - 'stats.turns': '轮次', - 'stats.steps': '步数', - 'stats.answers': '模型回复', - 'stats.skills': '技能加载', - 'stats.skillsJump': '在上下文浏览器中展开技能注入', - 'stats.answersJump': '在上下文浏览器中筛选回答', - 'stats.humanInputs': '用户输入', - 'stats.humanInputsTip': '当前会话中的用户消息与问题回答次数。', - 'stats.io': '输入输出', - 'stats.events': '上下文事件', - 'stats.toolCalls': '工具调用', - 'stats.toolsMore': '其他 +{n}', - 'stats.cacheHit': '缓存命中', - 'stats.cacheHitTip': '整个会话累计的缓存读取占计费输入的比例。', - 'stats.cost': '费用', - 'stats.costTip': '估算的费用,含当前智能体及所有层级的子智能体,仅供参考。', - 'stats.costTipDeepseek': 'DeepSeek 高峰时段(北京时间工作日 9:00–12:00、14:00–18:00)按挂牌价计费,其余时段半价。', - 'stats.costTipCny': '人民币按 1 元 = 0.15 美元换算。', - 'stats.currentAgent': '当前 Agent', - 'stats.teamSubs': '子 Agent × {n}', - 'stats.billedTip': 'Token 用量为计费合计:未缓存输入、缓存读取、缓存写入与输出。', - 'stats.subCostTip': '全部层级的子 Agent 会话各自累计费用(同口径估算)的合计,不含当前 Agent 自身。', - 'stats.costPriceHead': '每百万 Token 价格:', - 'stats.costPriceBy': '按 {p} · {m} 在 models.dev 的刊登价格如上。', - 'stats.costHit': '缓存输入', - 'stats.costMiss': '未缓存输入', - 'stats.costWrite': '缓存写入', - 'stats.costOut': '输出', - 'stats.costUnavailable': '模型价格暂不可用(自动重试中),费用暂无法估算。', - 'timing.title': '耗时统计', - 'timing.total': '活跃时长', - 'timing.ttft': '模型等待', - 'timing.gen': '模型生成', - 'timing.reasoning': '模型思考', - 'timing.text': '模型回复', - 'timing.toolArgs': '工具参数', - 'timing.tools': '工具执行', - 'timing.other': '其他开销', - 'timing.callTimes': '{n}次', - 'timing.toolTimes': '{n}次', - 'timing.blockTimes': '{n}次', - 'timing.empty': '暂无耗时数据 · 对话开始后这里会显示时长分布', - 'timing.tps': '输出速度 {tps} tok/s', - 'timing.tpsTip': '输出速度(TPS):累计解码输出 tokens ÷ 累计解码时长,与 DeepSeek Harness 会话统计同口径。', - 'timing.strip': '耗时时间轴:各段按发生次序紧凑铺排,宽度为耗时占比,刻度为零、四分位与全程', - 'tokens.title': 'Token 统计', - 'tokens.total': '总用量', - 'tokens.output': '输出', - 'tokens.outputNote': '含思考', - 'plugin.title': '插件信息', - 'plugin.hint': 'The best DSH context plugin ⭐', - 'plugin.name': '插件', - 'plugin.github': 'GitHub', - 'plugin.settings': '插件设置', - 'plugin.settingsOpen': '打开插件设置', - 'trend.title': '上下文趋势', - 'gran.step': '步骤', - 'gran.turn': '轮次', - 'settings.placement': '入口位置', - 'placement.tab': '标签页', - 'placement.sidebar': '侧边栏', - 'placement.all': '全部', - 'settings.insightsEntry': '上下文洞察入口', - 'settings.fleetTab': '编队标签页', - 'showHide.show': '显示', - 'showHide.hide': '隐藏', - 'settings.gran': '趋势图 · 默认粒度', - 'settings.mode': '趋势图 · 默认展示方式', - 'settings.durationCurve': '趋势图 · 耗时曲线', - 'settings.deltaBase': '上下文浏览器 · 对比基线', - 'settings.toolSort': '工具定义 · 默认排序', - 'settings.fileSort': '文件活动 · 默认排序', - 'settings.readOnly': '当前环境的设置为只读', - 'settings.promptPrefix': '系统提示词 · 前缀', - 'settings.promptSuffix': '系统提示词 · 后缀', - 'settings.promptHint': '拼接在所有会话系统提示词的最前/最后,对所有代理(含子代理)生效;修改从下一轮对话开始应用', - 'settings.promptPlaceholder': '留空则不启用', - 'gran.total': '全量', - 'gran.delta': '增量', - 'gran.modeHint': '全量:累计构成;增量:相对上一条请求的变化量', - 'trend.adaptive': '自适应', - 'trend.adaptiveHint': '按当前可视范围内的柱子重新缩放高度,滚动时随之变化', - 'trend.duration': '耗时', - 'trend.durationTip': '在柱子上叠加每步的活跃耗时曲线(步骤开始至结束,含模型与工具调用,不含等待你决策或回答的时间),按图中右侧的四分位坐标轴读数;轮次粒度下为一轮各步耗时之和', - 'trend.dna': 'DNA 模式', - 'trend.dnaTip': '把每根柱子画成该次请求的上下文指纹:按模型读取顺序逐条铺色,配合增量模式逐条展示每次请求的增减;悬停查看条目,点击让上下文浏览器定位到该条目,同一条目在所有柱子中亮出其存续变化', - 'trend.dnaItem': '{label}:{n}', - 'trend.empty': '发起一轮对话后,这里会展示每次模型请求的上下文构成', - 'detail.step': '第 {t} 轮 · 第 {s} 步 (共 {n} 步)', - 'detail.turn': '第 {t} 轮 · 共 {n} 步', - 'detail.lastStep': '末步', - 'detail.estTotal': '估算合计 ≈ {n}', - 'detail.actual': '实际 {n}', - 'detail.output': '输出 {n}', - 'detail.cache': '缓存 {n}%', - 'brief.turn': '本轮', - 'brief.input': '输入', - 'brief.reply': '回复', - 'brief.more': '+{n}', - 'brief.noInputs': '(无新增)', - 'brief.locate': '在上下文浏览器中查看', - 'jump.title': '在上下文视图中查看此轮', - 'brief.turnTip': '这一轮开场时用户发送的消息;回合内的每一步都会回显同一条', - 'brief.inputTip': '上一步回复之后、本次请求发出前新进入上下文的内容——通常是上一步所调工具的结果;每轮的第一步无新增', - 'brief.replyTip': '这一步模型返回的内容(文本回复或工具调用);此步发起的调用,其结果会出现在下一柱的「输入」行', - 'events.title': '上下文事件', - 'events.empty': '暂无上下文事件(压缩、注入、模型切换会出现在这里)', - // Locale-neutral position stamps, matching the browser rows' own `browser.stepAt`. - 'events.at': 'T{t} S{s}', - 'events.range': 'T{t} S{a}→{b}', - 'events.rangeTo': 'T{a} S{as} → T{b} S{bs}', - 'kind.inject': '注入', - 'kind.compaction': '压缩', - 'kind.prune': '剪枝', - 'kind.model': '切换', - 'kind.mode': '模式', - 'files.title': '文件活动', - 'files.scopeLatest': '截至最新 · 跟随趋势图的选择', - 'files.kind.all': '全部', - 'files.kind.read': '读取', - 'files.kind.write': '写入', - 'files.kind.search': '搜索', - 'files.kind.image': '图片', - 'files.chipTip': '{files} 个文件 · {ops} 次操作', - 'files.search': '按路径过滤…', - 'files.sort.count': '按次数', - 'files.sort.latest': '按最新', - 'files.sort.path': '按路径', - 'files.sortTip': '文件排序:按操作次数(选中分类时按该分类的次数)、最近操作时间或路径', - 'files.files': '{n} 个文件', - 'files.deltaTip': '按 edit/write 调用参数估算的累计行数变化:+ 新增 / − 删除', - 'files.empty': '该范围内没有文件读取、写入或搜索操作', - 'files.noMatch': '没有匹配当前过滤条件的文件', - 'files.locate': '在上下文浏览器中查看此次操作', - 'files.hits': '{n} 处命中', - 'files.readTip': '读取第 {a}–{b} 行', - 'files.open': '在系统中打开', - 'files.preview': '在侧边栏预览', - 'files.readEst': '按调用参数 limit 估算的读取行数', - 'files.errs': '{n} 次失败', - 'files.form.image': '图片', - 'files.form.dir': '目录', - 'files.form.text': '文件', - 'files.glyph.root': '工作区根', - 'files.glyph.tests': '测试', - 'files.glyph.docs': '文档目录', - 'files.glyph.deps': '依赖', - 'files.glyph.build': '构建产物', - 'files.glyph.scripts': '脚本', - 'files.glyph.config': '配置', - 'files.glyph.assets': '静态资源', - 'files.glyph.hidden': '元数据目录', - 'files.glyph.lock': '锁文件', - 'files.glyph.docker': 'Docker', - 'files.glyph.ignore': '忽略规则', - 'files.glyph.license': '许可证', - 'files.glyph.python': 'Python', - 'files.glyph.notebook': 'Notebook', - 'files.glyph.shell': 'Shell', - 'files.glyph.style': '样式', - 'files.glyph.database': '数据库', - 'files.glyph.data': '数据清单', - 'files.glyph.markdown': '标记文档', - 'files.glyph.log': '日志', - 'files.glyph.sheet': '表格', - 'files.glyph.document': '文档', - 'files.glyph.archive': '压缩包', - 'files.glyph.font': '字体', - 'files.glyph.media': '媒体', - 'files.glyph.lang.ts': 'TypeScript', - 'files.glyph.lang.js': 'JavaScript', - 'files.glyph.lang.go': 'Go', - 'files.glyph.lang.rust': 'Rust', - 'files.glyph.lang.java': 'Java', - 'files.glyph.lang.kotlin': 'Kotlin', - 'files.glyph.lang.ruby': 'Ruby', - 'files.glyph.lang.php': 'PHP', - 'files.glyph.lang.c': 'C', - 'files.glyph.lang.cpp': 'C++', - 'files.glyph.lang.csharp': 'C#', - 'files.glyph.lang.scala': 'Scala', - 'files.glyph.lang.lua': 'Lua', - 'files.glyph.lang.dart': 'Dart', - 'files.glyph.lang.swift': 'Swift', - 'files.glyph.lang.vue': 'Vue', - 'files.glyph.lang.svelte': 'Svelte', - 'files.glyph.lang.html': 'HTML', - 'agents.title': 'Agent 网络', - 'agents.sub': '当前 Agent 与子 Agent 的实时上下文 · 点击节点跳转会话', - 'agents.chip.count': '{n} 个 Agent', - 'agents.chip.running': '{n} 个运行中', - 'agents.chip.tokens': '上下文合计 {n}', - 'agents.more': '另有 {n} 个未显示', - 'agents.solo': '还没有子 Agent — 当 Agent 通过 subagent 工具委派任务时,协作网络会在这里展开', - 'agents.self': '当前', - 'agents.running': '运行中', - 'agents.legend.free': '空闲窗口', - 'agents.oneshot': '一次性', - 'agents.continuable': '多轮', - 'agents.steps': '{n} 步', - 'agents.billed': '累计计费 {n}', - 'fleet.teamChip': '团队 · {m} 成员 · {n} 任务', - 'fleet.unpin': '取消固定', - 'fleet.open': '打开会话', - 'fleet.membership': '团队身份', - 'fleet.role.lead': '主导', - 'fleet.role.teammate': '成员', - 'fleet.phase.provisioning': '准备中', - 'fleet.phase.failed': '失败', - 'fleet.memberInactive': '未运行', - 'fleet.config': '配置', - 'fleet.prompt': '委派提示词', - 'fleet.expand': '展开', - 'fleet.collapse': '收起', - 'fleet.detailLoading': '正在读取会话记录…', - 'fleet.messages': '通讯', - 'fleet.kind.relay': '私信', - 'fleet.kind.mailbox': '邮箱', - 'fleet.kind.settled': '回报', - 'fleet.task.pending': '待处理', - 'fleet.task.in_progress': '进行中', - 'fleet.task.completed': '已完成', - 'fleet.taskReady': '可开始', - 'fleet.taskBlocked': '被依赖阻塞', - 'fleet.taskUnowned': '未分配', - 'fleet.taskScopes': '写入范围', - 'fleet.members.title': '团队成员', - 'fleet.members.count': '{n} 名成员', - 'fleet.members.reply': '最新回报', - 'fleet.members.tasks': '{n} 项进行中任务', - 'fleet.members.noTasks': '无进行中任务', - 'fleet.members.tasksTip': '在任务看板中只看该成员', - 'fleet.tasks.title': '任务看板', - 'fleet.tasks.sub': '共享任务与依赖 · 只读', - 'fleet.tasks.ownerTip': '在右侧详情中固定该成员', - 'fleet.tasks.depTip': '依赖 {id} · 点击定位', - 'fleet.tasks.focusTip': '在任务看板中定位', - 'fleet.tasks.dependsOn': '依赖', - 'fleet.tasks.noMatch': '该成员当前没有任务', - 'fleet.taskCol.pending': '待处理', - 'fleet.taskCol.in_progress': '进行中', - 'fleet.taskCol.completed': '已完成', - 'fleet.team.empty': '暂无共享任务,可以通过对话创建', - 'fleet.team.failureShort': '持久记录无效', - 'fleet.settled.finished': '完成了任务,等待新指令', - 'fleet.settled.finishedFinal': '已完成(一次性,无法追问)', - 'fleet.settled.stopped': '被中断,未完成', - 'fleet.settled.outOfRoom': '上下文耗尽,未完成', - 'fleet.settled.declined': '拒绝了任务', - 'fleet.settled.failed': '执行失败', - 'fleet.list.title': '编队名录', - 'fleet.list.sub': '家族内所有 Agent · 点击行固定到右侧详情', - 'fleet.list.search': '搜索名称…', - 'fleet.list.filter': '状态过滤', - 'fleet.list.sort': '排序', - 'fleet.list.empty': '没有匹配的 Agent', - 'fleet.filter.all': '全部', - 'fleet.filter.running': '运行中', - 'fleet.filter.done': '已完成', - 'fleet.filter.idle': '空闲', - 'fleet.sort.spawn': '派生顺序', - 'fleet.sort.tokens': '上下文用量', - 'fleet.sort.duration': '运行时长', - 'fleet.sort.steps': '步数', - 'fleet.sort.recent': '最近活跃', - 'fleet.comms.title': '通讯记录', - 'fleet.comms.sub': '跨 Agent 消息 · 按需扫描各会话日志', - 'fleet.comms.scan': '扫描 {n} 个会话的通讯', - 'fleet.comms.scanning': '扫描中 {done}/{total}…', - 'fleet.comms.rows': '{n} 条消息', - 'fleet.comms.stale': '有新动态', - 'fleet.comms.rescan': '重新扫描', - 'fleet.comms.filter': '按 Agent 过滤', - 'fleet.comms.all': '全部 Agent', - 'fleet.comms.empty': '没有发现跨 Agent 消息', - 'fleet.comms.truncated': '仅展示摘录(已达路由上限)', - 'loading': '正在读取会话日志…', - 'detail.loading': '正在加载历史数据…', - 'detail.loadFailed': '历史数据加载失败,点击重试', - 'error': '上下文数据读取失败:', - 'error.retry': '重试', - 'gate.title': '请更新 DeepSeek Harness 版本', - 'gate.body': 'dsh-context 插件支持 DeepSeek Harness v{minimum} 或更新版本。', - 'gate.current': '当前版本', - 'gate.minimum': '最低要求', - 'gate.orNewer': '及更新的版本', - 'gate.ok': '知道了', - 'footer': 'Token 数量统计:「估算」与 DeepSeek Harness 内置 tokenMeter 相同的固定密度启发式(约 4 字符 ≈ 1 token);「实际」为供应商上报用量。', - 'tip.step': '第 {t} 轮 · 第 {s} 步 (共 {n} 步)', - 'tip.turn': '第 {t} 轮 · 共 {n} 步', - 'tip.turn1': '第 {t} 轮 · 共 1 步', - 'tip.total': '合计 ≈ {n}', - 'tip.cat': '{cat} ≈ {n}', - 'tip.delta': 'Δ {n}', - 'tip.duration': '耗时 {n}', - 'ev.compaction': '压缩上下文(摘要替换 {n} 条消息)', - 'ev.prune': '剪枝工具输出', - 'ev.skill': 'Skill 注入({name})', - 'ev.model': '模型切换:{a} → {b}', - 'ev.mode.plan.on': '进入计划模式', - 'ev.mode.plan.off': '退出计划模式', - 'form.instructions': '指令注入', - 'form.catalog': '目录更新', - 'form.snapshot': '状态快照', - 'form.notice': '通知', - 'form.relay': '代理转发', - 'form.recall': '历史召回', - 'form.context': '上下文注入', - 'node.toolResult': '工具结果', - 'node.calls': '调用 ', - 'node.empty': '(空回复)', - 'node.nonText': '(非文本消息)', - 'node.snapshot': '快照: ', - 'node.skillTag': '技能 · {name}', - 'cmd.label': '上下文', - 'cmd.section': '上下文', - 'cmd.desc': '查看当前上下文构成,浏览各步骤组成', - 'cmd.close': '关闭', - 'browser.title': '上下文浏览器', - 'browser.live': '当前(下一次请求)', - 'browser.liveNow': '当前 · 下一次请求', - 'browser.items': '{n} 项', - 'browser.stepAt': 'T{t} S{s}', - 'browser.stepAtTip': '首次随第 {t} 轮 · 第 {s} 步的请求进入上下文', - 'browser.stepPendingTip': '预计随第 {t} 轮 · 第 {s} 步的请求进入上下文(尚未发送)', - 'browser.missingLive': '… 另有 {n} 条更早的消息也在上下文中(超出展示窗口)', - 'browser.approx': '该步骤涉及的部分已移除消息超出保留范围,以下为近似构成', - 'browser.base.step': '比前步', - 'browser.base.turn': '比前轮', - 'browser.base.tip': '变动对比的基线:比前步=与上一步对比;比前轮=与上一轮最后一步对比(首轮无基线,全部计为变动)', - 'browser.dna': 'DNA 模式', - 'browser.dnaTip': '按模型读取上下文的次序逐条展示每一项:系统提示词、工具定义,然后是按时间排列的消息;悬停查看条目,点击定位到下方列表', - 'browser.noHeader': '此数据来自旧版插件:仅提供 token 估算,无实际内容', - 'browser.noEpoch': '该步骤的头部内容(系统提示词 / 工具定义)不在保留范围内', - 'browser.headerMetaOnly': '此环境不支持按需读取头部内容,仅显示 token 估算', - 'browser.noSystem': '该请求头部未包含系统提示词', - 'browser.noContent': '完整内容不在当前加载的消息窗口内(在聊天页加载更早历史后可查看)', - 'browser.search.user': '按消息内容过滤…', - 'browser.search.inject': '按注入内容过滤…', - 'browser.search.skill': '按技能过滤…', - 'browser.search.assistant': '按回复、调用或思考过滤…', - 'browser.search.tool': '按工具或参数过滤…', - 'browser.kind.think': '思考', - 'browser.kind.tool': '工具', - 'browser.kind.answer': '回答', - 'browser.kindTip': '按内容种类过滤回复:思考、工具调用、回答文本', - 'browser.rowNoMatch': '没有匹配当前过滤条件的行', - 'browser.loading': '正在从更早的会话历史加载完整内容…', - 'browser.notInLog': '会话日志中未找到该条目的完整内容(可能已被压缩或清理)', - 'browser.loadFailed': '内容加载失败,点击重试', - 'tool.desc': '描述', - 'tool.params': '参数', - 'tool.paramsEmpty': '(无参数)', - 'tool.plugin': '该工具的注册插件(仅供参考)', - 'tool.unknown': '未知插件', - 'tool.unknownTitle': '因早于上下文插件加载或原插件已卸载,无法查询该工具的提供者', - 'tool.jsonToggle': '查看原始 JSON', - 'tool.jsonHide': '收起', - 'tool.search': '按名称、描述或参数过滤…', - 'tool.sort.size': '按大小', - 'tool.sort.count': '按次数', - 'tool.sort.name': '按名称', - 'tool.sortTip': '工具排序:按当前步骤中的调用次数(默认)、token 大小或名称', - 'tool.hitsTip': '当前展示步骤的上下文中,该工具被调用并返回结果的次数', - 'tool.noMatch': '没有匹配当前过滤条件的工具', - 'rich.raw': '原文', - 'rich.md': 'Markdown', - 'rich.toMd': '按 Markdown 渲染查看', - 'rich.toRaw': '查看原始文本', - 'rich.copy': '复制原文', - 'rich.copied': '已复制', - 'rich.md.copy': '复制', - 'rich.md.copied': '已复制', - 'rich.md.footnotes': '脚注', - 'rich.find': '在文本中查找', - 'rich.findPlaceholder': '查找…', - 'rich.findPrev': '上一个匹配', - 'rich.findNext': '下一个匹配', - 'rich.findClose': '关闭查找', - 'block.thinking': '思考', - 'block.answer': '回答', - 'block.content': '内容', - 'block.result': '结果', - 'block.summary': '摘要', - // The zh measure word never inflects, so the singular/plural forms are identical. - 'block.line': '{n} 行', - 'block.lines': '{n} 行', - 'call.ok': '正常', - 'call.fail': '失败', - 'call.exit': 'exit {n}', - 'node.failed': '工具执行失败', - 'attach.images': '图片附件', - 'attach.other': '其他内容', - 'attach.image': '图片', - 'attach.open': '查看原图', - 'attach.preview': '图片预览', - 'attach.close': '关闭', - 'attach.loading': '…', - 'attach.loadFailed': '加载失败 · 点击重试', - 'attach.raw': '原图', - 'attach.sent': '发送', - 'attach.token': 'Token', - 'attach.tokensTip': '按 DeepSeek 官方图片尺寸换算(单图上限 384 tokens)估算的 token 消耗', - 'ov.title': '上下文洞察', - 'ov.unavailable': '会话列表暂不可用', - 'ov.range.label': '统计范围', - 'ov.range.today': '今天', - 'ov.range.7d': '近 7 天', - 'ov.range.30d': '近 30 天', - 'ov.range.all': '全部', - 'ov.date.label': '日期范围', - 'ov.date.open': '选择自定义日期范围', - 'ov.date.from': '开始日期', - 'ov.date.to': '结束日期', - 'ov.date.pick': '选择日期', - 'ov.date.prev': '上个月', - 'ov.date.next': '下个月', - 'ov.date.hint': '点击选择开始日期', - 'ov.date.hintEnd': '再点一下选择结束日期', - 'ov.date.clear': '清除', - 'ov.date.wd.0': '日', - 'ov.date.wd.1': '一', - 'ov.date.wd.2': '二', - 'ov.date.wd.3': '三', - 'ov.date.wd.4': '四', - 'ov.date.wd.5': '五', - 'ov.date.wd.6': '六', - 'ov.kpi.sessions': '活跃会话', - 'ov.kpi.ofTotal': '共 {n} 个', - 'ov.kpi.tokens': '累计消耗', - 'ov.kpi.sessionsSub': '含 {n} 个会话', - 'ov.kpi.pricedSub': '已计价 {n}/{total} 个会话', - 'ov.kpi.toolSub': '工具执行 {dur}', - 'ov.kpi.wallSub': '模型调用 {n}', - 'ov.stats.empty': '统计范围内暂无 Token 用量', - 'ov.usage.title': '近 7 天用量', - 'ov.usage.tokens': 'Token', - 'ov.usage.cost': '费用(仅含支持计价映射的模型)', - 'ov.usage.costTip': '费用', - 'ov.usage.empty': '近 7 天暂无用量 — 会话产生模型请求后,这里会显示每日 Token 与费用', - 'balance.title': 'DeepSeek 余额', - 'balance.tip.granted': '赠送余额', - 'balance.tip.toppedUp': '充值余额', - 'ov.heat.title': '活跃度', - 'ov.heat.sub': '按日期筛选', - 'ov.heat.empty': '暂无活跃数据 — 会话产生模型请求后,这里会显示每日用量', - 'ov.heat.sessions': '{n} 个活跃会话', - 'ov.heat.less': '少', - 'ov.heat.more': '多', - 'ov.heat.metric': '指标', - 'ov.heat.metric.sessions': '会话', - 'ov.heat.metric.steps': '步数', - 'ov.heat.steps': '{n} 步', - 'ov.heat.wd.1': '星期一', - 'ov.heat.wd.3': '星期三', - 'ov.heat.wd.5': '星期五', - 'ov.heat.mon.01': '1月', - 'ov.heat.mon.02': '2月', - 'ov.heat.mon.03': '3月', - 'ov.heat.mon.04': '4月', - 'ov.heat.mon.05': '5月', - 'ov.heat.mon.06': '6月', - 'ov.heat.mon.07': '7月', - 'ov.heat.mon.08': '8月', - 'ov.heat.mon.09': '9月', - 'ov.heat.mon.10': '10月', - 'ov.heat.mon.11': '11月', - 'ov.heat.mon.12': '12月', - 'ov.skills.empty': '统计范围内暂无技能加载 — 加载技能后,这里会按名称列出次数与最近加载', - 'ov.skills.noMatch': '没有匹配当前筛选的技能', - 'ov.skills.search': '搜索技能…', - 'ov.skills.more': '另有 {n} 个技能', - 'ov.skills.loads': '{n} 次加载', - 'ov.skills.summary': '{skills} 个技能 · {loads} 次加载', - 'ov.skills.sortLabel': '技能排序', - 'ov.skills.sort.loads': '次数', - 'ov.skills.sort.recent': '最近', - 'ov.skills.sessions': '{n} 个会话', - 'ov.skills.clickFilter': '点击筛选加载过它的会话', - 'ov.skills.clickRelease': '再次点击取消筛选', - 'ov.skills.src.project': '项目', - 'ov.skills.src.user': '用户', - 'ov.skills.src.bundled': '内置', - 'ov.skills.k.source': '来源', - 'ov.skills.k.usage': '用量', - 'ov.skills.k.last': '最近', - 'ov.skills.k.path': '路径', - 'ov.skills.copyPath': '点击复制路径', - 'ov.skills.copied': '已复制', - 'ov.list.title': '会话', - 'ov.list.search': '搜索标题 / 目录 / 最后消息…', - 'ov.list.sortLabel': '排序', - 'ov.list.sort.recent': '最近更新', - 'ov.list.sort.tokens': 'Token 总用量', - 'ov.list.sort.context': '当前 Context', - 'ov.list.empty': '还没有会话 — 发起一轮对话后,这里会列出每个会话的上下文画像', - 'ov.list.noMatch': '没有匹配当前筛选条件的会话', - 'ov.list.noData': '暂无上下文数据 — 该会话产生模型请求后才会统计', - 'ov.list.dayFilter': '{day} 当日活跃', - 'ov.list.dayClear': '清除日期筛选', - 'ov.list.skillClear': '清除技能筛选', - 'ov.list.pager': '会话分页', - 'ov.list.page': '第 {n} / {total} 页', - 'ov.list.prev': '上一页', - 'ov.list.next': '下一页', - 'ov.group.label': '分组', - 'ov.group.ungrouped': '未分组', - 'ov.running': '运行中', - 'ov.current': '当前', - 'ov.card.turns': '{n} 轮 {s} 步', - 'ov.card.teamUsage': 'Token 总用量', - 'ov.card.teamCost': '总预估费用', - 'ov.card.lastUser': '最后消息', - 'ov.time.now': '刚刚', - 'ov.time.m': '{n} 分钟前', - 'ov.time.h': '{n} 小时前', - 'ov.time.d': '{n} 天前', -} satisfies Record - -/** The key union every locale of this plugin must carry in full. */ -export type DictKey = keyof typeof DICT_ZH - -export const DICT_EN = { - 'tab.context': 'Context', - 'tab.fleet': 'Fleet', - 'sidebar.guideDescription': 'Inspect context composition, stats, and evolution.', - 'cat.system': 'System Prompt', - 'cat.tools': 'Tool Schemas', - 'cat.user': 'User Messages', - 'cat.inject': 'Injected Context', - 'cat.skill': 'Skill Injections', - 'cat.assistant': 'Assistant Messages', - 'cat.tool': 'Tool Results', - 'overview.title': 'Current Context', - 'overview.estimate': 'tokens (estimated)', - 'overview.free': 'Free Window', - 'overview.used': 'of context used', - 'overview.ofUsed': 'of used context', - 'overview.compactReserve': 'Auto-compaction reserve: auto-compaction triggers at {pct}% of the window — this area is normally kept as headroom, not actually used', - 'stats.title': 'Context Stats', - 'stats.session': 'Current Session', - 'stats.turns': 'Turns', - 'stats.steps': 'Steps', - 'stats.answers': 'Answers', - 'stats.skills': 'Skill Loads', - 'stats.skillsJump': 'Open Skill Injections in the Context Browser', - 'stats.answersJump': 'Filter Answers in the Context Browser', - 'stats.humanInputs': 'Human Inputs', - 'stats.humanInputsTip': 'User messages and question answerings in current session.', - 'stats.io': 'Input / Output', - 'stats.events': 'Context Events', - 'stats.toolCalls': 'Tool Calls', - 'stats.toolsMore': '+{n} more', - 'stats.cacheHit': 'Cache Hit', - 'stats.cacheHitTip': 'Cumulative cache-read share of billed input across the session.', - 'stats.cost': 'Cost', - 'stats.costTip': 'Estimated cost for this agent and every descendant subagent session, for reference only.', - 'stats.costTipDeepseek': 'DeepSeek bills peak windows (Beijing Time weekdays 09:00–12:00, 14:00–18:00) at list price; all other hours are half price.', - 'stats.costTipCny': 'The CNY display converts at 1 CNY = 0.15 USD.', - 'stats.currentAgent': 'Current Agent', - 'stats.teamSubs': 'Subagents × {n}', - 'stats.billedTip': 'Token usage is the billed total: uncached input, cache read, cache write, and output.', - 'stats.subCostTip': 'Summed estimates of every descendant subagent session’s own cumulative cost — all levels of the subtree (same basis); the current agent is not included.', - 'stats.costPriceHead': 'Per-1M-token rates:', - 'stats.costPriceBy': 'Priced as listed on models.dev for {p} · {m}.', - 'stats.costHit': 'Cache input', - 'stats.costMiss': 'Uncached input', - 'stats.costWrite': 'Cache write', - 'stats.costOut': 'Output', - 'stats.costUnavailable': 'Model prices are unavailable (retrying automatically) — the cost cannot be estimated yet.', - 'timing.title': 'Timing Stats', - 'timing.total': 'Active Time', - 'timing.ttft': 'TTFT', - 'timing.gen': 'LLM Gen', - 'timing.reasoning': 'Thinking', - 'timing.text': 'Answers', - 'timing.toolArgs': 'Tool args', - 'timing.tools': 'Tool runs', - 'timing.other': 'Overhead', - 'timing.callTimes': '{n} calls', - 'timing.toolTimes': '{n} runs', - 'timing.blockTimes': '{n} blocks', - 'timing.empty': 'No timing data yet — durations appear as the conversation runs', - 'timing.tps': 'TPS {tps} tok/s', - 'timing.tpsTip': 'Output speed (TPS): summed decoded output tokens over summed decode time — the same pairing as the harness session stats.', - 'timing.strip': 'Session-time strip: slices packed in occurrence order, width as share of the active time; ticks at zero, the quartiles, and the full span', - 'tokens.title': 'Token Stats', - 'tokens.total': 'Total', - 'tokens.output': 'Output', - 'tokens.outputNote': 'incl. reasoning', - 'plugin.title': 'Plugin Info', - 'plugin.hint': 'The best DSH context plugin ⭐', - 'plugin.name': 'Plugin', - 'plugin.github': 'GitHub', - 'plugin.settings': 'Plugin Settings', - 'plugin.settingsOpen': 'Open plugin settings', - 'trend.title': 'Context Trend', - 'gran.step': 'Step', - 'gran.turn': 'Turn', - 'settings.placement': 'Entry Options', - 'placement.tab': 'Tab', - 'placement.sidebar': 'Sidebar', - 'placement.all': 'All', - 'settings.insightsEntry': 'Context Insights entry', - 'settings.fleetTab': 'Fleet tab', - 'showHide.show': 'Show', - 'showHide.hide': 'Hide', - 'settings.gran': 'Trend Chart · Default granularity', - 'settings.mode': 'Trend Chart · Default display', - 'settings.durationCurve': 'Trend Chart · Duration curve', - 'settings.deltaBase': 'Context Browser · Diff baseline', - 'settings.toolSort': 'Tool Schemas · Default sort', - 'settings.fileSort': 'File Activity · Default sort', - 'settings.readOnly': 'Settings are read-only in this environment', - 'settings.promptPrefix': 'System Prompt · Prefix', - 'settings.promptSuffix': 'System Prompt · Suffix', - 'settings.promptHint': 'Joined at the very start/end of every session\'s system prompt, for all agents (subagents included); edits apply from the next turn', - 'settings.promptPlaceholder': 'Leave empty to disable', - 'gran.total': 'Total', - 'gran.delta': 'Delta', - 'gran.modeHint': 'Total: cumulative makeup; Delta: change vs the previous request', - 'trend.adaptive': 'Adaptive', - 'trend.adaptiveHint': 'Rescale bar heights to the visible range, following the scroll', - 'trend.duration': 'Duration', - 'trend.durationTip': 'Overlay each step’s active time (step start to end — model and tool calls, excluding waits for your decisions or answers) as a curve over the bars, read off the quartile axis on the chart’s right; turn granularity sums a turn’s steps', - 'trend.dna': 'DNA Mode', - 'trend.dnaTip': 'Draw each bar as that request’s context fingerprint — one band per item in the order the model reads it; with Delta, each band shows that item’s change against the previous bar. Hover for the item, click to reveal it in the Context browser, and every bar lights the same item’s lifetime', - 'trend.dnaItem': '{label}: {n}', - 'trend.empty': 'Send a message and each model request’s context makeup shows up here', - 'detail.step': 'Turn {t} · Step {s} of {n}', - 'detail.turn': 'Turn {t} · {n} steps', - 'detail.lastStep': 'Last Step', - 'detail.estTotal': 'Estimated ≈ {n}', - 'detail.actual': 'Actual {n}', - 'detail.output': 'Output {n}', - 'detail.cache': 'Cache {n}%', - 'brief.turn': 'User', - 'brief.input': 'In', - 'brief.reply': 'Response', - 'brief.more': '+{n}', - 'brief.noInputs': '(nothing new)', - 'brief.locate': 'Reveal in Context Browser', - 'jump.title': 'View this turn in the Context view', - 'brief.turnTip': 'The user message that opened this turn — every step of the turn recalls it', - 'brief.inputTip': 'What entered after the previous reply and before this request went out — usually the previous tool-call results; a turn opener has nothing new', - 'brief.replyTip': 'What the model returned on this step (a text reply or tool calls) — results of calls made here appear in the In row of the next bar', - 'events.title': 'Context Events', - 'events.empty': 'No context events yet (compaction, injections, model switches appear here)', - 'events.at': 'T{t} S{s}', - 'events.range': 'T{t} S{a}→{b}', - 'events.rangeTo': 'T{a} S{as} → T{b} S{bs}', - 'kind.inject': 'Inject', - 'kind.compaction': 'Compact', - 'kind.prune': 'Prune', - 'kind.model': 'Switch', - 'kind.mode': 'Mode', - 'files.title': 'File Activity', - 'files.scopeLatest': 'Up to latest · follows the trend chart pick', - 'files.kind.all': 'All', - 'files.kind.read': 'Read', - 'files.kind.write': 'Written', - 'files.kind.search': 'Searched', - 'files.kind.image': 'Images', - 'files.chipTip': '{files} files · {ops} ops', - 'files.search': 'Filter by path…', - 'files.sort.count': 'Most active', - 'files.sort.latest': 'Latest', - 'files.sort.path': 'By path', - 'files.sortTip': 'Sort files by operation counts (of the selected kind when a kind chip is active), most recent activity, or path', - 'files.files': '{n} files', - 'files.deltaTip': 'Cumulative line change estimated from edit/write call arguments: + added / − removed', - 'files.empty': 'No file reads, writes, or searches in this range', - 'files.noMatch': 'No files match the current filters', - 'files.locate': 'Reveal this operation in the Context Browser', - 'files.hits': '{n} hits', - 'files.readTip': 'Read lines {a}–{b}', - 'files.open': 'Open on your system', - 'files.preview': 'Preview in the sidebar', - 'files.readEst': 'Lines read, estimated from the limit argument', - 'files.errs': '{n} failed', - 'files.form.image': 'Image', - 'files.form.dir': 'Directory', - 'files.form.text': 'File', - 'files.glyph.root': 'Workspace root', - 'files.glyph.tests': 'Tests', - 'files.glyph.docs': 'Docs', - 'files.glyph.deps': 'Dependencies', - 'files.glyph.build': 'Build output', - 'files.glyph.scripts': 'Scripts', - 'files.glyph.config': 'Config', - 'files.glyph.assets': 'Assets', - 'files.glyph.hidden': 'Metadata directory', - 'files.glyph.lock': 'Lockfile', - 'files.glyph.docker': 'Docker', - 'files.glyph.ignore': 'Ignore rules', - 'files.glyph.license': 'License', - 'files.glyph.python': 'Python', - 'files.glyph.notebook': 'Notebook', - 'files.glyph.shell': 'Shell', - 'files.glyph.style': 'Styles', - 'files.glyph.database': 'Database', - 'files.glyph.data': 'Data / manifest', - 'files.glyph.markdown': 'Markup document', - 'files.glyph.log': 'Log', - 'files.glyph.sheet': 'Spreadsheet', - 'files.glyph.document': 'Document', - 'files.glyph.archive': 'Archive', - 'files.glyph.font': 'Font', - 'files.glyph.media': 'Media', - 'files.glyph.lang.ts': 'TypeScript', - 'files.glyph.lang.js': 'JavaScript', - 'files.glyph.lang.go': 'Go', - 'files.glyph.lang.rust': 'Rust', - 'files.glyph.lang.java': 'Java', - 'files.glyph.lang.kotlin': 'Kotlin', - 'files.glyph.lang.ruby': 'Ruby', - 'files.glyph.lang.php': 'PHP', - 'files.glyph.lang.c': 'C', - 'files.glyph.lang.cpp': 'C++', - 'files.glyph.lang.csharp': 'C#', - 'files.glyph.lang.scala': 'Scala', - 'files.glyph.lang.lua': 'Lua', - 'files.glyph.lang.dart': 'Dart', - 'files.glyph.lang.swift': 'Swift', - 'files.glyph.lang.vue': 'Vue', - 'files.glyph.lang.svelte': 'Svelte', - 'files.glyph.lang.html': 'HTML', - 'agents.title': 'Agent Network', - 'agents.sub': 'Live context of this agent and its subagents · click a node to open its session', - 'agents.chip.count': '{n} agents', - 'agents.chip.running': '{n} running', - 'agents.chip.tokens': '{n} tokens in context', - 'agents.more': '{n} more not shown', - 'agents.solo': 'No subagents yet — when the agent delegates work through the subagent tool, the network unfolds here', - 'agents.self': 'current', - 'agents.running': 'running', - 'agents.legend.free': 'free window', - 'agents.oneshot': 'one-shot', - 'agents.continuable': 'continuable', - 'agents.steps': '{n} steps', - 'agents.billed': '{n} billed', - 'fleet.teamChip': 'team · {m} members · {n} tasks', - 'fleet.unpin': 'Unpin', - 'fleet.open': 'Open session', - 'fleet.membership': 'Team membership', - 'fleet.role.lead': 'lead', - 'fleet.role.teammate': 'teammate', - 'fleet.phase.provisioning': 'provisioning', - 'fleet.phase.failed': 'failed', - 'fleet.memberInactive': 'inactive', - 'fleet.config': 'Configuration', - 'fleet.prompt': 'Delegation prompt', - 'fleet.expand': 'Expand', - 'fleet.collapse': 'Collapse', - 'fleet.detailLoading': 'Reading the session log…', - 'fleet.messages': 'Messages', - 'fleet.kind.relay': 'relay', - 'fleet.kind.mailbox': 'mailbox', - 'fleet.kind.settled': 'settled', - 'fleet.task.pending': 'pending', - 'fleet.task.in_progress': 'in progress', - 'fleet.task.completed': 'completed', - 'fleet.taskReady': 'ready', - 'fleet.taskBlocked': 'blocked', - 'fleet.taskUnowned': 'unowned', - 'fleet.taskScopes': 'Write scopes:', - 'fleet.members.title': 'Team Members', - 'fleet.members.count': '{n} members', - 'fleet.members.reply': 'Latest reply:', - 'fleet.members.tasks': '{n} active tasks', - 'fleet.members.noTasks': 'no active tasks', - 'fleet.members.tasksTip': 'Show only this member on the task board', - 'fleet.tasks.title': 'Task Board', - 'fleet.tasks.sub': 'Shared tasks and dependencies · read-only', - 'fleet.tasks.ownerTip': 'Pin this member in the inspector', - 'fleet.tasks.depTip': 'depends on {id} · click to locate', - 'fleet.tasks.focusTip': 'Locate on the task board', - 'fleet.tasks.dependsOn': 'depends on', - 'fleet.tasks.noMatch': 'No tasks for this member', - 'fleet.taskCol.pending': 'Pending', - 'fleet.taskCol.in_progress': 'In progress', - 'fleet.taskCol.completed': 'Done', - 'fleet.team.empty': 'No shared tasks yet — create them in conversation', - 'fleet.team.failureShort': 'records rejected', - 'fleet.settled.finished': 'finished; awaiting further instructions', - 'fleet.settled.finishedFinal': 'finished (one-shot; no follow-ups)', - 'fleet.settled.stopped': 'stopped before finishing', - 'fleet.settled.outOfRoom': 'ran out of context', - 'fleet.settled.declined': 'declined the task', - 'fleet.settled.failed': 'failed before finishing', - 'fleet.list.title': 'Fleet Roster', - 'fleet.list.sub': 'Every agent of the family · click a row to pin it in the inspector', - 'fleet.list.search': 'Search by name…', - 'fleet.list.filter': 'Status filter', - 'fleet.list.sort': 'Sort', - 'fleet.list.empty': 'No agents match', - 'fleet.filter.all': 'All', - 'fleet.filter.running': 'Running', - 'fleet.filter.done': 'Done', - 'fleet.filter.idle': 'Idle', - 'fleet.sort.spawn': 'Spawn order', - 'fleet.sort.tokens': 'Context tokens', - 'fleet.sort.duration': 'Duration', - 'fleet.sort.steps': 'Steps', - 'fleet.sort.recent': 'Recently active', - 'fleet.comms.title': 'Agent Comms', - 'fleet.comms.sub': 'Inter-agent messages · scans session logs on demand', - 'fleet.comms.scan': 'Scan {n} sessions for messages', - 'fleet.comms.scanning': 'Scanning {done}/{total}…', - 'fleet.comms.rows': '{n} messages', - 'fleet.comms.stale': 'new activity', - 'fleet.comms.rescan': 'Rescan', - 'fleet.comms.filter': 'Filter by agent', - 'fleet.comms.all': 'All agents', - 'fleet.comms.empty': 'No inter-agent messages found', - 'fleet.comms.truncated': 'Showing excerpts only (route caps)', - 'loading': 'Reading the session log…', - 'detail.loading': 'Loading history…', - 'detail.loadFailed': 'History failed to load — click to retry', - 'error': 'Failed to read context data: ', - 'error.retry': 'Retry', - 'gate.title': 'Update DeepSeek Harness', - 'gate.body': 'dsh-context supports DeepSeek Harness v{minimum} or newer.', - 'gate.current': 'Current', - 'gate.minimum': 'Minimum required', - 'gate.orNewer': 'or newer', - 'gate.ok': 'Got it', - 'footer': 'Token amount: “Estimated” uses the same fixed-density heuristic as DeepSeek Harness’s built-in tokenMeter (~4 chars ≈ 1 token); “Actual” is provider-reported usage.', - 'tip.step': 'Turn {t} · Step {s} of {n}', - 'tip.turn': 'Turn {t} · {n} steps', - 'tip.turn1': 'Turn {t} · 1 step', - 'tip.total': 'Total ≈ {n}', - 'tip.cat': '{cat} ≈ {n}', - 'tip.delta': 'Δ {n}', - 'tip.duration': 'Duration {n}', - 'ev.compaction': 'Context compacted (summary replaced {n} messages)', - 'ev.prune': 'Tool output pruned', - 'ev.skill': 'Skill injected ({name})', - 'ev.model': 'Model switched: {a} → {b}', - 'ev.mode.plan.on': 'Plan mode on', - 'ev.mode.plan.off': 'Plan mode off', - 'form.instructions': 'Instructions', - 'form.catalog': 'Catalog Update', - 'form.snapshot': 'State Snapshot', - 'form.notice': 'Notice', - 'form.relay': 'Agent Relay', - 'form.recall': 'Recall', - 'form.context': 'Context Injection', - 'node.toolResult': 'Tool Result', - 'node.calls': 'Calls ', - 'node.empty': '(empty reply)', - 'node.nonText': '(non-text message)', - 'node.snapshot': 'Snapshot: ', - 'node.skillTag': 'Skill · {name}', - 'cmd.label': 'Context', - 'cmd.section': 'Context', - 'cmd.desc': 'View current context makeup, browse per-step composition', - 'cmd.close': 'Close', - 'browser.title': 'Context Browser', - 'browser.live': 'Live (Next Request)', - 'browser.liveNow': 'Live · Next Request', - 'browser.items': '{n} Items', - 'browser.stepAt': 'T{t} S{s}', - 'browser.stepAtTip': 'First carried by the Turn {t} · Step {s} request', - 'browser.stepPendingTip': 'Expected in the Turn {t} · Step {s} request (not yet sent)', - 'browser.missingLive': '… {n} earlier messages are also part of the context (outside the served window)', - 'browser.approx': 'Some removed messages of this step exceed retention — the makeup below is approximate', - 'browser.base.step': 'prev step', - 'browser.base.turn': 'prev turn', - 'browser.base.tip': 'Diff baseline: the previous step, or the previous turn’s last step — with no predecessor, everything counts as change', - 'browser.dna': 'DNA Mode', - 'browser.dnaTip': 'One band per item in the order the model reads the context — system prompt, tool schemas, then messages chronologically; hover for details, click to open its row below', - 'browser.noHeader': 'Served by an older plugin build: token estimates only, no content', - 'browser.noEpoch': 'The header content (System Prompt / Tool Schemas) of this step is outside retention', - 'browser.headerMetaOnly': 'This environment cannot fetch header content on demand; token estimates only', - 'browser.noSystem': 'This request header carried no system prompt', - 'browser.noContent': 'Full content is outside the loaded message window (load older history in Chat to view)', - 'browser.search.user': 'Filter by message text…', - 'browser.search.inject': 'Filter injected context…', - 'browser.search.skill': 'Filter skills…', - 'browser.search.assistant': 'Filter by reply, calls, or thinking…', - 'browser.search.tool': 'Filter by tool or arguments…', - 'browser.kind.think': 'Thinking', - 'browser.kind.tool': 'Tools', - 'browser.kind.answer': 'Answer', - 'browser.kindTip': 'Filter replies by content kind: thinking, tool calls, or answer text', - 'browser.rowNoMatch': 'No rows match the current filter', - 'browser.loading': 'Loading full content from older session history…', - 'browser.notInLog': 'This item is not in the session log anymore (it may have been compacted away or cleared)', - 'browser.loadFailed': 'Load failed — click to retry', - 'tool.desc': 'Description', - 'tool.params': 'Parameters', - 'tool.paramsEmpty': '(no parameters)', - 'tool.plugin': 'The registering plugin of this tool (for reference)', - 'tool.unknown': 'Unknown plugin', - 'tool.unknownTitle': 'The tool was registered before the context plugin loaded, or its plugin has been unloaded, so its provider cannot be determined', - 'tool.jsonToggle': 'View Raw JSON', - 'tool.jsonHide': 'Collapse', - 'tool.search': 'Filter by name, description, or parameters…', - 'tool.sort.size': 'By size', - 'tool.sort.count': 'By calls', - 'tool.sort.name': 'By name', - 'tool.sortTip': 'Sort tools by call count in the shown step (default), token size, or name', - 'tool.hitsTip': 'Times this tool was called and answered within the shown step’s context', - 'tool.noMatch': 'No tools match the current filter', - 'rich.raw': 'Raw', - 'rich.md': 'Markdown', - 'rich.toMd': 'View as Markdown', - 'rich.toRaw': 'View Raw Text', - 'rich.copy': 'Copy Raw Text', - 'rich.copied': 'Copied', - 'rich.md.copy': 'Copy', - 'rich.md.copied': 'Copied', - 'rich.md.footnotes': 'Footnotes', - 'rich.find': 'Find in Text', - 'rich.findPlaceholder': 'Find…', - 'rich.findPrev': 'Previous Match', - 'rich.findNext': 'Next Match', - 'rich.findClose': 'Close Find', - 'block.thinking': 'Reasoning', - 'block.answer': 'Answer', - 'block.content': 'Content', - 'block.result': 'Result', - 'block.summary': 'Summary', - 'block.line': '1 line', - 'block.lines': '{n} lines', - 'call.ok': 'OK', - 'call.fail': 'Failed', - 'call.exit': 'exit {n}', - 'node.failed': 'Tool execution failed', - 'attach.images': 'Images', - 'attach.other': 'Other content', - 'attach.image': 'Image', - 'attach.open': 'Open full image', - 'attach.preview': 'Image preview', - 'attach.close': 'Close', - 'attach.loading': '…', - 'attach.loadFailed': 'Load failed · click to retry', - 'attach.raw': 'Raw', - 'attach.sent': 'Sent', - 'attach.token': 'Token', - 'attach.tokensTip': 'Estimated token cost via DeepSeek\'s official image-size conversion (384-token cap per image)', - 'ov.title': 'Context Insights', - 'ov.unavailable': 'The session list is unavailable', - 'ov.range.label': 'Range', - 'ov.range.today': 'Today', - 'ov.range.7d': 'Last 7 days', - 'ov.range.30d': 'Last 30 days', - 'ov.range.all': 'All', - 'ov.date.label': 'Date range', - 'ov.date.open': 'Pick a custom date range', - 'ov.date.from': 'Start date', - 'ov.date.to': 'End date', - 'ov.date.pick': 'Pick a date', - 'ov.date.prev': 'Previous month', - 'ov.date.next': 'Next month', - 'ov.date.hint': 'Click a start date', - 'ov.date.hintEnd': 'Now click the end date', - 'ov.date.clear': 'Clear', - 'ov.date.wd.0': 'S', - 'ov.date.wd.1': 'M', - 'ov.date.wd.2': 'T', - 'ov.date.wd.3': 'W', - 'ov.date.wd.4': 'T', - 'ov.date.wd.5': 'F', - 'ov.date.wd.6': 'S', - 'ov.kpi.sessions': 'Active Sessions', - 'ov.kpi.ofTotal': 'of {n} total', - 'ov.kpi.tokens': 'Tokens Used', - 'ov.kpi.sessionsSub': 'across {n} sessions', - 'ov.kpi.pricedSub': '{n} of {total} sessions priced', - 'ov.kpi.toolSub': 'tool runs {dur}', - 'ov.kpi.wallSub': '{n} model calls', - 'ov.stats.empty': 'No billed tokens in this range', - 'ov.usage.title': 'Last 7 Days', - 'ov.usage.tokens': 'Tokens', - 'ov.usage.cost': 'Cost (price-mapped models only)', - 'ov.usage.costTip': 'Cost', - 'ov.usage.empty': 'No usage in the last 7 days — daily tokens and cost appear once sessions make model requests', - 'balance.title': 'DeepSeek balance', - 'balance.tip.granted': 'Granted balance', - 'balance.tip.toppedUp': 'Topped-up balance', - 'ov.heat.title': 'Activity', - 'ov.heat.sub': 'Filter by date', - 'ov.heat.empty': 'No activity yet — daily usage appears once sessions make model requests', - 'ov.heat.sessions': '{n} active sessions', - 'ov.heat.less': 'Less', - 'ov.heat.more': 'More', - 'ov.heat.metric': 'Metric', - 'ov.heat.metric.sessions': 'Sessions', - 'ov.heat.metric.steps': 'Steps', - 'ov.heat.steps': '{n} steps', - 'ov.heat.wd.1': 'Mon', - 'ov.heat.wd.3': 'Wed', - 'ov.heat.wd.5': 'Fri', - 'ov.heat.mon.01': 'Jan', - 'ov.heat.mon.02': 'Feb', - 'ov.heat.mon.03': 'Mar', - 'ov.heat.mon.04': 'Apr', - 'ov.heat.mon.05': 'May', - 'ov.heat.mon.06': 'Jun', - 'ov.heat.mon.07': 'Jul', - 'ov.heat.mon.08': 'Aug', - 'ov.heat.mon.09': 'Sep', - 'ov.heat.mon.10': 'Oct', - 'ov.heat.mon.11': 'Nov', - 'ov.heat.mon.12': 'Dec', - 'ov.skills.empty': 'No skill loads in this range — loaded skills appear here with their counts and last load', - 'ov.skills.noMatch': 'No skills match the current filter', - 'ov.skills.search': 'Search skills…', - 'ov.skills.more': '{n} more skills', - 'ov.skills.loads': '{n} loads', - 'ov.skills.summary': '{skills} skills · {loads} loads', - 'ov.skills.sortLabel': 'Skill sort', - 'ov.skills.sort.loads': 'Loads', - 'ov.skills.sort.recent': 'Recent', - 'ov.skills.sessions': '{n} sessions', - 'ov.skills.clickFilter': 'Click to filter the sessions that loaded it', - 'ov.skills.clickRelease': 'Click again to release the filter', - 'ov.skills.src.project': 'Project', - 'ov.skills.src.user': 'User', - 'ov.skills.src.bundled': 'Built-in', - 'ov.skills.k.source': 'Source', - 'ov.skills.k.usage': 'Usage', - 'ov.skills.k.last': 'Last', - 'ov.skills.k.path': 'Path', - 'ov.skills.copyPath': 'Click to copy the path', - 'ov.skills.copied': 'Copied', - 'ov.list.title': 'Sessions', - 'ov.list.search': 'Search title / path / last message…', - 'ov.list.sortLabel': 'Sort', - 'ov.list.sort.recent': 'Last updated', - 'ov.list.sort.tokens': 'Total Tokens', - 'ov.list.sort.context': 'Current Context', - 'ov.list.empty': 'No sessions yet — each session’s context profile appears here once you start one', - 'ov.list.noMatch': 'No sessions match the current filters', - 'ov.list.noData': 'No context data yet — stats appear once the session makes model requests', - 'ov.list.dayFilter': 'active on {day}', - 'ov.list.dayClear': 'Clear the day filter', - 'ov.list.skillClear': 'Clear the skill filter', - 'ov.list.pager': 'Session pagination', - 'ov.list.page': 'Page {n} of {total}', - 'ov.list.prev': 'Previous page', - 'ov.list.next': 'Next page', - 'ov.group.label': 'Group', - 'ov.group.ungrouped': 'Ungrouped', - 'ov.running': 'Running', - 'ov.current': 'current', - 'ov.card.turns': '{n} turns · {s} steps', - 'ov.card.teamUsage': 'Total Tokens', - 'ov.card.teamCost': 'Total Est. Cost', - 'ov.card.lastUser': 'Last message', - 'ov.time.now': 'just now', - 'ov.time.m': '{n}m ago', - 'ov.time.h': '{n}h ago', - 'ov.time.d': '{n}d ago', -} satisfies Record +export { DICT_ZH, type DictKey } from './i18nZh' +export { DICT_EN } from './i18nEn' diff --git a/src/client/i18nEn.ts b/src/client/i18nEn.ts new file mode 100644 index 0000000..2a51d19 --- /dev/null +++ b/src/client/i18nEn.ts @@ -0,0 +1,539 @@ +/** The English dictionary; `DictKey` pins it to the zh key set at compile time. */ + +import type { DictKey } from './i18nZh' + +export const DICT_EN = { + 'tab.context': 'Context', + 'tab.fleet': 'Fleet', + 'sidebar.guideDescription': 'Inspect context composition, stats, and evolution.', + 'cat.system': 'System Prompt', + 'cat.tools': 'Tool Schemas', + 'cat.user': 'User Messages', + 'cat.inject': 'Injected Context', + 'cat.skill': 'Skill Injections', + 'cat.assistant': 'Assistant Messages', + 'cat.tool': 'Tool Results', + 'overview.title': 'Current Context', + 'overview.estimate': 'tokens (estimated)', + 'overview.free': 'Free Window', + 'overview.used': 'of context used', + 'overview.ofUsed': 'of used context', + 'overview.compactReserve': 'Auto-compaction reserve: auto-compaction triggers at {pct}% of the window — this area is normally kept as headroom, not actually used', + 'stats.title': 'Context Stats', + 'stats.session': 'Current Session', + 'stats.turns': 'Turns', + 'stats.steps': 'Steps', + 'stats.answers': 'Answers', + 'stats.skills': 'Skill Loads', + 'stats.skillsJump': 'Open Skill Injections in the Context Browser', + 'stats.answersJump': 'Filter Answers in the Context Browser', + 'stats.humanInputs': 'Human Inputs', + 'stats.humanInputsTip': 'User messages and question answerings in current session.', + 'stats.io': 'Input / Output', + 'stats.events': 'Context Events', + 'stats.toolCalls': 'Tool Calls', + 'stats.toolsMore': '+{n} more', + 'stats.cacheHit': 'Cache Hit', + 'stats.cacheHitTip': 'Cumulative cache-read share of billed input across the session.', + 'stats.cost': 'Cost', + 'stats.costTip': 'Estimated cost for this agent and every descendant subagent session, for reference only.', + 'stats.costTipDeepseek': 'DeepSeek bills peak windows (Beijing Time weekdays 09:00–12:00, 14:00–18:00) at list price; all other hours are half price.', + 'stats.costTipCny': 'The CNY display converts at 1 CNY = 0.15 USD.', + 'stats.currentAgent': 'Current Agent', + 'stats.teamSubs': 'Subagents × {n}', + 'stats.billedTip': 'Token usage is the billed total: uncached input, cache read, cache write, and output.', + 'stats.subCostTip': 'Summed estimates of every descendant subagent session’s own cumulative cost — all levels of the subtree (same basis); the current agent is not included.', + 'stats.costPriceHead': 'Per-1M-token rates:', + 'stats.costPriceBy': 'Priced as listed on models.dev for {p} · {m}.', + 'stats.costHit': 'Cache input', + 'stats.costMiss': 'Uncached input', + 'stats.costWrite': 'Cache write', + 'stats.costOut': 'Output', + 'stats.costUnavailable': 'Model prices are unavailable (retrying automatically) — the cost cannot be estimated yet.', + 'timing.title': 'Timing Stats', + 'timing.total': 'Active Time', + 'timing.ttft': 'TTFT', + 'timing.gen': 'LLM Gen', + 'timing.reasoning': 'Thinking', + 'timing.text': 'Answers', + 'timing.toolArgs': 'Tool args', + 'timing.tools': 'Tool runs', + 'timing.other': 'Overhead', + 'timing.callTimes': '{n} calls', + 'timing.toolTimes': '{n} runs', + 'timing.blockTimes': '{n} blocks', + 'timing.empty': 'No timing data yet — durations appear as the conversation runs', + 'timing.tps': 'TPS {tps} tok/s', + 'timing.tpsTip': 'Output speed (TPS): summed decoded output tokens over summed decode time — the same pairing as the harness session stats.', + 'timing.strip': 'Session-time strip: slices packed in occurrence order, width as share of the active time; ticks at zero, the quartiles, and the full span', + 'tokens.title': 'Token Stats', + 'tokens.total': 'Total', + 'tokens.output': 'Output', + 'tokens.outputNote': 'incl. reasoning', + 'plugin.title': 'Plugin Info', + 'plugin.hint': 'The best DSH context plugin ⭐', + 'plugin.name': 'Plugin', + 'plugin.github': 'GitHub', + 'plugin.settings': 'Plugin Settings', + 'plugin.settingsOpen': 'Open plugin settings', + 'trend.title': 'Context Trend', + 'gran.step': 'Step', + 'gran.turn': 'Turn', + 'settings.placement': 'Entry Options', + 'placement.tab': 'Tab', + 'placement.sidebar': 'Sidebar', + 'placement.all': 'All', + 'settings.insightsEntry': 'Context Insights entry', + 'settings.fleetTab': 'Fleet tab', + 'showHide.show': 'Show', + 'showHide.hide': 'Hide', + 'settings.gran': 'Trend Chart · Default granularity', + 'settings.mode': 'Trend Chart · Default display', + 'settings.durationCurve': 'Trend Chart · Duration curve', + 'settings.deltaBase': 'Context Browser · Diff baseline', + 'settings.toolSort': 'Tool Schemas · Default sort', + 'settings.fileSort': 'File Activity · Default sort', + 'settings.readOnly': 'Settings are read-only in this environment', + 'settings.promptPrefix': 'System Prompt · Prefix', + 'settings.promptSuffix': 'System Prompt · Suffix', + 'settings.promptHint': 'Joined at the very start/end of every session\'s system prompt, for all agents (subagents included); edits apply from the next turn', + 'settings.promptPlaceholder': 'Leave empty to disable', + 'gran.total': 'Total', + 'gran.delta': 'Delta', + 'gran.modeHint': 'Total: cumulative makeup; Delta: change vs the previous request', + 'trend.adaptive': 'Adaptive', + 'trend.adaptiveHint': 'Rescale bar heights to the visible range, following the scroll', + 'trend.duration': 'Duration', + 'trend.durationTip': 'Overlay each step’s active time (step start to end — model and tool calls, excluding waits for your decisions or answers) as a curve over the bars, read off the quartile axis on the chart’s right; turn granularity sums a turn’s steps', + 'trend.dna': 'DNA Mode', + 'trend.dnaTip': 'Draw each bar as that request’s context fingerprint — one band per item in the order the model reads it; with Delta, each band shows that item’s change against the previous bar. Hover for the item, click to reveal it in the Context browser, and every bar lights the same item’s lifetime', + 'trend.dnaItem': '{label}: {n}', + 'trend.empty': 'Send a message and each model request’s context makeup shows up here', + 'detail.step': 'Turn {t} · Step {s} of {n}', + 'detail.turn': 'Turn {t} · {n} steps', + 'detail.lastStep': 'Last Step', + 'detail.estTotal': 'Estimated ≈ {n}', + 'detail.actual': 'Actual {n}', + 'detail.output': 'Output {n}', + 'detail.cache': 'Cache {n}%', + 'brief.turn': 'User', + 'brief.input': 'In', + 'brief.reply': 'Response', + 'brief.more': '+{n}', + 'brief.noInputs': '(nothing new)', + 'brief.locate': 'Reveal in Context Browser', + 'jump.title': 'View this turn in the Context view', + 'brief.turnTip': 'The user message that opened this turn — every step of the turn recalls it', + 'brief.inputTip': 'What entered after the previous reply and before this request went out — usually the previous tool-call results; a turn opener has nothing new', + 'brief.replyTip': 'What the model returned on this step (a text reply or tool calls) — results of calls made here appear in the In row of the next bar', + 'events.title': 'Context Events', + 'events.empty': 'No context events yet (compaction, injections, model switches appear here)', + 'events.at': 'T{t} S{s}', + 'events.range': 'T{t} S{a}→{b}', + 'events.rangeTo': 'T{a} S{as} → T{b} S{bs}', + 'kind.inject': 'Inject', + 'kind.compaction': 'Compact', + 'kind.prune': 'Prune', + 'kind.model': 'Switch', + 'kind.mode': 'Mode', + 'files.title': 'File Activity', + 'files.scopeLatest': 'Up to latest · follows the trend chart pick', + 'files.kind.all': 'All', + 'files.kind.read': 'Read', + 'files.kind.write': 'Written', + 'files.kind.search': 'Searched', + 'files.kind.image': 'Images', + 'files.chipTip': '{files} files · {ops} ops', + 'files.search': 'Filter by path…', + 'files.sort.count': 'Most active', + 'files.sort.latest': 'Latest', + 'files.sort.path': 'By path', + 'files.sortTip': 'Sort files by operation counts (of the selected kind when a kind chip is active), most recent activity, or path', + 'files.files': '{n} files', + 'files.deltaTip': 'Cumulative line change estimated from edit/write call arguments: + added / − removed', + 'files.empty': 'No file reads, writes, or searches in this range', + 'files.noMatch': 'No files match the current filters', + 'files.locate': 'Reveal this operation in the Context Browser', + 'files.hits': '{n} hits', + 'files.readTip': 'Read lines {a}–{b}', + 'files.open': 'Open on your system', + 'files.preview': 'Preview in the sidebar', + 'files.readEst': 'Lines read, estimated from the limit argument', + 'files.errs': '{n} failed', + 'files.form.image': 'Image', + 'files.form.dir': 'Directory', + 'files.form.text': 'File', + 'files.glyph.root': 'Workspace root', + 'files.glyph.tests': 'Tests', + 'files.glyph.docs': 'Docs', + 'files.glyph.deps': 'Dependencies', + 'files.glyph.build': 'Build output', + 'files.glyph.scripts': 'Scripts', + 'files.glyph.config': 'Config', + 'files.glyph.assets': 'Assets', + 'files.glyph.hidden': 'Metadata directory', + 'files.glyph.lock': 'Lockfile', + 'files.glyph.docker': 'Docker', + 'files.glyph.ignore': 'Ignore rules', + 'files.glyph.license': 'License', + 'files.glyph.python': 'Python', + 'files.glyph.notebook': 'Notebook', + 'files.glyph.shell': 'Shell', + 'files.glyph.style': 'Styles', + 'files.glyph.database': 'Database', + 'files.glyph.data': 'Data / manifest', + 'files.glyph.markdown': 'Markup document', + 'files.glyph.log': 'Log', + 'files.glyph.sheet': 'Spreadsheet', + 'files.glyph.document': 'Document', + 'files.glyph.archive': 'Archive', + 'files.glyph.font': 'Font', + 'files.glyph.media': 'Media', + 'files.glyph.lang.ts': 'TypeScript', + 'files.glyph.lang.js': 'JavaScript', + 'files.glyph.lang.go': 'Go', + 'files.glyph.lang.rust': 'Rust', + 'files.glyph.lang.java': 'Java', + 'files.glyph.lang.kotlin': 'Kotlin', + 'files.glyph.lang.ruby': 'Ruby', + 'files.glyph.lang.php': 'PHP', + 'files.glyph.lang.c': 'C', + 'files.glyph.lang.cpp': 'C++', + 'files.glyph.lang.csharp': 'C#', + 'files.glyph.lang.scala': 'Scala', + 'files.glyph.lang.lua': 'Lua', + 'files.glyph.lang.dart': 'Dart', + 'files.glyph.lang.swift': 'Swift', + 'files.glyph.lang.vue': 'Vue', + 'files.glyph.lang.svelte': 'Svelte', + 'files.glyph.lang.html': 'HTML', + 'agents.title': 'Agent Network', + 'agents.sub': 'Live context of this agent and its subagents · click a node to open its session', + 'agents.chip.count': '{n} agents', + 'agents.chip.running': '{n} running', + 'agents.chip.tokens': '{n} tokens in context', + 'agents.more': '{n} more not shown', + 'agents.solo': 'No subagents yet — when the agent delegates work through the subagent tool, the network unfolds here', + 'agents.self': 'current', + 'agents.running': 'running', + 'agents.legend.free': 'free window', + 'agents.oneshot': 'one-shot', + 'agents.continuable': 'continuable', + 'agents.steps': '{n} steps', + 'agents.billed': '{n} billed', + 'fleet.teamChip': 'team · {m} members · {n} tasks', + 'fleet.unpin': 'Unpin', + 'fleet.open': 'Open session', + 'fleet.membership': 'Team membership', + 'fleet.role.lead': 'lead', + 'fleet.role.teammate': 'teammate', + 'fleet.phase.provisioning': 'provisioning', + 'fleet.phase.failed': 'failed', + 'fleet.memberInactive': 'inactive', + 'fleet.config': 'Configuration', + 'fleet.prompt': 'Delegation prompt', + 'fleet.expand': 'Expand', + 'fleet.collapse': 'Collapse', + 'fleet.detailLoading': 'Reading the session log…', + 'fleet.messages': 'Messages', + 'fleet.kind.relay': 'relay', + 'fleet.kind.mailbox': 'mailbox', + 'fleet.kind.settled': 'settled', + 'fleet.task.pending': 'pending', + 'fleet.task.in_progress': 'in progress', + 'fleet.task.completed': 'completed', + 'fleet.taskReady': 'ready', + 'fleet.taskBlocked': 'blocked', + 'fleet.taskUnowned': 'unowned', + 'fleet.taskScopes': 'Write scopes:', + 'fleet.members.title': 'Team Members', + 'fleet.members.count': '{n} members', + 'fleet.members.reply': 'Latest reply:', + 'fleet.members.tasks': '{n} active tasks', + 'fleet.members.noTasks': 'no active tasks', + 'fleet.members.tasksTip': 'Show only this member on the task board', + 'fleet.tasks.title': 'Task Board', + 'fleet.tasks.sub': 'Shared tasks and dependencies · read-only', + 'fleet.tasks.ownerTip': 'Pin this member in the inspector', + 'fleet.tasks.depTip': 'depends on {id} · click to locate', + 'fleet.tasks.focusTip': 'Locate on the task board', + 'fleet.tasks.dependsOn': 'depends on', + 'fleet.tasks.noMatch': 'No tasks for this member', + 'fleet.taskCol.pending': 'Pending', + 'fleet.taskCol.in_progress': 'In progress', + 'fleet.taskCol.completed': 'Done', + 'fleet.team.empty': 'No shared tasks yet — create them in conversation', + 'fleet.team.failureShort': 'records rejected', + 'fleet.settled.finished': 'finished; awaiting further instructions', + 'fleet.settled.finishedFinal': 'finished (one-shot; no follow-ups)', + 'fleet.settled.stopped': 'stopped before finishing', + 'fleet.settled.outOfRoom': 'ran out of context', + 'fleet.settled.declined': 'declined the task', + 'fleet.settled.failed': 'failed before finishing', + 'fleet.list.title': 'Fleet Roster', + 'fleet.list.sub': 'Every agent of the family · click a row to pin it in the inspector', + 'fleet.list.search': 'Search by name…', + 'fleet.list.filter': 'Status filter', + 'fleet.list.sort': 'Sort', + 'fleet.list.empty': 'No agents match', + 'fleet.filter.all': 'All', + 'fleet.filter.running': 'Running', + 'fleet.filter.done': 'Done', + 'fleet.filter.idle': 'Idle', + 'fleet.sort.spawn': 'Spawn order', + 'fleet.sort.tokens': 'Context tokens', + 'fleet.sort.duration': 'Duration', + 'fleet.sort.steps': 'Steps', + 'fleet.sort.recent': 'Recently active', + 'fleet.comms.title': 'Agent Comms', + 'fleet.comms.sub': 'Inter-agent messages · scans session logs on demand', + 'fleet.comms.scan': 'Scan {n} sessions for messages', + 'fleet.comms.scanning': 'Scanning {done}/{total}…', + 'fleet.comms.rows': '{n} messages', + 'fleet.comms.stale': 'new activity', + 'fleet.comms.rescan': 'Rescan', + 'fleet.comms.filter': 'Filter by agent', + 'fleet.comms.all': 'All agents', + 'fleet.comms.empty': 'No inter-agent messages found', + 'fleet.comms.truncated': 'Showing excerpts only (route caps)', + 'loading': 'Reading the session log…', + 'detail.loading': 'Loading history…', + 'detail.loadFailed': 'History failed to load — click to retry', + 'error': 'Failed to read context data: ', + 'error.retry': 'Retry', + 'gate.title': 'Update DeepSeek Harness', + 'gate.body': 'dsh-context supports DeepSeek Harness v{minimum} or newer.', + 'gate.current': 'Current', + 'gate.minimum': 'Minimum required', + 'gate.orNewer': 'or newer', + 'gate.ok': 'Got it', + 'footer': 'Token amount: “Estimated” uses the same fixed-density heuristic as DeepSeek Harness’s built-in tokenMeter (~4 chars ≈ 1 token); “Actual” is provider-reported usage.', + 'tip.step': 'Turn {t} · Step {s} of {n}', + 'tip.turn': 'Turn {t} · {n} steps', + 'tip.turn1': 'Turn {t} · 1 step', + 'tip.total': 'Total ≈ {n}', + 'tip.cat': '{cat} ≈ {n}', + 'tip.delta': 'Δ {n}', + 'tip.duration': 'Duration {n}', + 'ev.compaction': 'Context compacted (summary replaced {n} messages)', + 'ev.prune': 'Tool output pruned', + 'ev.skill': 'Skill injected ({name})', + 'ev.model': 'Model switched: {a} → {b}', + 'ev.mode.plan.on': 'Plan mode on', + 'ev.mode.plan.off': 'Plan mode off', + 'form.instructions': 'Instructions', + 'form.catalog': 'Catalog Update', + 'form.snapshot': 'State Snapshot', + 'form.notice': 'Notice', + 'form.relay': 'Agent Relay', + 'form.recall': 'Recall', + 'form.context': 'Context Injection', + 'node.toolResult': 'Tool Result', + 'node.calls': 'Calls ', + 'node.empty': '(empty reply)', + 'node.nonText': '(non-text message)', + 'node.snapshot': 'Snapshot: ', + 'node.skillTag': 'Skill · {name}', + 'cmd.label': 'Context', + 'cmd.section': 'Context', + 'cmd.desc': 'View current context makeup, browse per-step composition', + 'cmd.close': 'Close', + 'browser.title': 'Context Browser', + 'browser.live': 'Live (Next Request)', + 'browser.liveNow': 'Live · Next Request', + 'browser.items': '{n} Items', + 'browser.stepAt': 'T{t} S{s}', + 'browser.stepAtTip': 'First carried by the Turn {t} · Step {s} request', + 'browser.stepPendingTip': 'Expected in the Turn {t} · Step {s} request (not yet sent)', + 'browser.missingLive': '… {n} earlier messages are also part of the context (outside the served window)', + 'browser.approx': 'Some removed messages of this step exceed retention — the makeup below is approximate', + 'browser.base.step': 'prev step', + 'browser.base.turn': 'prev turn', + 'browser.base.tip': 'Diff baseline: the previous step, or the previous turn’s last step — with no predecessor, everything counts as change', + 'browser.dna': 'DNA Mode', + 'browser.dnaTip': 'One band per item in the order the model reads the context — system prompt, tool schemas, then messages chronologically; hover for details, click to open its row below', + 'browser.noHeader': 'Served by an older plugin build: token estimates only, no content', + 'browser.noEpoch': 'The header content (System Prompt / Tool Schemas) of this step is outside retention', + 'browser.headerMetaOnly': 'This environment cannot fetch header content on demand; token estimates only', + 'browser.noSystem': 'This request header carried no system prompt', + 'browser.noContent': 'Full content is outside the loaded message window (load older history in Chat to view)', + 'browser.search.user': 'Filter by message text…', + 'browser.search.inject': 'Filter injected context…', + 'browser.search.skill': 'Filter skills…', + 'browser.search.assistant': 'Filter by reply, calls, or thinking…', + 'browser.search.tool': 'Filter by tool or arguments…', + 'browser.kind.think': 'Thinking', + 'browser.kind.tool': 'Tools', + 'browser.kind.answer': 'Answer', + 'browser.kindTip': 'Filter replies by content kind: thinking, tool calls, or answer text', + 'browser.rowNoMatch': 'No rows match the current filter', + 'browser.loading': 'Loading full content from older session history…', + 'browser.notInLog': 'This item is not in the session log anymore (it may have been compacted away or cleared)', + 'browser.loadFailed': 'Load failed — click to retry', + 'tool.desc': 'Description', + 'tool.params': 'Parameters', + 'tool.paramsEmpty': '(no parameters)', + 'tool.plugin': 'The registering plugin of this tool (for reference)', + 'tool.unknown': 'Unknown plugin', + 'tool.unknownTitle': 'The tool was registered before the context plugin loaded, or its plugin has been unloaded, so its provider cannot be determined', + 'tool.jsonToggle': 'View Raw JSON', + 'tool.jsonHide': 'Collapse', + 'tool.search': 'Filter by name, description, or parameters…', + 'tool.sort.size': 'By size', + 'tool.sort.count': 'By calls', + 'tool.sort.name': 'By name', + 'tool.sortTip': 'Sort tools by call count in the shown step (default), token size, or name', + 'tool.hitsTip': 'Times this tool was called and answered within the shown step’s context', + 'tool.noMatch': 'No tools match the current filter', + 'rich.raw': 'Raw', + 'rich.md': 'Markdown', + 'rich.toMd': 'View as Markdown', + 'rich.toRaw': 'View Raw Text', + 'rich.copy': 'Copy Raw Text', + 'rich.copied': 'Copied', + 'rich.md.copy': 'Copy', + 'rich.md.copied': 'Copied', + 'rich.md.footnotes': 'Footnotes', + 'rich.find': 'Find in Text', + 'rich.findPlaceholder': 'Find…', + 'rich.findPrev': 'Previous Match', + 'rich.findNext': 'Next Match', + 'rich.findClose': 'Close Find', + 'block.thinking': 'Reasoning', + 'block.answer': 'Answer', + 'block.content': 'Content', + 'block.result': 'Result', + 'block.summary': 'Summary', + 'block.line': '1 line', + 'block.lines': '{n} lines', + 'call.ok': 'OK', + 'call.fail': 'Failed', + 'call.exit': 'exit {n}', + 'node.failed': 'Tool execution failed', + 'attach.images': 'Images', + 'attach.other': 'Other content', + 'attach.image': 'Image', + 'attach.open': 'Open full image', + 'attach.preview': 'Image preview', + 'attach.close': 'Close', + 'attach.loading': '…', + 'attach.loadFailed': 'Load failed · click to retry', + 'attach.raw': 'Raw', + 'attach.sent': 'Sent', + 'attach.token': 'Token', + 'attach.tokensTip': 'Estimated token cost via DeepSeek\'s official image-size conversion (384-token cap per image)', + 'ov.title': 'Context Insights', + 'ov.unavailable': 'The session list is unavailable', + 'ov.range.label': 'Range', + 'ov.range.today': 'Today', + 'ov.range.7d': 'Last 7 days', + 'ov.range.30d': 'Last 30 days', + 'ov.range.all': 'All', + 'ov.date.label': 'Date range', + 'ov.date.open': 'Pick a custom date range', + 'ov.date.from': 'Start date', + 'ov.date.to': 'End date', + 'ov.date.pick': 'Pick a date', + 'ov.date.prev': 'Previous month', + 'ov.date.next': 'Next month', + 'ov.date.hint': 'Click a start date', + 'ov.date.hintEnd': 'Now click the end date', + 'ov.date.clear': 'Clear', + 'ov.date.wd.0': 'S', + 'ov.date.wd.1': 'M', + 'ov.date.wd.2': 'T', + 'ov.date.wd.3': 'W', + 'ov.date.wd.4': 'T', + 'ov.date.wd.5': 'F', + 'ov.date.wd.6': 'S', + 'ov.kpi.sessions': 'Active Sessions', + 'ov.kpi.ofTotal': 'of {n} total', + 'ov.kpi.tokens': 'Tokens Used', + 'ov.kpi.sessionsSub': 'across {n} sessions', + 'ov.kpi.pricedSub': '{n} of {total} sessions priced', + 'ov.kpi.toolSub': 'tool runs {dur}', + 'ov.kpi.wallSub': '{n} model calls', + 'ov.stats.empty': 'No billed tokens in this range', + 'ov.usage.title': 'Last 7 Days', + 'ov.usage.tokens': 'Tokens', + 'ov.usage.cost': 'Cost (price-mapped models only)', + 'ov.usage.costTip': 'Cost', + 'ov.usage.empty': 'No usage in the last 7 days — daily tokens and cost appear once sessions make model requests', + 'balance.title': 'DeepSeek balance', + 'balance.tip.granted': 'Granted balance', + 'balance.tip.toppedUp': 'Topped-up balance', + 'ov.heat.title': 'Activity', + 'ov.heat.sub': 'Filter by date', + 'ov.heat.empty': 'No activity yet — daily usage appears once sessions make model requests', + 'ov.heat.sessions': '{n} active sessions', + 'ov.heat.less': 'Less', + 'ov.heat.more': 'More', + 'ov.heat.metric': 'Metric', + 'ov.heat.metric.sessions': 'Sessions', + 'ov.heat.metric.steps': 'Steps', + 'ov.heat.steps': '{n} steps', + 'ov.heat.wd.1': 'Mon', + 'ov.heat.wd.3': 'Wed', + 'ov.heat.wd.5': 'Fri', + 'ov.heat.mon.01': 'Jan', + 'ov.heat.mon.02': 'Feb', + 'ov.heat.mon.03': 'Mar', + 'ov.heat.mon.04': 'Apr', + 'ov.heat.mon.05': 'May', + 'ov.heat.mon.06': 'Jun', + 'ov.heat.mon.07': 'Jul', + 'ov.heat.mon.08': 'Aug', + 'ov.heat.mon.09': 'Sep', + 'ov.heat.mon.10': 'Oct', + 'ov.heat.mon.11': 'Nov', + 'ov.heat.mon.12': 'Dec', + 'ov.skills.empty': 'No skill loads in this range — loaded skills appear here with their counts and last load', + 'ov.skills.noMatch': 'No skills match the current filter', + 'ov.skills.search': 'Search skills…', + 'ov.skills.more': '{n} more skills', + 'ov.skills.loads': '{n} loads', + 'ov.skills.summary': '{skills} skills · {loads} loads', + 'ov.skills.sortLabel': 'Skill sort', + 'ov.skills.sort.loads': 'Loads', + 'ov.skills.sort.recent': 'Recent', + 'ov.skills.sessions': '{n} sessions', + 'ov.skills.clickFilter': 'Click to filter the sessions that loaded it', + 'ov.skills.clickRelease': 'Click again to release the filter', + 'ov.skills.src.project': 'Project', + 'ov.skills.src.user': 'User', + 'ov.skills.src.bundled': 'Built-in', + 'ov.skills.k.source': 'Source', + 'ov.skills.k.usage': 'Usage', + 'ov.skills.k.last': 'Last', + 'ov.skills.k.path': 'Path', + 'ov.skills.copyPath': 'Click to copy the path', + 'ov.skills.copied': 'Copied', + 'ov.list.title': 'Sessions', + 'ov.list.search': 'Search title / path / last message…', + 'ov.list.sortLabel': 'Sort', + 'ov.list.sort.recent': 'Last updated', + 'ov.list.sort.tokens': 'Total Tokens', + 'ov.list.sort.context': 'Current Context', + 'ov.list.empty': 'No sessions yet — each session’s context profile appears here once you start one', + 'ov.list.noMatch': 'No sessions match the current filters', + 'ov.list.noData': 'No context data yet — stats appear once the session makes model requests', + 'ov.list.dayFilter': 'active on {day}', + 'ov.list.dayClear': 'Clear the day filter', + 'ov.list.skillClear': 'Clear the skill filter', + 'ov.list.pager': 'Session pagination', + 'ov.list.page': 'Page {n} of {total}', + 'ov.list.prev': 'Previous page', + 'ov.list.next': 'Next page', + 'ov.group.label': 'Group', + 'ov.group.ungrouped': 'Ungrouped', + 'ov.running': 'Running', + 'ov.current': 'current', + 'ov.card.turns': '{n} turns · {s} steps', + 'ov.card.teamUsage': 'Total Tokens', + 'ov.card.teamCost': 'Total Est. Cost', + 'ov.card.lastUser': 'Last message', + 'ov.time.now': 'just now', + 'ov.time.m': '{n}m ago', + 'ov.time.h': '{n}h ago', + 'ov.time.d': '{n}d ago', +} satisfies Record diff --git a/src/client/i18nZh.ts b/src/client/i18nZh.ts new file mode 100644 index 0000000..c537815 --- /dev/null +++ b/src/client/i18nZh.ts @@ -0,0 +1,542 @@ +/** The Chinese (Simplified) dictionary — the key-set source of truth every other locale must carry in full. */ +export const DICT_ZH = { + 'tab.context': '上下文', + 'tab.fleet': '编队', + 'sidebar.guideDescription': '查看上下文的构成、统计、演变。', + 'cat.system': '系统提示词', + 'cat.tools': '工具定义', + 'cat.user': '用户消息', + 'cat.inject': '注入内容', + 'cat.skill': '技能注入', + 'cat.assistant': '助手消息', + 'cat.tool': '工具结果', + 'overview.title': '当前上下文', + 'overview.estimate': 'tokens(估算)', + 'overview.free': '剩余窗口', + 'overview.used': '上下文已用', + 'overview.ofUsed': '占已用上下文', + 'overview.compactReserve': '自动压缩预留:占用达 {pct}% 窗口时触发压缩,此区域一般不实际占用', + 'stats.title': '上下文统计', + 'stats.session': '当前会话', + 'stats.turns': '轮次', + 'stats.steps': '步数', + 'stats.answers': '模型回复', + 'stats.skills': '技能加载', + 'stats.skillsJump': '在上下文浏览器中展开技能注入', + 'stats.answersJump': '在上下文浏览器中筛选回答', + 'stats.humanInputs': '用户输入', + 'stats.humanInputsTip': '当前会话中的用户消息与问题回答次数。', + 'stats.io': '输入输出', + 'stats.events': '上下文事件', + 'stats.toolCalls': '工具调用', + 'stats.toolsMore': '其他 +{n}', + 'stats.cacheHit': '缓存命中', + 'stats.cacheHitTip': '整个会话累计的缓存读取占计费输入的比例。', + 'stats.cost': '费用', + 'stats.costTip': '估算的费用,含当前智能体及所有层级的子智能体,仅供参考。', + 'stats.costTipDeepseek': 'DeepSeek 高峰时段(北京时间工作日 9:00–12:00、14:00–18:00)按挂牌价计费,其余时段半价。', + 'stats.costTipCny': '人民币按 1 元 = 0.15 美元换算。', + 'stats.currentAgent': '当前 Agent', + 'stats.teamSubs': '子 Agent × {n}', + 'stats.billedTip': 'Token 用量为计费合计:未缓存输入、缓存读取、缓存写入与输出。', + 'stats.subCostTip': '全部层级的子 Agent 会话各自累计费用(同口径估算)的合计,不含当前 Agent 自身。', + 'stats.costPriceHead': '每百万 Token 价格:', + 'stats.costPriceBy': '按 {p} · {m} 在 models.dev 的刊登价格如上。', + 'stats.costHit': '缓存输入', + 'stats.costMiss': '未缓存输入', + 'stats.costWrite': '缓存写入', + 'stats.costOut': '输出', + 'stats.costUnavailable': '模型价格暂不可用(自动重试中),费用暂无法估算。', + 'timing.title': '耗时统计', + 'timing.total': '活跃时长', + 'timing.ttft': '模型等待', + 'timing.gen': '模型生成', + 'timing.reasoning': '模型思考', + 'timing.text': '模型回复', + 'timing.toolArgs': '工具参数', + 'timing.tools': '工具执行', + 'timing.other': '其他开销', + 'timing.callTimes': '{n}次', + 'timing.toolTimes': '{n}次', + 'timing.blockTimes': '{n}次', + 'timing.empty': '暂无耗时数据 · 对话开始后这里会显示时长分布', + 'timing.tps': '输出速度 {tps} tok/s', + 'timing.tpsTip': '输出速度(TPS):累计解码输出 tokens ÷ 累计解码时长,与 DeepSeek Harness 会话统计同口径。', + 'timing.strip': '耗时时间轴:各段按发生次序紧凑铺排,宽度为耗时占比,刻度为零、四分位与全程', + 'tokens.title': 'Token 统计', + 'tokens.total': '总用量', + 'tokens.output': '输出', + 'tokens.outputNote': '含思考', + 'plugin.title': '插件信息', + 'plugin.hint': 'The best DSH context plugin ⭐', + 'plugin.name': '插件', + 'plugin.github': 'GitHub', + 'plugin.settings': '插件设置', + 'plugin.settingsOpen': '打开插件设置', + 'trend.title': '上下文趋势', + 'gran.step': '步骤', + 'gran.turn': '轮次', + 'settings.placement': '入口位置', + 'placement.tab': '标签页', + 'placement.sidebar': '侧边栏', + 'placement.all': '全部', + 'settings.insightsEntry': '上下文洞察入口', + 'settings.fleetTab': '编队标签页', + 'showHide.show': '显示', + 'showHide.hide': '隐藏', + 'settings.gran': '趋势图 · 默认粒度', + 'settings.mode': '趋势图 · 默认展示方式', + 'settings.durationCurve': '趋势图 · 耗时曲线', + 'settings.deltaBase': '上下文浏览器 · 对比基线', + 'settings.toolSort': '工具定义 · 默认排序', + 'settings.fileSort': '文件活动 · 默认排序', + 'settings.readOnly': '当前环境的设置为只读', + 'settings.promptPrefix': '系统提示词 · 前缀', + 'settings.promptSuffix': '系统提示词 · 后缀', + 'settings.promptHint': '拼接在所有会话系统提示词的最前/最后,对所有代理(含子代理)生效;修改从下一轮对话开始应用', + 'settings.promptPlaceholder': '留空则不启用', + 'gran.total': '全量', + 'gran.delta': '增量', + 'gran.modeHint': '全量:累计构成;增量:相对上一条请求的变化量', + 'trend.adaptive': '自适应', + 'trend.adaptiveHint': '按当前可视范围内的柱子重新缩放高度,滚动时随之变化', + 'trend.duration': '耗时', + 'trend.durationTip': '在柱子上叠加每步的活跃耗时曲线(步骤开始至结束,含模型与工具调用,不含等待你决策或回答的时间),按图中右侧的四分位坐标轴读数;轮次粒度下为一轮各步耗时之和', + 'trend.dna': 'DNA 模式', + 'trend.dnaTip': '把每根柱子画成该次请求的上下文指纹:按模型读取顺序逐条铺色,配合增量模式逐条展示每次请求的增减;悬停查看条目,点击让上下文浏览器定位到该条目,同一条目在所有柱子中亮出其存续变化', + 'trend.dnaItem': '{label}:{n}', + 'trend.empty': '发起一轮对话后,这里会展示每次模型请求的上下文构成', + 'detail.step': '第 {t} 轮 · 第 {s} 步 (共 {n} 步)', + 'detail.turn': '第 {t} 轮 · 共 {n} 步', + 'detail.lastStep': '末步', + 'detail.estTotal': '估算合计 ≈ {n}', + 'detail.actual': '实际 {n}', + 'detail.output': '输出 {n}', + 'detail.cache': '缓存 {n}%', + 'brief.turn': '本轮', + 'brief.input': '输入', + 'brief.reply': '回复', + 'brief.more': '+{n}', + 'brief.noInputs': '(无新增)', + 'brief.locate': '在上下文浏览器中查看', + 'jump.title': '在上下文视图中查看此轮', + 'brief.turnTip': '这一轮开场时用户发送的消息;回合内的每一步都会回显同一条', + 'brief.inputTip': '上一步回复之后、本次请求发出前新进入上下文的内容——通常是上一步所调工具的结果;每轮的第一步无新增', + 'brief.replyTip': '这一步模型返回的内容(文本回复或工具调用);此步发起的调用,其结果会出现在下一柱的「输入」行', + 'events.title': '上下文事件', + 'events.empty': '暂无上下文事件(压缩、注入、模型切换会出现在这里)', + // Locale-neutral position stamps, matching the browser rows' own `browser.stepAt`. + 'events.at': 'T{t} S{s}', + 'events.range': 'T{t} S{a}→{b}', + 'events.rangeTo': 'T{a} S{as} → T{b} S{bs}', + 'kind.inject': '注入', + 'kind.compaction': '压缩', + 'kind.prune': '剪枝', + 'kind.model': '切换', + 'kind.mode': '模式', + 'files.title': '文件活动', + 'files.scopeLatest': '截至最新 · 跟随趋势图的选择', + 'files.kind.all': '全部', + 'files.kind.read': '读取', + 'files.kind.write': '写入', + 'files.kind.search': '搜索', + 'files.kind.image': '图片', + 'files.chipTip': '{files} 个文件 · {ops} 次操作', + 'files.search': '按路径过滤…', + 'files.sort.count': '按次数', + 'files.sort.latest': '按最新', + 'files.sort.path': '按路径', + 'files.sortTip': '文件排序:按操作次数(选中分类时按该分类的次数)、最近操作时间或路径', + 'files.files': '{n} 个文件', + 'files.deltaTip': '按 edit/write 调用参数估算的累计行数变化:+ 新增 / − 删除', + 'files.empty': '该范围内没有文件读取、写入或搜索操作', + 'files.noMatch': '没有匹配当前过滤条件的文件', + 'files.locate': '在上下文浏览器中查看此次操作', + 'files.hits': '{n} 处命中', + 'files.readTip': '读取第 {a}–{b} 行', + 'files.open': '在系统中打开', + 'files.preview': '在侧边栏预览', + 'files.readEst': '按调用参数 limit 估算的读取行数', + 'files.errs': '{n} 次失败', + 'files.form.image': '图片', + 'files.form.dir': '目录', + 'files.form.text': '文件', + 'files.glyph.root': '工作区根', + 'files.glyph.tests': '测试', + 'files.glyph.docs': '文档目录', + 'files.glyph.deps': '依赖', + 'files.glyph.build': '构建产物', + 'files.glyph.scripts': '脚本', + 'files.glyph.config': '配置', + 'files.glyph.assets': '静态资源', + 'files.glyph.hidden': '元数据目录', + 'files.glyph.lock': '锁文件', + 'files.glyph.docker': 'Docker', + 'files.glyph.ignore': '忽略规则', + 'files.glyph.license': '许可证', + 'files.glyph.python': 'Python', + 'files.glyph.notebook': 'Notebook', + 'files.glyph.shell': 'Shell', + 'files.glyph.style': '样式', + 'files.glyph.database': '数据库', + 'files.glyph.data': '数据清单', + 'files.glyph.markdown': '标记文档', + 'files.glyph.log': '日志', + 'files.glyph.sheet': '表格', + 'files.glyph.document': '文档', + 'files.glyph.archive': '压缩包', + 'files.glyph.font': '字体', + 'files.glyph.media': '媒体', + 'files.glyph.lang.ts': 'TypeScript', + 'files.glyph.lang.js': 'JavaScript', + 'files.glyph.lang.go': 'Go', + 'files.glyph.lang.rust': 'Rust', + 'files.glyph.lang.java': 'Java', + 'files.glyph.lang.kotlin': 'Kotlin', + 'files.glyph.lang.ruby': 'Ruby', + 'files.glyph.lang.php': 'PHP', + 'files.glyph.lang.c': 'C', + 'files.glyph.lang.cpp': 'C++', + 'files.glyph.lang.csharp': 'C#', + 'files.glyph.lang.scala': 'Scala', + 'files.glyph.lang.lua': 'Lua', + 'files.glyph.lang.dart': 'Dart', + 'files.glyph.lang.swift': 'Swift', + 'files.glyph.lang.vue': 'Vue', + 'files.glyph.lang.svelte': 'Svelte', + 'files.glyph.lang.html': 'HTML', + 'agents.title': 'Agent 网络', + 'agents.sub': '当前 Agent 与子 Agent 的实时上下文 · 点击节点跳转会话', + 'agents.chip.count': '{n} 个 Agent', + 'agents.chip.running': '{n} 个运行中', + 'agents.chip.tokens': '上下文合计 {n}', + 'agents.more': '另有 {n} 个未显示', + 'agents.solo': '还没有子 Agent — 当 Agent 通过 subagent 工具委派任务时,协作网络会在这里展开', + 'agents.self': '当前', + 'agents.running': '运行中', + 'agents.legend.free': '空闲窗口', + 'agents.oneshot': '一次性', + 'agents.continuable': '多轮', + 'agents.steps': '{n} 步', + 'agents.billed': '累计计费 {n}', + 'fleet.teamChip': '团队 · {m} 成员 · {n} 任务', + 'fleet.unpin': '取消固定', + 'fleet.open': '打开会话', + 'fleet.membership': '团队身份', + 'fleet.role.lead': '主导', + 'fleet.role.teammate': '成员', + 'fleet.phase.provisioning': '准备中', + 'fleet.phase.failed': '失败', + 'fleet.memberInactive': '未运行', + 'fleet.config': '配置', + 'fleet.prompt': '委派提示词', + 'fleet.expand': '展开', + 'fleet.collapse': '收起', + 'fleet.detailLoading': '正在读取会话记录…', + 'fleet.messages': '通讯', + 'fleet.kind.relay': '私信', + 'fleet.kind.mailbox': '邮箱', + 'fleet.kind.settled': '回报', + 'fleet.task.pending': '待处理', + 'fleet.task.in_progress': '进行中', + 'fleet.task.completed': '已完成', + 'fleet.taskReady': '可开始', + 'fleet.taskBlocked': '被依赖阻塞', + 'fleet.taskUnowned': '未分配', + 'fleet.taskScopes': '写入范围', + 'fleet.members.title': '团队成员', + 'fleet.members.count': '{n} 名成员', + 'fleet.members.reply': '最新回报', + 'fleet.members.tasks': '{n} 项进行中任务', + 'fleet.members.noTasks': '无进行中任务', + 'fleet.members.tasksTip': '在任务看板中只看该成员', + 'fleet.tasks.title': '任务看板', + 'fleet.tasks.sub': '共享任务与依赖 · 只读', + 'fleet.tasks.ownerTip': '在右侧详情中固定该成员', + 'fleet.tasks.depTip': '依赖 {id} · 点击定位', + 'fleet.tasks.focusTip': '在任务看板中定位', + 'fleet.tasks.dependsOn': '依赖', + 'fleet.tasks.noMatch': '该成员当前没有任务', + 'fleet.taskCol.pending': '待处理', + 'fleet.taskCol.in_progress': '进行中', + 'fleet.taskCol.completed': '已完成', + 'fleet.team.empty': '暂无共享任务,可以通过对话创建', + 'fleet.team.failureShort': '持久记录无效', + 'fleet.settled.finished': '完成了任务,等待新指令', + 'fleet.settled.finishedFinal': '已完成(一次性,无法追问)', + 'fleet.settled.stopped': '被中断,未完成', + 'fleet.settled.outOfRoom': '上下文耗尽,未完成', + 'fleet.settled.declined': '拒绝了任务', + 'fleet.settled.failed': '执行失败', + 'fleet.list.title': '编队名录', + 'fleet.list.sub': '家族内所有 Agent · 点击行固定到右侧详情', + 'fleet.list.search': '搜索名称…', + 'fleet.list.filter': '状态过滤', + 'fleet.list.sort': '排序', + 'fleet.list.empty': '没有匹配的 Agent', + 'fleet.filter.all': '全部', + 'fleet.filter.running': '运行中', + 'fleet.filter.done': '已完成', + 'fleet.filter.idle': '空闲', + 'fleet.sort.spawn': '派生顺序', + 'fleet.sort.tokens': '上下文用量', + 'fleet.sort.duration': '运行时长', + 'fleet.sort.steps': '步数', + 'fleet.sort.recent': '最近活跃', + 'fleet.comms.title': '通讯记录', + 'fleet.comms.sub': '跨 Agent 消息 · 按需扫描各会话日志', + 'fleet.comms.scan': '扫描 {n} 个会话的通讯', + 'fleet.comms.scanning': '扫描中 {done}/{total}…', + 'fleet.comms.rows': '{n} 条消息', + 'fleet.comms.stale': '有新动态', + 'fleet.comms.rescan': '重新扫描', + 'fleet.comms.filter': '按 Agent 过滤', + 'fleet.comms.all': '全部 Agent', + 'fleet.comms.empty': '没有发现跨 Agent 消息', + 'fleet.comms.truncated': '仅展示摘录(已达路由上限)', + 'loading': '正在读取会话日志…', + 'detail.loading': '正在加载历史数据…', + 'detail.loadFailed': '历史数据加载失败,点击重试', + 'error': '上下文数据读取失败:', + 'error.retry': '重试', + 'gate.title': '请更新 DeepSeek Harness 版本', + 'gate.body': 'dsh-context 插件支持 DeepSeek Harness v{minimum} 或更新版本。', + 'gate.current': '当前版本', + 'gate.minimum': '最低要求', + 'gate.orNewer': '及更新的版本', + 'gate.ok': '知道了', + 'footer': 'Token 数量统计:「估算」与 DeepSeek Harness 内置 tokenMeter 相同的固定密度启发式(约 4 字符 ≈ 1 token);「实际」为供应商上报用量。', + 'tip.step': '第 {t} 轮 · 第 {s} 步 (共 {n} 步)', + 'tip.turn': '第 {t} 轮 · 共 {n} 步', + 'tip.turn1': '第 {t} 轮 · 共 1 步', + 'tip.total': '合计 ≈ {n}', + 'tip.cat': '{cat} ≈ {n}', + 'tip.delta': 'Δ {n}', + 'tip.duration': '耗时 {n}', + 'ev.compaction': '压缩上下文(摘要替换 {n} 条消息)', + 'ev.prune': '剪枝工具输出', + 'ev.skill': 'Skill 注入({name})', + 'ev.model': '模型切换:{a} → {b}', + 'ev.mode.plan.on': '进入计划模式', + 'ev.mode.plan.off': '退出计划模式', + 'form.instructions': '指令注入', + 'form.catalog': '目录更新', + 'form.snapshot': '状态快照', + 'form.notice': '通知', + 'form.relay': '代理转发', + 'form.recall': '历史召回', + 'form.context': '上下文注入', + 'node.toolResult': '工具结果', + 'node.calls': '调用 ', + 'node.empty': '(空回复)', + 'node.nonText': '(非文本消息)', + 'node.snapshot': '快照: ', + 'node.skillTag': '技能 · {name}', + 'cmd.label': '上下文', + 'cmd.section': '上下文', + 'cmd.desc': '查看当前上下文构成,浏览各步骤组成', + 'cmd.close': '关闭', + 'browser.title': '上下文浏览器', + 'browser.live': '当前(下一次请求)', + 'browser.liveNow': '当前 · 下一次请求', + 'browser.items': '{n} 项', + 'browser.stepAt': 'T{t} S{s}', + 'browser.stepAtTip': '首次随第 {t} 轮 · 第 {s} 步的请求进入上下文', + 'browser.stepPendingTip': '预计随第 {t} 轮 · 第 {s} 步的请求进入上下文(尚未发送)', + 'browser.missingLive': '… 另有 {n} 条更早的消息也在上下文中(超出展示窗口)', + 'browser.approx': '该步骤涉及的部分已移除消息超出保留范围,以下为近似构成', + 'browser.base.step': '比前步', + 'browser.base.turn': '比前轮', + 'browser.base.tip': '变动对比的基线:比前步=与上一步对比;比前轮=与上一轮最后一步对比(首轮无基线,全部计为变动)', + 'browser.dna': 'DNA 模式', + 'browser.dnaTip': '按模型读取上下文的次序逐条展示每一项:系统提示词、工具定义,然后是按时间排列的消息;悬停查看条目,点击定位到下方列表', + 'browser.noHeader': '此数据来自旧版插件:仅提供 token 估算,无实际内容', + 'browser.noEpoch': '该步骤的头部内容(系统提示词 / 工具定义)不在保留范围内', + 'browser.headerMetaOnly': '此环境不支持按需读取头部内容,仅显示 token 估算', + 'browser.noSystem': '该请求头部未包含系统提示词', + 'browser.noContent': '完整内容不在当前加载的消息窗口内(在聊天页加载更早历史后可查看)', + 'browser.search.user': '按消息内容过滤…', + 'browser.search.inject': '按注入内容过滤…', + 'browser.search.skill': '按技能过滤…', + 'browser.search.assistant': '按回复、调用或思考过滤…', + 'browser.search.tool': '按工具或参数过滤…', + 'browser.kind.think': '思考', + 'browser.kind.tool': '工具', + 'browser.kind.answer': '回答', + 'browser.kindTip': '按内容种类过滤回复:思考、工具调用、回答文本', + 'browser.rowNoMatch': '没有匹配当前过滤条件的行', + 'browser.loading': '正在从更早的会话历史加载完整内容…', + 'browser.notInLog': '会话日志中未找到该条目的完整内容(可能已被压缩或清理)', + 'browser.loadFailed': '内容加载失败,点击重试', + 'tool.desc': '描述', + 'tool.params': '参数', + 'tool.paramsEmpty': '(无参数)', + 'tool.plugin': '该工具的注册插件(仅供参考)', + 'tool.unknown': '未知插件', + 'tool.unknownTitle': '因早于上下文插件加载或原插件已卸载,无法查询该工具的提供者', + 'tool.jsonToggle': '查看原始 JSON', + 'tool.jsonHide': '收起', + 'tool.search': '按名称、描述或参数过滤…', + 'tool.sort.size': '按大小', + 'tool.sort.count': '按次数', + 'tool.sort.name': '按名称', + 'tool.sortTip': '工具排序:按当前步骤中的调用次数(默认)、token 大小或名称', + 'tool.hitsTip': '当前展示步骤的上下文中,该工具被调用并返回结果的次数', + 'tool.noMatch': '没有匹配当前过滤条件的工具', + 'rich.raw': '原文', + 'rich.md': 'Markdown', + 'rich.toMd': '按 Markdown 渲染查看', + 'rich.toRaw': '查看原始文本', + 'rich.copy': '复制原文', + 'rich.copied': '已复制', + 'rich.md.copy': '复制', + 'rich.md.copied': '已复制', + 'rich.md.footnotes': '脚注', + 'rich.find': '在文本中查找', + 'rich.findPlaceholder': '查找…', + 'rich.findPrev': '上一个匹配', + 'rich.findNext': '下一个匹配', + 'rich.findClose': '关闭查找', + 'block.thinking': '思考', + 'block.answer': '回答', + 'block.content': '内容', + 'block.result': '结果', + 'block.summary': '摘要', + // The zh measure word never inflects, so the singular/plural forms are identical. + 'block.line': '{n} 行', + 'block.lines': '{n} 行', + 'call.ok': '正常', + 'call.fail': '失败', + 'call.exit': 'exit {n}', + 'node.failed': '工具执行失败', + 'attach.images': '图片附件', + 'attach.other': '其他内容', + 'attach.image': '图片', + 'attach.open': '查看原图', + 'attach.preview': '图片预览', + 'attach.close': '关闭', + 'attach.loading': '…', + 'attach.loadFailed': '加载失败 · 点击重试', + 'attach.raw': '原图', + 'attach.sent': '发送', + 'attach.token': 'Token', + 'attach.tokensTip': '按 DeepSeek 官方图片尺寸换算(单图上限 384 tokens)估算的 token 消耗', + 'ov.title': '上下文洞察', + 'ov.unavailable': '会话列表暂不可用', + 'ov.range.label': '统计范围', + 'ov.range.today': '今天', + 'ov.range.7d': '近 7 天', + 'ov.range.30d': '近 30 天', + 'ov.range.all': '全部', + 'ov.date.label': '日期范围', + 'ov.date.open': '选择自定义日期范围', + 'ov.date.from': '开始日期', + 'ov.date.to': '结束日期', + 'ov.date.pick': '选择日期', + 'ov.date.prev': '上个月', + 'ov.date.next': '下个月', + 'ov.date.hint': '点击选择开始日期', + 'ov.date.hintEnd': '再点一下选择结束日期', + 'ov.date.clear': '清除', + 'ov.date.wd.0': '日', + 'ov.date.wd.1': '一', + 'ov.date.wd.2': '二', + 'ov.date.wd.3': '三', + 'ov.date.wd.4': '四', + 'ov.date.wd.5': '五', + 'ov.date.wd.6': '六', + 'ov.kpi.sessions': '活跃会话', + 'ov.kpi.ofTotal': '共 {n} 个', + 'ov.kpi.tokens': '累计消耗', + 'ov.kpi.sessionsSub': '含 {n} 个会话', + 'ov.kpi.pricedSub': '已计价 {n}/{total} 个会话', + 'ov.kpi.toolSub': '工具执行 {dur}', + 'ov.kpi.wallSub': '模型调用 {n}', + 'ov.stats.empty': '统计范围内暂无 Token 用量', + 'ov.usage.title': '近 7 天用量', + 'ov.usage.tokens': 'Token', + 'ov.usage.cost': '费用(仅含支持计价映射的模型)', + 'ov.usage.costTip': '费用', + 'ov.usage.empty': '近 7 天暂无用量 — 会话产生模型请求后,这里会显示每日 Token 与费用', + 'balance.title': 'DeepSeek 余额', + 'balance.tip.granted': '赠送余额', + 'balance.tip.toppedUp': '充值余额', + 'ov.heat.title': '活跃度', + 'ov.heat.sub': '按日期筛选', + 'ov.heat.empty': '暂无活跃数据 — 会话产生模型请求后,这里会显示每日用量', + 'ov.heat.sessions': '{n} 个活跃会话', + 'ov.heat.less': '少', + 'ov.heat.more': '多', + 'ov.heat.metric': '指标', + 'ov.heat.metric.sessions': '会话', + 'ov.heat.metric.steps': '步数', + 'ov.heat.steps': '{n} 步', + 'ov.heat.wd.1': '星期一', + 'ov.heat.wd.3': '星期三', + 'ov.heat.wd.5': '星期五', + 'ov.heat.mon.01': '1月', + 'ov.heat.mon.02': '2月', + 'ov.heat.mon.03': '3月', + 'ov.heat.mon.04': '4月', + 'ov.heat.mon.05': '5月', + 'ov.heat.mon.06': '6月', + 'ov.heat.mon.07': '7月', + 'ov.heat.mon.08': '8月', + 'ov.heat.mon.09': '9月', + 'ov.heat.mon.10': '10月', + 'ov.heat.mon.11': '11月', + 'ov.heat.mon.12': '12月', + 'ov.skills.empty': '统计范围内暂无技能加载 — 加载技能后,这里会按名称列出次数与最近加载', + 'ov.skills.noMatch': '没有匹配当前筛选的技能', + 'ov.skills.search': '搜索技能…', + 'ov.skills.more': '另有 {n} 个技能', + 'ov.skills.loads': '{n} 次加载', + 'ov.skills.summary': '{skills} 个技能 · {loads} 次加载', + 'ov.skills.sortLabel': '技能排序', + 'ov.skills.sort.loads': '次数', + 'ov.skills.sort.recent': '最近', + 'ov.skills.sessions': '{n} 个会话', + 'ov.skills.clickFilter': '点击筛选加载过它的会话', + 'ov.skills.clickRelease': '再次点击取消筛选', + 'ov.skills.src.project': '项目', + 'ov.skills.src.user': '用户', + 'ov.skills.src.bundled': '内置', + 'ov.skills.k.source': '来源', + 'ov.skills.k.usage': '用量', + 'ov.skills.k.last': '最近', + 'ov.skills.k.path': '路径', + 'ov.skills.copyPath': '点击复制路径', + 'ov.skills.copied': '已复制', + 'ov.list.title': '会话', + 'ov.list.search': '搜索标题 / 目录 / 最后消息…', + 'ov.list.sortLabel': '排序', + 'ov.list.sort.recent': '最近更新', + 'ov.list.sort.tokens': 'Token 总用量', + 'ov.list.sort.context': '当前 Context', + 'ov.list.empty': '还没有会话 — 发起一轮对话后,这里会列出每个会话的上下文画像', + 'ov.list.noMatch': '没有匹配当前筛选条件的会话', + 'ov.list.noData': '暂无上下文数据 — 该会话产生模型请求后才会统计', + 'ov.list.dayFilter': '{day} 当日活跃', + 'ov.list.dayClear': '清除日期筛选', + 'ov.list.skillClear': '清除技能筛选', + 'ov.list.pager': '会话分页', + 'ov.list.page': '第 {n} / {total} 页', + 'ov.list.prev': '上一页', + 'ov.list.next': '下一页', + 'ov.group.label': '分组', + 'ov.group.ungrouped': '未分组', + 'ov.running': '运行中', + 'ov.current': '当前', + 'ov.card.turns': '{n} 轮 {s} 步', + 'ov.card.teamUsage': 'Token 总用量', + 'ov.card.teamCost': '总预估费用', + 'ov.card.lastUser': '最后消息', + 'ov.time.now': '刚刚', + 'ov.time.m': '{n} 分钟前', + 'ov.time.h': '{n} 小时前', + 'ov.time.d': '{n} 天前', +} satisfies Record + +/** The key union every locale of this plugin must carry in full. */ +export type DictKey = keyof typeof DICT_ZH +