Skip to main content

Guide react-intl : configuration de l'internationalisation React

Configurez FormatJS react-intl dans votre application React avec IntlProvider, FormattedMessage, useIntl, le format de message ICU et des traductions automatisées.

Vous utilisez plutôt react-i18next ? Consultez notre guide react-i18next

1

Installer react-intl

react-intl fait partie du projet FormatJS. Il fournit des composants et des hooks React pour formater les chaînes, les nombres, les dates et les pluriels selon la norme ICU MessageFormat.

react-intl n'a aucune dépendance d'exécution en dehors de React. Il utilise l'API Intl intégrée du navigateur pour le formatage des nombres et des dates, et embarque son propre analyseur ICU MessageFormat pour les pluriels, les select et le texte enrichi.
Terminal
npm install react-intl
2

Configurer IntlProvider

Enveloppez votre application avec IntlProvider à la racine. Transmettez la locale active et un objet messages à plat. Chaque composant peut ensuite accéder aux traductions via FormattedMessage ou useIntl.

src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { IntlProvider } from 'react-intl';
import App from './App';
import enMessages from './messages/en.json';
import deMessages from './messages/de.json';

const messages: Record<string, Record<string, string>> = {
  en: enMessages,
  de: deMessages,
};

// Detect locale from browser or your routing layer
const locale = navigator.language.split('-')[0] || 'en';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <IntlProvider locale={locale} messages={messages[locale] || messages.en}>
      <App />
    </IntlProvider>
  </React.StrictMode>
);
IntlProvider nécessite un objet messages à plat, sous forme clé-valeur (par exemple, { "app.greeting": "Hello" }). Le JSON imbriqué doit être aplati avant d'être transmis à IntlProvider, ou vous pouvez utiliser un utilitaire comme flat pour convertir les structures imbriquées.

Fichiers de messages

Créez un fichier JSON par locale. react-intl utilise nativement la syntaxe ICU MessageFormat : les pluriels, les select et les variables sont tous exprimés directement dans les chaînes de message.

messages/en.json & messages/de.json
// messages/en.json
{
  "app.greeting": "Hello, {name}!",
  "nav.home": "Home",
  "nav.about": "About",
  "nav.settings": "Settings",
  "cart.itemCount": "{count, plural, one {# item} other {# items}} in your cart"
}

// messages/de.json
{
  "app.greeting": "Hallo, {name}!",
  "nav.home": "Startseite",
  "nav.about": "Über uns",
  "nav.settings": "Einstellungen",
  "cart.itemCount": "{count, plural, one {# Artikel} other {# Artikel}} in Ihrem Warenkorb"
}
Utilisez des identifiants séparés par des points comme "nav.home" pour l'organisation. Contrairement à react-i18next, react-intl attend un objet messages à plat : ce sont les clés que vous aplatissez, pas la structure.
3

Utiliser les traductions dans les composants

react-intl vous propose deux API principales : le composant FormattedMessage pour afficher du JSX traduit, et le hook useIntl pour un accès impératif (espaces réservés, libellés aria, formatage programmatique).

Composant FormattedMessage

Utilisez FormattedMessage pour des traductions déclaratives en JSX. Transmettez l'identifiant du message et les éventuelles valeurs d'interpolation. Il affiche directement la chaîne traduite.

Greeting.tsx
import { FormattedMessage } from 'react-intl';

function Greeting({ userName }: { userName: string }) {
  return (
    <div>
      <h1>
        <FormattedMessage
          id="app.greeting"
          values={{ name: userName }}
        />
      </h1>
      <nav>
        <a href="/"><FormattedMessage id="nav.home" /></a>
        <a href="/about"><FormattedMessage id="nav.about" /></a>
      </nav>
    </div>
  );
}

Hook useIntl

Utilisez useIntl() lorsque vous avez besoin de la chaîne traduite sous forme de simple valeur : pour les espaces réservés de champs de saisie, les aria-label, document.title, ou pour transmettre des chaînes à des API non React. Il fournit également formatNumber, formatDate et formatRelativeTime.

SearchBar.tsx
import { useIntl } from 'react-intl';

function SearchBar() {
  const intl = useIntl();

  return (
    <input
      type="search"
      placeholder={intl.formatMessage({ id: 'search.placeholder' })}
      aria-label={intl.formatMessage({ id: 'search.ariaLabel' })}
    />
  );
}

// useIntl also gives you formatNumber, formatDate, formatRelativeTime:
function PriceTag({ amount, currency }: { amount: number; currency: string }) {
  const intl = useIntl();
  return (
    <span>{intl.formatNumber(amount, { style: 'currency', currency })}</span>
  );
}

Texte enrichi (HTML dans les traductions)

Intégrez du JSX dans les traductions à l'aide de balises de type XML dans vos chaînes de message. Transmettez les gestionnaires de balises via la prop values pour afficher des liens, du texte en gras ou n'importe quel composant React au sein d'un message traduit.

SignUp.tsx
import { FormattedMessage } from 'react-intl';

// Message: "By signing up, you agree to our <link>Terms</link>."
// Key: "signup.terms"
// Value: "By signing up, you agree to our <link>Terms</link>."

function SignUp() {
  return (
    <FormattedMessage
      id="signup.terms"
      values={{
        link: (chunks) => <a href="/terms" className="underline">{chunks}</a>,
      }}
    />
  );
}
FormattedMessage affiche un React Fragment par défaut. Si vous avez besoin d'un élément conteneur spécifique, transmettez la prop textComponent à IntlProvider ou enveloppez FormattedMessage dans votre propre élément.

