Comment formater des listes avec ou en JavaScript
Utilisez Intl.ListFormat avec le type disjonction pour formater correctement les alternatives dans n'importe quelle langue
Introduction
Les applications présentent souvent aux utilisateurs des choix ou des alternatives. Un composant de téléchargement de fichiers accepte les fichiers "PNG, JPEG, ou SVG". Un formulaire de paiement permet d'utiliser "carte de crédit, carte de débit, ou PayPal" comme méthodes de paiement. Un message d'erreur suggère de corriger "nom d'utilisateur, mot de passe, ou adresse e-mail" pour résoudre les échecs d'authentification.
Ces listes utilisent "ou" pour indiquer des alternatives. Les formater manuellement avec une concaténation de chaînes ne fonctionne pas dans d'autres langues car différentes langues ont différentes règles de ponctuation, différents mots pour "ou", et différentes conventions de placement des virgules. L'API Intl.ListFormat avec le type disjonction formate correctement ces listes d'alternatives pour n'importe quelle langue.
Ce que sont les listes disjonctives
Une liste disjonctive présente des alternatives où généralement une seule option s'applique. Le mot "disjonction" signifie séparation ou alternatives. En français, les listes disjonctives utilisent "ou" comme conjonction :
const paymentMethods = ["carte de crédit", "carte de débit", "PayPal"];
// Résultat souhaité : "carte de crédit, carte de débit ou PayPal"
Cela diffère des listes conjonctives qui utilisent "et" pour indiquer que tous les éléments s'appliquent ensemble. Les listes disjonctives communiquent un choix, les listes conjonctives communiquent une combinaison.
Les contextes courants pour les listes disjonctives comprennent les options de paiement, les restrictions de format de fichier, les suggestions de dépannage, les alternatives de filtres de recherche et toute interface où les utilisateurs sélectionnent une option parmi plusieurs possibilités.
Pourquoi le formatage manuel échoue
Les francophones écrivent les listes disjonctives comme "A, B ou C" avec des virgules entre les éléments et "ou" avant le dernier élément. Ce modèle ne fonctionne pas dans d'autres langues :
// Modèle anglais codé en dur
const items = ["pomme", "orange", "banane"];
const text = items.slice(0, -1).join(", ") + ", or " + items[items.length - 1];
// "pomme, orange, or banane"
Ce code produit une sortie incorrecte en espagnol, français, allemand et la plupart des autres langues. Chaque langue a des règles de formatage distinctes pour les listes disjonctives.
L'espagnol utilise "o" sans virgule avant :
Attendu : "manzana, naranja o plátano"
Le modèle anglais produit : "manzana, naranja, or plátano"
Le français utilise "ou" sans virgule avant :
Attendu : "pomme, orange ou banane"
Le modèle anglais produit : "pomme, orange, or banane"
L'allemand utilise "oder" sans virgule avant :
Attendu : "Apfel, Orange oder Banane"
Le modèle anglais produit : "Apfel, Orange, or Banane"
Le japonais utilise la particule "か" (ka) avec une ponctuation différente :
Attendu : "りんご、オレンジ、またはバナナ"
Le modèle anglais produit : "りんご、オレンジ、 or バナナ"
Ces différences vont au-delà du simple remplacement de mots. Le placement de la ponctuation, les règles d'espacement et les particules grammaticales varient tous selon la langue. La concaténation manuelle de chaînes ne peut pas gérer cette complexité.
Utilisation d'Intl.ListFormat avec le type disjonction
L'API Intl.ListFormat formate les listes selon les règles spécifiques à chaque langue. Définissez l'option type sur "disjunction" pour formater des listes d'alternatives :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
const paymentMethods = ["credit card", "debit card", "PayPal"];
console.log(formatter.format(paymentMethods));
// "credit card, debit card, or PayPal"
Le formateur gère les tableaux de toute longueur :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
console.log(formatter.format([]));
// ""
console.log(formatter.format(["credit card"]));
// "credit card"
console.log(formatter.format(["credit card", "PayPal"]));
// "credit card or PayPal"
console.log(formatter.format(["credit card", "debit card", "PayPal"]));
// "credit card, debit card, or PayPal"
L'API applique automatiquement la ponctuation et la conjonction correctes pour chaque cas.
Comprendre les styles de disjonction
L'option style contrôle la verbosité du formatage. Trois styles existent : long, short et narrow. Le style long est celui par défaut.
const items = ["email", "phone", "SMS"];
const long = new Intl.ListFormat("en", {
type: "disjunction",
style: "long"
});
console.log(long.format(items));
// "email, phone, or SMS"
const short = new Intl.ListFormat("en", {
type: "disjunction",
style: "short"
});
console.log(short.format(items));
// "email, phone, or SMS"
const narrow = new Intl.ListFormat("en", {
type: "disjunction",
style: "narrow"
});
console.log(narrow.format(items));
// "email, phone, or SMS"
En anglais, les trois styles produisent un résultat identique pour les listes disjonctives. D'autres langues montrent plus de variations. L'allemand utilise "oder" dans le style long et peut abréger dans le style narrow. Les différences deviennent plus apparentes dans les langues avec plusieurs niveaux de formalité ou des mots de conjonction plus longs.
Le style narrow supprime généralement les espaces ou utilise des conjonctions plus courtes pour économiser de l'espace dans les mises en page contraintes. Utilisez le style long pour du texte standard, le style short pour des affichages modérément compacts, et le style narrow pour des contraintes d'espace serrées comme les interfaces mobiles ou les tableaux compacts.
Comment les listes disjonctives apparaissent dans différentes langues
Chaque langue formate les listes disjonctives selon ses propres conventions. Intl.ListFormat gère ces différences automatiquement.
L'anglais utilise des virgules avec "or" :
const en = new Intl.ListFormat("en", { type: "disjunction" });
console.log(en.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG, or SVG"
L'espagnol utilise des virgules avec "o" et pas de virgule avant la conjonction finale :
const es = new Intl.ListFormat("es", { type: "disjunction" });
console.log(es.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG o SVG"
Le français utilise des virgules avec "ou" et pas de virgule avant la conjonction finale :
const fr = new Intl.ListFormat("fr", { type: "disjunction" });
console.log(fr.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG ou SVG"
L'allemand utilise des virgules avec "oder" et pas de virgule avant la conjonction finale :
const de = new Intl.ListFormat("de", { type: "disjunction" });
console.log(de.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG oder SVG"
Le japonais utilise une ponctuation et des particules différentes :
const ja = new Intl.ListFormat("ja", { type: "disjunction" });
console.log(ja.format(["PNG", "JPEG", "SVG"]));
// "PNG、JPEG、またはSVG"
Le chinois utilise des signes de ponctuation chinois :
const zh = new Intl.ListFormat("zh", { type: "disjunction" });
console.log(zh.format(["PNG", "JPEG", "SVG"]));
// "PNG、JPEG或SVG"
Ces exemples montrent comment l'API s'adapte aux conventions grammaticales et de ponctuation de chaque langue. Le même code fonctionne pour toutes les langues lorsque vous fournissez la locale appropriée.
Formatage des options de paiement
Les formulaires de paiement présentent plusieurs choix de méthodes de paiement. Formatez-les avec des listes disjonctives :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
function getPaymentMessage(methods) {
if (methods.length === 0) {
return "No payment methods available";
}
return `Pay with ${formatter.format(methods)}.`;
}
const methods = ["credit card", "debit card", "PayPal", "Apple Pay"];
console.log(getPaymentMessage(methods));
// "Pay with credit card, debit card, PayPal, or Apple Pay."
Pour les applications internationales, passez la locale de l'utilisateur :
const userLocale = navigator.language; // par ex., "fr-FR"
const formatter = new Intl.ListFormat(userLocale, { type: "disjunction" });
function getPaymentMessage(methods) {
if (methods.length === 0) {
return "No payment methods available";
}
return `Pay with ${formatter.format(methods)}.`;
}
Cette approche fonctionne dans les flux de paiement, les sélecteurs de méthode de paiement et toute interface où les utilisateurs choisissent comment payer.
Formatage des restrictions de téléchargement de fichiers
Les composants de téléchargement de fichiers spécifient quels types de fichiers le système accepte :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
function getAcceptedFormatsMessage(formats) {
if (formats.length === 0) {
return "No file formats accepted";
}
if (formats.length === 1) {
return `Accepted format: ${formats[0]}`;
}
return `Accepted formats: ${formatter.format(formats)}`;
}
const imageFormats = ["PNG", "JPEG", "SVG", "WebP"];
console.log(getAcceptedFormatsMessage(imageFormats));
// "Accepted formats: PNG, JPEG, SVG, or WebP"
const documentFormats = ["PDF", "DOCX"];
console.log(getAcceptedFormatsMessage(documentFormats));
// "Accepted formats: PDF or DOCX"
Ce modèle fonctionne pour les téléchargements d'images, les soumissions de documents et tout champ de saisie de fichier avec des restrictions de format.
Formatage des suggestions de dépannage
Les messages d'erreur suggèrent souvent plusieurs façons de résoudre un problème. Présentez ces suggestions sous forme de listes disjonctives :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
function getAuthenticationError(missingFields) {
if (missingFields.length === 0) {
return "Authentication failed";
}
return `Please check your ${formatter.format(missingFields)} and try again.`;
}
console.log(getAuthenticationError(["username", "password"]));
// "Please check your username or password and try again."
console.log(getAuthenticationError(["email", "username", "password"]));
// "Please check your email, username, or password and try again."
La liste disjonctive clarifie que les utilisateurs doivent corriger l'un des champs mentionnés, pas nécessairement tous.
Formatage des alternatives de filtres de recherche
Les interfaces de recherche affichent les filtres actifs. Lorsque les filtres présentent des alternatives, utilisez des listes disjonctives :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
function getFilterSummary(filters) {
if (filters.length === 0) {
return "No filters applied";
}
if (filters.length === 1) {
return `Showing results for: ${filters[0]}`;
}
return `Showing results for: ${formatter.format(filters)}`;
}
const categories = ["Electronics", "Books", "Clothing"];
console.log(getFilterSummary(categories));
// "Showing results for: Electronics, Books, or Clothing"
Cela fonctionne pour les filtres de catégories, les sélections de tags et toute interface de filtre où les valeurs sélectionnées représentent des alternatives plutôt que des combinaisons.
Réutilisation des formateurs pour la performance
La création d'instances Intl.ListFormat génère des frais généraux. Créez les formateurs une seule fois et réutilisez-les :
// Créer une fois au niveau du module
const disjunctionFormatter = new Intl.ListFormat("en", { type: "disjunction" });
// Réutiliser dans plusieurs fonctions
function formatPaymentMethods(methods) {
return disjunctionFormatter.format(methods);
}
function formatFileTypes(types) {
return disjunctionFormatter.format(types);
}
function formatErrorSuggestions(suggestions) {
return disjunctionFormatter.format(suggestions);
}
Pour les applications prenant en charge plusieurs locales, stockez les formateurs dans un cache :
const formatters = new Map();
function getDisjunctionFormatter(locale) {
if (!formatters.has(locale)) {
formatters.set(
locale,
new Intl.ListFormat(locale, { type: "disjunction" })
);
}
return formatters.get(locale);
}
const formatter = getDisjunctionFormatter("en");
console.log(formatter.format(["A", "B", "C"]));
// "A, B, or C"
Ce modèle réduit les coûts d'initialisation tout en prenant en charge plusieurs locales dans toute l'application.
Utilisation de formatToParts pour un rendu personnalisé
La méthode formatToParts() renvoie un tableau d'objets représentant chaque partie de la liste formatée. Cela permet une personnalisation du style :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
const parts = formatter.formatToParts(["PNG", "JPEG", "SVG"]);
console.log(parts);
// [
// { type: "element", value: "PNG" },
// { type: "literal", value: ", " },
// { type: "element", value: "JPEG" },
// { type: "literal", value: ", or " },
// { type: "element", value: "SVG" }
// ]
Chaque partie a un type et une value. Le type est soit "element" pour les éléments de la liste, soit "literal" pour la ponctuation et les conjonctions.
Utilisez ceci pour appliquer différents styles aux éléments et aux littéraux :
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
const formats = ["PNG", "JPEG", "SVG"];
const html = formatter.formatToParts(formats)
.map(part => {
if (part.type === "element") {
return `<code>${part.value}</code>`;
}
return part.value;
})
.join("");
console.log(html);
// "<code>PNG</code>, <code>JPEG</code>, or <code>SVG</code>"
Cette approche maintient une ponctuation et des conjonctions correctes selon la locale tout en appliquant une présentation personnalisée aux éléments réels.
Prise en charge et compatibilité des navigateurs
Intl.ListFormat fonctionne dans tous les navigateurs modernes depuis avril 2021. La prise en charge inclut Chrome 72+, Firefox 78+, Safari 14.1+ et Edge 79+.
Vérifiez la prise en charge avant d'utiliser l'API :
if (typeof Intl.ListFormat !== "undefined") {
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
return formatter.format(items);
} else {
// Solution de repli pour les navigateurs plus anciens
return items.join(", ");
}
Pour une compatibilité plus large, utilisez un polyfill comme @formatjs/intl-listformat. Installez-le uniquement où nécessaire :
if (typeof Intl.ListFormat === "undefined") {
await import("@formatjs/intl-listformat/polyfill");
}
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
Étant donné la prise en charge actuelle des navigateurs, la plupart des applications peuvent utiliser Intl.ListFormat directement sans polyfills.
Erreurs courantes à éviter
Utiliser le type de conjonction au lieu de la disjonction produit un sens incorrect :
// Incorrect : suggère que toutes les méthodes sont requises
const wrong = new Intl.ListFormat("en", { type: "conjunction" });
console.log(`Pay with ${wrong.format(["credit card", "debit card"])}`);
// "Pay with credit card and debit card"
// Correct : suggère de choisir une méthode
const correct = new Intl.ListFormat("en", { type: "disjunction" });
console.log(`Pay with ${correct.format(["credit card", "debit card"])}`);
// "Pay with credit card or debit card"
Créer de nouveaux formateurs de façon répétée gaspille des ressources :
// Inefficace
function formatOptions(options) {
return new Intl.ListFormat("en", { type: "disjunction" }).format(options);
}
// Efficace
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
function formatOptions(options) {
return formatter.format(options);
}
Coder en dur "ou" dans les chaînes empêche la localisation :
// Ne fonctionne pas dans d'autres langues
const text = items.join(", ") + ", or other options";
// Fonctionne dans toutes les langues
const formatter = new Intl.ListFormat(userLocale, { type: "disjunction" });
const allItems = [...items, "other options"];
const text = formatter.format(allItems);
Ne pas gérer les tableaux vides peut provoquer des résultats inattendus :
// Défensif
function formatPaymentMethods(methods) {
if (methods.length === 0) {
return "No payment methods available";
}
return formatter.format(methods);
}
Bien que format([]) renvoie une chaîne vide, la gestion explicite de l'état vide améliore l'expérience utilisateur.
Quand utiliser des listes disjonctives
Utilisez des listes disjonctives lorsque vous présentez des alternatives ou des choix où généralement une seule option s'applique. Cela inclut la sélection de méthodes de paiement, les restrictions de format de fichier, les suggestions d'erreur d'authentification, les options de filtres de recherche et les choix de types de compte.
N'utilisez pas de listes disjonctives lorsque tous les éléments doivent s'appliquer ensemble. Utilisez plutôt des listes conjonctives. Par exemple, "Nom, email et mot de passe sont requis" utilise une conjonction car tous les champs doivent être fournis, pas seulement un.
N'utilisez pas de listes disjonctives pour des énumérations neutres sans implications de choix. Les mesures et les spécifications techniques utilisent généralement des listes d'unités plutôt que des disjonctions ou des conjonctions.
L'API remplace les modèles de concaténation manuelle de chaînes pour les alternatives. Chaque fois que vous écririez du code qui joint des éléments avec "ou" pour du texte destiné aux utilisateurs, considérez si Intl.ListFormat avec le type disjonction offre un meilleur support de localisation.