Skip to the content.

Developer’s guide to internationalization

Step by step how to internationalize your i18n component

1. Provide t function to your component

Use useTranslation hook in functional components.

A convention: Please use the current module name as i18next namespace. E.g. component within modules/users should have useTranslation('users').

import React from 'react';
import { useTranslation } from 'react-i18next';
// import '@/config/client/i18n'; // sometimes you'll also need to import i18n config

export default function MyComponent(props) {
  const { t, i18n } = useTranslation('currentModule');

  return <div>I am a React component!</div>;
}

Don’t use class components, use hooks instead.

2. Wrap your strings for translating in the t() function

export function MyComponent() {
  const { t } = useTranslation('currentModule');

  return <div>{t('I am a React component!')}</div>;
}

3. If your strings include html, wrap them in Trans component

Note: Please provide the current namespace to Trans component by passing ns="currentModule" and t={t} in props. @TODO remove the ns part when issue in upstream gets resolved.)

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

export function MyComponent() {
  const { t } = useTranslation('currentModule');

  return (
    <>
      <div>{t('I am a text to translate!')}</div>
      <div>
        <Trans ns="currentModule" t={t}>
          I'm a text with <span>some</span> <a href="">html</a>.
        </Trans>
      </div>
    </a>
  );
}

4. Enjoy!

When you merge your pull request, we extract new strings into a file in Github action using npm run i18n:extract. We then do little re-formatting to comply with Weblate’s requirements for json using npm run i18n:fix-weblate. As a developer, you do not have to run these commands locally.

Your extracted translation files should appear in /public/locales/{locale}/{namespace}.json when you run npm run build.

Somebody still needs to translate them at Weblate. Read more about translating..

{
  "I am a text to translate!": "Já jsem text k přeložení!",
  "I am a text with <1>some</1> <2>html</2>.": "Já jsem text s <1>nějakým</1> <2>html</2>."
}

It’s also possible to translate text with variables. See below, or read a documentation of react-i18next and i18next.

More info

We’re using react-i18next library for internationalization. They have nice to read guides and documentation. The i18next documentation is useful, too.

The translations are living in /public/locales/{lng}/{namespace}.json.

As a developer we don’t need to provide translations. Our objective is to wrap the English text with t() function or <Trans> component from react-i18next. The rest relies on extraction tools and people who wish to translate Trustroots.

We use natural keys. We wrap the English text as it is. In effect, in /public/locales/eng/{namespace}.json, the keys equal their (English) values.

Namespace name is equivalent to the file name in which the translation lives.

Testing

We want to export and test the unwrapped component.

Further topics

Various namespaces in a single component

When we need to use multiple namespaces in a single component, we need to:

Translation with variables

The translated string can contain variables.

// unformatted
t('A translation string with 8 words.', { count: 6 });

// formatted
t('Translation created on .', {
  date: new Date('2018-12-25'),
});

You can see available formattings in ./config/client/i18n.js. And you can add more there.

For the translations containing html, you can use Trans component.

// ... put all the necessary imports, too
import { Trans } from 'react-i18next';


// ...

  // Trans without variables
  <Trans>This is a translated string with a <a href="">link</a> inside.</Trans>

  // Trans with variables
  const variable = 'variable value';
  ...
  <Trans variable={variable}>Translated string with a <a href="">link</a> and </Trans>

// ...

Ignoring strings

You can mark files or lines to be ignored if you are developing a feature and would like to merge to master, but not get new strings extract.

Read more.

Fixing “Failed rebase on repository” errors with Weblate

You will likely see conflicting files listed, for example:

CONFLICT (add/add): Merge conflict in public/locales/pt_BR/users.json
Auto-merging public/locales/pt_BR/users.json
CONFLICT (add/add): Merge conflict in public/locales/pt_BR/support.json
Auto-merging public/locales/pt_BR/support.json
Automatic merge failed; fix conflicts and then commit the result.

Open each “CONFLICT” file, and resolve conflicts manually on each file. Resolve favouring weblate/master branch.

After saving files, add them by:

git add public/locales/pt_BR/users.json public/locales/pt_BR/support.json

You can now continue merge with git merge --continue