React-Intlを使用して言語を変更する方法を見つけようとしています。これは私の最初のReactアプリであり、create-react-appで作成されました。ReduxもFluxも使用していません。
私のindex.jsには次のコードがあります:
import React from 'react';
import ReactDOM from 'react-dom';
import TodoApp from './components/TodoApp';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
// Bootstrap CSS libraries
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/css/bootstrap-theme.css';
import { IntlProvider, addLocaleData } from 'react-intl';
import intlEN from 'react-intl/locale-data/en';
import intlES from 'react-intl/locale-data/es';
import intlMessagesES from './i18n/locales/es.json';
import intlMessagesEN from './i18n/locales/en.json';
addLocaleData([...intlEN, ...intlES]);
/* Define your translations */
let i18nConfig = {
locale: 'es',
messages: intlMessagesES
};
let changeLanguage = (lang) => {
i18nConfig = { locale: lang, messages: intlMessagesEN };
return i18nConfig;
}
ReactDOM.render(
<IntlProvider locale={ i18nConfig.locale } key={ i18nConfig.locale } messages={ i18nConfig.messages }>
<TodoApp onChangeLanguage={changeLanguage} />
</IntlProvider>,
document.getElementById('root'));
registerServiceWorker();
TodoAppは、i18nConfigを変更すると、小道具(つまり、「es」または「en」)によって「lang」パラメーターで文字列を送信しますが、IntlProviderで何も変わらないようです。私の考えは、私のi18nConfig変数を変更すると、アプリもすべて言語を変更するだろうというものでした。
TodoAppにFormattedMessagesがあり、2つのJSONメッセージは次のように入力されます。
// i18n/locales/en.json
{
"footer.add.placeholder": "Enter a name ...",
"footer.add.priority0.text": "No priority",
"footer.add.priority1.text": "Priority 1",
...
}
私のコードに何が欠けているのか知っていますか?たぶん、React-Intlについて正しいことを理解していないかもしれません。アドバイスは役に立ちます、ありがとう。
ルートからすべて削除すると機能します:
ReactDOM.render(<TodoApp />, document.getElementById('root'));
しかし、今度はTodoAppコンポーネントを次のように変更します。
1)コンポーネントの状態として「ロケール」を追加し、React-Intlをインポートします。
import { IntlProvider, addLocaleData } from 'react-intl';
import intlEN from 'react-intl/locale-data/en';
import intlES from 'react-intl/locale-data/es';
import intlMessagesES from './../i18n/locales/es.json';
import intlMessagesEN from './../i18n/locales/en.json';
addLocaleData([...intlEN, ...intlES]);
/* Define your default translations */
let i18nConfig = {
locale: 'en',
messages: intlMessagesEN
};
2)changeLanguage関数(今回は 'onChangeLanguage'と呼ばれる)を変更し、この関数はsubComponent言語セレクターから 'lang'を受け取ります。
onChangeLanguage(lang) {
switch (lang) {
case 'ES': i18nConfig.messages = intlMessagesES; break;
case 'EN': i18nConfig.messages = intlMessagesEN; break;
default: i18nConfig.messages = intlMessagesEN; break;
}
this.setState({ locale: lang });
i18nConfig.locale = lang;
}
そして最後にレンダリングします:
render() {
return (
<IntlProvider key={ i18nConfig.locale } locale={ i18nConfig.locale } messages={ i18nConfig.messages }>
<div>
<Header onChangeLanguage={this.onChangeLanguage} />
// Other components ...
</div>
</IntlProvider>
);
}
誰かがまったく理解できない場合は、コメントで尋ねてください! @TomásEhrichに感謝
新しいReact Context API を使用すると、非常に簡単です。ラッパーを作成します。
import React from "react";
import Types from "prop-types";
import { IntlProvider, addLocaleData } from "react-intl";
import en from "react-intl/locale-data/en";
import de from "react-intl/locale-data/de";
import deTranslation from "../../lang/de";
import enTranslation from "../../lang/en";
addLocaleData([...en, ...de]);
const Context = React.createContext();
class IntlProviderWrapper extends React.Component {
constructor(...args) {
super(...args);
this.switchToEnglish = () =>
this.setState({ locale: "en", messages: enTranslation });
this.switchToDeutsch = () =>
this.setState({ locale: "de", messages: deTranslation });
// pass everything in state to avoid creating object inside render method (like explained in the documentation)
this.state = {
locale: "en",
messages: enTranslation,
switchToEnglish: this.switchToEnglish,
switchToDeutsch: this.switchToDeutsch
};
}
render() {
const { children } = this.props;
const { locale, messages } = this.state;
return (
<Context.Provider value={this.state}>
<IntlProvider
key={locale}
locale={locale}
messages={messages}
defaultLocale="en"
>
{children}
</IntlProvider>
</Context.Provider>
);
}
}
export { IntlProviderWrapper, Context as IntlContext };
そして、そのプロバイダーとコンシューマーを使用します。
import { Provider } from "react-redux";
import { IntlProviderWrapper } from "./IntlContext";
class App extends Component {
render() {
return (
<Provider store={store}>
<IntlProviderWrapper>
...
</IntlProviderWrapper>
</Provider>
);
}
}
アプリのどこかで:
import React from "react";
import { Text, Button } from "native-base";
import { IntlContext } from "../IntlContext";
const LanguageSwitch = () => (
<IntlContext.Consumer>
{({ switchToEnglish, switchToDeutsch }) => (
<React.Fragment>
<button onClick={switchToEnglish}>
English
</button>
<button onClick={switchToDeutsch}>
Deutsch
</button>
</React.Fragment>
)}
</IntlContext.Consumer>
);
// with hooks
const LanguageSwitch2 = () => {
const { switchToEnglish, switchToDeutsch } = React.useContext(IntlContext);
return (
<>
<button onClick={switchToEnglish}>English</button>
<button onClick={switchToDeutsch}>Deutsch</button>
</>
);
};
export default LanguageSwitch;
CodeSandbox の例
関連する リポジトリ をより一般的なソリューションで示します。
注:現時点では、react-intlはまだ古いコンテキストAPIを使用していますが、将来このようなソリューションはすぐに動作する可能性があります。
reduxを使用して、ロケールとlocaleMessageを管理できます。 IntlProviderにキーを追加するだけです。
import React, { Component } from 'react';
import { IntlProvider } from 'react-intl';
class Inter extends Component {
render() {
let { locale, localeMessage, children } = this.props;
return (
<IntlProvider key={locale} locale={locale} messages={localeMessage}>
{children}
</IntlProvider>
)
}
};
export default Inter;