12k
All articles

Ajouter l'internationalisation à une application React

Configurez linternationalisation dun app React avec react-i18next : interpolation, pluriels, RTL, formats locaux et SSR Next.js.

OpenReplay Team
OpenReplay Team
Ajouter l'internationalisation à une application React

Ajouter l’internationalisation à une application React consiste à externaliser chaque chaîne visible par l’utilisateur dans des fichiers par langue, puis à les restituer via une couche de traduction plutôt que de coder le texte en dur dans le JSX.

Si vous avez déjà livré un build où un t('main.header') brut s’est affiché sur l’écran d’un client, ou regardé une chaîne en allemand faire déborder un bouton qui semblait parfait en anglais, vous savez déjà que la mise en place n’est pas la partie difficile. Le câblage prend une après-midi ; les cas limites propres à chaque locale occupent le reste du sprint. La solution standard en production est react-i18next, le binding React du framework i18next. Adoptez react-i18next comme référence : il est basé sur les hooks, prend en charge les namespaces et le chargement différé, fonctionne avec le rendu côté serveur, et bénéficie du plus grand écosystème de plugins i18next. Ne vous tournez vers react-intl que si vous êtes résolument engagé dans la syntaxe des messages ICU. Ce guide couvre la configuration actuelle correcte, puis les cinq points qui posent problème en production : l’interpolation, la pluralisation, le formatage des nombres et des dates selon la locale, la mise en page de droite à gauche, et le SSR.

Points clés à retenir

  • Définissez interpolation.escapeValue: false dans votre configuration i18next, car React échappe déjà les valeurs avant le rendu ; laisser l’échappement d’i18next activé entraîne un double échappement de vos chaînes.
  • Dans les versions actuelles d’i18next, les clés de pluriel utilisent les suffixes CLDR/Intl (_zero, _one, _two, _few, _many, _other), et le suffixe historique _plural appartient à l’ancien format JSON v3 ; la variable de sélection doit impérativement s’appeler count.
  • Le formatage des nombres et des dates dépend de la région, pas seulement de la langue : qualifiez vos locales (en-US, ar-EG) et formatez via les formateurs Intl d’i18next avec {{value, number}} et {{date, datetime}}.
  • Chargez les traductions depuis des fichiers JSON avec i18next-http-backend et un loadPath ; les intégrer avec require() inclut toutes les langues dans votre bundle principal et empêche le chargement différé.
  • Sur Next.js, ne réinventez pas le SSR i18n manuellement : next-i18next v16 prend en charge à la fois l’App Router et le Pages Router en un seul package.

Comment configurer react-i18next ?

Installez le framework principal, le binding React, et deux plugins qui gèrent la détection et le chargement des fichiers. Quatre packages assurent la configuration, chacun avec un rôle bien défini :

PackageVersionRôle
i18next26.xMoteur principal : lookup, interpolation, pluriels, formatage
react-i18next17.xBinding React : useTranslation, Trans
i18next-browser-languagedetector8.xDétecte la langue de l’utilisateur
i18next-http-backend4.xCharge les fichiers JSON de traduction via HTTP

Notez un point important : i18next-http-backend v4 requiert fetch natif. Node ≥ 18, tous les navigateurs modernes, Deno et Bun embarquent fetch par défaut. Sur des environnements d’exécution plus anciens, fournissez un ponyfill ou restez sur la v3.

npm install i18next react-i18next i18next-browser-languagedetector i18next-http-backend

Créez src/i18n.ts et initialisez une seule fois :

import i18n from 'i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next';

i18n
  .use(Backend)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    fallbackLng: 'en',
    supportedLngs: ['en', 'es', 'ar'],
    load: 'languageOnly',
    backend: { loadPath: '/locales/{{lng}}/{{ns}}.json' },
    interpolation: { escapeValue: false },
  });

export default i18n;

Définissez interpolation.escapeValue: false car React échappe déjà les valeurs avant le rendu ; laisser l’échappement d’i18next activé entraîne un double échappement de vos chaînes. Le loadPath est important : intégrer les ressources avec require() (un pattern de l’ère Create React App / Webpack) inclut toutes les langues dans votre bundle principal et empêche le chargement différé. Importez la configuration une seule fois au point d’entrée, avant le rendu : import './i18n'; dans main.tsx.

Externaliser les chaînes avec le hook useTranslation

Les traductions résident dans des fichiers JSON par langue sous public/locales/<lng>/translation.json, et les composants y accèdent via la fonction t du hook useTranslation. Remplacez chaque chaîne codée en dur par un appel de clé.

