web-dev-qa-db-fra.com

React-Intl comment changer les paramètres régionaux et les messages de variable

J'essaie de comprendre comment changer de langue en utilisant React-Intl. Ceci est ma première application React et elle a été réalisée avec create-react-app, je n'utilise ni Redux ni Flux.

Dans mon index.js j'ai le code suivant:

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 envoie une chaîne sur le paramètre 'lang' par props (c'est-à-dire: 'es' ou 'en'), lorsque je change i18nConfig rien ne semble changer avec IntlProvider. Ma pensée était que changer ma i18nConfig variable alors toute mon application changerait aussi la langue.

J'ai FormattedMessages dans TodoApp et mes deux messages JSON sont remplis comme suit: 

// i18n/locales/en.json
{
  "footer.add.placeholder": "Enter a name ...",
  "footer.add.priority0.text": "No priority",
  "footer.add.priority1.text": "Priority 1",
   ...
}

Savez-vous ce qui me manque sur mon code ?? Peut-être que je n'ai pas bien compris quelque chose à propos de React-Intl. Tout conseil sera utile, merci.

5

Cela fonctionne si vous supprimez tout de la racine:

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

Mais maintenant, nous changeons le composant TodoApp comme ceci:

1) Nous ajoutons 'locale' comme état du composant et importons 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) Changer notre fonction changeLanguage (cette fois appelée 'onChangeLanguage'), cette fonction reçoit 'lang' d'un sélecteur de langue de sous-composant:

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

Et enfin rendre:

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

Si quelqu'un ne comprend pas du tout, demandez dans les commentaires! Merci à TomásEhrich

8

Avec la nouvelle API React Context , il est assez facile à faire. Créer un 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 { Provider, Consumer } = 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 (
      <Provider value={this.state}>
        <IntlProvider
          key={locale}
          locale={locale}
          messages={messages}
          defaultLocale="en"
        >
          {children}
        </IntlProvider>
      </Provider>
    );
  }
}

export { IntlProviderWrapper as IntlProvider, Consumer as IntlConsumer };

Et utilisez ensuite ce fournisseur et ce consommateur:

import { Provider } from "react-redux";
import {  IntlProvider } from "./IntlContext";

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

quelque part dans l'application:

import React from "react";
import { Text, Button } from "native-base";
import { IntlConsumer } from "../IntlContext";

const LanguageSwitch = () => (
  <IntlConsumer>
    {({ switchToEnglish, switchToDeutsch }) => (
      <React.Fragment>
        <button onClick={switchToEnglish}>
          English
        </button>
        <button onClick={switchToDeutsch}>
          Deutsch
        </button>
      </React.Fragment>
    )}
  </IntlConsumer>
);

export default LanguageSwitch;

Voici le répertoire correspondant avec une solution plus générale.

Remarque: pour le moment, react-intl utilise toujours une ancienne API de contexte mais, à l'avenir, une solution comme celle-ci pourrait fonctionner immédiatement.

5
Tomasz Mularczyk

vous pouvez utiliser redux pour gérer vos paramètres régionaux et localeMessage. ajoutez simplement une clé dans 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
carroll cai