国际化(i18n)实战:从硬编码文案到全球可用

举报
yd_237615889 发表于 2026/10/03 12:43:38 2026/10/03
【摘要】 博客 · 工程实践 / 产品工程 · 2026-10-03国际化(i18n)实战:从硬编码文案到全球可用i18n 不是「把文案翻译一下」——时区算错会跨天、复数规则会翻出翻译腔、写死的按钮宽度会让德语文案溢出。这篇按「结构 → 格式化 → 布局 → 链路 → 验收」给一条可落地的路径。工程实践手记 ·2026-10-03 ·约 12 分钟阅读一、先分清 i18n 与 l10n:结构先行很多团...
博客 · 工程实践 / 产品工程 · 2026-10-03

国际化(i18n)实战:从硬编码文案到全球可用

i18n 不是「把文案翻译一下」——时区算错会跨天、复数规则会翻出翻译腔、写死的按钮宽度会让德语文案溢出。这篇按「结构 → 格式化 → 布局 → 链路 → 验收」给一条可落地的路径。


工程实践手记 ·2026-10-03 ·约 12 分钟阅读

一、先分清 i18n 与 l10n:结构先行

很多团队把国际化理解成「上线前找翻译把文案过一遍」,结果改一处文案要翻二十个文件、时间格式全靠各写各的。国际化(i18n)是让代码"具备多语言能力"的工程结构;本地化(l10n)才是针对具体语言的适配。正确顺序:先把结构搭好(文案外置、格式化统一、布局弹性),翻译随时可以进来;反过来则全是返工。

i18n 是一次性的工程结构,l10n 是可重复的运营流程——先修路,再跑车。
· · ·

二、文案外置与 key 设计

所有用户可见文案进资源文件或翻译平台,代码只引用 key。两个关键决策:key 怎么起名(语义化如 checkout.submit 便于重组,原文做 key 便于查找——团队选一种坚持);绝不拼接句子——不同语言语序不同,拼接必然翻译腔。

场景 ✗ 反例 ✓ 做法
问候语 "你好," + name + "!" 整句 + 占位符:hello: "你好,{name}!"
数量文案 n + "条消息" + (n > 1 ? "s" : "") 复数规则引擎按语言处理(见下一节)
单位拼接 price + "元/月" 整句 + 金额格式化:per_month: "每月 {price}"

三、格式化的四件套:别自己造轮子

  • 日期时间:数据库存 UTC,按用户时区渲染;「跨天」这类业务判断用时间戳比较,不要先格式化再比字符串
  • 数字与货币:用平台国际化 API(如 Intl.NumberFormat)处理千分位与货币符号;金额以最小单位整数存储,避免浮点误差
  • 复数与语序:英语只有单复数两态,阿拉伯语有六态——交给规则引擎(如 ICU MessageFormat),别用三元表达式硬编码
  • 姓名与地址:不要假设「姓在前」或地址从小到大,用结构化字段加各地区的显示模板
// 用标准 API,而不是手写格式化(示意)
new Intl.DateTimeFormat(locale, { dateStyle: "long" }).format(date);
new Intl.NumberFormat(locale, { style: "currency", currency }).format(amount);

// ICU 消息(复数规则由引擎处理)
// "{count, plural, =0 {没有消息} one {# 条消息} other {# 条消息}}"

四、布局与书写方向:给文字留「膨胀余量」

  • 长度膨胀:同一句话德语比英语长约三成——按钮、标签、表单一律弹性布局,别写死宽高;截断要有合理策略(省略号 + 悬浮全称)
  • RTL 书写方向:阿拉伯语、希伯来语从右向左——用逻辑属性(start/end)而不是 left/right,图标、进度条、边距都要镜像;数字与代码保持 LTR
  • 排版细节:中日韩没有空格断词,需要按字符断行;西文注意连字符与避免孤字

五、工程链路:提取 → 翻译 → 构建 → 运行时

  • 提取:用 lint 规则拦截硬编码文案;CI 里检查资源文件与代码引用的一致性(缺失 key 直接失败)
  • 翻译:接入翻译平台,给译者提供上下文(界面截图、所属模块、字数上限)——「Book」是书还是预订,全靠上下文说清
  • 构建:语言包按需加载,首屏只带当前语言;新增语言不改业务代码
  • 运行时:语言优先级 = 用户手动选择 > 账号设置 > 浏览器偏好 > 默认语言;回退链(如 zh-HK → zh-Hant → zh → en)与缺失 key 的兜底展示要显式定义

六、测试与验收:让问题在发布前现形

  • 伪本地化:把文案自动加长、加乱字符跑一遍界面——十分钟找出大部分写死宽度与截断问题
  • 截图回归:关键页面在目标语言下截图对比,翻译更新一目了然
  • 边界用例:跨天、夏令时切换、货币零小数(日元)与三位小数(第纳尔)、极端长姓名

七、五个常见坑

  • 拼接句子:不同语言语序不同,拼接的文案永远是翻译腔——整句 + 占位符才是正解
  • 写死宽高:英语下刚好,德语下溢出,RTL 下错位——布局为文字留余量
  • 本地时间存库:服务器换时区或用户跨时区,时间全线漂移——存 UTC、显示时再转换
  • 复数硬编码:n > 1 的三元表达式撑不过第二种语言——交给规则引擎
  • 翻译缺上下文:同一个词在不同界面含义不同,没有截图与模块信息,译者只能猜

速查卡

场景 做法
用户可见文案 全部外置为 key;杜绝拼接,整句 + 占位符
时间处理 存 UTC;渲染用 Intl / 各语言库按用户时区
金额处理 最小单位整数存储;显示交给货币格式化 API
复数与语序 ICU 规则引擎,不用 if / 三元硬编码
布局适配 弹性布局留膨胀余量;逻辑属性支持 RTL
翻译质量 给上下文:截图、模块、字数限制;截图回归验收
快速自检 伪本地化跑一遍界面,专找溢出与截断

写在最后

国际化的本质不是翻译,而是把「只对一种语言成立」的假设从代码里清出去:文案外置、格式交给标准库、布局留余量、时区存 UTC。结构做对了,新增一种语言就只是加一份资源文件——而不是一次重构。

下一步 · 搜一遍代码里的用户可见硬编码文案
从按钮与错误提示开始——顺手把「n > 1」这类复数判断换成规则引擎,两件小事就能暴露大部分结构问题。系列下一篇候选:A/B 实验与数据驱动决策、性能预算实践、结构化日志规范。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。