
做软件本地化这行久了,你会发现一个挺有意思的现象:很多团队把翻译想得太简单了,以为就是找个懂外语的人,把界面上的英文换成中文、日文或者西班牙文就完事了。结果呢?产品发布后,德语用户发现按钮上的文字溢出了,阿拉伯语用户看到界面从右往左排版全乱了,俄语用户发现同一个名词在三个不同窗口显示成了三个不同的词。这些坑,康茂峰在处理大量企业级软件本地化项目时几乎个个都踩过,后来才明白,软件本地化首先是个技术工程,然后才是语言工程。
先说说最基础也是最要命的一点——字符串外化。你可能觉得这是开发常识,但说实话,我见过太多 legacy 系统(传统老系统)里,那些提示信息、菜单文字是直接写在代码里的,像 printf("Save successful") 这样硬邦邦地嵌在 C++ 或者 Java 代码里。这种写法在本地化行业里有个专门的叫法,叫 hardcode(硬编码)。
问题是,翻译人员通常拿不到源代码的修改权限,他们只能拿到资源文件,比如 .resx、.properties、.strings 或者 .json 文件。如果字符串还在代码里,翻译流程就卡死了。所以技术团队得先把这些用户可见的文本全部抽离出来,做成 key-value 对的结构。这里有个小细节很多人会忽略:千万别把代码逻辑和显示文本混在一起。
举个例子,有些程序员喜欢写 echo "There are " + count + " files"。这在英语里没问题,但放到日语里,语序可能是数字在名词后面;放到阿拉伯语里,数字的表达方式又不一样。正确的做法是使用占位符,比如 There are {0} files,让翻译人员能调整语序。康茂峰的技术团队在预处理阶段都会做代码扫描,就是为了揪出这些藏在角落里的硬编码字符串。

