How to translate your React app with react-i18next

Joachim Grill

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 my-app
cd my-app
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
npm install --save react-i18next

Add internationalization

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

ReactDOM.render(
    <App/>,
    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 {I18nextProvider} from 'react-i18next';
import i18next from 'i18next';

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

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

In the next step we have to wrap the components with the translate() function, which automatically adds the t() function to the properties of a component. We can pass a default namespace to translate(), in our example we're setting it to common. If you omit the namespace parameter you have to specify the namespace each time a translation key is used, or you have to define a default namespace in the i18next.init() options. Add the following code to the App.js file:

    import { translate, Trans } from 'react-i18next';

    // ... definition of App class ...

    export default translate('common')(App);   // instead of "export default App;"

Now we have to find all language-specific string in our app. In the simple application generated by create-react-app there are two such strings in App.js:

    <h1 className="App-title">Welcome to React</h1>
    ...
    To get started, edit <code>src/App.js</code> and save to reload.

Replace these strings as shown below:

            ...
            <h1 className="App-title">
                { this.props.t('welcome.title', { framework: "react-i18next" }) }
            </h1>
            ...
            <Trans i18nKey='welcome.intro'>
                To get started, edit <code>src/App.js</code> and save to reload.
            </Trans>
            ...

If you refresh your browser window the title changes from "Welcome to React" to "welcome.intro", as we haven't defined a translation for this ID yet. The Trans component displays its unchanged content if no translation is found.

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}}",
        "intro": "To get started, edit <1><0></0></1> and save to reload."
    }
}

src/translations/de/common.json:

{
    "welcome": {
        "title": "Willkommen bei {{framework}}",
        "intro": "Zum Loslegen editiere <1><0></0></1>. Beim Speichern wird die App im Browser automatisch neu geladen."
    }
}

Now we can 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
            },
        },
    });

With this initialization the translations can be accessed using keys like common:welcome.title. If you pass default namespace to the translate() function or specify defaultNS in the init options, the common: prefix may be omitted.

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:

    render()
    {
        const { t, i18n } = this.props;
        return (
            <div>
                ...
                <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

In the next screen click Scan and select the src/translations directory. BabelEdit searches the directory for translations and asks you to confirm the languages. Click Ok if you are happy with the selection.

Adding translations to your i18next project

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

Adding translations to your i18next project

Did you like the tutorial? Please share!