skip to content
Nikolas Barwicki - Javascript Blog Nikolas's Blog

Internationalize React application with i18n

/ 5 min read

Internationalization (also known as i18n) allows your application to be available in different locales. The aim of internationalization is to remove the barriers to localizing or deploying an application internationally. Application’s users may speak different languages and have varying conventions for numbers, dates or strings.

In Javascript there are plenty of libraries for internationalization: i18next, node-gettext or gloablize. However, in this article we will focus on using the i18next library with React.js.

React-i18next

react-i18next is an internationalization framework that can be used with both React and React Native apps. This framework is based on i18next.

The i18next and react-i18next is the most popular duo when it comes to React localization. Here are the main advantages of this solution for your application:

  • i18next can be used in any Javascript environment with any UI framework,
  • the library was created in 2011 and is available open source,
  • there is plenty of extensions that can be used with this solution.

Setup project

In this article I’ll be using simple React project bootstrapped with Create React App (CRA) with the following command:

npx create-react-app react-i18n-project

After creating the project you can change the directory and start the server:

cd react-i18n-project
npm start

Add the dependencies

As stated previously react-i18next is based on i18next, so we will need both packages to successfully translate our app:

npm install react-i18next i18next i18next-browser-languagedetector --save

Speaking of extensions, i18next-browser-languagedetector is an i18next plugin used to detect user language in the browser. It also supports features as cookies, localStorage, query strings and more.

Getting started

Let’s start with basic config listed in i18n.js file:

import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import LanguageDetector from 'i18next-browser-languagedetector'

i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    debug: true,
    fallbackLng: 'en',
    resources: {
      en: {
        translation: {
          // here we will place our translations...
        },
      },
    },
  })

export default i18n

We should have it imported in the index.jsx file:

import React from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App'

// import i18n (needs to be bundled ;))
import './i18n'

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

Let’s quickly go through each line of the configuration file:

  • .use(LanguageDetector) - detects user language,
  • .use(initReactI18next) - passes the i18n instance to the module of react-i18next,
  • .init({... - inits i18next,
  • debug: true - helps in i18n debugging with browser’s console,
  • fallbackLng: 'en' - sets default language to English,

Create translation files

In this section we are going to learn how to translate normal text from one language to another. We need to have some place to store translated texts in all languages that we need. Let’s create directory named eg. locales and inside we should create JSON files with names corresponding to the language codes of the translations - es for Spanish, fr for French and so on.

// locales/es.json
{
    "welcome": "Angular es mi framework Javascirpt favorito",
    "article": {
        "heading": "Por qué me gusta tanto Angular",
    }
};

// locales/fr.json
{
    "welcome": "Angular est mon framework Javascirpt préféré.",
    "article": {
        "heading": "Pourquoi j'adore Angular",
    }
};

Disclaimer: I have no knowledge of Spanish and French. I used Google Translate to take these texts!

The last part of the setup is to import those JSON files to out config file:

// ...
import translation_es from './locales/es.json';
import translation_fr from './locales/fr.json';

// ...
resources: {
    es: {
        translations: translation_es
    },
    fr: {
        translations: translation_fr
    }
}

Using Trans component and useTranslation hook

Now we have the translations ready. Of course the folders structure and file names may differ in your applications. In much more complex apps it is recommended to come with better system where you can have separate translation files for different views in your app or even use lazy loading to drastically improve your application performance.

To use the translations and translate the content we can use to solutions provided by i18next-react.

Trans component

import React from 'react'
import { Trans, useTranslation } from 'react-i18next'

function MyComponent() {
  return (
    <h1>
      <Trans i18nKey="welcome">
        Angular is my favorite Javascript framework
      </Trans>
    </h1>
  )
}

Please keep in mind that according to the documentation: “s long you have no React/HTML nodes integrated into a cohesive sentence (text formatting like strong, em, link components, maybe others), you won’t need it - most of the times you will be using the good old t function”. So, here is an alternative way to translate your content.

useTranslation

import React, { Suspense } from 'react'
import { useTranslation } from 'react-i18next'

function MyComponent() {
  const { t, i18n } = useTranslation()

  return <h1>{t('welcome')}</h1>
}

How to switch languages

Let’s add s simple component with buttons that allows users to switch the language of our app.

import React, { Suspense } from 'react'
import { useTranslation } from 'react-i18next'

const languages = {
  en: { displayName: 'English' },
  es: { displayName: 'Spanish' },
}

function MyComponent() {
  const { t, i18n } = useTranslation()

  return (
    <div>
      <h1>{t('welcome')}</h1>
      <div>
        <button
          onClick={() => i18n.changeLanguage(languages.en)}
          style={{
            fontWeight:
              i18n.resolvedLanguage === languages.en ? 'bold' : 'normal',
          }}
        >
          {languages.en.displayName}
        </button>
        <button
          onClick={() => i18n.changeLanguage(languages.es)}
          style={{
            fontWeight:
              i18n.resolvedLanguage === languages.es ? 'bold' : 'normal',
          }}
        >
          {languages.es.displayName}
        </button>
      </div>
    </div>
  )
}

As you can see in the code example above useTranslation hook gives us possibility to read current active language and change the language of the whole app.

Here we have added two buttons that switch the language of the app and the font weight of the text inside of them indicates the active language.

As you may remember form the previous paragraphs we have installed i18next-browser-languagedetector and added it to our config file. i18next tries to detect the browser language and automatically use that language if the corresponding translation file is available.

Speaking of our buttons for switching languages - manually selected language is persisted in the localStorage and it will be used as preferred language even after closing the browser and opening the app the other day.

Summary

There are many other topics to cover in terms of internationalization React apps using i18next. In the next articles I’m going to explain how to handle plurals, interpolation and formatting dates. I hope that it was a great introduction to the i18n, peace 🏻.