frontend / javascript
Intl : internationalisation native
Explication
Ce que vous allez apprendre
- Formater un nombre et une date selon les conventions d'une locale avec
Intl.NumberFormat/Intl.DateTimeFormat - Expliquer pourquoi un formatage manuel par manipulation de chaînes est fragile à l'international
- Générer un texte relatif naturel ("il y a 3 jours") avec
Intl.RelativeTimeFormat - Gérer l'accord grammatical au pluriel selon la langue avec
Intl.PluralRules - Trier des chaînes de caractères en respectant les conventions linguistiques avec
Intl.Collator
Dans quel contexte ?
Une application e-commerce affiche "1234.5 €" à ses clients français au lieu de "1 234,50 €", et son tri alphabétique des noms de produits place systématiquement "Éclair" après "Zèbre" à cause de l'accent, perturbant les utilisateurs qui cherchent leurs produits. Ces deux problèmes viennent du même réflexe évitable : formater et trier "à la main" au lieu d'utiliser Intl.NumberFormat("fr-FR") et Intl.Collator("fr"), qui encapsulent déjà correctement ces conventions culturelles et linguistiques.
1. Rien ne s'écrit pareil partout
Un nombre, une date ou une liste ne s'écrivent pas de la même façon partout dans le monde : la virgule décimale française devient un point en anglais américain, l'ordre jour/mois/année s'inverse selon les régions.
Prérequis
Aucune connaissance préalable spécifique n'est nécessaire, mais avoir déjà manipulé des dates JavaScript natives (Date) aide à comprendre les exemples de formatage de dates de cette leçon.
2. Pourquoi le formatage manuel ne suffit pas
Formater ces valeurs "à la main" avec des manipulations de chaînes est fragile et rapidement incorrect dès qu'une application vise plusieurs pays.
3. Intl encapsule ces règles pour vous
L'espace de noms Intl, natif du navigateur et de Node.js, encapsule ces règles culturelles. Intl.NumberFormat et Intl.DateTimeFormat couvrent le cas le plus fréquent : afficher un nombre ou une date selon les conventions d'une locale.
API Intl | Rôle |
|---|---|
Intl.NumberFormat | Formater un nombre ou une devise selon une locale |
Intl.DateTimeFormat | Formater une date selon une locale |
Intl.RelativeTimeFormat | Produire un texte relatif ("il y a 3 jours") |
Intl.PluralRules | Déterminer la forme grammaticale plurielle correcte |
Intl.Collator | Trier du texte selon les conventions linguistiques |
4. Des besoins plus subtils, déjà résolus
Intl.RelativeTimeFormat produit un texte naturel ("il y a 3 jours") plutôt qu'une date brute. Intl.PluralRules détermine la bonne forme grammaticale d'un mot selon la quantité et la langue.
5. Un exemple qui montre la difficulté réelle
Cette règle de pluriel varie radicalement d'une langue à l'autre, et aucune formule simple ne peut la généraliser — d'où l'intérêt de s'appuyer sur une API déjà correcte plutôt que de la réinventer.
Astuce
Ne codez jamais vous-même la règle "ajouter un 's' si n > 1" : certaines langues ont plus de deux formes plurielles (l'arabe en a six). Intl.PluralRules(locale).select(n) renvoie la catégorie correcte (one, few, many, other...) pour n'importe quelle langue prise en charge.
6. Trier du texte correctement aussi
Intl.Collator trie des chaînes en respectant les conventions linguistiques réelles d'une langue, là où le tri par défaut de sort() classe les caractères accentués de façon souvent incohérente.
Cette leçon est une invitation à ne jamais réinventer ces règles soi-même : chaque cas semble simple isolément, mais leur combinaison à l'échelle internationale est un piège classique déjà résolu.
Commandes & code
Intl : internationalisation native
L'API standard du navigateur/Node pour formater dates, nombres et textes selon une locale.
// --- Intl.NumberFormat : nombres, devises, pourcentages, unites ---
const nombre = 1234567.891;
console.log(new Intl.NumberFormat("fr-FR").format(nombre)); // "1 234 567,891"
console.log(new Intl.NumberFormat("en-US").format(nombre)); // "1,234,567.891"
console.log(new Intl.NumberFormat("de-DE").format(nombre)); // "1.234.567,891"
const formatteurEUR = new Intl.NumberFormat("fr-FR", {
style: "currency",
currency: "EUR",
});
console.log(formatteurEUR.format(49.9)); // "49,90 €"
const formatteurUSD = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
console.log(formatteurUSD.format(49.9)); // "$49.90"
console.log(new Intl.NumberFormat("fr-FR", { style: "percent" }).format(0.256)); // "26 %"
console.log(
new Intl.NumberFormat("fr-FR", { notation: "compact" }).format(1_500_000)
); // "1,5 M" -- notation compacte pour l'affichage de statistiques
console.log(
new Intl.NumberFormat("en-US", { style: "unit", unit: "kilometer-per-hour" }).format(80)
); // "80 km/h"
// --- Intl.DateTimeFormat : dates et heures localisees ---
const maintenant = new Date(2024, 5, 15, 14, 30);
console.log(new Intl.DateTimeFormat("fr-FR").format(maintenant)); // "15/06/2024"
console.log(new Intl.DateTimeFormat("en-US").format(maintenant)); // "6/15/2024"
const formatteurComplet = new Intl.DateTimeFormat("fr-FR", {
weekday: "long", year: "numeric", month: "long", day: "numeric",
hour: "2-digit", minute: "2-digit",
});
console.log(formatteurComplet.format(maintenant)); // "samedi 15 juin 2024 a 14:30"
// Plage de dates formatee de facon compacte
const debut = new Date(2024, 5, 15);
const fin = new Date(2024, 5, 20);
console.log(new Intl.DateTimeFormat("fr-FR").formatRange(debut, fin)); // "15-20/06/2024"
// --- Intl.RelativeTimeFormat : "il y a 3 jours", "dans 2 heures" ---
const rtf = new Intl.RelativeTimeFormat("fr", { numeric: "auto" });
console.log(rtf.format(-3, "day")); // "il y a 3 jours"
console.log(rtf.format(2, "hour")); // "dans 2 heures"
console.log(rtf.format(-1, "day")); // "hier" (numeric: "auto" utilise les formes idiomatiques)
console.log(rtf.format(0, "day")); // "aujourd'hui"
// --- Intl.ListFormat : listes grammaticalement correctes ---
const fruits = ["pommes", "bananes", "cerises"];
console.log(new Intl.ListFormat("fr", { type: "conjunction" }).format(fruits));
// "pommes, bananes et cerises"
console.log(new Intl.ListFormat("fr", { type: "disjunction" }).format(fruits));
// "pommes, bananes ou cerises"
console.log(new Intl.ListFormat("en", { type: "conjunction" }).format(fruits));
// "pommes, bananes, and cerises"
// --- Intl.PluralRules : regles de pluriel correctes selon la locale (pas juste s/pas de s) ---
const pr = new Intl.PluralRules("fr");
console.log(pr.select(0)); // "one" (en francais, 0 se comporte comme le singulier)
console.log(pr.select(1)); // "one"
console.log(pr.select(2)); // "other"
function pluraliser(n, singulier, pluriel) {
return `${n} ${pr.select(n) === "one" ? singulier : pluriel}`;
}
console.log(pluraliser(0, "article", "articles")); // "0 article"
console.log(pluraliser(5, "article", "articles")); // "5 articles"
// --- Intl.Collator : tri de chaines respectant les regles linguistiques de la locale ---
const mots = ["cote", "coté", "côte", "côté"];
console.log(mots.sort()); // tri par code point brut, souvent incorrect
console.log(mots.sort(new Intl.Collator("fr").compare)); // tri linguistiquement correct
// Tri insensible a la casse ET aux accents, tres utile pour une recherche utilisateur
const collatorRecherche = new Intl.Collator("fr", { sensitivity: "base" });
console.log(collatorRecherche.compare("cafe", "CAFÉ")); // 0 -- considere egal pour la recherche
// --- Intl.Segmenter : decouper un texte en mots/phrases selon la locale (gere les emojis, CJK...) ---
const segmenteur = new Intl.Segmenter("fr", { granularity: "word" });
const segments = Array.from(segmenteur.segment("Bonjour le monde !"));
console.log(segments.filter((s) => s.isWordLike).map((s) => s.segment)); // ["Bonjour", "le", "monde"]
// --- Detection de la locale/langue preferee de l'utilisateur ---
console.log(navigator.language); // "fr-FR"
console.log(navigator.languages); // ["fr-FR", "fr", "en-US", "en"]Résumé
Intl.NumberFormat/DateTimeFormatévitent tout formatage manuel fragile et respectent les conventions de chaque locale.Intl.RelativeTimeFormatetIntl.ListFormatproduisent un texte idiomatique ("il y a 3 jours", "A, B et C").Intl.PluralRulesgère les règles de pluriel réelles d'une langue, pas juste l'ajout d'un "s".Intl.Collatortrie des chaînes selon les règles linguistiques de la locale, contrairement àArray.sort()par défaut.
Exercices pratiques
Mission : réparer un tri et un pluriel codés à la main
Objectif : Diagnostiquer un tri alphabétique incorrect et une pluralisation codée à la main, puis les remplacer par les bonnes API Intl.
Contexte
Un catalogue produit trie ses articles ainsi :
produits.sort((a, b) => (a.nom > b.nom ? 1 : -1));Le tri place systématiquement "Éclair" après "Zèbre". Par ailleurs, une fonction affiche ${n} article(s) codée en dur pour tous les cas de quantité.