How do you localize React applications?
TL;DR
To localize a React application, you typically use a library like react-i18next or react-intl. First, you set up your translation files for different languages. Then, you configure the localization library in your React app. Finally, you use the provided hooks or components to display localized text in your components.
Setting up localization in React
Localization combines message lookup with locale selection, plural rules, formatting, layout direction, and server/client consistency.
Choosing a localization library
There are several libraries available for localizing React applications, including react-i18next and react-intl. The examples below use react-i18next.
Installing the library
First, install the necessary packages:
Setting up translation files
Create JSON files for each language you want to support. For example, create en.json and fr.json in a locales directory:
locales/en.json:
locales/fr.json:
Configuring the localization library
Set up i18next and react-i18next in your application. Create an i18n.js file for the configuration:
Integrating with your React application
Because initReactI18next already registers the i18n instance with React, you no longer need to wrap your tree in I18nextProvider (only use it when you want to scope a different instance to a subtree). Just import the config once at your entry and render with createRoot:
Using translations in components
Use the useTranslation hook to access the t function for translating text:
Switching languages
To switch languages, use the i18n.changeLanguage method:
Interpolation and variables
Most translations need to inject runtime values. Pass an options object as the second argument to t:
locales/en.json:
For rich text with embedded React elements (e.g. links inside a sentence), use the Trans component so translators can reorder children without breaking JSX:
Pluralization
i18next picks the correct plural form based on the active language's CLDR rules. Define keys with the _one, _other, _zero, _few, _many suffixes and pass count:
Namespaces
Splitting translations into namespaces (one JSON file per feature) keeps bundles small and avoids key collisions. Load only the namespaces a component needs:
Lazy-loading translations
Shipping every locale to every user wastes bandwidth. Use i18next-http-backend to fetch translation files on demand and i18next-browser-languagedetector to pick the user's language automatically:
With Suspense mode enabled in the same initialization call, components can render a fallback while a translation file loads:
Right-to-left (RTL) layout
For languages like Arabic or Hebrew, set the document direction when the language changes and let CSS logical properties (margin-inline-start, padding-inline-end, etc.) handle the rest:
Date, number, and currency formatting
Don't hand-format numbers or dates. Use the built-in Intl APIs, which respect the locale's conventions for separators, ordering, and currency symbols:
i18next can call these via its built-in formatter: t('updated', { date, formatParams: { date: { dateStyle: 'long' } } }).
SSR and Next.js considerations
Server rendering adds request isolation and serialization constraints to the localization setup:
- For Next.js App Router, use
next-intlori18nextwith thei18next/react-i18nextSSR setup. Initialize i18next per request so the server doesn't leak one user's language to another. - Send the active language in the initial HTML (
<html lang="...">) and serialize the loaded resources so the client can hydrate without a flash of untranslated content. - Server Components can translate after the request-specific i18n instance is initialized. Pass translated strings or other serializable data to Client Components; a
tfunction cannot cross the Server-to-Client Component boundary because functions are not serializable.
Further reading
- react-i18next documentation
- i18next documentation
- react-intl documentation
- i18next plurals
- i18next namespaces
- Suspense mode in react-i18next
- MDN: Intl.NumberFormat
- MDN: Intl.DateTimeFormat
- next-intl for Next.js App Router
- React
'use client'serialization requirements