loading...

How to translate your React.js app with i18next

ksushiva profile image Oksana Ivanchenko Updated on ・3 min read

Today, I will show you how to translate the text and date in your React.js application.

First of all, you must install some dependencies:

yarn add i18next i18next-xhr-backend i18next-browser-languagedetector react-i18next

Now we need to create a file called i18n.js in our src folder:

import i18n from 'i18next';
import Backend from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';

const fallbackLng = ['en']; 
const availableLanguages = ['en', 'ru'];

i18n
  .use(Backend) // load translation using xhr -> see /public/locales. We will add locales in the next step

  .use(LanguageDetector) // detect user language

  .use(initReactI18next) // pass the i18n instance to react-i18next.

  .init({
    fallbackLng, // if user computer language is not on the list of available languages, than we will be using the fallback language specified earlier
    debug: true,
    whitelist: availableLanguages,

    interpolation: {
      escapeValue: false
    },
  });

export default i18n;

Then we will import i18n in index.js in src/index.js:

...
import './i18n';

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

The next step is to create our locales: public/locales/en/translation.json and public/locales/ru/translation.json. This translation will be loaded automatically thanks to i18next-xhr-backend.

Also, in our App.js we need to add Suspense in oder to display a loading indicator.

import React, { Suspense } from 'react';
...
function App() {
  return (
    <div className="App">
      <Suspense fallback={(<div>Loading</div>)}>
      <WeatherForecast /> 
      </Suspense>
    </div>
  );
}
...

Now we go to the component that we want to translate. If you have a Class Component we will be using the Higher Order Component withTranslation:

import React, { Component } from 'react';
import { withTranslation } from 'react-i18next';

class News extends Component {

   render(){
     const { t } = this.props;

     return (
       <h1>{t('news.title')}</h1>
     )
   };
};

export default withTranslation()(News);

If you have a Functional Component you should use the react hook useTranslation:

import React from 'react';
import { useTranslation } from 'react-i18next';

const WeatherForecast = () => {
  const { t } = useTranslation();
  return (
    <h1>{t('weather.title')}</h1>
  )
};

export default WeatherForecast;

Now we will modify our locales. In public/locales/en/translation.json:

{
  "news": {
    "title": "Our news"
  },
  "weather": {
    "title": "Weather forecast"
  }
}

In public/locales/ru/translation.json:

{
  "news": {
    "title": "Наши новости"
  },
  "weather": {
    "title": "Прогноз погоды"
  }
}

If you want to translate a phrase with a variable in it, you need do this:

  <p>{t('weather.temprature', {number: temprature})}</p>

And in your .json locale file you need to write:

  "temprature": "Today in Lyon is cloudy: {{number}}°C."

We will the same do for our Russian or any other version.

Now I will show you how to translate a date. To do this I will be using moment.js.

yarn add moment

In my WeatherForecast.js I add:

<p>{t('weather.date', {date: Date.now()})}</p>

Now in public/locales/en/translation.json:

"weather": {
        "date": "Today's date: {{date, currentDate}}"
    },

Here in {{}} date is value, variable that we asigned in our component and currentDate is the format that we will use next.

In our i18n.js file, we must import moment.js and configure the translation for our date:

import moment from 'moment';

...

availableLanguages.forEach((element) => {
  if (element !== 'en') {
     import(`moment/locale/${element}`);
   }
}); // we are importing only the locales that we need.

.init({
    ...
    interpolation: {
      escapeValue: false, 
       format: (value, format, lng) => {
        if (format === 'currentDate') return 
           moment(value).locale(lng).format('LL');
          return value;
       },//if the format is 'currentDate', then take its __value__ transfom it to a moment object, translate it to the current language and show it in Month DD, YYYY format.    
    },
  });

It should work well. Hope this article was helpful.

Discussion

pic
Editor guide
Collapse
tonixtuft profile image
Anton Bagdatyev (Tonix-Tuft)

Thank you for your article Oksana!

How do you manage the fact that translations files may be cached by the browser and therefore if you publish an updated translation file, let's say public/locales/ru/translation.json, the browser may still continue to use an outdated cached version of public/locales/ru/translation.json.

Did you find a solution for that as well?

Collapse
superturbis profile image
Super Turbo

Hi Oksana! Great solution, thank you! I'd like to ask you about an issue I have whenever I run it...

It outputs a red screen, with white fonts and the following error:

“A React component suspended while rendering, but no fallback UI was specified. Add a component higher in the tree to provide a loading indicator or placeholder to display”

I don't understand where does it come from, since the <Suspense/> component has already been filled with the fallback:

const Loader = () => {
  return <div>loading...</div>
};
export default props => {
    return (
        <Suspense fallback={<Loader />}>
        ...
        </Suspense>
    )
}

Thank you in advance Oksana!

Collapse
gtobar profile image
Guillermo Tobar

Thanks for sharing the post, its content is very valuable.

Collapse
kilofafeure profile image
kilofafeure

Beginner web developer? I've read a lot of solutions for i18next and you have been the only one that has made my app be translated correctly, all very clear. You are agoddess!!! Thanks a lot!!!

Collapse
ksushiva profile image
Oksana Ivanchenko Author

Wow! Thanks for your comment! I’m very happy that you found this article helpful

Collapse
fkirc profile image
Felix Kirchengast

Thank you for the summary. I found that those i18n-libraries are not enough to keep translation-files in sync, which is why I wrote "attranslate" as an additional tool for file-synchronization: github.com/fkirc/attranslate you can give it a try if you are seeking a free solution

Collapse
burzumumbra profile image
Ronald Flores Sequeira

Cool, now I have something to play with on the weekend.

Collapse
etainlove profile image
RemeberIamLove

Thank you Oksana! It works like a charm!

Collapse
ahmetcetin profile image
Ahmet Cetin

The simplest just to the point explanation I've seen so far about i18next. Thx a lot for sharing this. i18next should put this article in their website as Getting Started.

Collapse
jericfarias profile image
Eric Farias

It works fine with props? I mean suppose I have a header component that receive a prop title to render some things like this.

Collapse
duongynguyen profile image
Nguyen Duong

I read and integrated follow i18next documents but my project failed. Since I read your post and follow it, I very surprise. I got it. You are my idol. Thank you so much!

Collapse
trejocode profile image
Sergio A. Trejo

Thank you, for me es better i18n than react-intl, works fine and it's super easy to config

Collapse
kanags91 profile image
Kanagaraj Palanisamy

Wonderful. Able to set up our entire app in just a week..!! Thanks a lot :)

Collapse
hd4ng profile image
Huy Dang

Thanks Oksana, nice article. Could you explain why locales should be placed in the public folder? Thanks