Mike Giannakopoulos

From react-i18next to Transifex Native: Migration Guide

React-i18next migration to Transifex

If you have your React application already internationalized (i18n) using React-i18next, there is a big chance you’re thinking “why bother”? If it plays smooth as it is then what’s the reason to switch to something new?

First of all, when we’re talking about React applications, we probably talk about applications that are always evolving. New features are added, existing features are changing.

This means that your localization framework needs to be affordable while in maintenance mode, applying small changes, propagating throughout the codebase. From the maintenance side these are the benefits that the Transifex Native React SDK offers:

  • File management is reduced to zero, as no extra files are needed to hold translations. There’s no need for additional management to send content for translation and parse that back into your app once ready. Or adjusting your automation once a new structure is introduced in a string that needs translation. 
  • Separate code from content, source & translations, offering more flexibility to apply changes on translations and even original language copywriting without the need for your involvement for an extra deployment & release.

Going past maintenance, with Transifex Native React SDK you also get:

  • Simpler initialization, by installing the required libraries and including them in your code.
  • Universal syntax, with ICU support that is built specifically for localization needs.
  • Play well with other web and mobile apps, as with Transifex Native you can use the exact same content across applications and technologies.

And benefits of such an approach?

How to Migrate

Follows a complete guide to help you migrate your react-i18next localization to Transifex Native React SDK.

Changes on the Initialization

Both frameworks require you to initialize a global object that will serve as a “gateway” between your application and the ability to localize it. In react-i18next this looks something like this:

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

const resources = {
  en: {
    translation: {
  	'Hello world': 'Hello world',
    },
  },
  el: {
    translation: {
  	'Hello world': 'Καλημέρα κόσμε',
    },
  },
};

i18n
  .use(initReactI18next)
  .init({
    resources,
    lng: 'en',
    interpolation: { escapeValue: false },
  });

This snippet doesn’t tell the whole story. The translated content (the ‘resources’ field) can originate from a variety of sources and can also be added after the initialization. Also the ‘init’ method accepts many more arguments and allows you to customize the experience to a great extent.

When migrating to Transifex Native, you lose some of this flexibility, given that the source of truth for your content is always the content on the Transifex Native Content Delivery Service, and in return, you end up with the simpler:

import { tx } from '@transifex/native';

tx.init({
  token: '...',
});

There are other initialization options in Transifex Native that allow you to:

  1. Limit the content you will receive from Transifex with the ‘filterTags’ field
  2. What to do when a translation is missing with the ‘missingPolicy’ field
  3. What to do when the translation cannot be rendered (because, for example, the translator made a formatting mistake) with the ‘errorPolicy’ field

Preparing the Code

For minimal inconvenience, you should replace the invocation of react-i18next’s ‘t’ function with Transifex Native’s ‘t’ function.

From:

import { useTranslation } from 'react-i18next';

function Paragraph() {
  const { t } = useTranslation();
  return <p>{t('Some text')}</p>;
}

to

import { useT } from '@transifex/react';

function Paragraph() {
  const t = useT();
  return <p>{t('Some text')}</p>;
}

However, it may be preferable to use the T-component:

import { T} from '@transifex/react';

function Paragraph() {
  return <p><T _str="Some text" /></p>;
}

Simple variable interpolation is done with single curly brackets instead of double.

From:

import { useTranslation } from 'react-i18next';

function Paragraph() {
  const { t } = useTranslation();
  return <p>{t('Hello {{username}}', { username: 'Bob' })}</p>;
}

to:

import { T } from '@transifex/react';

function Paragraph() {
  return <p><T _str="Hello {username}" username="Bob" /></p>;
}


For formatted content, your best bet is to replace ‘<Trans>’ with <UT />’.

From:

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

function Paragraph() {
  const { t } = useTranslation();
  return (
    <Trans t={t}>
  	<p>Some <strong>bold</strong> text</p>
    </Trans>
  );
}

To:

import { UT } from '@transifex/react';

function Paragraph() {
  return <UT _str="<p>Some <strong>bold</strong> text</p>" />;
}

Migrating the Translated Content

First, you need to upload your current translations to transifex.com on a file-based project. After creating the file-based project, you can use the transifex-client to help with uploading the resources (one namespace per resource):

# Install the client
wget https://github.com/transifex/cli/releases/download/v0.3.0/tx-linux-amd64.tar.gz
tar xf tx-linux-amd64.tar.gz tx
rm tx-linux-amd64.tar.gz
mv tx ~/bin

# Set up the mapping to transifex.com
tx init
tx add \
  --organization=... \
  --project=... \
  --resource=translations \
  --file-filter=locales/translations/<lang>.json \
  --type=KEYVALUEJSON \
  locales/translations/en.json
tx add \
  --organization=... \
  --project=... \
  --resource=helpdesk \
  --file-filter=locales/helpdesk/<lang>.json \
  --type=KEYVALUEJSON \
  locales/helpdesk/en.json

# Push the content to transifex
tx push --source --translation --all


Next, you need to
create a Native project. Make sure you keep the public and secret tokens for later.

Before pushing the content to the new project, you need to:

  1. Add the target languages to the new project
  2. Add both projects to the same Translation Memory Group(TM Group). A TM Group is sharing translation knowledge between projects and can automatically fill-up translations found on similar strings across projects.

Now in your local project, use the extraction cli to push content to the native project in transifex.com (use tags for namespacing, see here):

npm install --save-dev @transifex/cli
npx txjs-cli push --token=... --secret=... src

Because we put both projects in the same TM group, existing translations will be used to fill up the new ones.

In case you had to make minor changes to some of the strings while migrating the code, take a look in the editor to fill these in. Even if they were not filled up automatically, partial TM matches are displayed as suggestions in the Transifex editor and will make this job easy.

Finally, make sure you initialize the ‘tx’ object when your application boots up and you should be good to go!

Once everything is up and running, you can delete the old file-based project and keep your new Transifex Native React project.

Now your application is fully migrated. You can proceed with all upcoming developments using Transifex Native!

React localization

Wanna share a quick React localization guide with one of your fellow developers? You can download the PDF here!

Further reading: 

Want to learn more about Transifex?

Give Transifex a try with our free 15 day trial, or connect with one of our team members for a personal demo.

Subscribe to
Becoming Global

Get localization news and best practices delivered to your inbox each month.