今天给大家介绍一个轻量但神奇的国际化库tiny-i18n

在我们的项目日益庞大的情况下,国际化的字典愈变愈大,国际化文本的维护是一个问题;
有时候修改一个字段,查找就花费了很大的时间功夫。 这个时候 tiny-i18n 中的 @tiny-i18n/react-live 就可以发挥它的力量了,可以帮助我们在线可视化修改、新增国际化字段。

效果

体验在线编辑

实现原理

对 i18n 转换方法进行包装,转换成包含特殊字符(包裹)的字符串;同时对 React.createElement 方法进行包装,检测出包含特殊字符(包裹)的字符串,这时候就会被认为是国际化的文本,这个时候再去注入一些而外的交互逻辑。

以 codesandbox DEMO 为例,在下面这段 React 视图代码中:

class App extends React.Component {
  changeLang = lang => {
    this.context.i18n.setLanguage(lang);
  };
  render() {
    return (
      <div className="App">
        <h1>{_i("tpl.sayhello", _i("name"))}</h1>
        <h2 title={_i("content.text")}>{_i("content.text")}</h2>
        <a href="/?react-live">Open react-live mode</a>
        <div>
          <h3>
            {_i("label.current.lang")}: {i.getCurrentLanguage()}
          </h3>
          {i.getLanguages().map(lang => (
            <button key={lang} onClick={this.changeLang.bind(this, lang)}>
              {lang}
            </button>
          ))}
        </div>
      </div>
    );
  }
}

如下图,为国际化文本正常渲染的 DOM 结构:

并无什么异样,只不过是 _i(...) 方法转换为对应语言的译文字符串。

那么在开启 React-Live 功能之后呢?(点击 Open react-live mode

react-live 模式加载了下面的脚本

if (location.search === "?react-live") {
  require("@tiny-i18n/react-live/register");
  require("@tiny-i18n/react-live/lib/style.css");
}

视图就神奇地变成了下面所示!

观察 DOM 结构可以看出来,在 “你好呀,大家” 这段国际化文本中,对应代码为:

<h1>{_i("tpl.sayhello", _i("name"))}</h1>

字典数据为

i.setDictionary(
  {
    "label.current.lang": "当前语言",
    "name": "大家",
    "tpl.sayhello": "你好呀,${1}",
    "content.text": "点击下面的链接看看有什么神奇的事情发生吧!"
  },
  "zh-CN"
);
  • 未开启 react-live 对应的 HTML:

    <h1>你好呀,大家</h1>
  • 开启后变成:

不难发现,react-live 注入了一些额外的数据,并且各字段之间也被奇怪的字符: &#8203; &zwnj; 包裹,这两个字符是特殊的不可见字符。通过这两个字符包裹,可以找到对应翻译文本在 DOM 中的位置,进而可以进行替换

但是这两个不可见字符也会带来隐藏的问题,如复制下面“你好”文本

你​‌好

看来其中的字符串长度为2,但是实际上却是2

这是因为上面的文本,实际上为 你&#8203;&zwnj;好,而中间 2 个字符不可见。

其他问题

除了上文介绍的不可见字符带来的问题以外,还有如果开启 react-live 模式后,i18n 转换方法输出的字符串将不会再是正确的转换文本;只有通过 React.createElement 方法才能被正确转换为国际化的文本。

所以 document.title = _i('...') 这样的语句会有问题;

即使是使用 react-document-title 也是会有相同的问题。因为 react-live 只会对 html tag(React.createElement 第一个参数为字符串) 中的国际化文本进行转换。