Wie man Listen mit oder in JavaScript formatiert
Verwenden Sie Intl.ListFormat mit dem Typ disjunction, um Alternativen in jeder Sprache korrekt zu formatieren
Einführung
Anwendungen präsentieren Benutzern häufig Auswahlmöglichkeiten oder Alternativen. Eine Datei-Upload-Komponente akzeptiert "PNG, JPEG oder SVG"-Dateien. Ein Zahlungsformular erlaubt "Kreditkarte, Debitkarte oder PayPal" als Zahlungsmethoden. Eine Fehlermeldung schlägt vor, "Benutzername, Passwort oder E-Mail-Adresse" zu korrigieren, um Authentifizierungsfehler zu beheben.
Diese Listen verwenden "oder", um Alternativen anzuzeigen. Die manuelle Formatierung durch String-Verkettung funktioniert in anderen Sprachen nicht, da verschiedene Sprachen unterschiedliche Interpunktionsregeln, verschiedene Wörter für "oder" und unterschiedliche Kommasetzungskonventionen haben. Die Intl.ListFormat API mit dem Disjunktionstyp formatiert diese alternativen Listen korrekt für jede Sprache.
Was disjunktive Listen sind
Eine disjunktive Liste präsentiert Alternativen, bei denen typischerweise eine Option zutrifft. Das Wort "Disjunktion" bedeutet Trennung oder Alternativen. Im Deutschen verwenden disjunktive Listen "oder" als Konjunktion:
const paymentMethods = ["Kreditkarte", "Debitkarte", "PayPal"];
// Gewünschte Ausgabe: "Kreditkarte, Debitkarte oder PayPal"
Dies unterscheidet sich von konjunktiven Listen, die "und" verwenden, um anzuzeigen, dass alle Elemente zusammen gelten. Disjunktive Listen kommunizieren Auswahl, konjunktive Listen kommunizieren Kombination.
Häufige Kontexte für disjunktive Listen umfassen Zahlungsoptionen, Dateiformatbeschränkungen, Fehlerbehebungsvorschläge, Suchfilteralternativen und jede Schnittstelle, bei der Benutzer eine Option aus mehreren Möglichkeiten auswählen.
Warum manuelle Formatierung fehlschlägt
Deutschsprachige schreiben disjunktive Listen als "A, B oder C" mit Kommas zwischen den Elementen und "oder" vor dem letzten Element. Dieses Muster funktioniert in anderen Sprachen nicht:
// Fest codiertes deutsches Muster
const items = ["Apfel", "Orange", "Banane"];
const text = items.slice(0, -1).join(", ") + " oder " + items[items.length - 1];
// "Apfel, Orange oder Banane"
Dieser Code erzeugt falsche Ausgaben in Spanisch, Französisch, Englisch und den meisten anderen Sprachen. Jede Sprache hat eigene Formatierungsregeln für disjunktive Listen.
Spanisch verwendet "o" ohne Komma davor:
Erwartet: "manzana, naranja o plátano"
Deutsches Muster erzeugt: "manzana, naranja oder plátano"
Französisch verwendet "ou" ohne Komma davor:
Erwartet: "pomme, orange ou banane"
Deutsches Muster erzeugt: "pomme, orange oder banane"
Englisch verwendet "or" mit einem Komma davor:
Erwartet: "apple, orange, or banana"
Deutsches Muster erzeugt: "apple, orange oder banana"
Japanisch verwendet die Partikel "か" (ka) mit anderer Interpunktion:
Erwartet: "りんご、オレンジ、またはバナナ"
Deutsches Muster erzeugt: "りんご、オレンジ oder バナナ"
Diese Unterschiede gehen über einfachen Wortaustausch hinaus. Zeichensetzung, Abstandsregeln und grammatikalische Partikel variieren je nach Sprache. Manuelle String-Verkettung kann diese Komplexität nicht bewältigen.
Verwendung von Intl.ListFormat mit Disjunktionstyp
Die Intl.ListFormat-API formatiert Listen gemäß sprachspezifischen Regeln. Setzen Sie die Option type auf "disjunction", um alternative Listen zu formatieren:
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"
Der Formatierer verarbeitet Arrays jeder Länge:
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"
Die API wendet automatisch die korrekte Interpunktion und Konjunktion für jeden Fall an.
Verständnis der Disjunktionsstile
Die Option style steuert die Ausführlichkeit der Formatierung. Es gibt drei Stile: long, short und narrow. Der Stil long ist die Standardeinstellung.
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"
Im Englischen erzeugen alle drei Stile identische Ausgaben für disjunktive Listen. Andere Sprachen zeigen mehr Variation. Deutsch verwendet "oder" im langen Stil und kann im schmalen Stil abkürzen. Die Unterschiede werden in Sprachen mit mehreren Formalitätsebenen oder längeren Konjunktionswörtern deutlicher.
Der schmale Stil entfernt typischerweise Leerzeichen oder verwendet kürzere Konjunktionen, um Platz in eingeschränkten Layouts zu sparen. Verwenden Sie den langen Stil für Standardtext, den kurzen Stil für mäßig kompakte Anzeigen und den schmalen Stil für enge Platzbeschränkungen wie mobile Benutzeroberflächen oder kompakte Tabellen.
Wie disjunktive Listen in verschiedenen Sprachen erscheinen
Jede Sprache formatiert disjunktive Listen nach ihren eigenen Konventionen. Intl.ListFormat behandelt diese Unterschiede automatisch.
Englisch verwendet Kommas mit "or":
const en = new Intl.ListFormat("en", { type: "disjunction" });
console.log(en.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG, or SVG"
Spanisch verwendet Kommas mit "o" und kein Komma vor der letzten Konjunktion:
const es = new Intl.ListFormat("es", { type: "disjunction" });
console.log(es.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG o SVG"
Französisch verwendet Kommas mit "ou" und kein Komma vor der letzten Konjunktion:
const fr = new Intl.ListFormat("fr", { type: "disjunction" });
console.log(fr.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG ou SVG"
Deutsch verwendet Kommas mit "oder" und kein Komma vor der letzten Konjunktion:
const de = new Intl.ListFormat("de", { type: "disjunction" });
console.log(de.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG oder SVG"
Japanisch verwendet andere Interpunktion und Partikel:
const ja = new Intl.ListFormat("ja", { type: "disjunction" });
console.log(ja.format(["PNG", "JPEG", "SVG"]));
// "PNG、JPEG、またはSVG"
Chinesisch verwendet chinesische Interpunktionszeichen:
const zh = new Intl.ListFormat("zh", { type: "disjunction" });
console.log(zh.format(["PNG", "JPEG", "SVG"]));
// "PNG、JPEG或SVG"
Diese Beispiele zeigen, wie die API sich an die grammatikalischen und Interpunktionskonventionen jeder Sprache anpasst. Der gleiche Code funktioniert in allen Sprachen, wenn die entsprechende Locale angegeben wird.
Formatierung von Zahlungsoptionen
Zahlungsformulare präsentieren mehrere Zahlungsmethoden. Formatieren Sie diese mit disjunktiven Listen:
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."
Für internationale Anwendungen übergeben Sie die Locale des Benutzers:
const userLocale = navigator.language; // z.B. "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)}.`;
}
Dieser Ansatz funktioniert in Checkout-Flows, Zahlungsmethodenauswahl und jeder Schnittstelle, bei der Benutzer auswählen können, wie sie bezahlen möchten.
Formatierung von Datei-Upload-Beschränkungen
Datei-Upload-Komponenten geben an, welche Dateitypen das System akzeptiert:
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"
Dieses Muster funktioniert für Bild-Uploads, Dokumentübermittlungen und jede Dateieingabe mit Formatbeschränkungen.
Formatierung von Fehlerbehebungsvorschlägen
Fehlermeldungen schlagen oft mehrere Möglichkeiten zur Behebung eines Problems vor. Präsentieren Sie diese Vorschläge als disjunktive Listen:
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."
Die disjunktive Liste verdeutlicht, dass Benutzer nur eines der genannten Felder korrigieren müssen, nicht unbedingt alle.
Formatierung von Suchfilteralternativen
Suchoberflächen zeigen aktive Filter an. Wenn Filter Alternativen darstellen, verwenden Sie disjunktive Listen:
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"
Dies funktioniert für Kategoriefilter, Tag-Auswahlen und jede Filteroberfläche, bei der ausgewählte Werte Alternativen und keine Kombinationen darstellen.
Wiederverwendung von Formatierern für bessere Performance
Die Erstellung von Intl.ListFormat-Instanzen verursacht Overhead. Erstellen Sie Formatierer einmal und verwenden Sie sie wieder:
// Einmal auf Modulebene erstellen
const disjunctionFormatter = new Intl.ListFormat("en", { type: "disjunction" });
// In mehreren Funktionen wiederverwenden
function formatPaymentMethods(methods) {
return disjunctionFormatter.format(methods);
}
function formatFileTypes(types) {
return disjunctionFormatter.format(types);
}
function formatErrorSuggestions(suggestions) {
return disjunctionFormatter.format(suggestions);
}
Für Anwendungen, die mehrere Sprachen unterstützen, speichern Sie Formatierer in einem 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"
Dieses Muster reduziert die Initialisierungskosten und unterstützt gleichzeitig mehrere Sprachen in der gesamten Anwendung.
Verwendung von formatToParts für benutzerdefiniertes Rendering
Die Methode formatToParts() gibt ein Array von Objekten zurück, die jeden Teil der formatierten Liste repräsentieren. Dies ermöglicht benutzerdefinierte Formatierung:
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" }
// ]
Jeder Teil hat einen type und einen value. Der type ist entweder "element" für Listenelemente oder "literal" für Interpunktion und Konjunktionen.
Verwenden Sie dies, um verschiedene Stile auf Elemente und Literale anzuwenden:
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>"
Dieser Ansatz behält die sprachlich korrekte Interpunktion und Konjunktionen bei, während er eine benutzerdefinierte Darstellung auf die eigentlichen Elemente anwendet.
Browser-Unterstützung und Kompatibilität
Intl.ListFormat funktioniert in allen modernen Browsern seit April 2021. Die Unterstützung umfasst Chrome 72+, Firefox 78+, Safari 14.1+ und Edge 79+.
Überprüfen Sie die Unterstützung vor der Verwendung der API:
if (typeof Intl.ListFormat !== "undefined") {
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
return formatter.format(items);
} else {
// Fallback für ältere Browser
return items.join(", ");
}
Für eine breitere Kompatibilität verwenden Sie einen Polyfill wie @formatjs/intl-listformat. Installieren Sie ihn nur dort, wo er benötigt wird:
if (typeof Intl.ListFormat === "undefined") {
await import("@formatjs/intl-listformat/polyfill");
}
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
Angesichts der aktuellen Browser-Unterstützung können die meisten Anwendungen Intl.ListFormat direkt ohne Polyfills verwenden.
Häufige Fehler, die vermieden werden sollten
Die Verwendung des Konjunktionstyps anstelle der Disjunktion führt zu einer falschen Bedeutung:
// Falsch: deutet an, dass alle Methoden erforderlich sind
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"
// Richtig: deutet an, dass eine Methode ausgewählt werden soll
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"
Das wiederholte Erstellen neuer Formatter verschwendet Ressourcen:
// Ineffizient
function formatOptions(options) {
return new Intl.ListFormat("en", { type: "disjunction" }).format(options);
}
// Effizient
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
function formatOptions(options) {
return formatter.format(options);
}
Das Hardcoding von "oder" in Strings verhindert die Lokalisierung:
// Funktioniert in anderen Sprachen nicht
const text = items.join(", ") + ", or other options";
// Funktioniert in allen Sprachen
const formatter = new Intl.ListFormat(userLocale, { type: "disjunction" });
const allItems = [...items, "other options"];
const text = formatter.format(allItems);
Das Nichtbehandeln leerer Arrays kann zu unerwarteten Ausgaben führen:
// Defensiv
function formatPaymentMethods(methods) {
if (methods.length === 0) {
return "No payment methods available";
}
return formatter.format(methods);
}
Obwohl format([]) einen leeren String zurückgibt, verbessert die explizite Behandlung des leeren Zustands die Benutzererfahrung.
Wann disjunktive Listen zu verwenden sind
Verwenden Sie disjunktive Listen, wenn Sie Alternativen oder Auswahlmöglichkeiten präsentieren, bei denen typischerweise eine Option zutrifft. Dies umfasst die Auswahl von Zahlungsmethoden, Einschränkungen bei Dateiformaten, Vorschläge bei Authentifizierungsfehlern, Suchfilteroptionen und die Auswahl von Kontotypen.
Verwenden Sie keine disjunktiven Listen, wenn alle Elemente zusammen gelten müssen. Verwenden Sie stattdessen Konjunktionslisten. Zum Beispiel verwendet "Name, E-Mail und Passwort sind erforderlich" eine Konjunktion, weil alle Felder angegeben werden müssen, nicht nur eines.
Verwenden Sie keine disjunktiven Listen für neutrale Aufzählungen ohne Auswahlimplikationen. Messungen und technische Spezifikationen verwenden typischerweise Einheitenlisten anstelle von Disjunktion oder Konjunktion.
Die API ersetzt manuelle String-Verkettungsmuster für Alternativen. Jedes Mal, wenn Sie Code schreiben würden, der Elemente mit "oder" für benutzerorientierten Text verbindet, sollten Sie überlegen, ob Intl.ListFormat mit dem Typ disjunction eine bessere Lokalisierungsunterstützung bietet.