How to translate your React app with react-i18next

2018-04-13 Joachim Grill, Andreas Löw Get Sourcecode from GitHub

Setup your first React app

We're setting up a small React application to learn how localization works. Of course, you can skip this section if you want to use your own application for that.

If you haven't already installed the create-react-app scripts, install them using npm:

npm install -g create-react-app

With the following lines you create an empty react app and start it:

npx create-react-app react-i18next-translation-demo
cd react-i18next-translation-demo
npm start

The last line automatically opens the URL http://localhost:3000 and dislays the welcome message rendered by the created app.

As we want to use react-i18next to localize our application, add it to you project:

npm install --save i18next react-i18next

Add internationalization

The file src/index.js renders the App react element into your DOM:

ReactDOM.render(
    <React.StrictMode>
        <App/>
    </React.StrictMode>,
    document.getElementById('root')
);

To make the i18next configuration available in all our components we have to wrap the App component with I18nextProvider. It expects an i18next instance which must be initialized before:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {I18nextProvider} from "react-i18next";
import i18next from "i18next";

i18next.init({
    interpolation: { escapeValue: false },  // React already does escaping
});

ReactDOM.render(
    <React.StrictMode>
        <I18nextProvider i18n={i18next}>
            <App/>
        </I18nextProvider>
    </React.StrictMode>,
    document.getElementById('root')
);

serviceWorker.unregister();

Simple translations

Let's now create a simple component containing a translatable text. Name the component HeaderComponent. In order to use translations you have to call useTranslation() which returns the translation function t(), and the i18n object. Wrap all text you want to translate with the function - e.g. t('your.translation.id')

You can also pass a context (a.k.a. namespace) name to useTranslation() to organize your messages. Use useTranslation('main') to specify a single context, or useTranslation(['main','common']) if you want to use translations from multiple contexts.

Apply these changes to your App.js file:

import React, {Suspense} from 'react';
import './App.css';
import {useTranslation} from "react-i18next";

function HeaderComponent()
{
    const {t, i18n} = useTranslation('common');
    return <h1>{t('welcome.title')}</h1>
}

function App()
{
    return (
        <Suspense fallback="loading">
            <div className="App">
                <HeaderComponent/>
            </div>
        </Suspense>
    );
}

export default App;

Some more work is required if you want to use High-Order-Components (HOC). The t() function is available through the props. But you also have to wrap your component with withTranslation() to get access to the translation methods:

class HighOrderComponent extends Component {
    render() {
        const { t } = this.props;

        return (
            <h1>{t('welcome.title')}</h1>
        )
    }
}
const HighOrderComponentTranslated = withTranslation('common')(HighOrderComponent)

Adding parameters

The t() function also accepts a 2nd parameter: A javascript object with parameters that i18next uses to replace parts of the translation strings.

<h1>{t('welcome.title', {framework:'React'})}</h1>

Translation IDs vs Translation strings

The t() function does not really care what you use as translation string.

You'll see many examples where developers use the translation messages. E.g. t('Welcome to React'). We do not recommend using this. Especially when you are using our translation editor called BabelEdit.

For short texts like 'Welcome to React' it seems to be ok — but you'll also have longer texts which become harder and harder to handle.

Use meaningful identifiers instead. You can even use . to display them as a tree later. E.g.

This translates into a clean hierarchy:

This gives the translator a quite good idea where a text is used.

It also has another important advantage: Say you use the translation text Welcome to React and you decide that this text has to get an exclamation mark at the end for the English version Welcome to React!. This breaks all other translation files! The reference Welcome to React is not found anymore! Using IDs helps you keep the translation files consistent and well-structured!

Translate your application

The translations of our custom text messsages will be stored for each language in a separate directory. For each namespace we create a separate .json file. Let's create JSON files for English and German translations:

src/translations/en/common.json:

{
    "welcome": {
        "title": "Welcome to {{framework}}"
    }
}

src/translations/de/common.json:

{
    "welcome": {
        "title": "Willkommen bei {{framework}}"
    }
}

You now have to load these JSON files and add them to the options passed to i18next.init().

We are adding the translations at compile time to keep things simple for this tutorial. Translations can also be loaded at runtime, of course.

Update src/index.js with the following code:

    import common_de from "./translations/de/common.json";
    import common_en from "./translations/en/common.json";

    i18next.init({
        interpolation: { escapeValue: false },  // React already does escaping
        lng: 'en',                              // language to use
        resources: {
            en: {
                common: common_en               // 'common' is our custom namespace
            },
            de: {
                common: common_de
            },
        },
    });

Changing languages

To automatically select a language you might want to use one of the language detector plugins listed on this page. For our demo app we just add two buttons and trigger the language change manually. Add the following lines to the render() function in App.js:

function HeaderComponent()
{
    const [t, i18n] = useTranslation('common');
    return <div>
        <h1>{t('welcome.title', {framework:'React'})}</h1>
        <button onClick={() => i18n.changeLanguage('de')}>de</button>
        <button onClick={() => i18n.changeLanguage('en')}>en</button>
    </div>
}

Maintain translation files

Yes — editing and keeping track of JSON files is a pain. Especially if you have multiple languages to work with.

It's also quite painful to work with translators — most of them don't really like to work with JSON files some of them even don't accept JSON files at all.

This is why we've created a specialized editor to help you with this: BabelEdit.

To get started with BabelEdit download it from here: Download BabelEdit

Click the i18next button to create a react-i18next project:

Create a new i18next project

Drop the project's root directory onto the Configure languages dialog. BabelEdit should automatically find your translation files, and detect the languages. You can adjust the settings manually:

Adding translations to your i18next project

If the selected file locations are wrong go deeper into your project tree and directly drop the src/translations folder onto BabelEdit.

Finally, select your primary language:

Set your primary language in your i18next project

After opening the project you should see a screen with your translations:

BabelEdit with i18next

BabelEdit supports many nice features among others:

Press Save after editing your translations. BabelEdit asks you where to save the translation project file (.babel). This file stores the configuration and features like the approved flags and translator comments.

Translations are always saved to the .JSON files directly.

Did you like the tutorial? Please share!

Source code available for download

The source code is available on GitHub. Clone it using git:

git clone https://github.com/CodeAndWeb/how-to-translate-your-react-app-with-react-i18next.git

or download one of the archives:

how-to-translate-your-react-app-with-react-i18next.zip how-to-translate-your-react-app-with-react-i18next.tar.gz