React-Intl how to switch locale and messages from variable

后端 未结 3 520
Happy的楠姐
Happy的楠姐 2021-02-04 06:28

I\'m trying to figure out how to change language using React-Intl. This is my first React App and it has been made with create-react-app, I\'m not using Redux nor Flux.

相关标签:
3条回答
  • 2021-02-04 07:01

    you can use redux manage your locale and localeMessage. just add a key in 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;

    0 讨论(0)
  • 2021-02-04 07:21

    With a new React Context API it is quite easy to do. Create a wrapper:

    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 };
    

    And then use that Provider and Consumer:

    import { Provider } from "react-redux";
    import {  IntlProviderWrapper } from "./IntlContext";
    
    class App extends Component {
      render() {
        return (
          <Provider store={store}>
            <IntlProviderWrapper>
              ...
            </IntlProviderWrapper>
          </Provider>
        );
      }
    }
    

    somewhere in the app:

    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;
    

    Example on CodeSandbox

    Here is the relevant repository with a more general solution.

    Note: at the moment react-intl is still using an old context API but in the future solution like this might work out-of-the-box.

    0 讨论(0)
  • 2021-02-04 07:28

    It works if you remove all from root:

    ReactDOM.render(<TodoApp />, document.getElementById('root'));
    

    But now we change TodoApp component like this:

    1) We add 'locale' as component state and import 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) Change our changeLanguage function (this time called 'onChangeLanguage'), this function receives 'lang' from a subComponent language selector:

    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;
    }
    

    And finally render:

    render() {
            return (
                <IntlProvider key={ i18nConfig.locale } locale={ i18nConfig.locale }  messages={ i18nConfig.messages }>
                    <div>
                        <Header onChangeLanguage={this.onChangeLanguage} />
                        // Other components ...
                    </div>
                </IntlProvider>
            );
        }
    

    If someone doesn't understand at all, ask in comments! Thanks to @TomásEhrich

    0 讨论(0)
提交回复
热议问题