React-Intl 如何从变量切换语言环境和消息
Posted
技术标签:
【中文标题】React-Intl 如何从变量切换语言环境和消息【英文标题】:React-Intl how to switch locale and messages from variable 【发布时间】:2017-11-21 23:11:26 【问题描述】:我正在尝试弄清楚如何使用 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 正在通过 props 发送一个关于“lang”参数的字符串(即:“es”或“en”),当我更改 i18nConfig 时,IntlProvider 似乎没有任何变化。我的想法是更改我的 i18nConfig 变量,然后我的所有应用程序也会更改语言。
我在 TodoApp 中有 FormattedMessages,我的两条 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 有一些不明白的地方。任何建议都会有所帮助,谢谢。
【问题讨论】:
这可能会有所帮助:github.com/yahoo/react-intl/issues/243#issuecomment-165924794 谢谢@Calvin,很遗憾那是给 Redux 的 :( 你往下看了吗? github.com/yahoo/react-intl/issues/243#issuecomment-216946634 使用key
属性提及。
我觉得我完全不明白...key
的IntlProvider
必须要改?如果i18nConfig.locale
变了,key
不应该也变了吗?
谢谢@TomásEhrlich !!现在它起作用了!我会用我的解决方案发布答案。
【参考方案1】:
如果您从根目录中删除所有内容,它会起作用:
ReactDOM.render(<TodoApp />, document.getElementById('root'));
但是现在我们像这样改变 TodoApp 组件:
1) 我们添加 'locale' 作为组件状态并导入 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'),该函数从子组件语言选择器接收'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>
);
如果有人完全不明白,请在 cmets 中提问!感谢@TomásEhrich
【讨论】:
就像一个魅力,但在渲染方法中的一个小修改:this.onChangeLanguage.bind(this) 我知道这个问题很老,但我遇到了同样的问题。它几乎可以工作了,调用了 onChangeLanguage 方法,但翻译没有更新。【参考方案2】:你可以使用 redux 管理你的 locale 和 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;
【讨论】:
谢谢,但不幸的是,这个问题背后的想法是不要使用 Redux。【参考方案3】:使用新的 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 ;
然后使用那个 Provider 和 Consumer:
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 上的示例
这里是相关的repository,有一个更通用的解决方案。
注意:目前 react-intl 仍在使用旧的上下文 API,但在未来这样的解决方案可能会开箱即用。
【讨论】:
嗨,@tomaszmularczyk 我尝试使用上面的代码和 repo,但是在添加switchToEnglish
一开始似乎很糟糕,阅读文档后它变得更加清晰。链接reactjs.org/docs/…
但是如何在上下文本身上附加switchToEnglish,这样就可以在useEffect中通过useContext(intlContext).switchToEnglish()来访问呢?以上是关于React-Intl 如何从变量切换语言环境和消息的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 react-intl 使用标签(链接)格式化消息?