So formatieren Sie Listen mit oder in JavaScript
Verwenden Sie Intl.ListFormat mit Typ Disjunktion, um Alternativen in jeder Sprache korrekt zu formatieren
Einführung
Anwendungen präsentieren Nutzer:innen 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. Wenn Sie solche Listen manuell mit String-Verkettung formatieren, führt das in anderen Sprachen zu Fehlern, da verschiedene Sprachen unterschiedliche Zeichensetzungsregeln, verschiedene Wörter für „oder“ und unterschiedliche Kommaregeln haben. Die Intl.ListFormat-API mit dem Typ Disjunktion formatiert solche Alternativlisten in jeder Sprache korrekt.
Was disjunktive Listen sind
Eine disjunktive Liste präsentiert Alternativen, von denen in der Regel nur eine zutrifft. Das Wort „Disjunktion“ bedeutet Trennung oder Alternative. Im Deutschen (wie im Englischen) werden disjunktive Listen mit „oder“ als Konjunktion gebildet:
const paymentMethods = ["credit card", "debit card", "PayPal"];
// Desired output: "credit card, debit card, or PayPal"
Das unterscheidet sich von konjunktiven Listen, die mit „und“ anzeigen, dass alle Elemente gemeinsam gelten. Disjunktive Listen kommunizieren Auswahl, konjunktive Listen Kombination.
Typische Anwendungsfälle für disjunktive Listen sind Zahlungsoptionen, Dateiformatbeschränkungen, Fehlersuchvorschläge, alternative Suchfilter und jede Benutzeroberfläche, in der Nutzer:innen eine Option aus mehreren Möglichkeiten auswählen.
Warum manuelles Formatieren scheitert
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:
// Hardcoded English pattern
const items = ["apple", "orange", "banana"];
const text = items.slice(0, -1).join(", ") + ", or " + items[items.length - 1];
// "apple, orange, or banana"
Dieser Code erzeugt in Spanisch, Französisch, Deutsch und den meisten anderen Sprachen eine falsche Ausgabe. Jede Sprache hat eigene Regeln für die Formatierung disjunktiver Listen.
Spanisch verwendet „o" ohne Komma davor:
Expected: "manzana, naranja o plátano"
English pattern produces: "manzana, naranja, or plátano"
Französisch verwendet „ou" ohne Komma davor:
Expected: "pomme, orange ou banane"
English pattern produces: "pomme, orange, or banane"
Deutsch verwendet „oder" ohne Komma davor:
Expected: "Apfel, Orange oder Banane"
English pattern produces: "Apfel, Orange, or Banane"
Japanisch verwendet die Partikel „か
Expected: "りんご、オレンジ、またはバナナ"
English pattern produces: "りんご、オレンジ、 or バナナ"
Diese Unterschiede gehen über einfache Wortersetzung hinaus. Zeichensetzung, Abstandsregeln und grammatikalische Partikeln 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 nach sprachspezifischen Regeln. Setzen Sie die Option type auf "disjunction", um Alternativlisten 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 Formatter verarbeitet Arrays beliebiger 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 Zeichensetzung und Konjunktion für jeden Fall an.
Disjunktionsstile verstehen
Die Option style steuert die Formatierungsausführlichkeit. Es existieren 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ätsstufen 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 moderat kompakte Anzeigen und den schmalen Stil für enge Platzbeschränkungen wie mobile Oberflächen oder kompakte Tabellen.
Wie disjunktive Listen in verschiedenen Sprachen erscheinen
Jede Sprache formatiert disjunktive Listen nach ihren eigenen Konventionen. Intl.ListFormat berücksichtigt diese Unterschiede automatisch.
Im Englischen werden Kommas mit „or“ verwendet:
const en = new Intl.ListFormat("en", { type: "disjunction" });
console.log(en.format(["PNG", "JPEG", "SVG"]));
// "PNG, JPEG, or SVG"
Im Spanischen werden Kommas mit „o“ verwendet, jedoch 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"
Im Französischen werden Kommas mit „ou“ verwendet, jedoch 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"
Im Deutschen werden Kommas mit „oder“ verwendet, jedoch 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"
Im Japanischen werden andere Satzzeichen und Partikeln verwendet:
const ja = new Intl.ListFormat("ja", { type: "disjunction" });
console.log(ja.format(["PNG", "JPEG", "SVG"]));
// "PNG、JPEG、またはSVG"
Im Chinesischen werden chinesische Satzzeichen verwendet:
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 typografischen Konventionen jeder Sprache anpasst. Derselbe Code funktioniert in allen Sprachen, wenn Sie die passende Locale angeben.
Zahlungsoptionen formatieren
Zahlungsformulare bieten mehrere Zahlungsmethoden zur Auswahl an. 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 geben Sie die Locale des Nutzers an:
const userLocale = navigator.language; // e.g., "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-Prozessen, bei der Auswahl der Zahlungsmethode und in jeder Benutzeroberfläche, in der Nutzer auswählen, wie sie bezahlen möchten.
Formatierung von Dateiupload-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 eignet sich für Bild-Uploads, Dokumentenü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 eines der genannten Felder korrigieren müssen, nicht notwendigerweise alle.
Formatierung von Suchfilter-Alternativen
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 statt Kombinationen darstellen.
Wiederverwendung von Formatierern für Performance
Das Erstellen von Intl.ListFormat-Instanzen verursacht Overhead. Erstellen Sie Formatierer einmal und verwenden Sie sie wieder:
// Create once at module level
const disjunctionFormatter = new Intl.ListFormat("en", { type: "disjunction" });
// Reuse in multiple functions
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 Locales 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 Initialisierungskosten und unterstützt gleichzeitig mehrere Locales in der gesamten Anwendung.
Verwendung von formatToParts für benutzerdefiniertes Rendering
Die Methode formatToParts() gibt ein Array von Objekten zurück, die jedes Element der formatierten Liste repräsentieren. Dies ermöglicht benutzerdefiniertes Styling:
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 unterschiedliche 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 bewahrt locale-korrekte Interpunktion und Konjunktionen, während benutzerdefinierte Darstellung auf die tatsächlichen Elemente angewendet wird.
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+.
Prüfen Sie die Unterstützung, bevor Sie die API verwenden:
if (typeof Intl.ListFormat !== "undefined") {
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
return formatter.format(items);
} else {
// Fallback for older browsers
return items.join(", ");
}
Für breitere Kompatibilität verwenden Sie ein Polyfill wie @formatjs/intl-listformat. Installieren Sie es nur dort, wo es 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:
// Wrong: suggests all methods required
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: suggests choosing one method
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:
// Inefficient
function formatOptions(options) {
return new Intl.ListFormat("en", { type: "disjunction" }).format(options);
}
// Efficient
const formatter = new Intl.ListFormat("en", { type: "disjunction" });
function formatOptions(options) {
return formatter.format(options);
}
Das Hardcodieren von "oder" in Strings verhindert die Lokalisierung:
// Breaks in other languages
const text = items.join(", ") + ", or other options";
// Works across languages
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:
// Defensive
function formatPaymentMethods(methods) {
if (methods.length === 0) {
return "No payment methods available";
}
return formatter.format(methods);
}
Obwohl format([]) einen leeren String zurückgibt, verbessert eine explizite Behandlung des leeren Zustands die Benutzererfahrung.
Wann disjunktive Listen verwendet werden sollten
Verwenden Sie disjunktive Listen, wenn Sie Alternativen oder Auswahlmöglichkeiten präsentieren, bei denen typischerweise eine Option zutrifft. Dies umfasst die Auswahl von Zahlungsmethoden, Dateiformatbeschränkungen, Vorschläge bei Authentifizierungsfehlern, Suchfilteroptionen und Kontotypauswahl.
Verwenden Sie keine disjunktiven Listen, wenn alle Elemente zusammen zutreffen müssen. Verwenden Sie stattdessen konjunktive Listen. Zum Beispiel verwendet "Name, E-Mail und Passwort sind erforderlich" eine Konjunktion, da 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 Einheitslisten 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 benutzerseitigen Text verbindet, sollten Sie überlegen, ob Intl.ListFormat mit Disjunktionstyp eine bessere Locale-Unterstützung bietet.