i18n Internationalization & Pluralization

react-i18next is a powerful internationalization framework for React / React Native which is based on i18next. It is a library to manage internationalization and pluralization support for your React application. This involves multi-language support for both the static text but also things like variable numbers, words, or names that change with the application state.

Usage

The setup and translations are in the locales/ folder. You can add more language to subfolder de, en, fr, and so on.

i18n.ts is the setup file. It initiates i18next with the translations. We also include a helper function here to help use your translations with intellisense support in your project, rather than having to rely on a something.otherthing.title kind of string-based format which is error-prone and not refactorable. It maps your JSON translation file to JavaScript objects so that you can call them like, surprise, regular objects.

🧙Tips: Check the example application of this boilerplate to see how you can separate your translations into logical groups and make everything intellisense-supported 💪

Using translations with hooks

Let's say your translation JSON is this:

{
  "HomePage": {
    "Features": {
      "someItem": "Some text in English"
    }
  }
}

Now you can get the someItem translation very easily and safely with intellisense support.

import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { translations } from 'locales/translations';

export function MyComponent() {
  const { t, i18n } = useTranslation();
  const changLanguageButtonClicked = evt => {
    const language = event.target.value;
    i18n.changeLanguage(language);
  };
  // The nested objects are intellisense supported ✅
  return <div>{t(translations.HomePage.Features.someItem)}</div>;
}

Check the react-i18next docs for other usage types. Its very flexible and well-featured.

Extracting JSON Files

You don't have to add or delete each entry in translation.json manually. Using i18next-scanner its fairly straight-forward to extract all the translations into JSON files. It scans your code and whenever it sees something like t('a.b.c') it adds {a: {b : { c: ""}}} into the JSON files.

Simply, run this script

yarn run extract-messages

WARNING: The rest below only applies if you want to use translations object and want to extract messages later on. If you are going with the default t('a.b') approach or if you don't want to extract messages you don't need the messages.ts below

However, there is a catch here. As mentioned above, we provide helper object for translations so that they are type-safe and intellisense-supported. This ruins the scanning ability of i18next-scanner. In order to overcome this, we need to define our translated messages in a file

messages.ts

import { translations } from 'locales/translations';
import { _t } from 'utils/messages';

export const messages = {
  someItem: () => _t(translations.HomePage.Features.someItem, 'default value'),
  // ...
};

then we use messages in our react component

import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { messages } from './messages';

export function MyComponent() {
  const { t } = useTranslation();
  return <div>{t(...messages.someItem()}</div>;
}

The reason behind this is, we have to convert this

t(translations.Homepage.Features.someItem)

to

t('Homeage.Features.someItem')

before i18next-scanner parses the file. To do that there is custom function running before the parsing happens. This function looks at _t(...)'s and converts them to strings. Then, scanner carries out its duty...

The example application includes this usage and you can take a look at there for a working example.

Last updated