, поэтому мы наконец-то использовали react-intl
, экспортируя каждый компонент, заключенный в IntlProvider
, с любым языковым стандартом и сообщениями, которые просто необходимы. Конфигурация для IntlProvider устанавливается в состоянии компонента внутри конструктора:
this.state = {
i18nCfg: IntlUtils.init(props.language, 'SignOutMenu')
}
... и затем установить в компонентах 'render()
:
render() {
const { i18nCfg } = this.state;
return (
<IntlProvider locale={i18nCfg.language} messages={i18nCfg.messages}>
...
Локаль может быть предоставлена родительским компонентом, как указано injectIntl
HOC
<SignOutMenu language={this.props.intl.locale}/>
или обнаружен из браузера с помощью метода util getUserLanguage()
on init()
, если язык не определен.
Вы просто должны быть осторожны, чтобы предотвратить повторное появление идентификаторов сообщений в приложении, поэтому я инициализировал компонент строкой пространства имен, представляющей сообщения, относящиеся только к данному компоненту (сделано в 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) => {
// add the supported locale data
addLocaleData([...en, ...de]);
// get supported language
const lang = language && supportedLanguages.indexOf(language) > -1 ? language : IntlUtils.getUserLanguage();
// return back data for IntlProvider
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 = () => {
//if none available, take it from browser
const browserLanguage = window.navigator.userLanguage || window.navigator.language;
if (browserLanguage) {
// get the language code and store it in local prefs for nexttime
const m = browserLanguage.match(/^([a-z]+)/i);
if (m) {
return m[0];
}
}
// nothing found -> return default en
return defaultLanguage;
}
}
Чтобы иметь возможность импортировать файлы json в IntlUtil
, мне пришлось установить devDependency "babel-plugin-inline-json-import" и добавить его в файл .babelrc:
"plugins": [
["inline-json-import", {}]
]
Также я обнаружил, что использование injectIntl HOC с методом formatMessage()
не работало должным образом в том же компоненте, где IntlProvider был инициализирован, поскольку HOC использовал экземпляр IntlProvider
с сообщениями из компонента выше).
Обратите внимание, что наш механизм переключения языков включал обновление страницы, поэтому с init()
он работал как чудо. Но я не могу сказать, насколько хорошо это будет работать в случае использования контекста или редукса, когда вы переключаете язык без обновления страницы. Но мы собираемся использовать его в одном из таких приложений в ближайшее время, поэтому я могу выложить здесь обновления ...
Надеюсь, это поможет вам и другим, по крайней мере, как-то