Comment découper une sortie formatée pour la styliser
Utilisez formatToParts() pour accéder individuellement aux composants d’un résultat formaté et personnaliser leur style
Introduction
La méthode format() des formateurs JavaScript retourne des chaînes complètes comme « 1 234,56 $ » ou « 15 janvier 2025 ». Cela fonctionne bien pour un affichage simple, mais vous ne pouvez pas appliquer un style différent à chaque partie. Par exemple, impossible de mettre le symbole monétaire en gras, de colorer le nom du mois, ou d’ajouter un balisage personnalisé à certains éléments.
JavaScript propose la méthode formatToParts() pour résoudre ce problème. Plutôt que de renvoyer une seule chaîne, elle retourne un tableau d’objets représentant chaque composant du résultat formaté. Chaque élément possède un type comme currency, month ou element, et une valeur correspondant au texte réel. Vous pouvez alors traiter ces parties pour appliquer des styles personnalisés, construire des mises en page complexes ou intégrer ce formatage dans des interfaces riches.
La méthode formatToParts() est disponible sur plusieurs formateurs Intl, y compris NumberFormat, DateTimeFormat, ListFormat, RelativeTimeFormat et DurationFormat. Cela en fait une solution cohérente pour tout le formatage internationalisé en JavaScript.
Pourquoi les chaînes formatées ne peuvent pas être stylisées facilement
Lorsque vous recevez une chaîne formatée comme « 1 234,56 $ », il est difficile d’identifier précisément où s’arrête le symbole monétaire et où commence le nombre. Différents pays placent le symbole à divers endroits et utilisent d'autres séparateurs. Analyser ces chaînes correctement nécessite une logique complexe, qui reproduit en fait les règles déjà mises en œuvre dans l’API Intl.
Imaginez un tableau de bord qui affiche des montants avec le symbole de la devise dans une couleur différente. Avec format(), il faudrait :
- Détecter quels caractères constituent le symbole monétaire
- Gérer les espaces éventuels entre le symbole et le nombre
- Tenir compte des positions différentes du symbole selon les pays
- Analyser la chaîne avec soin pour ne pas casser le nombre
Cette méthode est fragile et sujette aux erreurs. Toute modification des règles de formatage locales casse votre logique d'analyse.
Le même problème se pose pour les dates, les listes et d'autres sorties formatées. Vous ne pouvez pas analyser de manière fiable les chaînes formatées pour identifier leurs éléments sans réimplémenter les règles de formatage propres à la locale.
La méthode formatToParts() élimine ce problème en fournissant les éléments séparément. Vous obtenez des données structurées qui indiquent précisément quelle partie correspond à quoi, quelle que soit la langue.
Comment fonctionne formatToParts
La méthode formatToParts() fonctionne de façon identique à format(), à l'exception de sa valeur de retour. Vous créez un formateur avec les mêmes options, puis vous appelez formatToParts() au lieu de format().
La méthode retourne un tableau d'objets. Chaque objet contient deux propriétés :
type: indique ce que représente la partie, par exemplecurrency,monthouliteralvalue: contient la chaîne de caractères réelle de cette partie
Les éléments apparaissent dans le même ordre que dans la sortie formatée. Vous pouvez le vérifier en joignant toutes les valeurs, ce qui produit exactement le même résultat que l'appel à format().
Ce modèle est valable pour tous les formateurs qui prennent en charge formatToParts(). Les types d'éléments spécifiques varient selon le formateur, mais la structure reste toujours la même.
Découper les nombres formatés en parties
Le formateur NumberFormat propose formatToParts() pour décomposer les nombres formatés. Cela fonctionne pour les nombres simples, les devises, les pourcentages et d'autres styles numériques.
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
});
const parts = formatter.formatToParts(1234.56);
console.log(parts);
Cela génère un tableau d'objets :
[
{ type: "currency", value: "$" },
{ type: "integer", value: "1" },
{ type: "group", value: "," },
{ type: "integer", value: "234" },
{ type: "decimal", value: "." },
{ type: "fraction", value: "56" }
]
Chaque objet indique à quoi correspond la partie et fournit sa valeur. Le type currency représente le symbole monétaire. Le type integer correspond aux chiffres entiers. Le type group désigne le séparateur des milliers. Le type decimal correspond au point décimal. Le type fraction correspond aux chiffres après la décimale.
Vous pouvez vérifier que les parties correspondent au résultat formaté :
const formatted = parts.map(part => part.value).join("");
console.log(formatted);
// Output: "$1,234.56"
Les parties concaténées produisent exactement le même résultat que l'appel à format().
Personnaliser le style des symboles monétaires dans les nombres formatés
L'utilisation principale de formatToParts() est d'appliquer des styles différents à différents composants. Vous pouvez traiter le tableau des parties pour envelopper certains types dans des éléments HTML.
Mettre le symbole monétaire en gras :
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
});
const parts = formatter.formatToParts(1234.56);
const html = parts
.map(part => {
if (part.type === "currency") {
return `<strong>${part.value}</strong>`;
}
return part.value;
})
.join("");
console.log(html);
// Output: "<strong>$</strong>1,234.56"
Cette méthode fonctionne avec n'importe quel langage de balisage. Vous pouvez générer du HTML, du JSX, ou tout autre format en traitant le tableau des parties.
Styliser différemment la partie décimale :
const formatter = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2
});
const parts = formatter.formatToParts(1234.5);
const html = parts
.map(part => {
if (part.type === "decimal" || part.type === "fraction") {
return `<span class="text-gray-500">${part.value}</span>`;
}
return part.value;
})
.join("");
console.log(html);
// Output: "1,234<span class="text-gray-500">.50</span>"
Ce modèle est courant dans les affichages de tarifs où la partie décimale apparaît plus petite ou plus claire.
Découper les dates formatées en parties
Le formateur DateTimeFormat fournit formatToParts() pour décomposer les dates et heures formatées.
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
console.log(parts);
Cela génère un tableau d'objets :
[
{ type: "month", value: "January" },
{ type: "literal", value: " " },
{ type: "day", value: "15" },
{ type: "literal", value: ", " },
{ type: "year", value: "2025" }
]
Le type month représente le nom ou le numéro du mois. Le type day représente le jour du mois. Le type year représente l'année. Le type literal représente les espaces, la ponctuation ou tout autre texte inséré par le formateur.
Personnaliser le style des noms de mois dans les dates formatées
Vous pouvez appliquer un style personnalisé aux composants de date en utilisant le même modèle que pour les nombres.
Mettre le nom du mois en gras :
const formatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const html = parts
.map(part => {
if (part.type === "month") {
return `<strong>${part.value}</strong>`;
}
return part.value;
})
.join("");
console.log(html);
// Output: "<strong>January</strong> 15, 2025"
Styliser plusieurs composants de date :
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
const date = new Date(2025, 0, 15);
const parts = formatter.formatToParts(date);
const html = parts
.map(part => {
switch (part.type) {
case "weekday":
return `<span class="font-bold">${part.value}</span>`;
case "month":
return `<span class="text-blue-600">${part.value}</span>`;
case "year":
return `<span class="text-gray-500">${part.value}</span>`;
default:
return part.value;
}
})
.join("");
console.log(html);
// Output: "<span class="font-bold">Wednesday</span>, <span class="text-blue-600">January</span> 15, <span class="text-gray-500">2025</span>"
Ce contrôle précis permet d'appliquer un style sur mesure à chaque composant.
Découper les listes formatées en parties
Le formateur ListFormat fournit formatToParts() pour décomposer les listes formatées.
const formatter = new Intl.ListFormat("en-US", {
style: "long",
type: "conjunction"
});
const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);
console.log(parts);
Ceci génère un tableau d'objets :
[
{ type: "element", value: "apples" },
{ type: "literal", value: ", " },
{ type: "element", value: "oranges" },
{ type: "literal", value: ", and " },
{ type: "element", value: "bananas" }
]
Le type element représente chaque élément de la liste. Le type literal représente les séparateurs et conjonctions ajoutés par le formateur.
Style des éléments de liste individuellement
Vous pouvez appliquer un style personnalisé aux éléments de liste en utilisant le même modèle.
Mettre les éléments de liste en gras :
const formatter = new Intl.ListFormat("en-US", {
style: "long",
type: "conjunction"
});
const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);
const html = parts
.map(part => {
if (part.type === "element") {
return `<strong>${part.value}</strong>`;
}
return part.value;
})
.join("");
console.log(html);
// Output: "<strong>apples</strong>, <strong>oranges</strong>, and <strong>bananas</strong>"
Styliser certains éléments de la liste :
const formatter = new Intl.ListFormat("en-US", {
style: "long",
type: "conjunction"
});
const items = ["apples", "oranges", "bananas"];
const parts = formatter.formatToParts(items);
let itemIndex = 0;
const html = parts
.map(part => {
if (part.type === "element") {
const currentIndex = itemIndex++;
if (currentIndex === 0) {
return `<span class="text-green-600">${part.value}</span>`;
}
return part.value;
}
return part.value;
})
.join("");
console.log(html);
// Output: "<span class="text-green-600">apples</span>, oranges, and bananas"
Cette méthode vous permet de mettre en avant certains éléments tout en conservant le bon formatage propre à chaque langue.
Découper les dates relatives formatées en parties
Le formateur RelativeTimeFormat fournit formatToParts() pour décomposer les expressions de temps relatif.
const formatter = new Intl.RelativeTimeFormat("en-US", {
numeric: "auto"
});
const parts = formatter.formatToParts(-1, "day");
console.log(parts);
Ceci génère un tableau d'objets :
[
{ type: "literal", value: "yesterday" }
]
Pour les temps relatifs numériques :
const formatter = new Intl.RelativeTimeFormat("en-US", {
numeric: "always"
});
const parts = formatter.formatToParts(-3, "day");
console.log(parts);
// [
// { type: "integer", value: "3" },
// { type: "literal", value: " days ago" }
// ]
Le type integer représente la valeur numérique. Le type literal correspond à l'unité de temps relative et à la direction.
Découper les durées formatées en parties
Le formateur DurationFormat fournit formatToParts() pour décomposer les durées formatées.
const formatter = new Intl.DurationFormat("en-US", {
style: "long"
});
const parts = formatter.formatToParts({
hours: 2,
minutes: 30,
seconds: 15
});
console.log(parts);
Ceci génère un tableau d'objets similaire à :
[
{ type: "integer", value: "2" },
{ type: "literal", value: " hours, " },
{ type: "integer", value: "30" },
{ type: "literal", value: " minutes, " },
{ type: "integer", value: "15" },
{ type: "literal", value: " seconds" }
]
Le type integer représente les valeurs numériques. Le type literal représente les noms d’unités et les séparateurs.
Générer du HTML à partir des parties formatées
Vous pouvez créer une fonction réutilisable qui traite les parties et applique les règles de style de façon cohérente.
function formatWithStyles(parts, styleMap) {
return parts
.map(part => {
const style = styleMap[part.type];
if (style) {
return `<span class="${style}">${part.value}</span>`;
}
return part.value;
})
.join("");
}
const numberFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
});
const parts = numberFormatter.formatToParts(1234.56);
const html = formatWithStyles(parts, {
currency: "font-bold text-gray-700",
integer: "text-2xl",
fraction: "text-sm text-gray-500"
});
console.log(html);
// Output: "<span class="font-bold text-gray-700">$</span><span class="text-2xl">1</span>,<span class="text-2xl">234</span>.<span class="text-sm text-gray-500">56</span>"
Ce modèle sépare les règles de style de la logique de formatage, ce qui facilite la maintenance et la réutilisation.
Comprendre l’ordre des parties selon la locale
Le tableau des parties applique automatiquement les règles de formatage propres à chaque locale. Selon les langues, les éléments sont placés dans un ordre différent et utilisent des formats distincts, mais formatToParts() gère ces différences.
const usdFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
});
console.log(usdFormatter.formatToParts(1234.56));
// [
// { type: "currency", value: "$" },
// { type: "integer", value: "1" },
// { type: "group", value: "," },
// { type: "integer", value: "234" },
// { type: "decimal", value: "." },
// { type: "fraction", value: "56" }
// ]
const eurFormatter = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR"
});
console.log(eurFormatter.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 allemand, le formatage place la devise après le nombre, avec un espace. Le séparateur de milliers est un point et celui des décimales une virgule. Votre code de style traite le tableau des parties de la même manière quel que soit la locale, et le formatage s’adapte automatiquement.
Créer des affichages formatés accessibles
Vous pouvez utiliser formatToParts() pour ajouter des attributs d’accessibilité à la sortie formatée. Cela aide les lecteurs d’écran à annoncer correctement les valeurs.
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD"
});
function formatAccessible(number) {
const parts = formatter.formatToParts(number);
const formatted = parts.map(part => part.value).join("");
return `<span aria-label="${number} US dollars">${formatted}</span>`;
}
console.log(formatAccessible(1234.56));
// Output: "<span aria-label="1234.56 US dollars">$1,234.56</span>"
Cela garantit que les lecteurs d’écran annoncent à la fois la valeur affichée formatée et la valeur numérique sous-jacente dans le bon contexte.
Combiner formatToParts avec des composants de frameworks
Les frameworks modernes comme React peuvent utiliser formatToParts() pour construire des composants efficacement.
function CurrencyDisplay({ value, locale, currency }) {
const formatter = new Intl.NumberFormat(locale, {
style: "currency",
currency: currency
});
const parts = formatter.formatToParts(value);
return (
<span className="currency-display">
{parts.map((part, index) => {
if (part.type === "currency") {
return <strong key={index}>{part.value}</strong>;
}
if (part.type === "fraction" || part.type === "decimal") {
return <span key={index} className="text-sm text-gray-500">{part.value}</span>;
}
return <span key={index}>{part.value}</span>;
})}
</span>
);
}
Ce composant applique des styles différents selon les parties tout en conservant un formatage correct pour n’importe quelle locale ou devise.
Quand utiliser formatToParts
Utilisez format() si vous avez juste besoin d’une chaîne formatée simple sans personnalisation. C’est le cas le plus courant pour l’affichage.
Utilisez formatToParts() lorsque vous souhaitez :
- Appliquer des styles différents selon les parties de la valeur formatée
- Générer du HTML ou JSX avec du contenu formaté
- Ajouter des attributs ou des métadonnées à certains éléments
- Intégrer la valeur formatée dans des agencements complexes
- Traiter la valeur formatée de façon programmatique
- Créer des designs personnalisés qui demandent un contrôle plus précis
La méthode formatToParts() a un peu plus de surcharge que format(), car elle crée un tableau d'objets au lieu d'une simple chaîne de caractères. Cette différence est négligeable pour la plupart des applications, mais si vous formatez des milliers de valeurs par seconde, format() sera plus performant.
Pour la majorité des applications, choisissez en fonction de vos besoins de style plutôt que de performances. Si vous n'avez pas besoin de personnaliser la sortie, utilisez format(). Si vous souhaitez appliquer un style personnalisé ou ajouter du balisage, utilisez formatToParts().
Types de parties courantes entre les formateurs
Les différents formateurs produisent différents types de parties, mais certains types se retrouvent dans plusieurs formateurs :
literal: espaces, ponctuation ou autre texte ajouté par le formatage. Apparaît dans les dates, nombres, listes et durées.integer: chiffres entiers. Apparaît dans les nombres, temps relatifs et durées.decimal: séparateur décimal. Apparaît dans les nombres.fraction: chiffres décimaux. Apparaît dans les nombres.
Les types spécifiques à chaque formateur incluent :
- Nombres :
currency,group,percentSign,minusSign,plusSign,unit,compact,exponentInteger - Dates :
weekday,era,year,month,day,hour,minute,second,dayPeriod,timeZoneName - Listes :
element - Temps relatifs : Les valeurs numériques apparaissent comme
integer, le texte apparaît commeliteral
Comprendre ces types vous aide à écrire du code de style qui gère correctement la sortie de n'importe quel formateur.