把已安装的官方 omp 界面汉化为简体中文,不改变版本、不替换安装、不动运行时结构。 补丁器跟随上游持续适配,不绑定具体版本号——上游发新版后重跑一条命令即可。 本项目已链接认可 LINUX DO 社区,并参与其 开源推广。
~/.omp-zh/
├── install.sh 一行命令入口(curl | bash)
├── omp-zh.sh 一键入口:apply / restore / verify / report / status
├── patch.ts 补丁器(AST 分类 + 词典替换 + 锚点自动适配 + 校验)
├── dict.json 2129 条英→中映射(源自 oh-my-pi-cn 汉化分支)
├── dict-extra.json 2700 条补充映射
├── analysis/ 侦察与词典构建脚本
└── tools/ 审计、实测、回退验证脚本
├── loose-anchor.ts 锚点通配匹配(重打包重命名自动适配)
└── patch-templates.ts 模板字面量包裹(拼接式提示)
备份位于 <omp>/dist/.omp-zh-backup/(跟着安装走,多份 clone 共享)
bin/、runtime/ 为本地生成物(启动器与侧载运行时),不入库
| omp 安装方式 | 汉化做法 |
|---|---|
bun install -g / npm / nix |
直接改写包内 dist/cli.js,omp 启动即中文 |
官方预编译二进制(curl https://omp.sh/install | sh) |
二进制内嵌字节码不可改写,改为侧载同版本 JS 运行时并生成 omp-zh 启动器;原 omp 不动 |
| Homebrew | 通常指向 npm 包,同第一种 |
| 源码构建 | 直接改写构建产物 |
侧载目录 ~/.omp-zh/runtime/<版本>/,启动器 ~/.omp-zh/bin/omp-zh。补丁器会按 omp --version 自动选择路径,无需手工配置。
二进制安装请用 omp-zh 启动(官方 omp 保持原样,仍是英文——这是设计如此,不是补丁失败)。
补丁器会自动把启动器软链到 ~/.local/bin/omp-zh(已存在则不覆盖),所以新开终端后直接敲 omp-zh 即可,无需手改 shell 配置。
启动器内部用绝对路径调用 bun,不依赖 ~/.bun/bin 是否在 PATH 中。
若 ~/.local/bin 也不在你的 PATH 中,会打印一行 export PATH=... 提示,或改用 ~/.omp-zh/bin/omp-zh 绝对路径。
不确定该敲哪个命令?
./omp-zh.sh status最后一行会写明「启动方式」。
curl -fsSL https://raw.githubusercontent.com/yebuwudong/omp-zh/main/install.sh | bash自动 clone/更新补丁仓库到 ~/.omp-zh、补齐依赖并应用汉化。omp 升级后重跑同一行命令即可——
每次都会拉取最新补丁(含新版本适配),无需手动改任何东西。
# 查看状态 / 还原英文 / 完整校验
curl -fsSL https://raw.githubusercontent.com/yebuwudong/omp-zh/main/install.sh | bash -s -- status
curl -fsSL https://raw.githubusercontent.com/yebuwudong/omp-zh/main/install.sh | bash -s -- restore
curl -fsSL https://raw.githubusercontent.com/yebuwudong/omp-zh/main/install.sh | bash -s -- test或手动 clone(等价):
git clone https://github.com/yebuwudong/omp-zh.git ~/.omp-zh
cd ~/.omp-zh && ./omp-zh.sh apply补丁会持续跟进上游版本,更新方式二选一(等价,第二条内部就是 git pull):
# 方式一:重跑安装命令(自动 pull + 应用)
curl -fsSL https://raw.githubusercontent.com/yebuwudong/omp-zh/main/install.sh | bash
# 方式二:手动更新已 clone 的目录
cd ~/.omp-zh && git pull && ./omp-zh.sh apply
git pull只对已经 clone 过的目录有效(默认位置~/.omp-zh,可用OMP_ZH_HOME改)。 第一次使用请走上方的安装命令。
cd ~/.omp-zh
./omp-zh.sh status # 查看当前汉化状态
./omp-zh.sh restore # 还原成官方英文版
./omp-zh.sh apply # 重新应用汉化临时切回英文(不改文件):
OMP_ZH=0 omp-zh # 二进制安装
OMP_ZH=0 omp # npm / bun -g 就地安装不确定该用哪个命令?跑一次 ./omp-zh.sh status,最后一行会写明启动方式。
omp upgrade / bun install -g 会覆盖 dist/cli.js,汉化随之丢失。重跑一条命令即可:
cd ~/omp-zh && ./omp-zh.sh apply补丁器自带两层自动适配,绝大多数上游发版无需人工介入:
一、标识符重命名(通配匹配) —— 官方每次重打包都会重命名压缩后的内部变量
(如 Ke→$e、$3e→Sje),补丁会在精确匹配失败时切换到通配匹配,
自动捕获新变量名并代入替换文本:
anchor adapted: help epilogue block ($3e→Sje)
anchor adapted: thinking flag description (S5→U5)
...
anchors: 61/61 applied
二、文案改为动态渲染(多形态锚点) —— 有时上游会把写死的提示文字改成按快捷键表拼装, 字面量彻底消失,通配匹配也无能为力:
// 旧:字面量
`${n}j/k:select Enter:open t:${s} Tab:details r/x:manage Esc:close`
// 新:按键名运行时渲染
`${n}${keys(["j","k"])}:select ${key("enter")}:open ...`这类情况由锚点的 alts 字段承载:同一处 UI 的多种上游形态并列声明,
精确匹配逐形态尝试、通配匹配兜底,取第一个命中者。设置页脚的模板包裹同理。
只有上游改动文案或删除代码(而非重命名、也非形态变化)时才会真正失配,此时 apply
会报错退出且不写出坏产物(英文版原样保留),把报错发 issue 即可。
模板目标(设置页脚等字面量改写够不到的界面)失配属硬失败,
check会以 exit 1 拦截,避免某块 UI 悄悄停留在英文。
大版本升级后建议顺便跑一次 ./omp-zh.sh report,
命中数量若骤降说明产物结构大改,需要同步补丁规则。
上游每次发版都会带来十几条新界面文案。补译只需一条命令:
cd ~/.omp-zh
bun tools/translate.ts它会依次执行(每步都有进度提示):
| 步骤 | 动作 |
|---|---|
| 1/6 扫描 | 对照词典找出版本里未翻译的界面英文 |
| 2/6 翻译 | 调用 OpenAI 兼容端点批量翻译 + 模型自查(带着上下文和校验标记复核草稿并修订;--no-review 可关) |
| 3/6 打印 | 输出全部候选(审计留痕,不打断流程) |
| 4/6 并入 | 写进 dict-extra.json |
| 5/6 验证 | 自动跑 apply + 完整断言(锚点、游离中文、回退) |
| 6/6 发布 | 需显式 --push 才提交推送 |
默认全自动:初译后由同一模型复核(看到原句、调用上下文、机械校验标记),修订结果重新过一遍校验才允许并入;
候选文件 dict-candidates.json 保留完整记录供事后追溯。
常用参数:
bun tools/translate.ts --review # 停在审阅(只打候选,不写词典)
bun tools/translate.ts --no-review # 关闭模型自查(单遍翻译)
bun tools/translate.ts --dry-run # 只扫描+翻译,不写任何文件
bun tools/translate.ts --push # 验证通过后自动 commit + push
bun tools/translate.ts --model cn:glm-5.3 # 换翻译模型
bun tools/translate.ts --endpoint https://api.openai.com/v1 # 换端点端点与凭据解析顺序(密钥永不入库):
--endpoint / OMP_ZH_ENDPOINT 环境变量
↓ 未设置时
~/.omp/agent/models.yml 里记录的本地网关
↓ 都没有
报错提示你配置
自动质量保障(无需人工):
- 结构校验(硬门禁):占位符
${x}、数字形态不一致 → 拒绝并入(词典里没有该键,界面保持原文,不会出错) - 术语锁(软提示):原文含
Compact/Vibe/Advisor/Prewalk… 时检查译文是否用了既定译法,违反则标记但仍并入,在输出里提示 - 审计留痕:全部候选写入
dict-candidates.json,随时可回看
需要手工介入时,底层工具可单独使用:
bun tools/extract-gaps.ts --json report-gaps.json扫描缺口,bun tools/auto-translate.ts生成候选,--accept并入。扫描/翻译工具自己解析补丁目标(含二进制安装的侧载目录),无需设置任何环境变量; 需要指定时用
OMP_ZH_SRC(直接给cli.js路径)或OMP_PKG(给包目录)。
已汉化:
- 设置面板:分组标题、条目名称、描述、页脚提示(
按 Enter/空格修改 · 按 Tab 跳转分区 · ←/→ 切换标签 · 输入以搜索 · 按 Esc 关闭) - 欢迎屏:
欢迎回来!、提示、LSP 服务器、最近会话、快捷键说明 - 首次启动向导与供应商登录流程的说明文字
- 状态栏通知、错误与警告文案、斜杠命令描述与状态(
loop 循环:关闭、循环:已暂停…) - 欢迎屏随机 Tip 正文(27 条全部)
- 约 4200 处调用点、3200 余条词条(随上游发版持续增长)
不汉化(有意保留英文):
| 类别 | 例子 | 原因 |
|---|---|---|
| 面向模型的提示词 | 工具 JSON-Schema 的 description、summary |
属于 prompt,翻译会改变 agent 行为 |
| 枚举与协议值 | low/high/xhigh、braille、rebuild、true/false |
参与 === 比较、switch 分支与持久化,翻译会破坏逻辑 |
| 设置分组标识 | TAB_GROUPS 数组与 ui.group |
排序用 indexOf 字符串匹配,必须两侧一致 |
| 命令与参数名 | --auto-approve、/settings |
输入标识符 |
| 用户数据 | 模型名、提供商名、版本号、工作目录 | 运行时数据,非界面文案 |
补丁器只改写能证明是展示用途的字符串字面量,判定基于 AST 上下文:
- ✅ 翻译:
label:/description:/title:等属性值、主题样式函数参数(fg/bold/showStatus…)、 设置分组名(属性侧与TAB_GROUPS数组侧同时翻译)、return语句中的短状态标签 - ❌ 跳过:对象键、import 源、比较运算、
switch分支、正则、计算属性、枚举数组、 集合构造调用、模型侧 schema 子树
任何字符串只要在某处出现在"逻辑/身份位",就整条跳过——避免同一文本半英半中出现不一致。
拼接模板(如页脚 Enter/Space to change · ${x}Type to search)单独处理:整段模板包裹进
运行时片段翻译函数 __omp_i18n_f,在字符串拼装完成后替换静态片段。
./omp-zh.sh verify 会重新解析产物并断言:
- 产物语法完整(约 27 MB,零解析错误)
- 所有 CJK 字面量都经由翻译函数,无游离中文落入逻辑位置
- 每次翻译调用的参数都在词典内
- 无标识符粘连(minified 代码
return"…"改写后不得变成return__omp_i18n_t) - 无原型属性名被包裹(见下)
JS 里 dict["__proto__"] 返回 Object.prototype 而非 undefined,会骗过 !== undefined 守卫。
修复前有 25 处上游原型污染防护被静默破坏:
// 上游源码:跳过原型污染键
if (k === "__proto__" || k === "constructor") continue;
// 错误改写后:__omp_i18n_t("__proto__") 返回 Object.prototype
if (k === __omp_i18n_t("__proto__") || ...) continue; // 恒为 false,防护失效修复:所有查表改用 Object.hasOwn 隔离原型链 + FORBIDDEN_KEYS 显式拒绝 13 个 JS 原型属性名,
verify 断言这两类键永不出现在调用点。
一轮补译暴露出三个问题,都影响「翻译结果是否可信」:
-
整批静默丢失(最严重)
chat()固定传max_tokens: 4000。20 条 UI 文案的 JSON 回包会超过这个上限而被截断, 解析器用lastIndexOf("}")取到的是中间某个括号,于是整批 20 条全部丢失, 表现为「模型返回了非法 JSON」。现在不再传max_tokens,用端点自己的默认值: 推理模型会先把预算花在隐藏思考上,任何我们选的上限要么截断 JSON、要么让content直接为空 (finish_reason: "length")。实测同一条请求:传 400 → 空内容;不传 → 完整返回。 -
全部批次失败却报成功 批次异常被
continue吞掉,死端点也能跑完并输出「完成」、exit=0。 现在累计失败数,一条候选都没产出时直接硬失败并给出端点地址。 -
翻译注定无效的词条 有些缺口键的同一文本也出现在逻辑/身份位,补丁器会整条跳过(
decideAll的 ban 规则), 给它们加词条永远不生效。新增patch.ts probe --keys <file>批量判定,translate.ts在花钱翻译之前先剔除这些键,并打印被排除的清单。
解析器同时改为括号配对扫描:截断会明确报 response was truncated,而不是含混的
model returned no JSON;chat() 还会区分「端点返回空内容」与「输出预算耗尽」。
bun tools/translate.ts 在二进制安装上报 ENOENT: ~/.bun/install/global/...:扫描工具写死了
npm 全局安装路径,而本机汉化产物在侧载目录。现在扫描/翻译工具自动向补丁器询问目标路径,
二进制安装、npm/bun 全局安装、OMP_PKG / OMP_ZH_SRC 显式指定都能正确解析。
同时修掉一个会卡住整个补译流程的验证误报:上游把面板标题从 super("History") 改成
常量对象后,锚点找不到,但键本身仍能被字面量扫描翻译到 —— 这类「救回」的锚点已正确写入产物,
verify 却仍报 anchor not applied,使 translate.ts 第 5 步(自动验证)失败、无法发布。
现在 planAnchors 显式返回被救回的锚点名,写入 manifest,verify 与 obsolete 同等对待。
顺带修掉两处易误判的地方:
check --code <已打补丁文件>现在自动回退到旁边的原始备份,不再把「已汉化」误报成 「锚点全部失配」(CI 里表现为假的硬失败)。check摘要改为按条目名去重统计(61/61 entries ok)。此前把all: true锚点的多个 写入点相加,会出现63/61这种自相矛盾的数字。
修掉「补丁显示成功、界面仍是英文」这一整类问题,共三处根因:
-
锚点失配导致
apply整体失败(上游某次重构后开始) 上游把 Agent Hub 快捷键提示与设置页脚从字面量改为按键表动态渲染, 6 处锚点/模板目标失效。新增alts多形态锚点机制:同一 UI 的多种上游形态并列声明, 精确匹配逐形态尝试、通配匹配兜底。回归测试覆盖新旧多种产物形态,均61/61 anchors applied。 -
启动器不在 PATH 二进制安装的汉化产物在侧载目录,必须用
omp-zh启动;而~/.omp-zh/bin默认不在 PATH, 用户敲omp看到英文,误以为补丁失败。现在补丁器自动软链到~/.local/bin(不覆盖已有文件),status与doctor都会报告启动方式与 PATH 状态。 -
启动器依赖
bun在 PATH 改用process.execPath记录的绝对路径调用bun,最小环境(无~/.bun/bin)也能启动。
另外修掉一个静默失败:patch.ts path 在首次侧载新版本时会把 bun add 的进度输出混进 stdout,
使 omp-zh.sh 里的 $CLI 变成多行、[[ -f ]] 判定失败后直接退出,补丁从未应用。
现进度输出一律走 stderr,且 omp-zh.sh 取最后一行并显式校验。
CI 门禁同步收紧:模板目标失配从「软警告(exit 2)」升为「硬失败(exit 1)」, 因为它和锚点一样会让某块 UI 悄悄停留在英文。
- 极少数词典未收录的条目仍为英文(如
Agent Reactions、Mouse Click-to-Focus)。 - 翻译来自社区分支
yequ172672/oh-my-pi-cn,个别术语可能与上游新增功能不完全对齐。 - 已实测:
--version、欢迎屏、设置面板(含页脚与右列值)、slash 补全描述、OMP_ZH=0回退、TUI 冒烟零残留。
设置面板每行右侧显示的是原始配置值(true/false/rebuild/braille/none…),官方英文版同样直显。
这里复刻了上游汉化分支的 valueLabels 机制(该分支在组件层实现;官方产物没有这个字段,
所以在字符串层等价重建):
defToItem构建行时,__omp_i18n_vlm(e.options)把该设置自己的选项标签映射成{原值 → 显示标签}(标签走词典,例如Rebuild→重建)。设置里none在不同条目下含义不同 (关/无/隐藏),所以必须按设置各自的选项表解析,不能全局一刀切。- 无选项的行(布尔值与少数就地循环的枚举,如
discard/keep、per-call)回退到全局表__omp_i18n_vd(true→是等),这些取值集合无歧义。 - 行渲染时
__omp_i18n_vr(e)先查第 1 步的表,再查全局表;文本框、多选、提供商限额等自由文本 行原样显示(代码里只对带values集合的行做映射,路径、API key、模型 id 不会被误翻)。 - 搜索索引同步收录映射后的标签,因此输入
重建能搜到「调整滚动历史」条目。
运行时可断言验证(无需截图):
./omp-zh.sh test # verify + 值标签断言(译文、歧义消解、自由文本原样)
OMP_ZH=0 bun tools/test-value-labels.ts # 回退断言(全英文)译文取自 yequ172672/oh-my-pi-cn(MIT,与上游 can1357/oh-my-pi 同许可)。本地仅做版本适配与安全裁剪,未改动译文语义。