现已升级至webpack-i18n-plugin
国际化方案react-i18n-auto文档
国际化方案——前言
国际化对于某些大型公司很常见的业务,他们基本也都有自己的一套国际化规范,但对于小公司而言可能并没有这些需求,平时也不太注重。如果有需求,通常解决的方法就是使用 react-intl
,react-i18next
等一些现有的npm包。以下是我大致了解的方案,以react-intl
为例,如下:
1. React组件引用
参考文档:react-intl 国际化 文档指引
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {IntlProvider, FormattedMessage} from 'react-intl';
...
ReactDOM.render(
<IntlProvider locale="en">
<App />
</IntlProvider>,
document.getElementById('container')
);)
复制代码
App.js
import {FormattedMessage} from 'react-intl';
...
class App extends Component {
constructor(props) {
super(props);
this.state = {
name: 'Eric',
unreadCount: 1000,
};
}
render() {
const {name, unreadCount} = this.state;
return <p>
<FormattedMessage id="welcome"
defaultMessage={
`Hello {name}, you have {unreadCount, number}
{unreadCount, plural, one {message} other {messages}}`
} values={{name: <b>{name}</b>, unreadCount}}/>
</p>
}
}
复制代码
看出来了吗?如果你没有学习过,你根本不会知道上面的属性代表着什么,这样的国际化已经变了原有的页面结构,而且每用到一处就得改动对应的代码,及其繁琐。
2.函数式调用
import React, {Component} from 'react';
import locale from './resources/locale';
import t from 'xxx';
...
class App extends Component {
render() {
return <div>
<header>{ t.i18n('我是要翻译的内容') }</header>
<div>{ t.text(locale.a.b) }</div> //这是我另一处要翻译的内容
</div>
}
}
复制代码
// resources语言包结构
const locale = {
a:{
b:'这是我另一处要翻译的内容',
c:'ccc',
d:'xxx',
...
}
...
}
复制代码
这是通过函数调用的思路来实现的,这种不会对react
的层级结构有太大影响,也相对灵活,其痛点在于语言包文件管理时命名让人很头痛,翻译字段少还好。一旦项目有几千个翻译字段,那就是地狱般的,而且很可能会遗漏和出错。
对于以上的方案,做一个国际化项目大概需要多久呢,少则半个月。
而我们的期望是一周以内,而且易维护,不出错。那么解决方案就不能单纯的靠人力了,要靠代码来自动实现。
解决方案
结合以上现有的方案,对于国际化这种重复性的工作,我们的思路是打包阶段把所有的文字提取出来,再结合翻译文件,实现国际化
自动化的大致思路就是通过代码自动实现上面的方案二,具体做法:
1. 自动提取语言包文件
2. 添加页面翻译
3. 额外的其他工作
为了实现自动化,webpack无疑是最好的入口,由于webpack的构建都是基于babel实现的,我们需要通过babel插件来实现。
babel根据AST规范将我们的js代码解析成树状结构,如同我们常见的dom树一样,用不同的标签,表示不同的语义。具体可参考@babel/typesAPI,列出了所有已实现的语法类型及其用法。
babel参考:
有了babel的认知基础之后我们就可以开始写babel插件了。它能够原子级别的控制我们的代码,实现我们想要的功能。
babel插件开发格式如下
export default function() {
return {
visitor: {
Identifier(path) { // 所有类型为Identifier的AST树,都会通过此方法进行处理
const name = path.node.name;
// reverse the name: JavaScript -> tpircSavaJ
// 编译前 var JavaScript;
// 编译后 var tpircSavaJ;
path.node.name = name .split("") .reverse() .join("");
},
StringLiteral(path) { // 处理StringLiteral(字符串)类型
let {node} = path;
...
},
},
};
}
复制代码
React国际化babel插件react-i18n-auto使用方法
使用安装
npm install react-i18n-auto --save-dev
添加babel插件配置项
{
"plugins": [
...
"react-i18n-auto"
...
]
}
复制代码
编译前效果:
export default class App extends React.Comment{
render(){
let title = '这是翻译的文字'
return <div title={title}>
<div title='这是要翻译的标题'>
我是要翻译的内容
</div>
</div>
}
}
复制代码
编译后效果:
export default class App extends React.Comment{
render(){
let title = $T('aa8ds','这是翻译的文字')
return <div title={title}>
<div title={$T('see23','这是要翻译的标题')}>
{$T('ae22s','我是要翻译的内容')}
</div>
</div>
}
}
复制代码
自动生成的语言包配置
locale.js
export let locale = {
"aa8ds":"这是翻译的文字",
"see23":"这是要翻译的标题",
"ae22s":"我是要翻译的内容",
}
复制代码
react-i18n-auto实现了对源码的无污染,开发时无感知,只影响打包后的代码,实现全部自动化。只需将locale.js翻译成对应的语言包文件,根据语言加载对应的语言包即可。对于React项目可实现快速完成国际化开发任务。
更多使用详情请参考:react-i18n-auto Github主页