给不断变化的 Web 应用做汉化,难点不是翻译
我在维护 Postman-Web-i18n 时发现,动态 DOM、状态原子性、规则安全和扩展权限比翻译字典更难。
刚开始做汉化时,我以为把英文字符串替换成中文只需要一个字典。真正让我反复修改的,是如何让一个持续更新、动态渲染的 Web 应用长期稳定地显示中文:DOM 生命周期、组件结构、状态切换、用户规则、浏览器权限和安全边界都不能绕过。
我在 2025 年 10 月建立 Postman-Web-i18n,最初就放入内容脚本、翻译文件、设置页、弹窗和构建流程。真正让我意识到“能翻译”不等于“可以维护”的节点,是 2026 年 5 月的一次质量审计。
时间线:14 个问题如何暴露系统结构
2025-10-17:建立完整扩展骨架
初始版本里,我覆盖了 Chrome/Edge、动态内容翻译、多语言文件、自定义规则、设置导入导出和自动发布。功能面已经很宽,但功能越多,状态组合也越多。
2026-05-25:P0 安全与数据问题
第一批修复里,我处理了四类基础问题:
- 用户开关中的
false被默认值逻辑覆盖。 - 自定义规则通过
innerHTML渲染,形成 XSS 风险。 - 导入翻译的入口存在,但缺少完整实现和活动页面通知。
- 代码调用标签页 API,却没有在清单中声明对应权限。
它们看似分散,实际都来自同一个问题:界面状态、持久化状态、扩展权限和页面状态没有形成闭环。
2026-05-25:P1 原子性与规则校验
第二批修复为语言切换增加状态快照与失败回滚,避免加载失败后页面变成空白;自定义规则在保存前检查选择器白名单、非空键值和正则合法性;文本替换从局部字符串操作改为明确赋值,减少翻译污染。
2026-05-25:P2 兼容与完整性
最后一批修复处理占位符全量替换、子元素保留、动画时序、语言兼容和重复值检查范围。最终 14 个 P0/P1/P2 问题在同一个审计分支中合并。
动态页面不是一棵静止的 DOM 树
现代 Web 应用会在路由切换、请求返回、虚拟列表滚动和组件状态变化时持续重建节点。扩展不能只在 DOMContentLoaded 后扫描一次。
Chrome 官方把 content script 运行在隔离环境中。它可以读取和修改页面 DOM,但与宿主页面的 JavaScript 世界分离。这个边界保护了变量作用域,却没有自动解决动态内容、重复翻译和组件更新问题。
可靠的翻译器需要区分:
- 首次扫描与后续增量节点。
- 文本节点、占位符、标题和无障碍标签。
- 原文、已翻译文本和用户编辑内容。
- 整段匹配与局部匹配。
- 被框架销毁后重新创建的节点。
如果没有幂等性,同一节点被观察两次就可能二次翻译;如果替换粒度太粗,给 label.textContent 赋值可能顺便删除图标或子组件。
本地化切换必须是一笔事务
语言切换通常包含多个步骤:读取目标语言、更新内存状态、保存设置、重翻页面、通知其他扩展页面。任何一步失败,都可能留下“设置显示中文,但页面仍是英文”或“旧字典已清空,新字典未加载”的半完成状态。
更稳妥的模型是:
保存旧状态 → 加载并校验新语言 → 一次性提交 → 通知页面
失败 ↓
恢复旧状态
这就是原子性。它不要求数据库,只要求把状态变化当作不可分割的用户操作。
自定义规则是代码输入
允许用户输入 CSS 选择器和正则表达式,会显著提高扩展能力,也会把配置变成一种小型程序。
规则至少需要验证:
- 选择器类型是否在允许集合中。
- 正则是否能编译,是否可能造成异常开销。
- 翻译键是否存在或明确属于自定义命名空间。
- 显示规则时是否使用安全 DOM API。
- 导入数据是否符合预期结构与大小限制。
Chrome 的扩展安全指南 建议把来自内容脚本和用户输入的数据视为不可信,并最小化权限。扩展拥有比普通网页更高的能力,设置页中的一个 XSS 不能被当作普通显示瑕疵。
Manifest V3 改变了默认假设
Manifest V3 不允许扩展执行远程托管代码,并用 Service Worker 替代长期后台页面。它的方向是让代码进入可审查包、减少常驻资源,并让权限更明确。
对于本地化扩展,这意味着:
- 翻译逻辑应随扩展打包,不能从远端下载脚本后执行。
- 远端更新适合传输数据,但数据仍需严格校验。
- 主机权限只覆盖确实需要翻译的站点。
- 新增
tabs、scripting等权限时,要能说明具体用途。
权限清单既是技术配置,也是用户可见的信任声明。
翻译质量不只是一致率
翻译文件可以通过缺失键、重复值和占位符检查,但最终质量还包括界面语义:
- 按钮文本是否在动作语境中自然。
- 术语在请求、集合、环境和测试等上下文中是否一致。
- 中文变长后是否挤压布局。
- 快捷键、变量名、代码和用户数据是否被误翻。
- 屏幕阅读器使用的
aria-label是否同步。
因此,自动检查适合发现结构问题,真实页面巡检负责发现语境问题。两者不能互相替代。
一个稳定翻译扩展的最小测试矩阵
| 维度 | 至少检查 |
|---|---|
| 页面生命周期 | 首次加载、路由切换、弹窗、延迟内容 |
| 文本结构 | 纯文本、含图标子元素、占位符、ARIA |
| 语言状态 | 首次选择、快速切换、加载失败、重启恢复 |
| 自定义规则 | 合法、非法正则、危险文本、重复规则 |
| 权限 | 新装、升级新增权限、无权限降级 |
| 浏览器 | Chrome、Edge、目标最低版本 |
“翻译了多少字符串”只能衡量覆盖率。一个汉化扩展真正的可靠性,取决于页面变化时是否保持结构、失败时是否恢复状态、用户规则是否被安全处理。