React-intl 多语言应用程序:更改语言和翻译存储

Posted

技术标签:

【中文标题】React-intl 多语言应用程序:更改语言和翻译存储【英文标题】:React-intl multi language app: changing languages and translations storage 【发布时间】:2016-06-17 01:03:09 【问题描述】:

我有 react-router 应用程序并想添加 i18n。在 react-intl example 根组件中包裹在 IntlProvider 中:

ReactDOM.render(
<IntlProvider locale="en">
    <App />
</IntlProvider>,
document.getElementById('container')

);

但是只有一种语言环境。如何更新应用程序以添加其他语言以及存储翻译的最佳方式是什么?

【问题讨论】:

【参考方案1】:

我遇到了同样的问题,这就是我发现的:

为了更改语言,我使用了here 提供的解决方案,它基本上是通过 Connect 函数将 IntlProvider 绑定到 ReduxStore。另外不要忘记在语言更改时包含重新渲染组件的键。这基本上是所有代码:

这是ConnectedIntlProvider.js,只是绑定了默认的IntlProvider(注意github原始评论中缺少的key prop)

import  connect  from 'react-redux';
import  IntlProvider  from 'react-intl';

// This function will map the current redux state to the props for the component that it is "connected" to.
// When the state of the redux store changes, this function will be called, if the props that come out of
// this function are different, then the component that is wrapped is re-rendered.
function mapStateToProps(state) 
  const  lang, messages  = state.locales;
  return  locale: lang, key: lang, messages ;


export default connect(mapStateToProps)(IntlProvider);

然后在你的入口点文件中:

// index.js (your top-level file)

import ConnectedIntlProvider from 'ConnectedIntlProvider';

const store = applyMiddleware(thunkMiddleware)(createStore)(reducers);

ReactDOM.render((
  <Provider store=store>
    <ConnectedIntlProvider>
      <Router history=createHistory()>routes</Router>
    </ConnectedIntlProvider>
  </Provider>
), document.getElementById( APP_DOM_CONTAINER ));

接下来要做的就是实现 reducer 来管理语言环境,并让动作创建者按需更改语言。

至于存储翻译的最佳方式 - 我发现很多关于这个主题的讨论和情况似乎很混乱,老实说,我很困惑 react-intl 的制造商如此关注日期和数字格式而忘记了翻译.所以,我不知道绝对正确的处理方法,但这就是我所做的:

创建文件夹“locales”并在其中创建一堆文件,如“en.js”、“fi.js”、“ru.js”等。基本上所有您使用的语言。 在每个文件中导出 json 对象,翻译如下:

export const ENGLISH_STATE = 
  lang: 'en',
  messages: 
      'app.header.title': 'Awesome site',
      'app.header.subtitle': 'check it out',
      'app.header.about': 'About',
      'app.header.services': 'services',
      'app.header.shipping': 'Shipping & Payment',
  

其他文件具有完全相同的结构,但内部包含已翻译的字符串。 然后在负责语言更改的 reducer 中,从这些文件中导入所有状态,并在调度更改语言的操作后立即将它们加载到 redux 存储中。您在上一步中创建的组件会将更改传播到 IntlProvider 并且将发生新的语言环境。使用 &lt;FormattedMessage&gt;intl.formatMessage(id: 'app.header.title') 在页面上输出它,在他们的 github wiki 上阅读更多信息。 他们那里有一些DefineMessages功能,但老实说我找不到任何好的信息如何使用它,基本上你可以忘记它并没问题。

【讨论】:

它与 redux 完美配合。我用阿波罗尝试了这种方法,但它不起作用。我很绝望。【参考方案2】:

有了新的 Context API,我相信现在不需要使用 redux:

IntlContext.jsx

import React from "react";
import  IntlProvider, addLocaleData  from "react-intl";
import en from "react-intl/locale-data/en";
import de from "react-intl/locale-data/de";

const deTranslation =  
  //... 
;
const enTranslation =  
  //... 
;

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 ;

App.jsx组件:

import  Provider  from "react-redux";
import   IntlProviderWrapper  from "./IntlContext";

class App extends Component 
  render() 
    return (
      <Provider store=store>
        <IntlProviderWrapper>
          ...
        </IntlProviderWrapper>
      </Provider>
    );
  

LanguageSwitch.jsx

import React from "react";
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;

我创建了一个 repository 来展示这个想法。 还有codesandbox example。

【讨论】:

效果很好。我只是好奇是否可以用 useContext 来代替。所以你可以使用上下文(IntlContext)并将switchToEnglish等附加到上下文? @Dac0d3r 当然,只需要导出整个上下文,检查编辑并链接到代码框。 非常感谢。看起来很棒,正是我需要的!!这值得 imo。成为公认的答案。 :-) Tomasz 我确实在这里创建了一个相关问题:***.com/questions/55541089/… 所以我可以删除它,或者您可以简单地链接到您的答案,我会接受它 - 由您决定 :-) @Dac0d3r 很高兴它有帮助!

以上是关于React-intl 多语言应用程序:更改语言和翻译存储的主要内容,如果未能解决你的问题,请参考以下文章

多语言反应webapp的最佳方法

多语言 wpf 应用程序

多语言 button

NSIS多语言

Magento 多语言 - 语言的双重变化导致 404(或如何在商店而不是视图中更改语言)

c# 多语言设置