提起React项目国际化,首先想到著名的 react-intl 库,这个库提供了针对组件、日期、数字、字符串等多种国际化方法。使用方法也很简单:javascript
将不一样语言的翻译文件放在各自的js文件中,同一处文本的多种语言翻译使用相同的key前端
// en_US.js
const en_US = {
"intl_hello": "Hello!",
}
export default en_US;
// zh_CN.js
const zh_CN = {
"intl_hello": "你好!",
}
export default zh_CN;
复制代码
在入口文件中配置 react-intl 库java
// index.js
import { addLocaleData, IntlProvider } from 'react-intl';
// 引入多语言环境
import en from 'react-intl/locale-data/en';
import zh from 'react-intl/locale-data/zh';
addLocaleData([...en, ...zh]);
// 引入翻译文本
import en_US from '.../intl/en_US.js';
import zh_CN from '.../intl/zh_CN.js';
const messagesMap = {
en: en_US,
zh: zh_CN
}
const locale = 'zh'; // 此处作了简化,下文将从redux中获取语言环境
render((
// 使用<IntlProvicer>包装项目组件,配置语言环境和翻译文本
<IntlProvider locale={local} messages={messages[local]}>
//···
</IntlProvider>
), document.getElementById("root"));
复制代码
使用 react-intl 中内置的组件或方法替换须要作多语言的字符串、时间等,具体可参考 API文档。react
因为项目使用redux来管理状态,将语言环境与翻译文本都放入reducer中,使用相关action来触发语言切换:git
// actions.js
export const switchLocal = local => ({
type: 'SWITCH_INTL_LOCAL',
payload: { local },
});
// reducers.js
import en_US from '.../intl/en_US.js';
import zh_CN from '.../intl/zh_CN.js';
const messagesMap = {
en: en_US,
zh: zh_CN
}
const defaultLocal = { //默认语言环境,也可从浏览器或用户配置数据中获取
local: 'zh',
messages: messagesMap.zh
};
export const intlLocal = (state=defaultLocal, action) => {
switch(action.type) {
case 'SWITCH_INTL_LOCAL':
return {
local: action.payload.local,
messages: messagesMap[action.payload.local],
}
default:
return state;
}
}
// index.js
// 略去了文件中的redux配置等代码
const { local, messages } = store.getState().intlLocal; // 从store中获取语言配置
render((
// react-redux中的Provider须要包在IntlProvider以外,IntlProvider才能访问到store
<Provider store={store}>
<IntlProvider locale={local} messages={messages}>
//···
</IntlProvider>
</Provider>
), document.getElementById("root"));
复制代码
完成以后发现初始化的时候能够访问到store,使用指定的默认语言环境,但切换语言无效,排查后发现触发action后reducer确实更改了,但没有触发组件更新。查阅相关文档后,使用react内部的key属性来强制触发更新:github
// index.js
render((
<Provider store={store}> // 加入key属性来强制触发更新 <IntlProvider key={local} locale={local} messages={messages}> //··· </IntlProvider> </Provider>
), document.getElementById("root"));
复制代码
在上一步中使用key来强制触发更新,对于通常简单的网站或前端系统来讲,到这一步就能够了。web
万恶的可是,因为接手的系统过于复杂,使用key强制触发组件更新时,会引发此<IntlProvider>
包裹下的全部组件所有被更新,致使相似于页面总体被刷新的效果,从而出现websocket重连、数据丢失等一系列问题,因为不便于动用其余模块,思考事后剩下两种方案:redux
<FormattedMessage>
组件,使用的时候又发现只能用于组件的局限性,又参考阿里的 react-intl-universal ,写了个直接由key生成翻译文本的方法。而这个方案目前还在完善和测试中。