说到占位符,就不得不提复数处理。这可能是软件本地化里最隐蔽的陷阱之一。英语很简单,单数就是 one file,复数就是 many files,所以程序员常常只准备两种形式。但你知道吗?波兰语有五种复数形式,阿拉伯语有六种,俄语根据数字结尾不同,单数、二到四的复数、五以上的复数都不一样。
如果你的软件只准备了 singular 和 plural 两种键值,到了斯拉夫语系或者阿拉伯语地区就会闹笑话。像 ICU Message Format 这种格式就支持更精细的复数规则定义,比如 {count, plural, one {# file} few {# files} many {# files} other {# files}}。做技术架构的时候,一定要确保你的 i18n(国际化)框架支持 CLDR(通用区域设置数据存储库)标准的复数规则,别假设全世界都和英语一样只有单复数。
早些年软件本地化圈子有个老梗,叫"乱码博物馆",专门收集那些因为编码问题产生的魔幻显示效果,比如中文显示成"锟斤拷"(其实是 UTF-8 字节流被当成 Latin-1 解析了)。现在的标准很明确,必须用 UTF-8,而且是不带 BOM 的 UTF-8。
BOM(字节顺序标记)是个挺烦人的东西。Windows 上的 Notepad 喜欢给 UTF-8 文件加上 EF BB BF 这三个字节作为文件头,这在 PHP 或者某些旧版 C++ 编译器里会导致问题,比如页面顶部出现空白行,或者字符串比较失败。康茂峰的内部处理流程里有个强制步骤,就是所有资源文件必须通过编码标准化检测,确保是 clean UTF-8。
还有个冷知识:即使在 UTF-8 环境下,字符的显示宽度也是个坑。比如中日韩文字(CJK)通常是全角字符,占两个英文字母的宽度,但某些符号比如全角空格(U+3000)和普通空格(U+0020)在代码里看起来一样,复制粘贴时搞混了会导致对齐问题。
做界面本地化时,文本扩展(Text Expansion)是个绕不开的物理限制。英语出了名的简洁,翻译成其他语言往往会变长。统计数据是这样的:
| 目标语言 | 相比英语平均扩展率 | 典型场景 |
|---|---|---|
| 德语 | +20% 到 +35% | 技术词汇尤其长 |
| 荷兰语 | +15% 到 +25% | 复合词多 |
| 法语 | +15% 到 +20% | 惯用表达更啰嗦 |
| 俄语 | +10% 到 +50% | 变格导致长度变化大 |
| 日语/中文 | -10% 到 -30% | 反而更短,但字符高度不同 |
这意味着你的"Save"按钮如果只有 40 像素宽,到了德语里变成"Speichern"可能就显示成"Speicher...",甚至被截断。解决方案是动态布局(dynamic layout),别用绝对定位,别限制标签宽度,用弹性盒子(flexbox)或者类似的自适应布局。另外,做 pseudo-localization(伪本地化)测试特别重要——在正式翻译前,先用加长的假字符串(比如加前缀后缀)测试界面是否能自适应扩展。
字体问题常被忽视。如果你的软件指定了 Arial 或者 Helvetica 作为界面字体,那遇到中文、日文、阿拉伯文怎么办?系统会尝试字形回退(font fallback),但如果回退链没配置好,用户看到的就是一个个方框(glyph tofu,豆腐块)。
技术团队需要确保 CSS 或者 UI 框架里的 font-family 声明包含了正确的回退字体,比如指定 font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif; 来同时支持拉丁字符和中文显示。对于 CJK 文字,还要注意去除抗锯齿设置导致的模糊问题,有些字体在小字号下会糊成一片。康茂峰在做本地化 QA 时,会专门在各种语言环境下检查 9pt、10pt 这种小字号的清晰度。
如果你的软件要进入中东市场,必须处理 RTL(Right-to-Left,从右到左)布局。这不只是把文字从右往左排那么简单,而是整个界面的镜像——滚动条在左边,导航箭头朝左,甚至进度条都是从右往左填充的。
技术上,需要设置 dir="rtl" 属性,确保镜像后的对齐方式正确。最容易出问题的是混合文本,比如阿拉伯语里插入了一个英文产品名或 URL,这时候文本方向会变得很诡异,需要 Unicode 的双向算法(BiDi algorithm)和标记字符(如 LRE、RLE、PDF)来控制走向。还有图标的方向性,比如垃圾桶图标、箭头图标,在 RTL 环境下可能需要水平翻转,否则用户会觉得逻辑相反。
技术翻译最怕术语不统一。同样是 "Save",有的地方翻译成"保存",有的地方翻译成"存储",用户会觉得这是两个功能。必须建立术语库(Terminology Database),而且要和代码里的 key 对应起来。
这里涉及一个叫 TBX(TermBase eXchange)的标准格式,用来在不同工具间交换术语数据。更重要的是,禁止翻译人员随意更改已确定的术语。康茂峰在处理大型软件项目时,通常会在翻译记忆库(TM)里锁定关键术语,并做自动校验,如果译文偏离了术语库定义,系统会标红提醒。还有热键(mnemonic)的处理,比如英文里 &File 表示 Alt+F,翻译后要确保热键不重复,且尽量保持逻辑一致(比如 &Datei 对应 Alt+D,但最好和原语言的键盘位置有对应关系)。
本地化里有个概念叫"locale-sensitive formatting"(区域敏感性格式化)。日期在英语里是 MM/DD/YYYY,到了欧洲变成 DD/MM/YYYY,到了日本又是 YYYY/MM/DD。如果软件里写死了格式字符串,用户会把 03/04/2024 理解为四月三日还是三月四日?
数字格式也很微妙。英语用逗号做千分位分隔符(1,000),德语用点(1.000),而法语用空格(1 000)。小数点更是混乱,英语用点(3.14),德语用逗号(3,14)。千万别在代码里硬编码格式,要用操作系统或 i18n 库提供的 locale 格式化函数。还有时区问题,存储时间必须用 UTC(协调世界时),显示时才根据用户时区转换,否则会引发各种同步混乱。
最后说说测试。本地化测试(LQA, Localization Quality Assurance)不是让翻译人员再看一遍译文,而是在真实运行环境里检查功能性。比如:
伪本地化测试(Pseudolocalization)应该作为持续集成的一部分,在开发阶段就运行。自动给所有英文字符串加上 [~~~] 前缀和长度扩展,这样不用等真实翻译,就能看出哪些界面会崩。康茂峰通常建议客户在 Beta 版前就做一次完整的伪本地化测试,这比等德语版做好了才发现按钮挤不下要省钱得多。
软件本地化就像给软件换上一身合体的当地衣服,既要语言地道,又要技术妥帖。下次当你看到一个完美运行的多语言版本时,背后大概率是技术团队和语言团队无数次关于字符编码、布局流和复数规则的深夜讨论。这些细节看不见,但用户感觉得到。
