React-intl multilingual application: changing languages ​​and storing translations

I have an action-router application and would like to add i18n. In the example file, the root component enclosed in IntlProvider:

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

);

But there is only one language. How to update the application to add other languages ​​and what is the best way to store translations?

+10
reactjs internationalization formatjs react-intl
source share
2 answers

I ran into the same problem, and here is what I found out:

To change the language, I used the provided solution here , which basically associates IntlProvider with ReduxStore with the Connect function. Also, do not forget to enable the key for reprocessing components when changing the language. This is basically all the code:

This is ConnectedIntlProvider.js, just binds the standard IntlProvider (note the key pillar missing from the original github comment)

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

And then in your entry point file:

 // 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 )); 

The next thing to do is simply implement the reducer for managing languages ​​and force action creators to change languages ​​on demand.

As for the best way to store translations, I found a lot of discussion on this topic, and the situation seems rather confusing, to be honest, I'm completely confused that the creators of the interactive focus pay so much attention to date and number formats and forget about the translation. So, I I don’t know the absolutely correct way to handle this, but this is what I am doing:

Create a folder "locales" and inside create a bunch of files like "en.js", "fi.js", "ru.js", etc. Basically all the languages ​​you work with.
In each file, a json object is exported with the following translations:

 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', } } 

Other files have exactly the same structure, but with translated strings inside.
Then, in the reducer, which is responsible for changing the language, import all the states from these files and upload them to the redux repository as soon as the action for changing the language is sent. Your component created in the previous step will propagate changes to IntlProvider, and a new locale will take place. Display it on the page using <FormattedMessage> or intl.formatMessage({id: 'app.header.title'})} , read more about this in your github wiki.
They have a DefineMessages function, but to be honest, I could not find any good information on how to use it, basically you can forget about it and be fine.

+17
source share

I believe that with the new context API you no longer need to use redundancy:

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

The main component of 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; 

I created a repository that demonstrates this idea. As well as an example of code and box .

+5
source share

All Articles