12

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

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

);

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

4

2 回答 2

22

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

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

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

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 并且将发生新的语言环境。<FormattedMessage>使用or将其输出到页面intl.formatMessage({id: 'app.header.title'})}上,在他们的 github wiki 上阅读更多内容。
他们在那里有一些 DefineMessages 功能,但老实说,我找不到任何好的信息如何使用它,基本上你可以忘记它并没问题。

于 2016-11-15T06:43:26.783 回答
13

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

国际上下文.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;

我创建了一个展示这个想法的存储库。还有代码沙盒示例

于 2018-07-27T11:03:30.457 回答