{ "main": { "header": "Welcome to the app!" } }
import { useTranslation } from 'react-i18next';

export default function Header() {
  const { t } = useTranslation();
  return <h1>{t('main.header')}</h1>;
}

Les clés imbriquées (main.header) et les namespaces permettent d’organiser de grands ensembles de chaînes. Pour du contenu contenant du balisage inline ou des liens, l’appel t() simple ne convient pas au JSX. Utilisez plutôt le composant Trans, qui interpole des éléments React dans une phrase traduite tout en conservant le balisage dans votre composant, et non dans votre JSON.

<Trans i18nKey="main.docs" components={{ docsLink: <a href="https://react.i18next.com/" /> }} />

Comment changer et détecter les langues ?

Changez la langue active avec i18n.changeLanguage(lng) ; chaque composant utilisant useTranslation se re-rend automatiquement. Un sélecteur de langue se résume à des boutons ou un <select> appelant cette méthode :

const { i18n } = useTranslation();
<select
  value={i18n.resolvedLanguage}
  onChange={(e) => i18n.changeLanguage(e.target.value)}
>
  <option value="en">English</option>
  <option value="ar">العربية</option>
</select>

La détection est gérée par le plugin de détection de langue, qui consulte les sources dans un ordre fixe : la chaîne de requête (?lng=en), un cookie, localStorage, le navigator du navigateur, puis l’attribut <html lang>. Il s’arrête à la première correspondance supportée. Il met en cache la langue résolue dans localStorage, de sorte que les utilisateurs qui reviennent conservent leur choix, et un appel manuel à changeLanguage met également à jour ce cache.

Les cinq points qui posent problème

La plupart des bugs i18n se situent en dehors du chemin nominal. Voici les modes d’échec qui passent la QA locale et ne se manifestent qu’avec la locale d’un utilisateur réel.

Interpolation. Injectez des valeurs dynamiques avec la syntaxe {{var}} et passez-les en second argument : t('greeting', { name }) avec "Hello, {{name}}". L’échappement de React combiné à escapeValue: false garantit la sécurité contre les failles XSS.

Pluralisation. L’anglais nécessite deux formes de pluriel et l’arabe en nécessite six, ce qui explique précisément pourquoi vous ne devez jamais écrire if (count === 1) manuellement. Passez count à t() et laissez Intl.PluralRules sélectionner la clé. Définissez les formes avec les suffixes CLDR : _zero, _one, _two, _few, _many, _other. La variable doit impérativement s’appeler count.

{
  "messages_one": "You have one message",
  "messages_other": "You have {{count}} new messages"
}

Le suffixe _plural est un héritage du format JSON v3. i18next a harmonisé ses suffixes de pluriel pour les aligner sur ceux de l’API Intl lors de l’introduction du format JSON v4. Depuis la v24, l’API Intl est obligatoire : si votre environnement d’exécution ne dispose pas de Intl.PluralRules, vous devez le polyfiller, car le fallback vers la gestion des pluriels v3 a été supprimé et compatibilityJSON n’accepte plus 'v3'.

Formatage des nombres et des dates. Formatez avec les formateurs Intl intégrés d’i18next : {{value, number}} et {{date, datetime}}, avec des options comme {{value, number(style: percent)}}. Étant donné que le formatage dépend de la région, qualifiez vos locales (en-US, ar-EG) afin que les numéraux et l’ordre des dates restent cohérents entre les navigateurs.

Mise en page de droite à gauche. Pour les langues RTL, définissez la direction du document depuis i18n.dir() à chaque changement de langue, afin que toute la mise en page se réorganise sans CSS par composant :

useEffect(() => {
  const apply = (lng: string) => {
    document.documentElement.lang = lng;
    document.documentElement.dir = i18n.dir(lng);
  };
  i18n.on('languageChanged', apply);
  return () => i18n.off('languageChanged', apply);
}, [i18n]);

Lisez i18n.dir() à l’intérieur du gestionnaire languageChanged, et non de manière synchrone en cours de changement : après changeLanguage(), i18next.language ne reflète la nouvelle langue qu’une fois les ressources chargées.

