这个话题对做过跨平台/跨国产品的架构师来说确实是绕不开的,而且第一版没做 i18n,后面想补,成本不是线性的,是几何级的。
---
架构师视角:i18n/l10n 不是翻译问题,是架构问题
很多团队把国际化和本地化当成"把字符串抽成资源文件"——这是最大的误解。从架构层面,它涉及五个层次:
---
五个层次逐层拆解
第一层:UI 层面(最基础,也最容易被低估)
字符串外部化 — 这步大多数人都知道:
// ❌ 不要这样
button.setText("提交订单");
// ✅ 要这样
button.setText(resources.getString(R.string.submit_order));
但真正坑人的不是字符串,而是复合句:
// ❌ 不同语言语序不同,拼接就炸
String msg = "用户 " + name + " 在 " + date + " 提交了 " + count + " 个订单";
// ✅ 用带占位符的模板
String msg = resources.getString(R.string.order_submitted, name, date, count);
// en: "{0} submitted {2} orders on {1}"
// zh: "用户{0}在{1}提交了{2}个订单"
// ja: "{0}が{1}に{2}件の注文を提出しました"
Qt 的做法:QObject::tr() + .ts 文件 + lrelease 编译成 .qm,这套机制在 C++ 生态里算是最成熟的了。
第二层:布局与设计层面(文字长度变化)
英文 "Submit" = 6 字符
中文 "提交" = 2 字符
德文 "Absenden" = 8 字符
按钮宽度要预留 30-50% 的余量,UILabel 要考虑自动换行,TableView 的列宽不能写死。
第三层:数据格式层面(数字、日期、货币、地址)
| 维度 | 中国 | 美国 | 德国 |
|:----:|:----:|:----:|:----:|
| 日期 | 2026-09-28 | 09/28/2026 | 28.09.2026 |
| 时间 | 14:30 | 2:30 PM | 14:30 |
| 数字 | 1,234.56 | 1,234.56 | 1.234,56 |
| 货币 | ¥1,234.56 | $1,234.56 | 1.234,56 € |
| 地址 | 国/省/市/区/路 | 门牌/路/市/州/邮编 | 同上类似但格式不同 |
架构要求:
服务端尽量存 UTC 时间戳 + 时区偏移
数字/货币格式化不要写死,用 ICU/CLDR 标准库
地址不能用简单的"省+市+区"三级结构,不同国家的地址字段完全不同
第四层:业务逻辑层面(法律合规)
这层是架构师最容易忽略的:
GDPR(欧洲):用户数据必须存储在 EU 区域,可删除权
CCPA(加州):数据披露和删除权
PIPL(中国):个人信息保护法,数据本地化要求
每种货币的舍入规则不同:日本的消费税、欧洲的 VAT、美国的州税
架构含义:
业务规则不能硬编码,要用策略模式或规则引擎
支付模块要设计成插件式,不同地区走不同的税务计算
用户数据的存储位置要可配置(EU 区、CN 区、US 区)
第五层:基础设施层面(CDN、域名、合规)
CDN 分发:不同地区的静态资源要就近分发
域名策略:example.com(全球)、example.cn(中国)、example.de(德国)
合规备案:在中国运营需要 ICP 备案,APP 需要 stiff 检测
支付网关:微信/支付宝(中国)、PayPal(全球)、Klarna(欧洲)
---
几个实战中的"坑"
坑 1:翻译键的命名规范
// ❌ 混乱的命名
btnsubmit, confirmbutton, okbutton001
// ✅ 按模块+组件+语义命名
order.submit_button.label
order.cancel_button.label
order.confirm_dialog.title
命名不规范,后期维护翻译文件就是灾难。
坑 2:复数规则
// ❌ 只处理了单数和复数
String msg = items.size() + " item(s)";
// ✅ 用 ICU MessageFormat
"{count, plural, one {# item} other {# items}}"
// 中文不分单复数,俄语有三套,阿拉伯语有六套
CLDR(通用区域数据仓库)定义了每种语言的复数规则——阿拉伯语有 6 种复数形式。
坑 3:RTL(从右到左)语言
阿拉伯语、希伯来语是从右往左读的。如果 UI 框架不支持 RTL(如早期的 Qt 版本),做阿拉伯语本地化的成本几乎等于重新设计一套 UI。
---
架构上的推荐做法
| 阶段 | 该做什么 |
|:----:|:--------|
| 第一版 | 所有用户可见字符串必须是资源文件,不能硬编码;时间存 UTC;金额存最小单位(分/厘) |
| 第二版 | 嵌入 ICU/CLDR 库处理地区格式;设计插件式的税务/合规模块 |
| 第三版 | 支持 RTL 布局;配置化的数据存储区域;多 CDN 分发 |
| 第四版 | 动态切换语言(不重启 App);A/B 测试不同地区的功能;自动化 i18n 回归测试 |
---
一句话总结:国际化不是"把中文翻译成英文",而是从架构层面承认"不同地区的用户生活在不同的规则体系里"——日期格式不同、法律不同、货币不同、地址结构不同、甚至阅读方向不同。第一版没留好接口,后面改起来就是重构。
发布评论