Réponse Rapide
react-intl est la liaison React pour FormatJS, fournissant le support du format de message ICU pour l'internationalisation. Installez avec npm install react-intl, enveloppez votre application avec <IntlProvider locale="en" messages={messages}>, puis utilisez <FormattedMessage id="greeting" /> ou le hook useIntl() pour afficher les traductions. Choisissez react-intl lorsque vous avez besoin d'une conformité ICU stricte ou d'un formatage de date/nombre intégré. Pour des besoins plus simples, react-i18next peut être plus facile.
Qu'est-ce que react-intl ?
react-intl fait partie de l'écosystème FormatJS, une implémentation officielle du Format de Message ICU pour JavaScript. Il fournit :
- Format de Message ICU : Syntaxe standard de l'industrie pour les pluriels, le genre et les messages complexes
- Formateurs intégrés : Dates, nombres, devises, temps relatif
- Support TypeScript : Extraction de message et formatage type-safe
- Testé en production : Utilisé par Yahoo, Microsoft, Airbnb
react-intl vs react-i18next
| Fonctionnalité | react-intl | react-i18next |
|---|---|---|
| Format de Message | ICU (strict) | JSON (flexible) |
| Taille Bundle | ~25KB | ~15KB |
| Pluriels | Syntaxe ICU | Clés suffixées |
| Formateurs | Intégrés | Plugin/manuel |
| Courbe d'Apprentissage | Plus élevée | Plus faible |
| TypeScript | Excellent | Excellent |
Choisissez react-intl quand :
- Vous avez besoin d'une conformité ICU stricte
- Votre équipe connaît la syntaxe ICU
- Vous voulez un formatage de date/nombre intégré
- Vous intégrez avec des outils de traduction qui utilisent ICU
Choisissez react-i18next quand :
- Vous voulez une syntaxe plus simple
- Vous avez besoin d'une taille de bundle plus petite
- Votre équipe préfère les clés basées sur JSON
Installation
Terminal1npm install react-intl 2# ou 3yarn add react-intl 4# ou 5pnpm add react-intl
Outils CLI Optionnels
Terminal1# Extraire les messages du code 2npm install -D @formatjs/cli 3 4# Compiler les messages pour la production 5npm install -D @formatjs/cli
Configuration de Base
Étape 1 : Créer les Fichiers de Traduction
src/
├── lang/
│ ├── en.json
│ ├── es.json
│ └── fr.json
└── App.tsx
fr.json:
JSON1{ 2 "app.greeting": "Bienvenue sur notre application !", 3 "app.nav.home": "Accueil", 4 "app.nav.about": "À propos", 5 "app.buttons.submit": "Envoyer", 6 "app.buttons.cancel": "Annuler" 7}
Étape 2 : Configurer IntlProvider
TSX1// src/App.tsx 2import { IntlProvider } from 'react-intl'; 3import { useState } from 'react'; 4 5import enMessages from './lang/en.json'; 6import frMessages from './lang/fr.json'; 7 8const messages: Record<string, Record<string, string>> = { 9 en: enMessages, 10 fr: frMessages, 11}; 12 13function App() { 14 const [locale, setLocale] = useState('fr'); 15 16 return ( 17 <IntlProvider 18 locale={locale} 19 messages={messages[locale]} 20 defaultLocale="fr" 21 onError={(err) => { 22 if (err.code !== 'MISSING_TRANSLATION') { 23 console.error(err); 24 } 25 }} 26 > 27 <MainApp onLocaleChange={setLocale} /> 28 </IntlProvider> 29 ); 30}
Étape 3 : Utiliser FormattedMessage
TSX1import { FormattedMessage } from 'react-intl'; 2 3function Header() { 4 return ( 5 <header> 6 <h1> 7 <FormattedMessage id="app.greeting" /> 8 </h1> 9 <nav> 10 <a href="/"><FormattedMessage id="app.nav.home" /></a> 11 <a href="/about"><FormattedMessage id="app.nav.about" /></a> 12 </nav> 13 </header> 14 ); 15}
Le Hook useIntl
Pour un accès programmatique au formatage :
TSX1import { useIntl } from 'react-intl'; 2 3function Form() { 4 const intl = useIntl(); 5 6 const handleSubmit = () => { 7 const confirmMessage = intl.formatMessage({ id: 'app.confirm' }); 8 if (confirm(confirmMessage)) { 9 // Soumettre formulaire 10 } 11 }; 12 13 return ( 14 <form onSubmit={handleSubmit}> 15 <button type="submit"> 16 {intl.formatMessage({ id: 'app.buttons.submit' })} 17 </button> 18 </form> 19 ); 20}
Méthodes du Hook
| Méthode | Objectif | Exemple |
|---|---|---|
formatMessage | Traduire message | intl.formatMessage({ id: 'key' }) |
formatDate | Formater date | intl.formatDate(new Date()) |
formatTime | Formater heure | intl.formatTime(new Date()) |
formatNumber | Formater nombre | intl.formatNumber(1234.56) |
formatRelativeTime | Temps relatif | intl.formatRelativeTime(-1, 'day') |
Format de Message ICU
ICU (International Components for Unicode) est la norme de l'industrie pour les messages complexes.
Variables (Arguments)
JSON1{ 2 "greeting": "Bonjour, {name} !", 3 "cartInfo": "Vous avez {count} articles valant {total}" 4}
TSX1<FormattedMessage 2 id="greeting" 3 values={{ name: user.name }} 4/> 5 6<FormattedMessage 7 id="cartInfo" 8 values={{ count: 5, total: '99,99 €' }} 9/>
Pluralisation
ICU gère les règles plurielles complexes pour toutes les langues :
JSON{ "items": "{count, plural, =0 {Aucun article} one {# article} other {# articles}}" }
TSX1<FormattedMessage id="items" values={{ count: 0 }} /> 2// "Aucun article" 3 4<FormattedMessage id="items" values={{ count: 1 }} /> 5// "1 article" 6 7<FormattedMessage id="items" values={{ count: 5 }} /> 8// "5 articles"
Formes plurielles complexes (Russe) :
JSON{ "items": "{count, plural, one {# товар} few {# товара} many {# товаров} other {# товаров}}" }
Select (Genre, Choix)
JSON{ "pronoun": "{gender, select, male {Il a} female {Elle a} other {Ils ont}} aimé votre article" }
TSX1<FormattedMessage 2 id="pronoun" 3 values={{ gender: 'female' }} 4/> 5// "Elle a aimé votre article"
Pluriel Imbriqué + Select
JSON{ "invites": "{gender, select, male {{count, plural, one {Il a invité # personne} other {Il a invité # personnes}}} female {{count, plural, one {Elle a invité # personne} other {Elle a invité # personnes}}} other {{count, plural, one {Ils ont invité # personne} other {Ils ont invité # personnes}}}}" }
Texte Riche (Composants HTML)
JSON1{ 2 "terms": "En vous inscrivant, vous acceptez nos <link>Conditions</link>", 3 "welcome": "Bienvenue <bold>{name}</bold> sur notre plateforme !" 4}
TSX1<FormattedMessage 2 id="terms" 3 values={{ 4 link: (chunks) => <a href="/terms">{chunks}</a> 5 }} 6/> 7 8<FormattedMessage 9 id="welcome" 10 values={{ 11 name: user.name, 12 bold: (chunks) => <strong>{chunks}</strong> 13 }} 14/>
Formateurs Intégrés
Formatage de Date
TSX1import { FormattedDate } from 'react-intl'; 2 3<FormattedDate 4 value={new Date()} 5 year="numeric" 6 month="long" 7 day="2-digit" 8/> 9// "17 janvier 2026" (fr)
Formatage d'Heure
TSX1import { FormattedTime } from 'react-intl'; 2 3<FormattedTime 4 value={new Date()} 5 hour="numeric" 6 minute="numeric" 7 timeZoneName="short" 8/> 9// "14:30 EST" (fr)
Formatage de Nombre
TSX1import { FormattedNumber } from 'react-intl'; 2 3// Nombre simple 4<FormattedNumber value={1234567.89} /> 5// "1 234 567,89" (fr) 6 7// Devise 8<FormattedNumber 9 value={99.99} 10 style="currency" 11 currency="EUR" 12/> 13// "99,99 €" (fr) 14 15// Pourcentage 16<FormattedNumber value={0.25} style="percent" /> 17// "25 %"
Temps Relatif
TSX1import { FormattedRelativeTime } from 'react-intl'; 2 3<FormattedRelativeTime value={-1} unit="day" /> 4// "hier" 5 6<FormattedRelativeTime value={3} unit="hour" /> 7// "dans 3 heures"
Intégration TypeScript
Définir les Types de Message
TypeScript1// src/types/intl.d.ts 2import fr from '../lang/fr.json'; 3 4type Messages = typeof fr; 5 6declare global { 7 namespace FormatjsIntl { 8 interface Message { 9 ids: keyof Messages; 10 } 11 } 12}
Maintenant TypeScript autocomplète et valide les IDs de message :
TSX<FormattedMessage id="app.greeting" /> // ✅ Valide <FormattedMessage id="invalid.key" /> // ❌ Erreur TypeScript
defineMessages pour l'Extraction
TSX1import { defineMessages, useIntl } from 'react-intl'; 2 3const messages = defineMessages({ 4 title: { 5 id: 'app.title', 6 defaultMessage: 'My Application', 7 description: 'Main application title', 8 }, 9 greeting: { 10 id: 'app.greeting', 11 defaultMessage: 'Hello, {name}!', 12 description: 'User greeting message', 13 }, 14});
Extraction de Message
Extraire avec FormatJS CLI
Terminal# Extraire les messages des fichiers sources npx formatjs extract 'src/**/*.ts*' --out-file lang/en.json --id-interpolation-pattern '[sha512:contenthash:base64:6]'
Compiler pour la Production
Terminal# Compiler en AST pour une meilleure performance npx formatjs compile lang/en.json --out-file lang/compiled/en.json npx formatjs compile lang/fr.json --out-file lang/compiled/fr.json
Utiliser les messages compilés :
TSX1import compiledMessages from './lang/compiled/fr.json'; 2 3<IntlProvider 4 locale="fr" 5 messages={compiledMessages} 6/>
Les messages compilés sont pré-analysés, améliorant la performance d'exécution de 30-50%.
Changement de Langue
TSX1import { useState, useCallback } from 'react'; 2import { IntlProvider } from 'react-intl'; 3 4const SUPPORTED_LOCALES = ['en', 'fr'] as const; 5type Locale = typeof SUPPORTED_LOCALES[number]; 6 7function App() { 8 const [locale, setLocale] = useState<Locale>('fr'); 9 const [messages, setMessages] = useState(frMessages); 10 11 const handleLocaleChange = useCallback(async (newLocale: Locale) => { 12 // Importer dynamiquement les traductions 13 const newMessages = await import(`./lang/${newLocale}.json`); 14 setMessages(newMessages.default); 15 setLocale(newLocale); 16 17 // Persister la préférence 18 localStorage.setItem('locale', newLocale); 19 document.documentElement.lang = newLocale; 20 }, []); 21 22 // ... Rendu 23}
Rendu Côté Serveur
Intégration Next.js
TSX1// app/[locale]/layout.tsx 2import { IntlProvider } from 'react-intl'; 3 4async function loadMessages(locale: string) { 5 return (await import(`../../lang/${locale}.json`)).default; 6} 7 8export default async function LocaleLayout({ 9 children, 10 params: { locale }, 11}: { 12 children: React.ReactNode; 13 params: { locale: string }; 14}) { 15 const messages = await loadMessages(locale); 16 17 return ( 18 <IntlProvider locale={locale} messages={messages}> 19 {children} 20 </IntlProvider> 21 ); 22}
Note : Pour Next.js App Router, considérez next-intl qui fournit une meilleure intégration RSC.
Tester
Configuration de Test
TSX1// test/test-utils.tsx 2import { render } from '@testing-library/react'; 3import { IntlProvider } from 'react-intl'; 4 5const messages = { 6 'app.greeting': 'Hello, {name}!', 7}; 8 9function Wrapper({ children }: { children: React.ReactNode }) { 10 return ( 11 <IntlProvider locale="en" messages={messages}> 12 {children} 13 </IntlProvider> 14 ); 15} 16 17export function renderWithIntl(ui: React.ReactElement) { 18 return render(ui, { wrapper: Wrapper }); 19}
Meilleures Pratiques de Production
1. Convention d'ID de Message
JSON1{ 2 "namespace.componsant.element": "Valeur", 3 "auth.login.title": "Se connecter" 4}
2. Toujours Fournir des Messages par Défaut
TSX1<FormattedMessage 2 id="app.greeting" 3 defaultMessage="Welcome to our app" 4/>
3. Utiliser des Messages Compilés en Production
Les messages AST compilés sautent l'analyse d'exécution, améliorant la performance.
Intégration avec IntlPull
IntlPull fonctionne parfaitement avec react-intl et le format ICU :
Flux de Travail CLI
Terminal1# Extraire les messages 2npx formatjs extract 'src/**/*.ts*' --out-file lang/extracted.json 3 4# Télécharger sur IntlPull 5npx @intlpullhq/cli upload --file lang/extracted.json --format icu 6 7# Traduire avec IA 8npx @intlpullhq/cli translate --target fr 9 10# Télécharger les traductions 11npx @intlpullhq/cli download --output lang/ --format json
Avantages
- Support ICU : IntlPull préserve parfaitement la syntaxe ICU
- Traduction IA : GPT-4 et Claude comprennent les espaces réservés ICU
- Validation : Attrape les erreurs de syntaxe ICU avant le déploiement
Foire Aux Questions
Qu'est-ce que react-intl ?
react-intl est la liaison React pour FormatJS, fournissant l'internationalisation avec le support du Format de Message ICU. Il offre des composants comme FormattedMessage, FormattedDate et FormattedNumber, plus le hook useIntl. C'est le choix de référence pour les projets nécessitant une conformité ICU stricte.
Quelle est la différence entre react-intl et react-i18next ?
react-intl utilise le Format de Message ICU avec une syntaxe stricte pour les pluriels et sélections. react-i18next utilise des clés JSON plus simples avec des pluriels basés sur des suffixes. react-intl a des formateurs intégrés pour dates/nombres ; react-i18next nécessite des plugins. Choisissez react-intl pour la conformité ICU ; choisissez react-i18next pour une syntaxe plus simple.
Comment j'utilise FormattedMessage avec des variables ?
Utilisez la syntaxe d'accolades dans les messages ICU : "greeting": "Bonjour, {name} !". Puis passez les valeurs : <FormattedMessage id="greeting" values={{ name: 'Jean' }} />.
Comment fonctionne la pluralisation dans react-intl ?
Utilisez la syntaxe plurielle ICU : "{count, plural, one {# article} other {# articles}}". ICU supporte les catégories zero, one, two, few, many, other.
Comment formater les dates et nombres dans react-intl ?
Utilisez les composants formateurs intégrés : <FormattedDate value={date} dateStyle="long" />, <FormattedNumber value={1234.56} style="currency" currency="EUR" />. Le formatage est automatiquement conscient de la locale.
Comment j'extrais les messages du code ?
Utilisez FormatJS CLI : npx formatjs extract 'src/**/*.ts*' --out-file lang/en.json. Définissez les messages avec defineMessages() pour une meilleure extraction.
Devrais-je compiler les messages pour la production ?
Oui, compilez les messages pour 30-50% de meilleure performance. Exécutez npx formatjs compile. Les messages compilés sont des ASTs pré-analysés, sautant l'analyse d'exécution.
Résumé
react-intl fournit une internationalisation robuste avec le Format de Message ICU :
| Aspect | Détails |
|---|---|
| Installation | npm install react-intl |
| Provider | <IntlProvider locale messages> |
| Composant | <FormattedMessage id values /> |
| Hook | useIntl().formatMessage() |
| Format de Message | ICU (standard) |
| Formateurs | Date, nombre, devise intégrés |
Meilleur pour : Équipes nécessitant une conformité ICU, des formateurs intégrés, ou une intégration avec des outils TAO qui utilisent ICU.
Pour des besoins plus simples, considérez react-i18next.
Prêt à gérer les traductions react-intl ? Commencez gratuitement avec IntlPull — support ICU complet avec traduction IA.
