From Mono to Multilingual: Supercharge Your React App with i18n
Tags: react, javascript, tutorial, webdev
Published: 2023-05-21 14:47:01

**What is i18n?**

Imagine you work as a developer at a growing startup, and your manager comes to you and says, "We are going to expand to a new country. In order to interact with local customers, you need to make changes to support their language and local requirements." This process is called internationalization, commonly referred to as i18n because there are 18 letters between "i" and "n" in "internationalization". In this post, we will focus on using the [i18next](https://react.i18next.com/) JavaScript package with React.

**i18n features**

i18n has many use cases, including:

- Language support
- Date and time format changes (e.g., DD/MM/YYYY, YYYY/MM/DD)
- User language detection
- Currency representation (placement of currency symbol with digits varies by country), and more.

**Installation**

To use i18n in React, we need to install two packages:

```js
npm i react-i18next i18next --save
```

The `i18next` package is the core package that works with all JavaScript frameworks and apps, while `react-i18next` is a plugin that makes it easy to use i18next with React.

**Make React Multilinugual - Setup**

Inside your app's src folder, create a new file called i18n.js (you can choose any name). Set up the file as follows:

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

const resources = {} // We'll fill this later

i18n.use(initReactI18next)
    .init({
      resources,
      lng: 'en', // default language option. en for english
      interpolation: {
        escapeValue: false
      }
    })

export default i18n
```

In the above code, we import the main `i18next` package and the `initReactI18next` class. Then we initialize the i18n class by passing the configuration data.

The `resources` object is where we store the translations for different languages. The `interpolation` key is used to prevent cross-site scripting attacks. The `escapeValue` is set to false because the safety check is enabled in React by default, and we don't want i18n to perform the check again as it may slow down the application.

Next, import this file into `src/index.js` as follows:

```react
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './i18n';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

Now you are ready to use it in the Components. Let's create a component called `Home.js` with the following code.

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

const Home = () => {
  const { t } = useTranslation()

  return (
    <div className='App-header'>
      <p>{t('home_text')}</p>
    </div>
  )
}

export default Home
```


Our app should look like this now. As we did not add any language resources in i18n.js. The key name will be displayed.

![Multilingual React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sv5tl98ll4ici0xy507v.png)

Let's go and update both `i18n.js` and `Home.js`

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

const resources = { // language specific data
  en: {
    translation: {
      'home_text': 'This is my home page',
      'ask user': 'How are you?'
    }
  },
  de: {
    translation: {
      'home_text': 'Dies ist meine Homepage'
    }
  }
}

i18n.use(initReactI18next)
    .init({
      resources,
      lng: 'en', // default language option. en for english
      interpolation: {
        escapeValue: false
      }
    })

```

```react
const Home = () => {
  const { t } = useTranslation()

  return (
    <div className='App-header'>
      <p>{t('home_text')}</p>
      <p>{t('ask user')}</p>
    </div>
  )
}
```

In the above code, we use the `useTranslation` hook from `react-i18next` to access the translation function `t()`. We can use `t('home_text')` to retrieve the translated text for the key `home_text`.

Now our app should look like this

![Multilingual React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oyk4uisepncqagqvvylp.png)

**Switch Language**

To switch between languages, `react-i18next` provides an i18n instance with several methods. Let's update `Home.js` to include language switching:

```react
const Home = () => {
  const { t, i18n } = useTranslation()
  const languages = {
    en: 'English',
    de: 'German'
  }

  return (
    <div className='App-header'>
      <p>{t('home_text')}</p>
      <p>{t('ask user')}</p>
      <div>
        { Object.keys(languages)
                .map((lng) => <button
                                onClick={() => i18n.changeLanguage(lng)}
                                disabled={i18n.resolvedLanguage == lng}
                                key={lng}
                              >
                                {languages[`${lng}`]}
                              </button>
                    )}
      </div>
    </div>
  )
}
```

With the above code you can switch between languages by using the provided buttons.

But there is a problem, when you switch to german instead of displaying the greeting it'll display the key name like this.

![Multilingual React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5avhtuod6snski1hckzr.png)

**Fallback Language**

To handle missing translation keys, we can specify a fallback language. Update the `i18n.init` call in `i18n.js` as follows:

```react
i18n.use(initReactI18next)
    .use(LanguageDetector)
    .init({
      resources,
      lng: 'en',
      interpolation: {
        escapeValue: false
      },
      debug: true, // Will display debug options in console
      fallbackLng: 'en' // If any key is missing, it will fallback to english
    })
```

**Language Detection**

Providing an option to switch languages is good, but we can do better.
To automatically detect the user's preferred language in the browser, we can use the `i18next-browser-languagedetector` package. Install the package and update `i18n.js` as follows:

```react
import LanguageDetector from 'i18next-browser-languagedetector';

const languageOptions = {
  order: ['navigator', 'querystring'], // Define order and way to find user preference
  lookupQuerystring: 'lng' // key name to find the preference
}

i18n.use(initReactI18next)
    .use(LanguageDetector)
    .init({
      resources,
      lng: 'en',
      interpolation: {
        escapeValue: false
      },
      detection: languageOptions,
      debug: true,
      fallbackLng: 'en'
    })
```

We need to import `LanguageDetector` from the package and pass it during i18n initialisation.
Also we need to pass options for language detection through `detection` key.

There are many other options which you can pass for language detection which you can find in the [documentation](https://github.com/i18next/i18next-browser-languageDetector)

**Conclusion**

Thank you for reading this blog post on making a React app multilingual using i18n. We covered the basics of i18n, installation, setup, language switching, fallback language, and language detection. Stay tuned for the next part where we'll explore more features provided by i18next.

If you have any corrections or questions, feel free to leave a comment. Thank you again for reading!

Thumbnail Photo by <a href="https://unsplash.com/@amadorloureiro?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Amador Loureiro</a> on <a href="https://unsplash.com/photos/BVyNlchWqzs?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>