How To Add Multiple Language Support In ReactJS
Tags: react, javascript, webdev, tutorial
Published: 2022-10-06 05:01:09

### Introduction
In this tutorial, we will learn how to add multiple language support with `react-i18next` library in React project. 

> [react-i18next](https://react.i18next.com/) is a powerful **internationalization** framework for [React](https://reactjs.org/) / [React Native](https://reactnative.dev/) which is based on [i18next](https://www.i18next.com/).

### Table Of Content

1. [Create New Project](#create-new-project)
2. [Development](#development)
3. [Adding Translations](#adding-translations)
4. [Language Switcher](#language-switcher)
5. [Translation Optimization](#translation-optimization)
6. [Final Result](#final-result)
7. [Reference](#reference)


### Demo

![Result Demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zqix2x14l05jc4oc1z5.gif)


### Create New Project
**Step 1:** Run code below to create new React project.

```js
npx create-react-app react-lang-support
```

Once project created, check if it working by running this code

```js
cd react-lang-support
npm start
```

Project opened successfully

![IProject init](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ru9g6vxbsygbiw10yxj8.png)


**Step 2:** Install dependencies
Run code below to install two libraries ``react-i18next`` and ``i18next``

```js
npm install react-i18next i18next
```

_``react-i18next`` - is an internationalization-framework for React and React Native which is based on i18next
``i18next`` - is an internationalization-framework written in and for JavaScript_
 
### Development
**Step 1:** First we need to create new file called ``i18n.js`` in our project

![i18n File](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1z6beat45lonrbvuafii.png)

**Step 2:** Add following code inside ``i18n.js`` file

```js
import i18n from "i18next";
import { initReactI18next } from "react-i18next";

i18n
    .use(initReactI18next) // passes i18n down to react-i18next
    .init({
        // the translations
        // (tip move them in a JSON file and import them,
        // or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
        resources: {
            en: {
                translation: {
                    "Welcome to React": "Welcome to React and react-i18next"
                }
            }
        },
        lng: "en", // if you're using a language detector, do not define the lng option
        fallbackLng: "en",

        interpolation: {
            escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
        }
    });
```
Now our file look like this 

![i18n file result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gb5iuw965d8tj2ynw67m.png)

**Step 3:** Now we need to make our translation file accessible throughout our project. That's why we need to import ``i18n.js`` file inside ``index.js``

Add code below inside ``index.js``
```js
import "./i18n"
```
Check if you correctly following tutorial by looking to this screenshot below
![Check for correctness](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v24ne2erjgqyskklvgo5.png)


Inside ``i18n.js`` file, there is translation object which is consist of keys and values. From here we will use these keys inside our JSX file.

**Step 4:** Inside ``App.js`` file lets import ``useTranslation`` hook.
```js
import { useTranslation } from 'react-i18next';

function App() {
 return (
    ...
  )
}
```

_`useTranslation` - gets the `t` function and `i18n` instance inside your functional component._

**Step 5:** As it stated above we will get `t` function from `useTranslation` hook inside ``App`` component

```js
function App() {
  const { t } = useTranslation()

  return (
    ...
   )
}
```

**Step 6:** Now we can use `t` function inside our JSX. `t` function looks for key `t('key')` from ``i18n.js`` file. Our keys located inside translation object..

Overall our App.js look like this
```js
import logo from './logo.svg';
import './App.css';
import { useTranslation } from 'react-i18next';

function App() {
  const { t } = useTranslation()
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('Welcome to React')}
        </a>
      </header>
    </div>
  );
}

export default App;
```

Check what we have done until this part
```js
npm start
```
Result

![One Language Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lxmrqa2dctuuf1slbdz1.png)

As you can see, we got _"Welcome to React and react-i18next"_ text from our `i18n.js` file. It means we successfully configured `react-i18next` and now ready for adding translations.

### Adding translations
In this project, three languages will be used. They are Uzbek, Russian and English. 
**Step 1** For demonstration purposes add following translations inside `i18n` file.

```bash
resources: {
            uz: {
                translation: {
                    welcome: "Xush kelibsiz",
                    goodbye: "Xayr"
                }
            },
            ru: {
                translation: {
                    welcome: "Добро пожаловать",
                    goodbye: "До свидания"
                }
            },
            en: {
                translation: {
                    welcome: "Welcome",
                    goodbye: "Goodbye"
                }
            }

       }
```
Now our `i18n` file look like this 
```js
import i18n from "i18next";
import { initReactI18next } from "react-i18next";

i18n
    .use(initReactI18next) // passes i18n down to react-i18next
    .init({
        // the translations
        // (tip move them in a JSON file and import them,
        // or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
        resources: {
            uz: {
                translation: {
                    welcome: "Xush kelibsiz",
                    goodbye: "Xayr"
                }
            },
            ru: {
                translation: {
                    welcome: "Добро пожаловать",
                    goodbye: "До свидания"
                }
            },
            en: {
                translation: {
                    welcome: "Welcome",
                    goodbye: "Goodbye"
                }
            }

        },
        lng: "en", // if you're using a language detector, do not define the lng option
        fallbackLng: "en",

        interpolation: {
            escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
        }
    });
```

Now let see result on browser.

![Only English Translation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0p2jejnhruqpp0u9mm8.png)

As you can see it is showing words from our `i18n` file. But it is showing only English version. 

Let change to Russian language. In order to do this, let's make change key `lng` to `ru` inside `i18n` file 

```js
import i18n from "i18next";
import { initReactI18next } from "react-i18next";

i18n
    .use(initReactI18next) // passes i18n down to react-i18next
    .init({
        // the translations
        // (tip move them in a JSON file and import them,
        // or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
        resources: {
            uz: {
                translation: {
                    welcome: "Xush kelibsiz",
                    goodbye: "Xayr"
                }
            },
            ru: {
                translation: {
                    welcome: "Добро пожаловать",
                    goodbye: "До свидания"
                }
            },
            en: {
                translation: {
                    welcome: "Welcome",
                    goodbye: "Goodbye"
                }
            }

        },
        lng: "ru", // change here
        fallbackLng: "en",

        interpolation: {
            escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
        }
    });

``` 

Let see result


![Russian Translation Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3njviqovg1tbw09z72m.png)

As you can see it's showing Russian translation on screen. Wow we did it. Congratulations! So if you need Uzbek translation just change `lng` to `uz`. But question arises will be every time change language like in this hardcoded way ?   

Answer is **No**. We will implement switcher to our project.

### Language Switcher

**Step 1:** Inside `App.js` add `<select>` tag in order to give options for choosing language for user.

```js
import logo from './logo.svg';
import './App.css';
import { useTranslation } from 'react-i18next';

function App() {
  const { t } = useTranslation()
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>

        <select>
          <option>Choose language</option>
          <option value="uz">Uzbek</option>
          <option value="ru">Russian</option>
          <option value="en">English</option>
        </select>

        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('welcome')}
          <br />
          {t('goodbye')}
        </a>


      </header>
    </div>
  );
}

export default App;

```

Now user will be able to choose language from `<select>` dropdown. But it won't change language since we didn't implement function for changing language. In order to change language we will get instance of `i18n` from `useTranslation` hook.

Basic syntax of changing language using `i18n`
```bash
i18n.changeLanguage('en-US');
``` 

**Step 2:** We need to get instance of `i18n` from 'useTranslation'

```js
function App() {
  const { t, i18n } = useTranslation()
  return (
      ...   
  )
}
```

Now inside `<select>` tag add `onChange` method, this is where we get values from options provided and pass it to `i18n` to change language

```js
    <select onChange={(e) => i18n.changeLanguage(e.target.value)}>
          <option>Choose language</option>
          <option value="uz">Uzbek</option>
          <option value="ru">Russian</option>
          <option value="en">English</option>
    </select>
```

Final `App.js`
```js
import logo from './logo.svg';
import './App.css';
import { useTranslation } from 'react-i18next';

function App() {
  const { t, i18n } = useTranslation()
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>

        <select onChange={(e) => i18n.changeLanguage(e.target.value)}>
          <option>Choose language</option>
          <option value="uz">Uzbek</option>
          <option value="ru">Russian</option>
          <option value="en">English</option>
        </select>

        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('welcome')}
          <br />
          {t('goodbye')}
        </a>


      </header>
    </div>
  );
}

export default App;
```

### Result
![video1109257644](https://user-images.githubusercontent.com/41279178/194035016-ba2bdf8e-4b37-4dc1-a819-c0b6b9f88172.gif)


### Translation optimization
**Step 1**: Now, did you noticed our translations are located inside `i18n.js` file. We haven't yet started splitting translations into multiple files (which is highly recommended for larger projects) but we already see that adding more languages would result in bundling unneeded translations into the application.


In order to separate our translation we will use package namely `i18next-http-backend`, which helps us to load our translations 
asynchronously.


Install `i18next-http-backend` by running this code on terminal

```js
npm install i18next-http-backend
```

Now we need to wire up i18next-http-backend into our `i18n.js` file

```js
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import backend from "i18next-http-backend";  // <--- import here

i18n
    .use(initReactI18next) // passes i18n down to react-i18next
    .use(backend) // <--- wire up here 
    .init({
        // the translations
        // (tip move them in a JSON file and import them,
        // or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
        resources: {
            uz: {
                translation: {
                    welcome: "Xush kelibsiz",
                    goodbye: "Xayr"
                }
            },
            ru: {
                translation: {
                    welcome: "Добро пожаловать",
                    goodbye: "До свидания"
                }
            },
            en: {
                translation: {
                    welcome: "Welcome",
                    goodbye: "Goodbye"
                }
            }

        },
        lng: "en", // if you're using a language detector, do not define the lng option
        fallbackLng: "en",

        interpolation: {
            escapeValue: false // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
        }
    });
```


Once we connected `i18next-http-backend`, by default it will load translation from this path

```bash
'../public/locales/{lang}/translation.json'
```
This path considered to be the default for the `i18next-http-backend` to load from. 

**Step 2:** We need to create this path `locales/{lang}/translation.json` inside public folder.


![Locales path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zind3e6r7h82bs70m6e4.png)

Now we need to remove  this part of code from `i18n.js` file

![Removed part of code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c3jxer4zpiqf12cr41gz.png)

And add our translations inside `translation.json` file for each language.

`UZ`
![Uzbek](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5uc13benexmxry0cxpdt.png)
`RU`
![Russian](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/10qwg93vs9nec1kr6rul.png)
`EN`
![English](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ug0u0zjopisq9rqkt0lb.png)


Now check result on browser



### Final Result
![Final Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zqix2x14l05jc4oc1z5.gif)

Link to full source of tutorial [here](https://github.com/jasurkurbanov/react-lang-support)


### Reference list
[i18next](https://www.i18next.com/)
[React.i18next](https://react.i18next.com/)
[Locize](https://locize.com/blog/react-i18next/)
[Geeksforgeeks](https://www.geeksforgeeks.org/multi-language-support-in-reactjs/)
[Legacy-v9](https://react.i18next.com/legacy-v9/step-by-step-guide#2-lazy-loading-translations)