Formatage des nombres en JavaScript : Guide complet d'Intl.NumberFormat
📷 Antoine Dautry / PexelsFormatage des nombres en JavaScript : Guide complet d'Intl.NumberFormat
Maîtrisez le formatage des nombres pour un public international. Apprenez à utiliser Intl.NumberFormat pour les devises, les pourcentages et l'affichage localisé des nombres en JavaScript.
J'ai découvert le problème du formatage des nombres de la manière la plus classique qui soit : un utilisateur français m'a signalé qu'un prix affiché sur mon application lui semblait bizarre. J'affichais 1,234.56 €, ce qui en France se lit comme "un virgule deux cent trente-quatre point cinquante-six euros" — une valeur absurde. Le bon format aurait dû être 1 234,56 €.
Cette expérience m'a appris que le formatage des nombres est l'un de ces détails qui paraissent insignifiants jusqu'au moment où ils posent un vrai problème. Heureusement, JavaScript dispose d'une API native qui gère tout ça parfaitement.
Le problème : les formats de nombres varient selon les pays
La même valeur 1234567.89 s'écrit différemment selon les régions :
- France / Belgique:
1 234 567,89(espace comme séparateur de milliers, virgule comme décimale) - Allemagne / Autriche:
1.234.567,89(point comme séparateur de milliers, virgule comme décimale) - États-Unis / Royaume-Uni:
1,234,567.89(virgule comme séparateur de milliers, point comme décimale) - Suisse:
1'234'567.89(apostrophe comme séparateur de milliers) - Inde:
12,34,567.89(regroupement particulier)
En France, si vous affichez 1,234.56, un utilisateur peut lire "un virgule deux cent trente-quatre" — ce qui correspond à environ 1,23, et non à 1 234 ! Dans une application financière, c'est une erreur grave.
L'API Intl.NumberFormat de JavaScript
L'espace de noms Intl a été introduit avec ES2015 et regroupe plusieurs outils d'internationalisation. Intl.NumberFormat est celui qu'il faut utiliser pour les nombres. La compatibilité navigateur est excellente : tous les navigateurs modernes et Node.js 10+ le supportent nativement.
// Utilisation de base
const formateur = new Intl.NumberFormat('fr-FR');
formateur.format(1234567.89);
// "1 234 567,89"
// Usage ponctuel
new Intl.NumberFormat('fr-FR').format(1234567.89);
// "1 234 567,89"
// Comparaison avec d'autres locales
new Intl.NumberFormat('de-DE').format(1234567.89);
// "1.234.567,89"
new Intl.NumberFormat('en-US').format(1234567.89);
// "1,234,567.89"
Contrôle des décimales
// Toujours 2 décimales
new Intl.NumberFormat('fr-FR', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(1234.5);
// "1 234,50"
// Maximum 3 décimales, sans zéros inutiles
new Intl.NumberFormat('fr-FR', {
minimumFractionDigits: 0,
maximumFractionDigits: 3
}).format(1234.5);
// "1 234,5"
Désactiver le séparateur de milliers
Pour les années ou les identifiants :
new Intl.NumberFormat('fr-FR', {
useGrouping: false
}).format(2024);
// "2024" (et non "2 024")
Formatage des devises
C'est là que Intl.NumberFormat démontre toute sa valeur. Les règles de formatage monétaire sont complexes : nombre de décimales, position du symbole, séparateurs — tout varie d'une devise et d'une région à l'autre.
// Euro (format français)
new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'EUR'
}).format(1234.56);
// "1 234,56 €"
// Dollar américain
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(1234.56);
// "$1,234.56"
// Yen japonais (pas de décimales)
new Intl.NumberFormat('ja-JP', {
style: 'currency',
currency: 'JPY'
}).format(1234);
// "¥1,234"
// Livre sterling
new Intl.NumberFormat('en-GB', {
style: 'currency',
currency: 'GBP'
}).format(1234.56);
// "£1,234.56"
Point important : la devise (currency) et la locale (le style de formatage) sont des paramètres indépendants. On peut afficher des dollars avec un formatage français — utile quand un utilisateur français achète quelque chose en USD :
new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'USD'
}).format(1234.56);
// "1 234,56 $US"
Choisir le mode d'affichage de la devise
const montant = 1234.56;
// Symbole (par défaut)
new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'symbol'
}).format(montant);
// "1 234,56 $US"
// Code ISO
new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'code'
}).format(montant);
// "1 234,56 USD"
// Nom complet
new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'name'
}).format(montant);
// "1 234,56 dollar des États-Unis"
Avec currencyDisplay: 'name' en locale française, on obtient "dollar des États-Unis" — l'API connaît les noms localisés des devises dans chaque langue.
Piège à éviter : certaines devises comme le yen japonais (JPY) ou le won coréen (KRW) n'ont pas de sous-unités. En mode currency, elles n'affichent pas de décimales, et les valeurs décimales sont automatiquement arrondies.
Formatage des pourcentages
Le formatage des pourcentages comporte un piège classique :
// Attention : passer une fraction décimale (0.75 = 75 %)
new Intl.NumberFormat('fr-FR', {
style: 'percent'
}).format(0.75);
// "75 %"
// Avec une décimale
new Intl.NumberFormat('fr-FR', {
style: 'percent',
minimumFractionDigits: 1,
maximumFractionDigits: 1
}).format(0.7523);
// "75,2 %"
Erreur fréquente : le style percent multiplie la valeur par 100. Passer 75 donne 7 500 %. Si vous avez déjà une valeur en pourcentage (75), divisez-la d'abord par 100 :
const valeurPourcent = 75;
new Intl.NumberFormat('fr-FR', {
style: 'percent'
}).format(valeurPourcent / 100);
// "75 %"
Notez aussi que la locale française place une espace insécable avant le symbole %. C'est visuellement correct, mais peut créer des surprises lors de comparaisons de chaînes.
Notation scientifique
Pour les applications scientifiques ou d'ingénierie :
new Intl.NumberFormat('fr-FR', {
notation: 'scientific'
}).format(1234567890);
// "1,235E9"
new Intl.NumberFormat('fr-FR', {
notation: 'engineering'
}).format(1234567890);
// "1,235E9"
Notation compacte
Très utile pour les tableaux de bord et les statistiques :
// Locale française
new Intl.NumberFormat('fr-FR', {
notation: 'compact',
compactDisplay: 'short'
}).format(1200);
// "1,2 k"
new Intl.NumberFormat('fr-FR', {
notation: 'compact',
compactDisplay: 'short'
}).format(3500000);
// "3,5 M"
new Intl.NumberFormat('fr-FR', {
notation: 'compact',
compactDisplay: 'long'
}).format(1200);
// "1,2 millier"
// Locale anglaise pour comparaison
new Intl.NumberFormat('en-US', {
notation: 'compact'
}).format(1200);
// "1.2K"
Pièges courants et cas limites
NaN et Infinity :
new Intl.NumberFormat('fr-FR').format(NaN);
// "NaN"
new Intl.NumberFormat('fr-FR').format(Infinity);
// "+Infini" (la locale française a sa propre représentation)
Il vaut mieux valider les données avant de les formater plutôt que d'afficher ces valeurs brutes aux utilisateurs.
Performance : la création d'une instance Intl.NumberFormat a un coût. Si vous formatez de nombreux nombres avec les mêmes options, réutilisez l'instance :
// Inefficace
nombres.forEach(n => new Intl.NumberFormat('fr-FR').format(n));
// Efficace
const formateur = new Intl.NumberFormat('fr-FR');
nombres.forEach(n => formateur.format(n));
La méthode formatToParts() : pour styliser différemment chaque partie d'un nombre formaté :
new Intl.NumberFormat('fr-FR', {
style: 'currency',
currency: 'EUR'
}).formatToParts(1234.56);
// [
// { type: 'integer', value: '1' },
// { type: 'group', value: ' ' },
// { type: 'integer', value: '234' },
// { type: 'decimal', value: ',' },
// { type: 'fraction', value: '56' },
// { type: 'literal', value: ' ' },
// { type: 'currency', value: '€' }
// ]
En React, cela permet d'appliquer une couleur ou une taille de police différente au symbole monétaire.
Grands nombres et BigInt : pour les entiers très grands (au-delà de 2^53), Intl.NumberFormat supporte les BigInt :
new Intl.NumberFormat('fr-FR').format(9007199254740993n);
// "9 007 199 254 740 993"
Limites d'Intl.NumberFormat
Soyons honnêtes : cette API a aussi ses limites.
- Pas d'analyse (parsing) : il n'existe pas d'équivalent
Intl.NumberParse. Convertir "1 234,56" en1234.56nécessite une implémentation personnalisée — ce qui est étonnamment complexe. - Pas de formats personnalisés : les formats type Excel (
#.##0,00) ne sont pas supportés. Des bibliothèques commenumeral.jscouvrent ce besoin. - Format comptable : l'affichage des négatifs entre parenthèses
(1 234,56)est partiellement supporté viacurrencySign: 'accounting', mais pas dans tous les locales.
Pour la grande majorité des applications web, Intl.NumberFormat est largement suffisant.
L'outil Number Formatter de ToolBox Hub
Si vous souhaitez tester différentes options de formatage sans écrire de code, l'outil Number Formatter de ToolBox Hub vous permet de :
- Saisir le nombre à formater
- Sélectionner une locale (plus de 30 locales disponibles)
- Choisir un style (decimal, currency, percent, scientific)
- Pour les devises, sélectionner le code de devise
- Définir le nombre de décimales
- Activer ou désactiver le séparateur de milliers
- Voir le résultat en temps réel et copier le code JavaScript correspondant
Pratique pour vérifier le rendu dans une locale inconnue avant de déployer.
Outils connexes
- Convertisseur d'unités — conversions entre unités de mesure
- Calculateur de pourcentages — calcul et affichage de pourcentages
- Convertisseur d'octets — conversion des tailles de fichiers
Conclusion
Intl.NumberFormat est l'une des API les mieux conçues de la bibliothèque standard JavaScript. Derrière sa simplicité apparente se cache un système complet pour la localisation des nombres.
Points essentiels à retenir :
- Toujours utiliser
Intl.NumberFormatpour les nombres destinés aux utilisateurs — jamais de manipulation manuelle de chaînes - La devise et la locale sont des paramètres indépendants
- Le style
percentmultiplie par 100 — passer une fraction décimale - La notation
compacten français donne "k" et "M" - Réutiliser la même instance pour des formatages répétés
formatToParts()permet un style granulaire sur chaque composant du nombre
Un formatage correct des nombres, c'est une marque de respect envers les utilisateurs du monde entier. Avec Intl.NumberFormat, c'est aussi un code beaucoup plus simple et fiable.