SSR. Ne réinventez pas le SSR i18n manuellement sur Next.js. next-i18next v16 est une fine couche au-dessus d’i18next et react-i18next qui prend en charge le câblage spécifique à Next.js : le middleware, la séparation serveur/client, et l’hydratation des ressources. Il supporte l’App Router (Server Components, Client Components, middleware) et le Pages Router, avec getT() pour les Server Components et useT() pour les Client Components. Encapsulez les arbres client dans <Suspense> plutôt que de supposer que window existe. Ces défauts spécifiques aux locales — une clé brute comme main.header rendue à l’utilisateur, un rembourrage RTL qui coupe le texte, ou du texte en langue de repli qui s’infiltre dans un écran traduit — sont précisément ceux qui passent la QA sur la locale par défaut et ne se révèlent qu’en observant une session réelle dans la locale cible, ce qui justifie pleinement l’utilisation d’un outil de rejeu de session.

Passer à l’échelle avec les namespaces et l’extraction de clés

À mesure que le nombre de chaînes augmente, répartissez les traductions en namespaces et chargez-les par route avec useTranslation('dashboard'), afin que chaque page ne récupère que son propre JSON et que les bundles restent légers. Lorsque les chaînes se multiplient dans toute la base de code, faites appel à des outils automatisés : i18next-cli est l’outil en ligne de commande officiel tout-en-un qui gère l’extraction des clés, le linting du code, la synchronisation des locales et la génération de types. Un système de gestion des traductions comme Lokalise, Phrase ou Crowdin coordonne les traducteurs dès lors que la localisation réelle commence.

Vous disposez désormais d’une configuration react-i18next correcte et d’une vue d’ensemble des problématiques avancées. Câblez la configuration, externalisez vos chaînes, puis adoptez les namespaces quand les bundles grossissent et next-i18next quand vous effectuez un rendu côté serveur. Vérifiez les versions exactes des packages sur npm au moment de l’installation, car le cœur d’i18next et ses bindings sont mis à jour fréquemment.

FAQ

Quelle est la différence entre i18next et react-i18next ?

i18next est le framework principal qui gère la logique de traduction proprement dite : la recherche de clés, l'interpolation, la pluralisation et le formatage. react-i18next est le binding React qui se superpose à i18next, en fournissant des hooks comme useTranslation, le composant Trans, et le re-rendu automatique lors d'un changement de langue. Vous installez les deux : i18next effectue le travail, react-i18next le connecte à vos composants. react-i18next requiert une version paire d'i18next compatible, veillez donc à les maintenir sur des versions majeures compatibles.

Pourquoi ma clé de traduction s'affiche-t-elle en texte brut au lieu de la chaîne traduite ?

Une clé brute comme main.header rendue à l'utilisateur signifie que la recherche n'a pas abouti, presque toujours parce que le fichier JSON pour cette langue ou ce namespace n'a jamais été chargé. Causes fréquentes : un loadPath qui ne correspond pas à l'emplacement de vos fichiers, un namespace non enregistré, la configuration i18n non importée avant le rendu, ou une clé inexistante dans le fichier. Vérifiez l'onglet réseau pour détecter une requête échouée vers votre chemin de locales, et confirmez que la clé existe dans le fichier de langue approprié.

Doit-on encore utiliser le suffixe _plural pour les clés de pluriel dans i18next ?

Non. Le suffixe _plural appartient au format JSON v3 hérité. Les versions actuelles d'i18next utilisent les suffixes textuels CLDR/Intl qui correspondent à Intl.PluralRules : _zero, _one, _two, _few, _many et _other. L'anglais utilise deux formes (_one et _other) tandis que l'arabe en utilise six. La variable qui sélectionne la forme doit impérativement s'appeler count et doit être présente, car il n'existe aucun fallback si count est absent. Si Intl.PluralRules n'est pas disponible, vous devez le polyfiller : depuis la v24, il n'existe plus de fallback vers l'ancienne gestion des pluriels v3, et compatibilityJSON n'accepte plus v3.

Dois-je stocker les traductions dans des fichiers JSON ou puis-je les intégrer directement dans la configuration ?

Vous pouvez intégrer les traductions via l'option resources, mais pour toute application non triviale, vous devriez les charger depuis des fichiers JSON avec i18next-http-backend et un loadPath tel que /locales/{{lng}}/{{ns}}.json. Intégrer toutes les langues avec require() les inclut toutes dans votre bundle principal et empêche le chargement différé, ce qui fait télécharger aux utilisateurs des chaînes pour des langues qu'ils n'utilisent jamais. Le chargement par fichiers ne récupère que la langue et le namespace actifs à la demande. Notez qu'i18next-http-backend v4 requiert fetch natif, c'est-à-dire Node 18 ou une version plus récente.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.