当某个功能能在任何语言中正常运行,且无需修改代码就能遵循各读者的使用惯例时,它才算为面向全球市场做好准备。本页面遵循微软的国际化检查清单:每个章节都会说明不同市场间的差异、如何编写正确的代码,以及全球化检查用于标记错误习惯的代码。
核心原则只有一条:由读者的区域设置来决定显示方式。浏览器的IntlAPI、框架内置的格式化工具以及背后的数据文化能识别各市场的使用惯例;硬编码某一市场规则的代码无法适配其他市场。
文本与句子
用户看到的每段文本都应收录在源目录中,对应一个键,并通过项目的翻译功能渲染出来。这包括标签、标题、按钮、提示信息、面向用户的错误信息、占位符alt文本及ARIA标签。代码:hardcoded_text。
一个句子即一条消息。不同语言的词序存在差异,因此由零散部分拼接而成的句子无法被翻译。需将数值作为占位符传入,计数则采用复数形式。代码:concatenated_text。
// Not world-ready: English word order and English plurals
'You have ' + count + ' new ' + (count === 1 ? 'message' : 'messages');
// World-ready: one ICU message
t('inbox.new', { count });
// "inbox.new": "{count, plural, one {You have # new message} other {You have # new messages}}"不同语言需要的复数形式各不相同:英语有两类,阿拉伯语有六类,日语仅有一类。编写源消息时需使用ICU复数规则,引擎会自动补充各语言所需的复数形式。
数字
同一数字在不同市场的写法各异:美国写为1,234.5,德国写为1.234,5,瑞典和法国写为1 234,5,部分阿拉伯市场还有其他的书写方式。需按照读者的区域设置来格式化数字。代码:locale_number。
new Intl.NumberFormat(locale).format(1234.5);
new Intl.NumberFormat(locale, { style: 'percent' }).format(0.25);读取用户输入的数字时需匹配其所在区域的格式,或使用数字输入框,浏览器会自动对输入值进行规范化处理。parseFloat('1,5')表示为1,而非one and a half。代码:locale_parsing。
日期、时间和时区
日期顺序、分隔符、月份名称、12小时制或24小时制以及日历都存在差异。需按照读者的区域设置来格式化日期,切勿使用固定模式,例如MM/dd/yyyy。代码:locale_date。
new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short', timeZone }).format(when);- 时间节点需以UTC格式存储,采用带偏移量的ISO 8601格式,再按照读者所在的时区进行格式化。计算“当天”和日边界时也需基于该时区,而非服务器所在时区。
- 不同市场的周起始日各不相同:美国以周日为一周起始日,欧洲大部分地区以周一为起始日,中东部分地区则以周六为起始日。周末的定义也存在差异。这两类信息均需从区域设置中获取(
new Intl.Locale(locale).getWeekInfo()如有相关配置的话),或采用日期库提供的区域数据,切勿使用固定值。代码:calendar_names。 - 星期名称和月份名称均来自区域设置(
Intl.DateTimeFormat(locale, { weekday: 'long' })),而非代码中预设的列表。代码:calendar_names。 - 日历。沙特阿拉伯、以色列和日本在采用公历的同时,也使用乌姆·古拉历、希伯来历和日本历;泰国和伊朗则默认采用佛历和波斯历。文化属性会标明某市场使用的日历类型。
货币
金额需按照对应货币和读者的区域设置来格式化,切勿将符号直接放在数字旁边。同一金额在不同读者看来会显示为$1,234.50、1.234,50 $或US$1,234.50具体显示效果取决于读者所在的地区,且很多市场会使用相同的货币符号。代码:hardcoded_currency。
new Intl.NumberFormat(locale, { style: 'currency', currency }).format(1234.5);货币属于商业决策范畴,而非格式化问题:更改读者的区域设置时不得自动转换商品价格。文化属性会记录各市场使用的货币类型。
排序、比较和大小写
每种语言都有自己的排序规则:瑞典语中å、ä、ö排在z之后,德语中ä与a归为一类,中文则按拼音或笔画排序。面向读者的文本排序需遵循读者的区域设置。代码:ordinal_sort。
names.sort(new Intl.Collator(locale).compare);大小写映射也与语言相关:土耳其语中字母i的大写形式为İ。针对面向读者的文本,需使用toLocaleUpperCase(locale)进行处理。代码:case_mapping。
列表
“Anna, Ben and Chen”在不同语言中的写法各不相同。列表拼接需遵循对应区域的规则。代码:joined_list。
new Intl.ListFormat(locale, { style: 'long', type: 'conjunction' }).format(names);名称、地址、邮政编码和电话号码
- 名称。很多市场将姓氏置于名前,很多人只有一个名字,或拥有两个以上名字。除非某市场有特殊要求,否则应将姓名存入同一个字段。需支持所有文字体系:Åsa、José、王和Мария都属于有效的姓名。代码:
latin_only_input。 - 地址。字段名称、排列顺序及称谓在不同市场存在差异:美国有州和邮政编码字段,日本有都道府县字段,部分市场甚至没有邮政编码。文化属性会标明各市场使用的地址格式,切勿要求用户填写某市场不需要的字段。
- 邮政编码。应将其作为文本处理,并按国家/地区规则验证,或直接不验证。五位数的正则模式无法覆盖全球大部分地区的邮政编码规则。代码:
postal_code_format。 - 电话号码。需以E.164格式存储(
+46 8 123 456 78),使用能够识别各国号码规划的规则库(如libphonenumber)来进行格式化和验证。类似(555) 555-1234拒绝所有非北美地区的数字。代码:phone_number_format。
计量单位和纸张
全球大部分地区采用公里、千克和摄氏度;美国使用英里、磅和华氏度;英国则两者兼用。需根据读者所在地区选取对应单位并按当地语言环境格式化。代码:fixed_unit。
new Intl.NumberFormat(locale, { style: 'unit', unit: 'kilometer' }).format(12);打印输出和PDF文档采用的纸张规格:北美为Letter纸,其他地区多为A4纸。代码:paper_size。
输入法和字体
中文、日文和韩文需通过输入法编辑器输入:按下Enter键是为了选择词语,而非提交内容。若处理逻辑在词语组合期间将Enter键的提交操作忽略,方可避免问题。代码:ime_composition。
onKeyDown={event => {
if (event.key === 'Enter' && !event.nativeEvent.isComposing) submit();
}}应选用能覆盖所有书写系统的字体,或回退至支持这些书写系统的系统字体;阿拉伯语、中文、希伯来语、日语、韩语和泰语各自需要专属字体。需为字符高度较高的书写系统预留行高空间,不要依赖斜体(中文和日文无斜体形式),且切勿将文本嵌入图片,因为图片无法进行本地化。
从右向左排版
阿拉伯语和希伯来语采用从右向左的书写方式,布局也会随之镜像调整:包括导航、对齐方式、指向性图标以及列顺序等。
- 设置
dir="rtl"在这些语言的根元素上设置,同时lang针对每种语言设置。 - 运用逻辑属性:
margin-inline-start替代。margin-left、padding-inline-end、inset-inline-start、text-align: start、float: inline-start,以及CSS框架提供的逻辑工具类(ms-4、pe-2、text-start)。代码:physical_direction、unmirrored_layout。 - 箭头和 chevron 等表示方向的图标需镜像处理,而时钟或播放按钮等则无需如此。
- 在数字、代码、URL及拉丁字母名称中,文字仍保持从左向右排列,即便处于从右向左的文本环境中。需将此类文本隔离于
<bdi>之中,以免其干扰周边内容的排序。
预留扩展空间
译文往往比英文更长,短标签的增长幅度尤为明显:德语中的“OK”可能演变为一个完整的单词,原本十个字符的标签长度甚至可能翻倍。需为文本预留空间:允许其自动换行,让按钮和标签页随标签内容扩展,切勿对文本设置固定的宽度和高度。不要截断用户操作所需的标签内容。代码:clipped_text。
该伪本地化会使每个字符串的长度增加上述数值,以便你在翻译人员介入前就能发现相关问题:
| 源字符串长度 | 新增长度 |
|---|---|
| 最多10个字符 | 100% |
| 11到20个字符 | 80% |
| 21到30个字符 | 60% |
| 31到50个字符 | 40% |
| 51到70个字符 | 31% |
| 超过70个字符 | 30% |
中文、日文和韩文通常字符数较少,但所需行高较大。
每次变更的核查清单
- 用户阅读的文本源自目录,每个句子对应一条消息。
- 数字、日期、时间、货币、单位和列表均需根据读者的语言环境进行处理。
- 排序和大小写映射也需遵循读者的语言环境。
- 名称、地址、邮政编码和电话号码需适配所有市场。
- 词语组合期间,按下Enter键不会触发提交操作。
- 布局采用逻辑属性,并为较长的文本预留空间。