国际化方案

前端 i18n 库的选择

市面上比较流行的只有两种,两者功能差不太多。

i18n-next

  • 可支持插件拓展
  • 不支持编译自动生成 key (但是可以直接用文案当作 key)

react-intl

  • 不支持插件拓展,但支持高阶 hoc 的拓展
  • 支持编译时自动生成 key

i18n 的本质

key - value 映射
不管哪种方案都是 key - value 的映射,抓住本质他的概念就很好理解。

如下

// 只是切换时候加载不同对象内容。
let languages = {
  en: {
    "common.hello": "hello",
  },
  zh: {
    "common.hello": "你好",
  },
};

i18n 需要解决的问题

key 的选取

如上所述 react-intl 支持自动生成 key,也支持手写 key。
i18n-next 貌似只支持手写 key。
key 的常见规则如下

// 规则一:手写,短语拼接
let languages = {
  en: {
    // 短语方式写key
    "common.hello": "hello",
  },
};
// 规则二: 手写,直接用文案当key
let languages = {
  en: {
    // 这种可能文案生成的json会很大
    "hello ,i am fine and you?": "hello ,i am fine and you?",
  },
};
// 规则三: 自动生成
//react intl 支持自动生成
// 举例
function Demo() {
  const intl = useIntl();
  return intl.formatMessage({ defaultMessage: "hello" });
  //                                          ^^^^^^^
  // 在编译时候会给你生成
  // intl.formatMessage({id:'generateKeyRule("hello")',defaultMessage:"hello"});
  // generateKeyRul 可以自己指定,还有一些额外上下文变量可以使用,比如文件路径。
  // 可以生成这种内容sha1
  // intl.formatMessage({id:'asdjfkasjdfxxx',defaultMessage:"hello"});
}

对比下三种规则优缺点

手写短语文案就是 key自动生成
优点无文案依赖,也就是说它只作为页面的一个占位符,你想换文案就可以换文案无文案依赖,相比手写更加易于理解无文案 key 维护成本,翻译易于复用
缺点累,维护 key 贼累,翻译可能不易复用代码显示文案可能与线上显示文案不符依赖文案生成 key,依赖文案的变更需要重新生成 key,重新上线,文案冲突频率变高,需要选择一种基准文案(建议项目母语,变更频率最低)
适用场景文案少,变更频繁,可自定义覆盖,c 端,组件库没想好文案多,变更不频繁,b 端

ps: 文案冲突

// 自动生成key的文案冲突问题
function Demo() {
  const intl = useIntl();
  return intl.formatMessage({ defaultMessage: "select" });
  //                                          ^^^^^^^
  // 对应中文可能是 选择图片,选择视频
  // 解决办法,添加描述性语句辅助生成key
  // return intl.formatMessage({ defaultMessage: "select",  description: 'image', });
  // zh: 选择图像 key-> select#video (react-intl 拼接规则)

  // return intl.formatMessage({ defaultMessage: "select",  description: 'video', });
  // zh: 选择视频 key-> select#video (react-intl 拼接规则)

  // return intl.formatMessage({ defaultMessage: "select" });
  // zh: 选择 key-> select
}

可能遇见的状况(低频)

货币,数字国际化,i18n 是提供这个 api 的,可放心食用。

基础库解决的问题

  • 文案提取的能力。
function Demo() {
  const intl = useIntl();
  return intl.formatMessage({ defaultMessage: "hello" });
  // return intl.formatMessage({ id:"id", defaultMessage: "hello" });
}

// ===> 提取json
// 类似这种
// {
// 	"id || generateKeyRule(text)" : "hello"
// }
  • key-value 映射

基础库未解决的问题

  • 文案管理

随着业务迭代,文案越来越多,会有废弃文案,新增文案的概念。
需要一个平台存储文案,然后前端项目获取文案,可根据从项目中提取的文案与存储文案的地方做对比,然后获取文案。

  • 文案完整度

如何确保多国翻译,或者部分国翻译 100%已有翻译,还是需要从项目中获取项目中使用的文案,然后对比语言包。

  • 翻译流程

一条文案的产生的源头通常 prd,然后设计复制一份并拓展,然后研发根据设计稿开发,当提测是应提交项目中的文案到,待翻译状态,然后翻译组/产品/机翻,进行翻译,然后前端项目获取这些文案,进行文案完整度上线前检测即可。
这个是最难的,要拉起设计、产品、研发的认知才能搞。

  • 翻译文案

    如何保证一条文案在语境下的正确性?

    • 方案一:
      文案+设计图
      实现难度低
    • 方案二:
      文案+页面
      实现难度复杂
  • 文案关联页面

    可通过webpack 插件开发处理chunk信息获取

    所以需要一个平台/平台周边生态去做这些事

参考

i18n-next 文案平台
https://locize.com/
vscode i18n all in one 插件
https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally

阿里的轮子
https://github.com/alibaba/react-intl-universal
https://github.com/alibaba/kiwi