国际化
中文与英文在这里是平等的。任何一方都不是另一方的「翻译」,并且由 CI 强制保证。
校验规则
src/i18n/i18n.test.ts 会在以下情况让构建失败:
- 某个 key 只存在于一种语言中。
- 存在空值。
zh-CN的值与英文完全相同。zh-CN的值包含拉丁字母且不含任何汉字。
第 4 条之所以存在,是因为第 3 条并不够。profile.technical 曾经是英文单词 "technical",而英文侧是 "Technical contact" —— 两者确实不同,但显然仍未翻译。
品牌名(Ant Design、React)、技术缩写(CPU、API)与文件名 (theme.ts、hero-dark.png)在白名单内,其余文案必须包含汉字。
排版不能共用
拉丁字母与汉字的度量并不相同。汉字字面饱满、等宽,且没有升降部形成的节奏, 因此拉丁文的行高会挤压汉字,拉丁文的字距又会把它们拉散。tokens.css 维护两套并行的 度量体系:
css
:root {
--text-base: 14px;
--leading-normal: 1.55;
--tracking-tight: -0.011em;
}
:root:lang(zh), :root:lang(ja), :root:lang(ko) {
--text-base: 15px; /* 相同字号下汉字视觉更小 */
--leading-normal: 1.75;
--tracking-tight: 0; /* 负字距在中文里是明显错误 */
--weight-bold: 600; /* 避免合成的伪粗体 */
}<html> 上的 lang 属性并非只是语义标记,它就是这套切换的开关。 buildTheme() 会把同样的差异同步到 antd 的 ConfigProvider。
按需加载
语言包按需拉取,这样身处上海的读者不会下载他们永远不会看到的英文文案:
ts
const LOADERS = {
'en-US': () => import('./locales/en-US/common.json'),
'zh-CN': () => import('./locales/zh-CN/common.json'),
};请使用 changeLocale() 而不是 i18n.changeLanguage():前者会先加载语言包再切换。 直接调用 changeLanguage 会在文案就位之前切换语言,导致界面闪现一帧原始 key。
新增语言
- 在
src/i18n/locales/下新增目录。 - 将其加入
SUPPORTED_LOCALES与LOADERS。 - 若属于 CJK,需同时加入
CJK_LOCALES以及tokens.css中的:lang()选择器。 漏掉第二步,正是新增日语后排版总觉得别扭的原因。 - 在
ThemeProvider中映射到对应的 antd 语言包。