写在前面:本地化不是把文本交给翻译
很多个人开发者谈本地化时,第一反应是:
把中文导出来。
找译者。
导回英文、日文、德文。
然后上线。
真正做过一次后才会发现,本地化首先是工程问题。
文本从哪里来?
字体能不能显示?
UI 是否会溢出?
术语是否一致?
构建时能不能发现缺翻译?
玩家切语言后存档、成就、教程提示会不会出错?
苏沅做过一款小型叙事经营游戏。
玩家经营一间夜间照相馆,为路过的客人拍摄证件照、遗照、纪念照,并从照片背后的留言里了解他们的故事。
游戏中文文本约 8 万字。
她计划首发中文和英文,发售后三个月加入日文。
最早她以为本地化只是内容工作。
后来在 Demo 测试时,英文版 UI 大面积溢出,部分字体缺字,存档里还保存了中文任务名,导致切换语言后任务列表混乱。
她最终重做了本地化技术管线。
这个决定让正式版多语言发布稳了很多。
一、先把文本从代码和场景里拿出来
项目早期,苏沅的文本分散在很多地方:
- 对话脚本里有角色台词
- UI Prefab 里写着按钮文字
- 任务系统里保存任务名称
- 教程提示写在触发器组件上
- 成就描述写在平台后台
- 图片里嵌着少量中文标题
这在单语言原型阶段很快。
但一旦多语言,就会变成灾难。
她做的第一步是建立文本 ID。
例如:
ui.confirmui.cancelquest.photo_album_01.titledialogue.mei.entrance.003tutorial.camera.focus
游戏运行时不直接使用中文文本,而是通过 ID 查当前语言。
这带来一个重要变化:
存档不再保存“寻找旧相册”,而是保存 quest.photo_album_01 和任务状态。
语言切换后,任务名称由本地化表重新显示。
二、为什么不用散落的 JSON 文件
苏沅考虑过每种语言一个 JSON 文件。
比如:
zh-CN.jsonen.jsonja.json
小项目这样可以。
但她的文本量不小,而且需要译者和校对一起工作。
JSON 对程序友好,但不适合非技术人员长期编辑。
换行、引号、逗号、转义字符,都容易出错。
她最后选择表格作为源数据,构建时生成游戏使用的 JSON。
表格字段包括:
idcontextspeakerzh_cnenjamax_widthnotestatus
其中 context 和 note 对翻译非常重要。
例如“冲洗”在照相馆里可能是冲洗照片,不是冲洗杯子。
如果不给上下文,译者很容易选错词。
三、字体方案要提前验证
本地化最容易被拖到后面的,是字体。
中文字体能显示中文,不代表能覆盖日文假名、日文汉字、拉丁扩展、标点和特殊符号。
英文字体漂亮,也不代表支持重音字符。
苏沅做了一个字符收集脚本。
它扫描所有语言文本,输出实际使用字符集合。
然后检查当前字体是否覆盖。
第一次检查时,她发现:
- 英文译文里有弯引号和长破折号
- 法语媒体引用里出现重音字符
- 日文测试文本里有几个字体缺字
- UI 图标字体缺少手柄按键符号
这些问题如果发售后才出现,就会变成玩家截图里的方块字。
她最终方案是:
- 中文使用一套 CJK 字体子集
- 英文使用单独拉丁字体
- 日文首发前生成日文子集
- 图标符号使用独立 sprite atlas
- 构建时检查缺字
字体子集让包体可控。
构建检查让缺字不会混进发布包。
四、文本长度不是 UI 的小问题
英文通常比中文长。
德文可能更长。
日文有时短,但换行规则不同。
苏沅在英文 Demo 里遇到最明显的问题:
“开始营业”变成 “Open for the Night”,按钮直接溢出。
“查看相册”变成 “Review Photo Album”,菜单布局被撑开。
她没有要求译者硬压短每一句。
而是从 UI 方案上处理:
- 按钮给出最小宽度和最大宽度
- 长文本允许换行
- 部分 UI 使用图标加短标签
- 任务描述区域改成可滚动
- 对话框按语言调整行高
- 构建时检测超出
max_width的文本
表格里的 max_width 字段就是给校验用的。
如果某条翻译超过指定宽度,构建脚本会报 warning,并截图标记对应 UI。
个人游戏不一定能做完整自动截图测试。
但至少要在导入阶段知道哪些文本可能溢出。
五、术语表比后期校对更便宜
照相馆游戏里有很多固定词:
- 底片
- 暗房
- 显影液
- 证件照
- 遗照
- 相纸
- 预约单
苏沅一开始让译者自由处理。
结果同一个“底片”在不同地方出现了 negative、film、plate 三种译法。
不是译者水平差。
而是没有术语表。
她后来建立 terms 表:
- 中文词
- 英文固定译法
- 日文固定译法
- 使用场景
- 禁用译法
- 备注
导入脚本不会强制替换术语,但会扫描译文,发现禁用词或疑似不一致时提示。
这对叙事游戏很有用。
术语一致会让世界观显得稳定。
术语混乱会让小项目显得粗糙。
六、图片文本尽量减少
苏沅早期有一些美术图直接写中文:
- 店门招牌
- 相册封面
- 旧报纸标题
- 教程示意图
这些很有氛围,但多语言成本高。
她没有全部删掉。
而是分三类处理:
第一类是世界内固定文字,比如店名。
保留中文,作为美术风格的一部分。
第二类是玩家必须理解的信息,比如教程图。
改成可本地化 UI 文字。
第三类是可选氛围文本,比如旧报纸。
如果重要,就做多语言贴图;如果不重要,就避免玩家必须阅读。
这个取舍避免了大量重复美术资产。
个人游戏做本地化时,不要随手把关键信息烘进图片。
后期会非常贵。
七、构建校验是最后一道线
苏沅的构建脚本会检查:
- 是否有缺失 ID
- 是否有重复 ID
- 当前发布语言是否缺翻译
- 字体是否缺字
- 是否有超宽文本 warning
- 是否存在未本地化的 UI 文本
- 是否有存档字段直接保存显示文本
构建失败不一定阻止所有 warning。
但正式发布包不能有 error。
这让本地化问题从“玩家发现”提前到“开发者构建时发现”。
结语:多语言发布靠的是管线,不是临时加班
苏沅的最终方案并不复杂:
- 文本 ID 化
- 表格作为源数据
- 构建时生成 JSON
- 字符集扫描和字体子集
- UI 文本长度校验
- 术语表
- 图片文本分类处理
- 存档只保存 ID 和状态
它花了两周时间搭建。
但这两周避免了发售前一个月的混乱。
个人游戏做本地化,最重要的不是一开始支持十种语言。
而是从第一种外语开始,就让文本、字体、UI、存档和构建流程站在正确的位置。
翻译可以外包。
本地化管线必须由开发者负责。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。