How to properly internationalize a React application using i18next

This page summarizes the projects mentioned and recommended in the original post on dev.to

Our great sponsors
  • SurveyJS - Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App
  • WorkOS - The modern identity platform for B2B SaaS
  • InfluxDB - Power Real-Time Data Analytics at Scale
  • i18next-browser-languageDetector

    language detector used in browser environment for i18next

  • import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import Backend from 'i18next-http-backend'; import { DateTime } from 'luxon'; i18n // i18next-http-backend // loads translations from your server // https://github.com/i18next/i18next-http-backend .use(Backend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(LanguageDetector) // pass the i18n instance to react-i18next. .use(initReactI18next) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', interpolation: { escapeValue: false, // not needed for react as it escapes by default format: (value, format, lng) => { if (value instanceof Date) { return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime[format]) } return value; } }, resources: { en: { translation: { description: { part1: 'Edit <1>src/App.js and save to reload.', part2: 'Learn React' }, counter: 'Changed language just once', counter_plural: 'Changed language already {{count}} times', footer: { date: 'Today is {{date, DATE_HUGE}}', date_morning: 'Good morning! Today is {{date, DATE_HUGE}} | Have a nice day!', date_afternoon: 'Good afternoon! It\'s {{date, DATE_HUGE}}', date_evening: 'Good evening! Today was the {{date, DATE_HUGE}}' } } }, de: { translation: { description: { part1: 'Ändere <1>src/App.js und speichere um neu zu laden.', part2: 'Lerne React' }, counter: 'Die Sprache wurde erst ein mal gewechselt', counter_plural: 'Die Sprache wurde {{count}} mal gewechselt', footer: { date: 'Heute ist {{date, DATE_HUGE}}', date_morning: 'Guten Morgen! Heute ist {{date, DATE_HUGE}} | Wünsche einen schönen Tag!', date_afternoon: 'Guten Tag! Es ist {{date, DATE_HUGE}}', date_evening: 'Guten Abend! Heute war {{date, DATE_HUGE}}' } } } } }); export default i18n;

  • i18next-http-backend

    i18next-http-backend is a backend layer for i18next using in Node.js, in the browser and for Deno.

  • import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import Backend from 'i18next-http-backend'; import { DateTime } from 'luxon'; i18n // i18next-http-backend // loads translations from your server // https://github.com/i18next/i18next-http-backend .use(Backend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(LanguageDetector) // pass the i18n instance to react-i18next. .use(initReactI18next) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', interpolation: { escapeValue: false, // not needed for react as it escapes by default format: (value, format, lng) => { if (value instanceof Date) { return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime[format]) } return value; } }, resources: { en: { translation: { description: { part1: 'Edit <1>src/App.js and save to reload.', part2: 'Learn React' }, counter: 'Changed language just once', counter_plural: 'Changed language already {{count}} times', footer: { date: 'Today is {{date, DATE_HUGE}}', date_morning: 'Good morning! Today is {{date, DATE_HUGE}} | Have a nice day!', date_afternoon: 'Good afternoon! It\'s {{date, DATE_HUGE}}', date_evening: 'Good evening! Today was the {{date, DATE_HUGE}}' } } }, de: { translation: { description: { part1: 'Ändere <1>src/App.js und speichere um neu zu laden.', part2: 'Lerne React' }, counter: 'Die Sprache wurde erst ein mal gewechselt', counter_plural: 'Die Sprache wurde {{count}} mal gewechselt', footer: { date: 'Heute ist {{date, DATE_HUGE}}', date_morning: 'Guten Morgen! Heute ist {{date, DATE_HUGE}} | Wünsche einen schönen Tag!', date_afternoon: 'Guten Tag! Es ist {{date, DATE_HUGE}}', date_evening: 'Guten Abend! Heute war {{date, DATE_HUGE}}' } } } } }); export default i18n;

  • SurveyJS

    Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App. With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.

    SurveyJS logo
  • react-tutorial

  • Now your app looks still the same, but your translations are separated. If you want to support a new language, you just create a new folder and a new translation json file. This gives you the possibility to send the translations to some translators. Or if you're working with a translation management system you can just synchronize the files with a cli.

  • i18next-locize-backend

    A simple i18next backend for locize.com which can be used in Node.js, in the browser and for Deno.

  • import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import Backend from 'i18next-locize-backend'; import LastUsed from 'locize-lastused'; import { locizePlugin } from 'locize'; import { DateTime } from 'luxon'; const isProduction = process.env.NODE_ENV === 'production'; const locizeOptions = { projectId: process.env.REACT_APP_LOCIZE_PROJECTID, apiKey: process.env.REACT_APP_LOCIZE_APIKEY, // YOU should not expose your apps API key to production!!! referenceLng: process.env.REACT_APP_LOCIZE_REFLNG, version: process.env.REACT_APP_LOCIZE_VERSION }; if (!isProduction) { // locize-lastused // sets a timestamp of last access on every translation segment on locize // -> safely remove the ones not being touched for weeks/months // https://github.com/locize/locize-lastused i18n.use(LastUsed); } i18n // locize-editor // InContext Editor of locize .use(locizePlugin) // i18next-locize-backend // loads translations from your project, saves new keys to it (saveMissing: true) // https://github.com/locize/i18next-locize-backend .use(Backend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(LanguageDetector) // pass the i18n instance to react-i18next. .use(initReactI18next) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', interpolation: { escapeValue: false, // not needed for react as it escapes by default format: (value, format, lng) => { if (value instanceof Date) { return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime[format]) } return value; } }, backend: locizeOptions, locizeLastUsed: locizeOptions, saveMissing: !isProduction // you should not use saveMissing in production }); export default i18n;

  • locize-lastused

    Using API lastUsed using in node.js, in the browser and for deno.

  • import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import Backend from 'i18next-locize-backend'; import LastUsed from 'locize-lastused'; import { locizePlugin } from 'locize'; import { DateTime } from 'luxon'; const isProduction = process.env.NODE_ENV === 'production'; const locizeOptions = { projectId: process.env.REACT_APP_LOCIZE_PROJECTID, apiKey: process.env.REACT_APP_LOCIZE_APIKEY, // YOU should not expose your apps API key to production!!! referenceLng: process.env.REACT_APP_LOCIZE_REFLNG, version: process.env.REACT_APP_LOCIZE_VERSION }; if (!isProduction) { // locize-lastused // sets a timestamp of last access on every translation segment on locize // -> safely remove the ones not being touched for weeks/months // https://github.com/locize/locize-lastused i18n.use(LastUsed); } i18n // locize-editor // InContext Editor of locize .use(locizePlugin) // i18next-locize-backend // loads translations from your project, saves new keys to it (saveMissing: true) // https://github.com/locize/i18next-locize-backend .use(Backend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(LanguageDetector) // pass the i18n instance to react-i18next. .use(initReactI18next) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', interpolation: { escapeValue: false, // not needed for react as it escapes by default format: (value, format, lng) => { if (value instanceof Date) { return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime[format]) } return value; } }, backend: locizeOptions, locizeLastUsed: locizeOptions, saveMissing: !isProduction // you should not use saveMissing in production }); export default i18n;

  • locize

    locize InContextEditor postMessage API

  • import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import Backend from 'i18next-locize-backend'; import LastUsed from 'locize-lastused'; import { locizePlugin } from 'locize'; import { DateTime } from 'luxon'; const isProduction = process.env.NODE_ENV === 'production'; const locizeOptions = { projectId: process.env.REACT_APP_LOCIZE_PROJECTID, apiKey: process.env.REACT_APP_LOCIZE_APIKEY, // YOU should not expose your apps API key to production!!! referenceLng: process.env.REACT_APP_LOCIZE_REFLNG, version: process.env.REACT_APP_LOCIZE_VERSION }; if (!isProduction) { // locize-lastused // sets a timestamp of last access on every translation segment on locize // -> safely remove the ones not being touched for weeks/months // https://github.com/locize/locize-lastused i18n.use(LastUsed); } i18n // locize-editor // InContext Editor of locize .use(locizePlugin) // i18next-locize-backend // loads translations from your project, saves new keys to it (saveMissing: true) // https://github.com/locize/i18next-locize-backend .use(Backend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(LanguageDetector) // pass the i18n instance to react-i18next. .use(initReactI18next) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', interpolation: { escapeValue: false, // not needed for react as it escapes by default format: (value, format, lng) => { if (value instanceof Date) { return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime[format]) } return value; } }, backend: locizeOptions, locizeLastUsed: locizeOptions, saveMissing: !isProduction // you should not use saveMissing in production }); export default i18n;

  • locize-cli

    locize cli to import / export locales, add / edit / remove, sync segments

  • First in locize, create a dedicated version for production. Do not enable auto publish for that version but publish manually or via API or via CLI. Lastly, enable Cache-Control max-age​ for that production version.

  • WorkOS

    The modern identity platform for B2B SaaS. The APIs are flexible and easy-to-use, supporting authentication, user identity, and complex enterprise features like SSO and SCIM provisioning.

    WorkOS logo
  • i18next

    i18next: learn once - translate everywhere

  • import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; import LanguageDetector from 'i18next-browser-languagedetector'; import Backend from 'i18next-http-backend'; import { DateTime } from 'luxon'; i18n // i18next-http-backend // loads translations from your server // https://github.com/i18next/i18next-http-backend .use(Backend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector .use(LanguageDetector) // pass the i18n instance to react-i18next. .use(initReactI18next) // init i18next // for all options read: https://www.i18next.com/overview/configuration-options .init({ debug: true, fallbackLng: 'en', interpolation: { escapeValue: false, // not needed for react as it escapes by default format: (value, format, lng) => { if (value instanceof Date) { return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime[format]) } return value; } }, resources: { en: { translation: { description: { part1: 'Edit <1>src/App.js and save to reload.', part2: 'Learn React' }, counter: 'Changed language just once', counter_plural: 'Changed language already {{count}} times', footer: { date: 'Today is {{date, DATE_HUGE}}', date_morning: 'Good morning! Today is {{date, DATE_HUGE}} | Have a nice day!', date_afternoon: 'Good afternoon! It\'s {{date, DATE_HUGE}}', date_evening: 'Good evening! Today was the {{date, DATE_HUGE}}' } } }, de: { translation: { description: { part1: 'Ändere <1>src/App.js und speichere um neu zu laden.', part2: 'Lerne React' }, counter: 'Die Sprache wurde erst ein mal gewechselt', counter_plural: 'Die Sprache wurde {{count}} mal gewechselt', footer: { date: 'Heute ist {{date, DATE_HUGE}}', date_morning: 'Guten Morgen! Heute ist {{date, DATE_HUGE}} | Wünsche einen schönen Tag!', date_afternoon: 'Guten Tag! Es ist {{date, DATE_HUGE}}', date_evening: 'Guten Abend! Heute war {{date, DATE_HUGE}}' } } } } }); export default i18n;

  • React

    The library for web and native user interfaces.

  • import logo from './logo.svg'; import './App.css'; import { useTranslation, Trans } from 'react-i18next'; import { useState, Suspense, useEffect } from 'react'; import Footer from './Footer' function App() { const { t, i18n } = useTranslation(); const [count, setCounter] = useState(0); const [lngs, setLngs] = useState({ en: { nativeName: 'English' }}); useEffect(() => { i18n.services.backendConnector.backend.getLanguages((err, ret) => { if (err) return // TODO: handle err... setLngs(ret); }); }, []); return (

    logo
    {Object.keys(lngs).map((lng) => ( { i18n.changeLanguage(lng); setCounter(count + 1); }}> {lngs[lng].nativeName} ))}

    {t('counter', { count })}

    Edit src/App.js and save to reload.

    {t('description.part2')}
    ); } // here app catches the suspense from page in case translations are not yet loaded export default function WrappedApp() { return ( ); }

  • react-i18next

    Internationalization for react done right. Using the i18next i18n ecosystem.

  • Make sure you have Node.js and npm installed. It's best, if you have some experience with simple HTML, JavaScript and basic React.js, before jumping to react-i18next.

  • Luxon

    ⏱ A library for working with dates and times in JS

  • Now, let’s check out how we can use different date formats with the help of i18next and Luxon to handle date and time.

  • create-react-app

    Set up a modern web app by running one command.

  • Take your own React project or create a new one, i.e. with create-react-app.

NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts