i18next

Last updated: September 11, 2024Author: Jakub Pomykała
i18next: changing translations in realtime

In this article, you will learn how to configure i18next and i18next-http-backend library to get live-updating translations in your React application. Additionally, you will learn you how to create translation keys automatically with default translation in web translation editor.

For a step-by-step guide on how to use i18next with SimpleLocalize, check out our blog post: How to localize React app using i18next.

Install dependencies

# Using NPM
npm install --save react-i18next i18next i18next-http-backend i18next-browser-languagedetector axios

Configure i18next

Create i18n.ts file with i18next-http-backend configuration. i18next-http-backend is responsible for:

  • fetching translations from a remote server,
  • creating new keys used in your project.
import i18n from 'i18next'
import Backend from 'i18next-http-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
import {initReactI18next} from 'react-i18next'
import axios from "axios";

const isProductionCode = process.env.NODE_ENV === 'production';
const fallbackLanguage = 'en'

const projectToken = "XXXXXXXXXXXXXX"; // YOUR PROJECT TOKEN
const apiKey = "XXXXXXXXXXXXXX"; // YOUR API KEY

const apiBaseUrl = "https://api.simplelocalize.io/api";
const cdnBaseUrl = "https://cdn.simplelocalize.io";
const environment = "_latest"; // or "_production"
const loadPath = `${cdnBaseUrl}/${projectToken}/${environment}/{{lng}}`;
const loadPathWithNamespaces = `${cdnBaseUrl}/${projectToken}/${environment}/{{lng}}/{{ns}}`;
const configuration = {
    headers: {
        'X-SimpleLocalize-Token': apiKey
    }
};

const createTranslationKeys = async (requestBody) => axios.post(`${apiBaseUrl}/v1/translation-keys/bulk`, requestBody, configuration)
const updateTranslations = async (requestBody) => axios.patch(`${apiBaseUrl}/v2/translations/bulk`, requestBody, configuration)

const missing = [];
const saveMissing = async () => {
    if (missing.length === 0 || isProductionCode) {
        return;
    }
    console.info(`Saving ${missing.length} missing translation keys`);

    const translationKeys = missing.map((element) => ({
        key: element.translationKey,
        namespace: element.namespace,
    }));

    await createTranslationKeys({translationKeys})
        .catch((error) => console.error(`Error during creating translation keys: ${error}`));

    const translations = missing.map((element) => ({
        key: element.translationKey,
        namespace: element.namespace,
        language: element.language,
        text: element.fallbackValue,
    }));
    await updateTranslations({translations})
        .catch((error) => console.error(`Error during updating translations: ${error}`));
    missing.length = 0;
}

// You can control how often a missing translation keys are sent to SimpleLocalize.
// Lowering this value may lead to hitting rate-limiter, 30 seconds is a sweet spot.
const SYNC_INTERVAL = 30 * 1000; // 30 seconds
setInterval(async () => {
    await saveMissing();
}, SYNC_INTERVAL);

i18n
    .use(Backend)
    .use(LanguageDetector)
    .use(initReactI18next)
    .init({
        fallbackLng: fallbackLanguage,
        backend: {
            loadPath: loadPath, // or loadPathWithNamespaces if you use namespaces
        },
        saveMissing: !isProductionCode, // save missing keys only in development mode
        defaultNS: "", // you can set default namespace here
        missingKeyHandler: async (languages, namespace, translationKey, fallbackValue) => {
            console.debug(`[${namespace}][${translationKey}] not available in Translation Hosting`);
            missing.push({
                translationKey: translationKey,
                namespace: namespace ?? "",
                language: languages[0] ?? fallbackLanguage,
                fallbackValue: fallbackValue ?? ""
            });
        }
    })
export default i18n;

The code uses official SimpleLocalize API to create new translation keys and update translations. The missing array is used to store missing translation keys and send them to SimpleLocalize every 30 seconds.

Import configuration

Import i18n.ts file in index.ts or layout.ts by adding import './i18n';.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import './i18n';

ReactDOM.render (
  <React.StrictMode>
    <Suspense fallback={<div>Loading...</div>}>
        <App />
    </Suspense>
  </React.StrictMode>,
  document.getElementById('root')
);

Source code

i18next is now configured and ready to use in your application. You can use it in your components like this:

import React from "react";
import { useTranslation } from "react-i18next";

function App() {
  const { t, i18n } = useTranslation();

  // uncomment if you use namespaces
  // const { t, i18n } = useTranslation('MY_NAMESPACE');

  const translatedMessage = t("USE_BUTTONS_BELOW");

  return (
        <div>
          <p>
            {translatedMessage}
          </p>
          <button onClick={() => i18n.changeLanguage("en")}>English</button>
          <button onClick={() => i18n.changeLanguage("es")}>Spanish</button>
        </div>
  );
}

export default App;

You can use t function to get translation for a given translation key and switch languages with i18n.changeLanguage(language) function, where language is a language key from SimpleLocalize.

Managing translations

Now, you can use translation editor as a control panel for all texts in your application. In the translation editor, you can auto-translate strings, invite translators, and manage translations in multiple languages. When you decide to update text in you app, click 'Save & Publish' button to deliver translations via SimpleLocalize CDN.

Changing translation strings in Translation Editor

Auto-translation feature can help you to translate your app in multiple languages fast with the help of machine translation and AI.

How to start auto-translation for many languages at once

Every time you publish translations, they are automatically updated in your application in a few seconds without need to redeploy your app.

CLI integration

Having real-time translations in your application is great, but sometimes you prefer to keep them in sync with your codebase. To automate a process of importing and exporting translations, you can use SimpleLocalize CLI.

Troubleshooting

Here are the most common problems that you may encounter while using i18next with SimpleLocalize. If you have any other issues that are not listed here, please contact us at [email protected].

Forbidden error

If you get Forbidden error, please make sure that you provided a correct API Key in apiKey variable.

"Origin starts with 'https://'" error

The integration is configured to work only with http:// origins that are used in development mode by default. It's a safety mechanism to make sure that you are not pushing missing keys from the production environment, which exposes your API Key.

CORS error

If you get CORS error, please make your you don't send any custom headers in your Axios request in missingKeyHandler function. The other reason for CORS error might be triggering a rate-limiter due to many missing translation keys requests.

Please make sure that you don't have any infinite loops in your code that trigger missingKeyHandler function, which is responsible for sending missing translation keys to SimpleLocalize.

Please also make sure that you didn't deploy any other code, that sends requests to this endpoint that might trigger rate-limiter, as requests counted are counted per API Key.

i18next-http-backend load error

The error might be caused by the custom requestOptions settings in backend property. Please make sure that your configuration is the same as above.

Incorrect API Key

Incorrect API Key log in console means that your provided an incorrect API Key to your project. Here is how to get your API Key:

  1. Go to SimpleLocalize
  2. Click on your project
  3. Click on Settings tab
  4. Open on Credentials tab from the left panel
  5. Copy your API Key and use in apiKey variable.

More resources:

Was this helpful?