前段时间,我终于把《虐杀原形1》的中文本地化项目彻底收尾了。
最开始我其实没把这件事想得多复杂。毕竟是 2009 年的老游戏,我当时的思路很直接:把资源拆出来,提取文本,翻成中文,处理字体,再重新打包回去。
真做进去以后才发现,翻译反而是整个项目里比较省心的一部分。
最后我做出来的也不再只是一个“能看到中文”的汉化包。
整个流程从资源提取、文本分类、中文整合、CJK 字体适配、Scaleform UI 调试,一直做到 archive 重建、自动化 QA、运行时测试和最终发布验证。Final 版本涉及 9 个游戏 archive;整个项目的最终 display / localization audit 覆盖了 20,389 个字符串,而冻结版本在项目自己的 release severity model 下没有留下 P0、P1、P2 问题。
文件看起来没问题,脚本也显示 PASS,可一进游戏,它还是会坏。
当时我已经写了字体检查脚本。脚本告诉我,字体资源里明明存在这个字,整套检查也是 PASS。按正常思路,这件事应该已经结束了。
排查到最后才发现,真正的问题不是字库里“有没有这个字”,而是我从一开始就问错了问题。
《虐杀原形1》里的字幕、UI 正文、标题等文本,并不是统一从一个字体里取字。不同字段在运行时会绑定到不同的字体资源。
后来我把这部分检查模型整个改掉,不再问“某个字符是否存在于任意字体”,而是按照:
runtime field → bound font → possible characters
也就是后来仓库里的 binding-aware glyph audit。
字幕和 UI 正文从此分开走各自的字体覆盖检查。最终字幕路径一共检查了 15,275 条字符串,针对实际绑定的 SubtitleFont 做验证,结果是 0 个缺失字形。
最终版本中的中文对话字幕。字体检查后来改成按实际绑定关系分别验证。
这个问题后来对我整个项目的影响,比那个“童”字本身大得多。
真正危险的是,脚本跑得非常漂亮,一路 PASS,但你一开始定义的 validation model 就是错的。
第二个让我折腾很久的问题,是 Ability Wheel,也就是技能轮盘。
但只要进入没有有效选择,或者技能仍处于 locked 的状态,中文标签就会出现白方块和异常几何线条。
最麻烦的是:同一个 UI,不同运行时状态,结果不一样。
如果只是静态看字体文件,很难解释。只看 GFX,也解释不了为什么 unlocked 正常、locked 却会坏。
我前面先做了 resource-level 和 tag-level 的 A/B build,用单变量实验排掉了几个看起来很合理的怀疑对象。还不够以后,我又在轮盘状态上加了很窄的 runtime instrumentation,把 no-selection、locked 和 unlocked 的行为拆开观察。
异常集中在 no-selection 和 locked 这些状态路径。
“确认什么状态会触发异常”和“已经证明底层 root cause”,不是一回事。
如果继续往下挖,还需要进入更深的字体和 UI runtime 层面继续做实验。
理论上当然可以接着查,但项目已经非常接近 Final,我开始考虑另外一个问题:值不值得。
如果为了最后几个中文字,继续去动一条已经基本稳定的 UI 路径,反而有可能引入新的回归。
所以我最后没有追求一个看起来更漂亮的“100% 中文化”数字。
正式版本里,没有有效选择时名称留空;locked 节点使用 ASCII LOCKED;已经解锁的技能保留验证过的稳定英文能力名称。
Locked 状态:最终采用稳定的 ASCII compatibility fallback。
修复方案确定以后,我又用新存档重新跑了五组场景:第一次打开轮盘、多个 locked 节点、正常 unlocked 节点、locked / unlocked 来回切换,以及技能刚刚解锁后的状态。
这些测试覆盖了之前最容易出问题的初始状态、状态切换和新解锁路径,最终全部通过。
真正改变我发布思路的,是后面的 01audio.rcf。
很长一段时间里,我一直默认对话字幕已经完整进入本地化流程。
直到最终审计时才发现,一个单独的 dialogue archive 之前并没有完整进入处理范围。
重新提取以后,一共暴露出 907 个物理字幕槽位。
因为在发现它之前,游戏能正常启动,很多场景也已经跑过。
那这个 archive 完全可能就这样跟着 Final 一起发出去。
后来我把 01audio 重新纳入完整流程,907 个槽位全部做 readback,最后没有再发现残留英文 body text,也没有空的目标语言条目。
但这件事真正留下来的不是一句“以后别忘了 01audio”。
我把它重新定义成了一个 pipeline coverage failure。
经历过 01audio 之后,我基本不再相信一句:
所以 Final 版本最后又完整跑了一遍 release verification。
冻结后的发布产物被重新独立解析和 readback。
最终的 9 个 archive 全部固定 SHA-256 身份。
17,523 个资源重新解析并对照批准的 resource-diff boundary 检查,结果是 0 个未批准的意外差异。
其中 2,219 个压缩资源重新做了 decompression / readback 验证。
与此同时,Final 的 display-string audit 一共覆盖了 20,389 个字符串。
17,523 是 release resource verification 的覆盖范围;20,389 是 display / localization string audit 的范围。它们代表的是检查边界,不是拿来放大工作量的数字。
- archive parsing / readback
- compressed-resource decompression / readback
- mirrored TextBible equality
- placeholder / control-code preservation
- visible-English classification
- bound-font glyph coverage
- binary / resource difference allowlist
- manifest / SHA verification
已经确认的玩家可见英文遗漏一共有 28 个,28 / 28 全部修复。
批准保留的人名和 compatibility fallback 单独分类,不混在“漏翻”里。
最终版本中的 Tutorial UI。发布前不仅检查文本,也检查实际 UI 路径和字体覆盖。
这些结果当然不等于“这个游戏从此绝对不存在任何未知 bug”。
P0 / P1 / P2 也是这个项目自己定义的 release severity model,不是什么第三方公司的认证。
但实际做到后面,它更多参与的是资源结构分析、脚本开发、批量审计、候选修复、实验 build、验证结果整理和文档工作。
但越往后,我越觉得“AI 能写多少代码”反而不是这里最重要的事。
谁决定一个异常是 Bug、兼容性 fallback,还是本来就不应该进入检查范围?
在整个项目里,我负责范围和验收标准、运行时测试、故障证据收集、实验方向、兼容性取舍以及最终 release decision;AI 则大量参与分析、编码、候选构建和文档工作。
所以做到最后,我对 AI 工程最大的感受不是“它能替代多少人”。
一旦问题被定义对,AI 可以把后面的执行速度拉得非常高。
反过来,如果问题一开始就错了,它也只会更快地帮你得到一个非常漂亮的错误答案。
项目冻结以后,我重新看了一遍,发现真正留下来的东西其实有三层。
一个已经冻结的 v2.3.4 Final release,有明确的 compatibility fallback,也有对应的验证记录。
第二层,是整套 QA / release workflow。
为了把这个项目做完,我陆续把很多原本一次性的人工检查工具化,包括:
- placeholder / control-code validation
- binding-aware glyph audit
- SHA / manifest verification
- guarded deploy / rollback
这些工具里,有一部分仍然明显是 Prototype-specific。
我没有把它包装成一个“拿去什么游戏都能直接跑”的通用框架,因为它现在还不是。
但像 visibility classification、token preservation、bound-font auditing、resource allowlist、release gate 这些检查思路,已经不再只属于《虐杀原形》。
我最后把能够公开的部分整理成了一个 Engineering Case Study #001。
里面保留了技术架构、典型故障的排查过程、QA 方法、release verification,以及一部分可以公开的通用工具。
原始游戏 archive、字体、音频和其他受版权保护的资产都没有放进去。
所以如果现在再让我给这个项目下一个定义,我不会只说:
我在 AI 深度参与下,主导完成了一次针对遗留 PC 游戏的端到端中文本地化工程。范围定义、运行时测试、故障调试、QA、兼容性取舍和最终发布决策,都由我负责把关。最后交付的不是一个“看起来能用”的版本,而是一个我能够说明它如何生成、如何验证,以及为什么达到冻结和发布标准的 Final release。
这也是为什么我最终决定把它留下来,作为我的 Case Study #001。
完整 Engineering Case Study 和公开工具:
仓库只包含案例、文档和可公开的通用工具,不提供游戏原始资源、字体、音频或其他受版权保护的游戏文件。
评论区
共 2 条评论热门最新