所以我们最终采用了react-intl
,将每个组件包装在所需的区域设置和消息内部的IntlProvider
中进行导出。IntlProvider的配置在组件的构造函数中通过state进行设置:
this.state = {
i18nCfg: IntlUtils.init(props.language, 'SignOutMenu')
}
然后在组件的 render()
中设置:
render() {
const { i18nCfg } = this.state;
return (
<IntlProvider locale={i18nCfg.language} messages={i18nCfg.messages}>
...
组件的地区设置可以由父组件通过injectIntl
高阶组件进行提供。
<SignOutMenu language={this.props.intl.locale}/>
如果没有定义语言,可以通过一个工具方法getUserLanguage()
在init()
中从浏览器检测到。
您只需要注意防止应用程序中出现消息id的重复出现,因此我使用一个命名空间字符串来初始化组件,该字符串表示仅与给定组件相关的消息(在getMessages()
中完成):
import {addLocaleData} from 'react-intl';
import en from 'react-intl/locale-data/en';
import de from 'react-intl/locale-data/de';
import messagesEn from '../locales/lang/i18n_en.json';
import messagesDe from '../locales/lang/i18n_de.json';
const defaultLanguage = 'en';
const supportedLanguages = ['en', 'de'];
export default class IntlUtils {
static init = (language, namespace) => {
addLocaleData([...en, ...de]);
const lang = language && supportedLanguages.indexOf(language) > -1 ? language : IntlUtils.getUserLanguage();
return {
language: lang,
messages: IntlUtils.getMessages(lang, namespace)
}
}
static getMessages = (language, namespace) => {
let langMsgs;
switch (language) {
case 'de': langMsgs = messagesDe; break;
case 'en':
default: langMsgs = messagesEn;
}
if (langMsgs) {
const matchNS = namespace + ".";
const filtered = {};
for (var key in langMsgs) {
if (key.startsWith(matchNS)) {
filtered[key] = langMsgs[key];
}
}
return filtered;
}
}
static getUserLanguage = () => {
const browserLanguage = window.navigator.userLanguage || window.navigator.language;
if (browserLanguage) {
const m = browserLanguage.match(/^([a-z]+)/i);
if (m) {
return m[0];
}
}
return defaultLanguage;
}
}
要能在
IntlUtil
中导入JSON文件,我必须安装
babel-plugin-inline-json-import的开发依赖,并将其添加到.babelrc文件中。
"plugins": [
["inline-json-import", {}]
]
我发现在与IntlProvider初始化的同一组件中使用带有方法formatMessage()的injectIntl HOC无法正常工作(因为HOC使用了来自上方组件的messages实例)。
请注意,我们的语言切换机制涉及页面刷新,所以它与init()一样完美。但是,在没有页面刷新的情况下使用上下文或redux进行语言切换时,我无法确定它会起多大作用。不过,我们很快就会在一个这样的应用程序中使用它,所以我可能会在这里发布更新......
希望这至少对您和其他人有所帮助。