Extraction des messages avec @formatjs/cli

FormatJS fournit un CLI pour extraire automatiquement les identifiants de message de votre code source vers un fichier JSON. Cela garantit que votre fichier de messages reste synchronisé avec vos composants, sans suivi manuel.

Terminal
# Install the CLI
npm install -g @formatjs/cli

# Extract messages from source code into a JSON file
formatjs extract 'src/**/*.tsx' --out-file messages/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'

# Or use explicit IDs (recommended):
formatjs extract 'src/**/*.tsx' --out-file messages/en.json

# Compile messages for production (optional, improves perf)
formatjs compile messages/en.json --out-file compiled/en.json
formatjs compile messages/de.json --out-file compiled/de.json
4

Pluriels et ICU select

react-intl utilise nativement ICU MessageFormat. Les pluriels, le select basé sur le genre et le formatage imbriqué sont tous exprimés directement dans les chaînes de message : aucune convention de suffixe ni de clé séparée n'est nécessaire.

ICU plural syntax by language
// ICU MessageFormat syntax — react-intl uses this natively
// English
{
  "cart.itemCount": "{count, plural, one {# item} other {# items}} in your cart",
  "inbox.unread": "You have {count, plural, =0 {no unread messages} one {# unread message} other {# unread messages}}"
}

// Arabic — 6 plural forms
{
  "cart.itemCount": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}} في سلتك"
}

// Japanese — 1 form (other)
{
  "cart.itemCount": "カートに{count}個の商品があります"
}
Ne codez jamais en dur la logique des pluriels en JavaScript. Des langues comme l'arabe ont 6 formes plurielles, le français considère 0 comme singulier, et le japonais ne fait aucune distinction de pluriel. Laissez ICU MessageFormat gérer les règles : contentez-vous de transmettre la valeur count.

ICU select pour le genre et les rôles

Utilisez la syntaxe ICU select pour les traductions dépendant du contexte, comme le genre, les rôles utilisateur ou les valeurs de statut. L'expression select choisit la bonne variante selon la valeur fournie.

ICU select syntax
// Gender-dependent messages using ICU select
{
  "user.greeting": "{gender, select, male {He} female {She} other {They}} liked your post.",
  "user.invitation": "{role, select, admin {You can manage all settings.} editor {You can edit content.} other {You can view content.}}"
}

// Usage:
<FormattedMessage
  id="user.greeting"
  values={{ gender: user.gender }}
/>

Automatiser la qualité des traductions

Détectez les clés manquantes et les espaces réservés cassés avant leur mise en production grâce à i18n-validate. Testez votre interface avec des pseudo-traductions grâce à i18n-pseudo avant l'arrivée des traductions réelles.

Pièges courants

Dépendance excessive à defaultMessage

defaultMessage est un filet de sécurité pour le développement, pas une stratégie de traduction. Si vous utilisez defaultMessage pour toutes les chaînes, le résultat de l'extraction des messages contiendra le texte anglais, mais les traducteurs risquent de manquer les nouvelles clés. Extrayez et maintenez toujours un fichier de locale source complet.

Objets imbriqués au lieu de clés à plat

IntlProvider attend un Record&lt;string, string&gt; à plat pour les messages. Si vous transmettez un JSON imbriqué comme { nav: { home: "Home" } }, react-intl ne trouvera pas la clé "nav.home". Aplatissez vos messages avant de les transmettre, ou utilisez une bibliothèque comme flat.

IntlProvider provoque des rendus inutiles

Si vous créez l'objet messages en ligne à l'intérieur de la fonction de rendu, IntlProvider reçoit une nouvelle référence d'objet à chaque rendu, ce qui provoque un nouveau rendu de tous les consommateurs. Mémoïsez messages avec useMemo ou définissez-le en dehors du composant.

IntlProvider manquant dans les tests

Les composants utilisant FormattedMessage ou useIntl lèveront une exception s'ils sont rendus sans ancêtre IntlProvider. Dans vos tests, enveloppez votre composant dans IntlProvider avec locale="en" et un objet messages vide ou minimal.

Structure de fichiers recommandée

Project Structure
my-react-app/
├── messages/
│   ├── en.json              # Source of truth (English)
│   ├── de.json              # German
│   ├── ja.json              # Japanese
│   └── es.json              # Spanish
├── compiled/                # Optional: compiled messages for prod
│   ├── en.json
│   └── ...
├── src/
│   ├── main.tsx             # App entry with IntlProvider
│   ├── App.tsx
│   └── components/
│       ├── Greeting.tsx      # Uses FormattedMessage
│       └── SearchBar.tsx     # Uses useIntl
└── package.json

Essayez i18n Agent maintenant

Déposez votre fichier de traduction ici

JSON, YAML, PO, XML, CSV, Markdown, Properties

ou cliquez pour parcourir

Langues cibles

Aucune inscription requiseEstimation instantanée

Repli de locale avec react-intl-locale-chain

Lorsqu'une clé de traduction est manquante dans une locale régionale comme pt-BR, react-intl bascule directement vers la locale par défaut au lieu de vérifier d'abord la locale parente pt.

Terminal
npm install react-intl-locale-chain
Configuration
<LocaleChainProvider
  fallbacks={{
    'pt-BR': ['pt', 'en'],
    'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
  }}
  defaultLocale="en"
>
  <App />
</LocaleChainProvider>

Consultez notre guide de repli de locale pour découvrir la liste complète des frameworks pris en charge et les 75 chaînes intégrées. Learn more →

Questions fréquentes