Creating Multilingual React Apps with i18n: A Step-by-Step Guide to Internationalisation
Tags: react, i18n, beginners, tutorial
Published: 2023-04-11 10:42:59

With over 20 languages having more than 80 million speakers, if you are building software or a website for the global market and want it to be widely accepted, giving the users an opportunity to use the product in their native language would definitely lead to a better user experience. I18next is an internationalisation framework that can help with internationalising/localising your app. 

#### What is internationalisation?

Internationalisation is a way of preparing and writing your apps so that they can be adapted to support certain local languages, cultures and regions. It enables localisation which is the adaptation of a product, application or document content to meet the language, cultural and other requirements of a specific target market (a locale). (https://www.w3.org/International/questions/qa-i18n)

In this article, we will go over how to perform internationalisation in our react app using the i18next framework.
I18next is an internationalisation framework written in JavaScript. It comes with everything you need to localise your web, desktop or mobile product such as user language detection, loading and caching translations, and  file conversion etc More features can be found in their documentation. (https://www.i18next.com/)

Now let us proceed to use i18n in our react application.

#### Step1 - Initialise the Project

First let us create our React project using Vite. Open your terminal and run the following command to create a new react project using Vite.

```
yarn create vite my-i18n-app --template react
```

Change your current directory to that of the new project using

```
cd my-i18n-app
```

Proceed to open the newly created project in any code editor of your choice.

#### Step2 - Install dependencies

Add i18next to the project using the command below

```
yarn add i18next react-i18next

```
Start the react project to make sure that everything is working fine

```
yarn run dev

```

![Initial app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5v9gnb81casb1jy2wfq1.png)
You should have the above when you navigate to your projects url.

#### Step3 - Change App content
Lets go ahead and replace the entire app.jsx with the following code:

```
import './App.css'

function App() {
  return (
    <div className="App">
      <h1>Welcome to my i18n project</h1>
      <h1>How is your day going?</h1>
      
    </div>
  )
}

export default App
```

Now our project should look like this:


![Initial project look](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tnf9d5deo1qjenq9bl6p.png)

#### Step4 - Add Translations
In order to maintain organisation in our code, let’s create translation files for each language in a translation folder. Our project will now have the following structure:

![Folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ed3xtsgca45585pdujg2.png)

Now, add language jsons to the translation files.
For English.json:

```
{
    "line1":"Welcome to my i18n project",
    "line2":"How is your day going?"
}

```
For Italian.json:

```
{
    "line1":"Benvenuti nel mio progetto i18n",
    "line2":"Come sta andando la tua giornata?"
}
```

#### Step4 - Add i18next

Now let’s import i18next into our project and configure it.
In the root of the project, create an i18next.jsx file and write the following code:

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

//Import all translation files
import English from "./Translation/English.json";
import Italian from "./Translation/Italian.json";

const resources = {
    en: {
        translation: English,
    },
    it: {
        translation: Italian,
    },
}

i18next.use(initReactI18next)
.init({
  resources,
  lng:"en", //default language
});

export default i18next;
```

In the code above, we are setting up and initialising i18n in our project. We provide the sources of the translations and also set english as the default language. Note that the ISO 639–1 standard language codes should be used when identifying/choosing languages.


Next, we import this i18n.jsx file inside our main.jsx file to connect it with our react app, It should look like this now: 

```
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'

import './i18n'

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

```

#### Step5 - Create context for languages
Next step is to create a language context that we will use to provide our i18n functionality all through our app.

Create a new folder and a languageContext.jsx file in it, put the following code in the file:


```
import React, {
  createContext,
  useContext,
} from "react";
import { useTranslation } from "react-i18next";


export const LanguageContext = createContext(undefined);

export const LanguageContextProvider = ({ children }) => {
  const languages = {
    en: { nativeName: "English" },
    It: { nativeName: “Italian” },
  };
  const { t, i18n } = useTranslation();

  const onClickLanguageChange = (e) => {
    const language = e.target.value;
    i18n.changeLanguage(language); //change the language
  };

  return (
    <LanguageContext.Provider
      value={{ t, i18n, onClickLanguageChange, languages }}
    >
      {children}
    </LanguageContext.Provider>
  );
};

export const useLanguageContext = () => useContext(LanguageContext);

```

Let’s go through the code above

```
import React, {
  createContext,
  useContext,
} from "react";
import { useTranslation } from "react-i18next";
```
Here we import the necessary dependencies, createContext and useContext are used for context while the useTranslation is a hook from react-18next which provides us with the t function used to translate text in our app and the i8n instance that will be used to change language.

```
export const LanguageContext = createContext(undefined);

```
This line creates the language context

```
const languages = {
    en: { nativeName: "English" },
    It: { nativeName: “Italian” },
  };
```
Here we are creating a languages object containing our supported languages, it will be used in our languageSelect component.

```
const { t, i18n } = useTranslation();

```
Extracting t function and i18n instance with object destructuring

```
const onClickLanguageChange = (e) => {
    const language = e.target.value;
    i18n.changeLanguage(language); //change the language
  };
```
We create an Event handler to change the current language. 

```
return (
    <LanguageContext.Provider
      value={{ t, i18n, onClickLanguageChange, languages }}
    >
      {children}
    </LanguageContext.Provider>)
```
Returning the language context provider and passing the necessary values

Now, go ahead and wrap the entire app with the language context provider in main.jsx

```
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
import { LanguageContextProvider } from "./context/LanguageContext";

import "./i18n";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <LanguageContextProvider>
      <App />
    </LanguageContextProvider>
  </React.StrictMode>
);
```

Let’s check that this is working by using it in the app.jsx file

```
import "./App.css";

import { useLanguageContext } from "./context/LanguageContext";
function App() {
  const { t } = useLanguageContext();
  return (
    <div className="App">
      <h1>{t("line1")}</h1>
      <h1>{t("line2")}</h1>
    </div>
  );
}

export default App;
```

If you followed all the steps, there should be no change in the UI and this means that everything is working perfectly.

Finally, let us create a LanguageSelect component that we can use to switch between languages.

Create a LanguageSelect.jsx file and add the following code to it.

```
import { useLanguageContext } from "./context/LanguageContext";
const LanguageSelect = () => {
  const { languages, onClickLanguageChange } = useLanguageContext();
  return (
    <select
      style={{
        width: 200,
        position: "absolute",
        top: 10,
        left: 10,
        height: "40px",
      }}
      onChange={onClickLanguageChange}
    >
      {Object.keys(languages).map((lng) => (
        <option key={languages[lng].nativeName} value={lng}>
          {languages[lng].nativeName}
        </option>
      ))}
    </select>
  );
};

export default LanguageSelect;
```

In the code above we are getting the languages from the language context and mapping over them to create a select component that will trigger the onClickLanguageChange when its current value is changed.

Go ahead and include the LanguageSelect component in our main.js file so it’s available throughout our app

```
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
import { LanguageContextProvider } from "./context/LanguageContext";

import "./i18n";
import LanguageSelect from "./LanguageSelect";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <LanguageContextProvider>
      <LanguageSelect/>
      <App />
    </LanguageContextProvider>
  </React.StrictMode>
);
```

Now our project should look like this

![Final Application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ekw8k1m4tth8eki2i33j.gif)

There you have it! You have successfully added internationalisation (i18n) functionality to your React app using i18next. Your app is now able to display text in different languages based on the user's preference.

By following the steps outlined in this tutorial, you have learned how to:

1. Install and configure i18next in a React app
2. Create translation files for multiple languages
3. Use the useTranslation hook to translate text in your app
4. Create a language context to provide i18n functionality throughout your app
5. Use the LanguageContextProvider to wrap your app with the language context
6. Create a LanguageSelect component to allow users to switch between languages

Remember that i18n is an ongoing process, and there may be more text that needs to be translated as your app grows. With i18next, you can easily add new translations and update existing ones as needed.

Thanks for following along, and happy internationalisation!