Codex桌面端汉化全攻略:从菜单到主界面的完整实现思路
Codex 桌面端一出来我就装上了,界面干净、交互也顺手,但有个特别现实的问题:整个界面几乎全是英文。Dashboard、New Chat、Settings、Attach files……常年混英文界面的开发者倒还好,但团队里不少同事装上之后第一句话就是——这玩意儿能汉化吗?
答案是能,而且不用等官方的中文版。Codex 桌面端是典型的 Electron 应用,界面本质就是一个跑在本地 Chromium 里的网页,所有文本资源都打包在一个叫 app.asar 的文件里。汉化的完整思路其实就一句话:解开 asar,找到文本,替换成中文,重新打包。但真正动起手来,从系统菜单到主界面中间有一堆细节问题,比如文本散落在哪些文件、菜单栏为什么和普通界面不一样、替换之后签名失效怎么办、应用自动更新会不会把汉化冲掉。这篇文章就把这套从菜单到主界面的实现思路完整拆开讲。
1. 为什么汉化 Codex 桌面端,本质上是在动"应用外壳"里的文本
1.1 Electron 应用给汉化带来的好消息和坏消息
Electron 应用的结构可以理解为:一个 Chromium 浏览器内核负责画界面,一个 Node.js 环境负责调系统能力,中间由主进程和渲染进程配合干活。Codex 桌面端就是这种结构,前端界面使用 HTML/CSS/JS 渲染,打包时这些文件会被封装进 app.asar。
这对汉化来说是双重影响。
好消息是,界面文本不是编译进二进制文件里的,而是以字符串形式保存在 JS、HTML、CSS 文件中。只要你能打开 asar 包,就能像改网页一样改文本,不需要逆向、不需要搞懂汇编,门槛比传统原生应用低得多。
坏消息也很直接:文本不是像传统软件那样集中放在一个 Language 或者 locale 目录里,而是散落在各个 JS bundle 中。你可能在一个文件里改 10 个词,隔壁文件里还藏着另外 20 个词。所以汉化过程更像"在包装箱里翻找每一张标签",而不是"打开一个语言包直接翻译"。
1.2 界面文本的三种藏身形式,先判断再动手
拿到一个 Electron 应用,不要上来就满文件搜单词,先判断文本属于哪一类。我从实际经验里总结出三种常见形式:
| 文本形式 | 典型特征 | 汉化优先级 | 说明 |
|---|---|---|---|
| 硬编码字符串 | 直接在 JS/HTML 里写死的英文 | 最高 | 绝大多数 Electron 应用的主战场 |
| 独立 locale 文件 | 存在 locales/、i18n/、lang/ 目录的 JSON/PO 文件 |
高,改动最安全 | 如果应用本身做了 i18n,优先改这里 |
| 远端下发内容 | 由服务端返回的公告、提示、运营位文案 | 无法在本地改 | 不要花时间折腾,本地改不了 |
判断方法很简单:解包之后搜索一个你确定会在界面上看到的词,比如 Settings。如果这个词出现在 .js 文件里一大串压缩代码中,说明是硬编码类型;如果出现在 locales/en.json 里,说明有独立语言包;如果解包目录里根本搜不到这个词但界面上却能看到,那基本就是远端下发内容。
Codex 桌面端目前以硬编码字符串为主,所以这篇文章后面讲的方法都是围绕"如何在压缩混淆后的 JS 文件里安全地做字符串替换"。
1.3 为什么菜单栏是汉化的分水岭
菜单栏和普通界面有一个本质区别:普通界面的文本跑在渲染进程,也就是网页层;而系统菜单栏的文本是在主进程里用 Electron 的 Menu API 创建的 label 定义的。
这就导致一个很常见的问题:你辛辛苦苦把主界面按钮都改成中文了,打开菜单栏一看,还是英文。这不是因为你漏改了,而是因为你根本没找到主进程那部分代码。
macOS 的顶部菜单栏、Windows 上的应用菜单、右键上下文菜单,这些区域的文本一般都在主进程入口文件里。Electron 的 MenuItem 有 role 概念,role: 'quit'、role: 'copy' 这类项目在某些系统语言环境下会自动本地化,但只要应用本身没有适配中文 locale,大部分情况下仍然以硬编码 label 为准。所以汉化菜单栏需要在主进程代码中硬改 label,这一步做完,整个应用的"本地化完成度"才真正上了一个台阶。
这也意味着,汉化思路可以做一个清晰的拆解:第一层是系统菜单和右键菜单,对应主进程代码;第二层是侧边栏、会话区、设置面板,对应渲染进程代码。两条线都要走一遍,才算是完整的桌面端汉化。
2. 解包前的准备工作:找到安装目录、拆开 asar、建立替换基线
2.1 定位 Codex 桌面端的安装目录与资源包
不管哪个系统,Electron 应用安装后一定会有一个 resources 目录,里面放着核心资源。
- macOS 路径通常为:
/Applications/Codex.app/Contents/Resources - Windows 路径通常为:
C:\Users\<用户名>\AppData\Local\Programs\codex\resources或安装时自选的目录
打开 resources 目录后,核心关注两个东西:app.asar 和 app.asar.unpacked。app.asar 是主程序资源包,界面文本基本都在里面;app.asar.unpacked 一般放原生 .node 模块和需要直接访问的文件,汉化通常不用碰它。
动手之前先做基线备份,把整个 resources 目录复制一份到别的路径。这一步很多人省略,等到改坏了才发现没有回滚手段。
2.2 解包 app.asar 的正确姿势
使用 @electron/asar 这个官方工具来解包和重打包。没有 Node 环境的话先装一个 Node.js LTS 版本,然后用 npx 直接执行:
解包完成后会生成一个 app.src 目录,里面就是完整的应用源代码。目录里通常能看到 package.json、dist、build、out 等文件夹,界面文本一般集中在 dist 或 out 下的 JS/HTML 文件里。
搜索文本资源时用下面两种方式之一:
压缩混淆过的 bundle 常常一整个文件只有一行,grep 输出会非常长。可以用 -o 只显示匹配片段周围的字符:
这样能快速看到匹配词上下文,判断它是用户可见文案还是内部标识符。
2.3 用 DevTools 远程调试端口精准定位界面元素
有些文本在代码里是动态拼接的,或者被拆成了多段,直接搜可能搜不到完整文案。这时可以借助 Electron 的远程调试能力。
在终端里手动启动 Codex,并加上远程调试参数:
然后打开本机 Chrome 访问 http://localhost:9222,会看到应用当前打开的页面列表,点击 inspect 就能进入 DevTools。用元素选择器点界面上的英文文本,直接看它对应的是哪个 DOM 节点、挂在哪个 CSS 类上,再到源码里搜相关关键词,定位效率会高很多。
需要提醒一句:远程调试端口会暴露应用内部状态,只建议在本地临时使用,用完就关,不要在公共网络环境里带着这个参数启动。
2.4 重打包前先建立一个只读基线
解包后不要立刻开改。先把关键文件的哈希值记下来,后续定位问题时能快速判断"我到底改过哪个文件":
改动过程中如果出现启动崩溃,把这个哈希列表和当前文件对比,能省掉大量排查时间。这个小动作成本极低,收益极高。
3. 从菜单栏开始汉化:系统菜单、右键菜单与侧边栏导航
3.1 系统菜单:在主进程代码里改 label
菜单栏文本藏在主进程代码中,通常以 label: 的形式出现。在解包目录里搜 label 时,目标文件一般是入口文件或主进程 bundle。常见菜单项包括 File、Edit、View、Window、Help,macOS 上还会有以应用名命名的 App 菜单。
搜索时可以这样执行:
你会看到一个 label 清单,按出现次数排列。汉化时逐条替换为中文,像这样:
(&F) 这种写法是助记符,Windows 和 Linux 下用户可以用 Alt+F 展开菜单,macOS 下一般显示为快捷键提示,保留它是比较专业的做法。
这里有个经验:菜单 label 并不全在同一个文件里。有些应用为了减少主进程体积,会把菜单模板单独拆成一个 menu.js 或 menu.ts 编译产物。如果主文件里搜不到,就到 dist 目录里再搜一遍 buildFromTemplate 或 Menu.setApplicationMenu 附近的代码。
3.2 右键菜单和上下文菜单:另一个高频文本区
右键菜单是汉化时最容易被遗漏的区域。它在界面上不会一直显示,等真正需要复制、粘贴、检查元素时才冒出来,而且很多应用在右键菜单里混用了硬编码文本和 role 类型。
右键菜单文本通常包括:Copy、Paste、Cut、Select All、Inspect Element、Reload 等。在主进程代码里搜索这些词时,建议使用带引号的完整匹配,例如搜 'Copy' 而非 Copy,避免匹配到变量名或函数名。
替换方式和系统菜单一致,找到 label 赋值即可。但要注意:如果某项菜单使用 role: 'copy' 且没有显式 label,Electron 会按系统 UI 语言提供默认文案。此时在中文系统上可能已经自动显示为"拷贝",不需要额外改。真正需要改的是那些 role 和 label 同时出现、label 硬编码为英文的项。
3.3 侧边栏与工作区导航:建立高频词替换表
侧边栏是界面文本最密集的区域之一。以我拿到的 Codex 桌面端版本为例,侧边栏包含工作区切换、新建会话、历史记录、设置入口等导航项。这些文本在渲染进程的 bundle 里,搜 Dashboard、New Session、History、Settings 等词就能定位。
这里强烈建议建一张替换表,而不是想起一个词改一个词。表格长这样:
| 原始文本 | 替换文本 | 出现文件 | 备注 |
|---|---|---|---|
| Dashboard | 仪表盘 | renderer.js | 侧边栏导航 |
| New Session | 新建会话 | renderer.js | 侧边栏按钮 |
| History | 历史记录 | renderer.js | 侧边栏导航 |
| Settings | 设置 | settings.js | 按钮与标题 |
| Attach files | 添加附件 | chat.js | 输入框附件按钮 |
| Send message | 发送消息 | chat.js | 输入框动作 |
把替换表维护好,后面写自动脚本时直接用这张表批量执行,比手动改稳妥得多。而且这张表能帮你控制替换范围——看到某个词在表格里没出现过,就不要顺手改掉,宁可漏掉也不要误伤。
4. 主界面汉化的核心区域:会话区、设置面板与状态提示
4.1 会话区:从 placeholder 到按钮文本的逐项替换
主界面最显眼的部分是会话区。输入框的 placeholder、发送按钮文本、会话标题、附件的提示文案,这些都是用户每次打开都会看到的。搜索关键词时建议从高频词入手:placeholder=、aria-label=、title= 这些属性往往藏着不少文本。
一个很实用的技巧:JS 的压缩代码里字符串可能同时出现在单引号、双引号和反引号中。比如同一类文本,可能在 A 处写作 "New Chat",在 B 处写作 'New Chat'。搜索时要注意覆盖三种形式,替换时也要三种情况都处理。
替换时还有一个容易踩的区分难点:同一串英文,可能在界面其他地方以内部 key 的形式存在,比如 id: "settings"、eventName: "settings"。这类内部标识符绝对不能改成中文,否则事件监听就找不到了。怎么判断?看上下文。如果字符串前后有 label、title、placeholder、textContent,基本可以放心改;如果前后有 key、id、type、event,不要动。
4.2 设置面板:最深的坑是那些不显眼的属性文本
设置面板的文本层级比会话区深得多,除了可见的标签,还有大量藏在属性里的辅助文本。title 属性决定鼠标悬停时的提示,aria-label 决定读屏器朗读内容,alt 是图标替代文本。这些区域漏改了,用户每鼠标悬停一次就看到一次英文,整体观感会瞬间打回原形。
处理设置面板时我习惯用 DevTools 远程调试配合操作:打开设置面板,逐项鼠标悬停、点击、展开下拉,把界面上出现的所有英文记录到替换表中,再去源码里搜索。
设置面板的下拉选项也值得注意,<option> 标签里的文本、select 的默认项、单选多选旁的说明文字,都属于硬编码文本。有些配置项在展开子菜单后才显示英文,不实际操作一遍根本发现不了。
4.3 状态提示与错误信息:能汉化的就汉化,不能汉化的先放过
状态提示、错误弹窗、加载提示这类动态文本处理起来要谨慎。比如请求失败时显示的 Request failed with status 500,前半段可以翻译成"请求失败",但 status 500 作为状态码最好不要动,否则排查问题时难以对应文档。
我的处理原则是:纯展示性的欢迎语、空状态提示、加载文案,直接翻译;混合了错误码、堆栈信息、变量占位符的报错信息,只翻译固定描述部分,保留参数和代码。汉化不是越彻底越好,保留一部分英文术语反而对日常开发排查更友好。
另外,错误信息经常是模板字符串拼出来的,源码里可能是:
替换时把 Failed to connect to 改成 连接失败,保留后面的模板变量即可。=${host} 这类占位符如果被改动,程序很可能在渲染时直接报模板解析错误。
5. 重打包、签名失效与显示问题的排查链路
5.1 重打包命令与安装目录替换
改完文本后,进入最关键的步骤:把 app.src 重新打包替换原文件。
打包完成后把生成的 app.asar 放回 resources 目录。替换之前必须完全退出 Codex,Windows 下如果提示文件被占用,检查后台进程是否真的结束。
macOS 上这里往往会出现一个门槛:应用签名失效。Electron 应用分发时带开发者签名,修改 app.asar 后签名校验过不去,系统可能直接拒绝启动,或提示应用已损坏。常见的处理方式是重新签名:
这是 ad-hoc 签名方式,没有 Apple Developer 证书也能在本机执行。签名完成后建议执行一次验证:
Windows 下一般没有这么强的签名校验机制,直接替换文件启动即可。如果双击没有反应,建议打开终端手动运行可执行文件,看标准输出里有没有报错信息,这一步比任何日志分析都直接。
5.2 中文乱码、按钮溢出和快捷键失效的定向排查
替换完重新启动,最可能遇到三类问题:
第一类是中文乱码或界面出现类似 \u5370\u8c61 的转义字符。 这通常是因为原始字符串在 JS 里就是以 Unicode 转义形式存储的,你只改了可见的英文部分,没有处理转义片段。排查方法是搜索汉化时对应的英文词,再看相邻代码是否是 \u 开头。如果是,说明源码里本身就是转义存储,需要你把中文一并转成 Unicode 形式再替换,或者直接替换转义序列对应的中文。
第二类是按钮文字溢出。 中文字符宽度明显大于英文字符,一个 8 字符的英文按钮"Settings",换成"设置"两个字不会变窄,但"New Dashboard"换成"新建仪表盘"后按钮就可能放不下。Electron 应用布局是网页流式布局,大部分按钮会自动撑开,但碰到固定宽度或 white-space: nowrap 的样式时就会溢出。这种时候需要在 DevTools 里查看按钮的样式,到 CSS 文件里调整 min-width 或 padding。改动 CSS 的流程和改文本一样,改完重新打包。
第三类是快捷键提示消失。 如果原文本里有 &F、&S 这类助记符写法,替换成中文时要保留。同时留意快捷键本身是否绑定在菜单项上,accelerator: 'CmdOrCtrl+N' 这种属性不属于文本,千万不要动。
5.3 启动即崩溃时的二分回退法
如果重打包后应用一启动就崩溃,不要慌,几乎可以肯定是一次错误的字符串替换导致代码逻辑断裂。最典型的场景是:某个字符串同时被用作事件名、存储 key 或路由标识,你把它改了,内部代码找不到对应关系。
排查方法不要用"抓瞎式搜索",用二分回退法更高效:
- 将刚才做过的替换记录按文件拆成几组;
- 先把分组后的文件恢复为原始状态,只保留第一组的替换内容,重新打包测试;
- 如果能正常启动,说明问题不在第一组,继续加第二组;
- 加到某组后崩溃,问题就锁定在那一组对应的文件或字符串中;
- 在该组内逐条替换字符串,最终锁定"罪魁祸首"。
这一步并不复杂,但很多人在崩溃后直接全部还原,把之前的汉化工作推倒重来,然后在第二遍时又踩同一个坑。保留替换记录并做分组,是更专业的工作方式。
6. 让汉化成果可维护:脚本化重放与更新覆盖问题
6.1 用 Node 脚本把替换流程固定下来
手动汉化一遍之后,Codex 只要更新一版,所有改动就会全部被新版本覆盖。最有效的应对不是"每次重新手动改",而是把替换流程脚本化——解包后,跑一个脚本,自动完成所有文本替换,再重新打包。
下面是一个基础版本的替换脚本,实际使用时把 replacements 数组维护成你的完整替换表:
这里我强烈建议替换表里写带引号的完整字符串,例如 '"Dashboard"' 而不是 Dashboard,原因前面已经说过了:不带引号会误伤大量内部标识符。使用 split 和 join 而不是正则表达式,是为了避免英文文本里的特殊字符(如 (、$)对正则表达式造成干扰,字符串替换是最粗暴也最安全的方式。
6.2 自动更新覆盖后的处理思路
Codex 桌面端默认开启自动更新。应用一旦更新,新的 app.asar 会覆盖你改过的版本,汉化失效。这个问题无法在文件层面彻底绕开,但有几条务实的处理路径:
一是优先看应用设置里是否提供关闭自动更新的选项,有的话直接关掉,保持当前版本稳定运行。
二是不要把汉化做成一次性手工活。沿用上面的脚本后,新版本发布时只需要三步:解包、跑脚本、重新打包。每轮花费五分钟,远低于重新手工改一遍的代价。
三是如果想长期保持汉化状态,又不想频繁手动操作,可以考虑只在确认新版本值得升级时才更新,而不是跟着每个小版本跑。
6.3 风险边界:哪些内容不该动
汉化过程中有几个雷区,踩到不只是界面问题,可能导致应用无法使用:
内部标识符不能改。 事件名、存储 key、API 路径、路由名、状态枚举值,看起来像英文,实际上是程序和服务器约定好的协议,改了以后轻则功能失效,重则登录态错乱。判断标准很简单:如果这个字符串在代码里还被另一个地方引用,那么它大概率不是纯展示文本。
远端内容不要试图本地 hack。 服务端返回的提示、模板变量、动态消息,本地改不了,界面该显示英文就显示英文,没有必要为了一两个词把请求结果拦截后再替换,那样做不仅复杂,还容易在版本更新时出现严重兼容问题。
错误堆栈和日志信息建议保留原文。 这类文本的价值在于排查问题,汉化后反而增加理解成本。处理原则是把面向用户的提示翻译好,面向开发者的信息保持原样。
另外说一句关于使用边界的个人看法:汉化补丁或者修改后的安装包,自己留着用就好,不要四处传播。应用本身有官方分发渠道,修改版传播既有违软件使用条款,也容易引入安全风险。自己动手折腾理解原理是一回事,把修改产物做成"绿色汉化版"分发是另一回事。
我自己跑完整条流程后最大的感受是:Electron 应用的汉化,真正考验人的不是替换字符串,而是判断"哪个字符串能改、哪个不能改"。把替换表维护好、脚本写好、基线和回滚手段准备好,一次汉化就不再是"一次性破解"式的操作,而是一条可以不断重放的工程流程。对 Codex 桌面端来说,这套思路短期内不会被官方更新击穿——即使被新版本覆盖,五分钟后又是一条好汉。如果你也正在折腾手头的 Electron 工具,建议从菜单栏先下手,那里往往是最容易见效也最容易建立信心的起点。