开群机器人|QQ群机器人|微信群机器人|三公机器人

微信群机器人 架构师视角:i18n/l10n 不是翻译问题,是架构问题

这个话题对做过跨平台/跨国产品的架构师来说确实是绕不开的,而且第一版没做 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 回归测试 |


---


一句话总结:国际化不是"把中文翻译成英文",而是从架构层面承认"不同地区的用户生活在不同的规则体系里"——日期格式不同、法律不同、货币不同、地址结构不同、甚至阅读方向不同。第一版没留好接口,后面改起来就是重构。


admin
admin
这个人很神秘

发布评论