Intl.PluralRules API
Wie man Pluralformen in JavaScript korrekt handhabt
Einführung
Pluralisierung ist der Prozess, unterschiedliche Texte basierend auf einer Anzahl anzuzeigen. Im Englischen würde man "1 item" für einen einzelnen Gegenstand und "2 items" für mehrere Gegenstände anzeigen. Die meisten Entwickler handhaben dies mit einer einfachen Bedingung, die ein "s" für Anzahlen ungleich eins hinzufügt.
Dieser Ansatz funktioniert nicht für andere Sprachen als Englisch. Polnisch verwendet unterschiedliche Formen für 1, 2-4 und 5 oder mehr. Arabisch hat Formen für null, eins, zwei, wenige und viele. Walisisch hat sechs verschiedene Formen. Selbst im Englischen erfordern unregelmäßige Plurale wie "person" zu "people" eine spezielle Behandlung.
Die Intl.PluralRules API löst dies, indem sie die Pluralformkategorie für jede Zahl in jeder Sprache bereitstellt. Sie geben eine Anzahl an, und die API teilt Ihnen mit, welche Form basierend auf den Regeln der Zielsprache zu verwenden ist. Dies ermöglicht es Ihnen, internationalisierungsbereiten Code zu schreiben, der sprachübergreifend korrekt funktioniert, ohne manuell sprachspezifische Regeln zu kodieren.
Wie Sprachen Pluralformen handhaben
Sprachen unterscheiden sich stark darin, wie sie Mengen ausdrücken. Englisch hat zwei Formen: Singular für eins, Plural für alles andere. Dies erscheint unkompliziert, bis man auf Sprachen mit unterschiedlichen Systemen trifft.
Russisch und Polnisch verwenden drei Formen. Der Singular gilt für einen Gegenstand. Eine spezielle Form gilt für Anzahlen, die auf 2, 3 oder 4 enden (aber nicht 12, 13 oder 14). Alle anderen Anzahlen verwenden eine dritte Form.
Arabisch verwendet sechs Formen: null, eins, zwei, wenige (3-10), viele (11-99) und andere (100+). Walisisch hat ebenfalls sechs Formen mit unterschiedlichen numerischen Grenzen.
Einige Sprachen wie Chinesisch und Japanisch unterscheiden überhaupt nicht zwischen Singular und Plural. Dieselbe Form funktioniert für jede Anzahl.
Die Intl.PluralRules-API abstrahiert diese Unterschiede mithilfe standardisierter Kategorienamen basierend auf Unicode CLDR-Pluralregeln. Die sechs Kategorien sind: zero, one, two, few, many und other. Nicht jede Sprache verwendet alle sechs Kategorien. Englisch verwendet nur one und other. Arabisch verwendet alle sechs.
Eine PluralRules-Instanz für ein Gebietsschema erstellen
Der Intl.PluralRules-Konstruktor nimmt einen Gebietsschema-Identifikator entgegen und gibt ein Objekt zurück, das bestimmen kann, welche Pluralkategorie auf eine gegebene Zahl zutrifft.
const enRules = new Intl.PluralRules('en-US');
Erstellen Sie eine Instanz pro Gebietsschema und verwenden Sie diese wieder. Das Erstellen einer neuen Instanz für jede Pluralisierung ist verschwenderisch. Speichern Sie die Instanz in einer Variablen oder verwenden Sie einen Caching-Mechanismus.
Der Standardtyp ist cardinal, der das Zählen von Objekten behandelt. Sie können auch Regeln für Ordinalzahlen erstellen, indem Sie ein Optionsobjekt übergeben.
const enOrdinalRules = new Intl.PluralRules('en-US', { type: 'ordinal' });
Kardinalregeln gelten für Zählungen wie "1 Apfel, 2 Äpfel". Ordinalregeln gelten für Positionen wie "1. Platz, 2. Platz".
select() verwenden, um die Pluralkategorie für eine Zahl zu erhalten
Die select()-Methode nimmt eine Zahl entgegen und gibt zurück, zu welcher Pluralkategorie sie in der Zielsprache gehört.
const enRules = new Intl.PluralRules('en-US');
enRules.select(0); // 'other'
enRules.select(1); // 'one'
enRules.select(2); // 'other'
enRules.select(5); // 'other'
Der Rückgabewert ist immer einer der sechs Kategorienamen: zero, one, two, few, many oder other. Englisch gibt nur one und other zurück, da dies die einzigen Formen sind, die Englisch verwendet.
Für Arabisch, das komplexere Regeln hat, sehen Sie alle sechs Kategorien im Einsatz:
const arRules = new Intl.PluralRules('ar-EG');
arRules.select(0); // 'zero'
arRules.select(1); // 'one'
arRules.select(2); // 'two'
arRules.select(6); // 'few'
arRules.select(18); // 'many'
arRules.select(100); // 'other'
Kategorien zu lokalisierten Strings zuordnen
Die API teilt Ihnen nur mit, welche Kategorie zutrifft. Sie stellen den tatsächlichen Text für jede Kategorie bereit. Speichern Sie die Textformen in einer Map oder einem Objekt, das nach Kategorienamen indiziert ist.
const enRules = new Intl.PluralRules('en-US');
const enForms = new Map([
['one', 'item'],
['other', 'items'],
]);
function formatItems(count) {
const category = enRules.select(count);
const form = enForms.get(category);
return `${count} ${form}`;
}
formatItems(1); // '1 item'
formatItems(5); // '5 items'
Dieses Muster trennt Logik von Daten. Die PluralRules-Instanz verarbeitet die Regeln. Die Map enthält die Übersetzungen. Die Funktion kombiniert sie.
Für Sprachen mit mehr Kategorien fügen Sie weitere Einträge zur Map hinzu:
const arRules = new Intl.PluralRules('ar-EG');
const arForms = new Map([
['zero', 'عناصر'],
['one', 'عنصر واحد'],
['two', 'عنصران'],
['few', 'عناصر'],
['many', 'عنصرًا'],
['other', 'عنصر'],
]);
function formatItems(count) {
const category = arRules.select(count);
const form = arForms.get(category);
return `${count} ${form}`;
}
Stellen Sie immer Einträge für jede Kategorie bereit, die die Sprache verwendet. Fehlende Kategorien führen zu undefinierten Lookups. Wenn Sie unsicher sind, welche Kategorien eine Sprache verwendet, prüfen Sie die Unicode CLDR-Pluralregeln oder testen Sie mit der API über verschiedene Zahlen hinweg.
Dezimal- und Bruchzahlen verarbeiten
Die select()-Methode funktioniert mit Dezimalzahlen. Englisch behandelt Dezimalzahlen als Plural, selbst für Werte zwischen 0 und 2.
const enRules = new Intl.PluralRules('en-US');
enRules.select(1); // 'one'
enRules.select(1.0); // 'one'
enRules.select(1.5); // 'other'
enRules.select(0.5); // 'other'
Andere Sprachen haben unterschiedliche Regeln für Dezimalzahlen. Einige behandeln jede Dezimalzahl als Plural, während andere differenziertere Regeln basierend auf dem Bruchteil verwenden.
Wenn Ihre Benutzeroberfläche Bruchmengen wie "1,5 GB" oder "2,7 Meilen" anzeigt, übergeben Sie die Bruchzahl direkt an select(). Runden Sie nicht zuerst, es sei denn, Ihre Benutzeroberfläche rundet den Anzeigewert.
Ordinalzahlen wie 1., 2., 3. formatieren
Ordinalzahlen geben Position oder Rang an. Englisch bildet Ordinalzahlen durch Hinzufügen von Suffixen: 1st, 2nd, 3rd, 4th. Das Muster ist nicht einfach "th hinzufügen", da 1, 2 und 3 spezielle Formen haben und Zahlen, die auf 1, 2 oder 3 enden, speziellen Regeln folgen (21st, 22nd, 23rd), außer wenn sie auf 11, 12 oder 13 enden (11th, 12th, 13th).
Die Intl.PluralRules-API verarbeitet diese Regeln, wenn Sie type: 'ordinal' angeben.
const enOrdinalRules = new Intl.PluralRules('en-US', { type: 'ordinal' });
enOrdinalRules.select(1); // 'one'
enOrdinalRules.select(2); // 'two'
enOrdinalRules.select(3); // 'few'
enOrdinalRules.select(4); // 'other'
enOrdinalRules.select(11); // 'other'
enOrdinalRules.select(21); // 'one'
enOrdinalRules.select(22); // 'two'
enOrdinalRules.select(23); // 'few'
Ordnen Sie die Kategorien den Ordinalsuffixen zu:
const enOrdinalRules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const enOrdinalSuffixes = new Map([
['one', 'st'],
['two', 'nd'],
['few', 'rd'],
['other', 'th'],
]);
function formatOrdinal(n) {
const category = enOrdinalRules.select(n);
const suffix = enOrdinalSuffixes.get(category);
return `${n}${suffix}`;
}
formatOrdinal(1); // '1st'
formatOrdinal(2); // '2nd'
formatOrdinal(3); // '3rd'
formatOrdinal(4); // '4th'
formatOrdinal(11); // '11th'
formatOrdinal(21); // '21st'
Andere Sprachen haben völlig unterschiedliche Ordinalsysteme. Französisch verwendet "1er" für den ersten und "2e" für alle anderen. Spanisch hat geschlechtsspezifische Ordinalzahlen. Die API liefert die Kategorie, und Sie stellen die lokalisierten Formen bereit.
Bereiche mit selectRange() verarbeiten
Die selectRange()-Methode bestimmt die Pluralkategorie für einen Zahlenbereich, wie "1-5 Elemente" oder "10-20 Ergebnisse". Einige Sprachen haben unterschiedliche Pluralregeln für Bereiche im Vergleich zu einzelnen Zählungen.
const enRules = new Intl.PluralRules('en-US');
enRules.selectRange(1, 5); // 'other'
enRules.selectRange(0, 1); // 'other'
Im Englischen stehen Bereiche fast immer im Plural, selbst wenn der Bereich bei 1 beginnt. Andere Sprachen haben komplexere Bereichsregeln.
const slRules = new Intl.PluralRules('sl');
slRules.selectRange(102, 201); // 'few'
const ptRules = new Intl.PluralRules('pt');
ptRules.selectRange(102, 102); // 'other'
Verwenden Sie selectRange(), wenn Sie Bereiche explizit in Ihrer Benutzeroberfläche anzeigen. Für einzelne Zählungen verwenden Sie select().
Kombination mit Intl.NumberFormat für lokalisierte Zahlenanzeige
Pluralformen erscheinen häufig zusammen mit formatierten Zahlen. Verwenden Sie Intl.NumberFormat, um die Zahl entsprechend den Konventionen der Locale zu formatieren, und verwenden Sie dann Intl.PluralRules, um den korrekten Text auszuwählen.
const locale = 'en-US';
const numberFormat = new Intl.NumberFormat(locale);
const pluralRules = new Intl.PluralRules(locale);
const forms = new Map([
['one', 'item'],
['other', 'items'],
]);
function formatCount(count) {
const formattedNumber = numberFormat.format(count);
const category = pluralRules.select(count);
const form = forms.get(category);
return `${formattedNumber} ${form}`;
}
formatCount(1); // '1 item'
formatCount(1000); // '1,000 items'
formatCount(1.5); // '1.5 items'
Für Deutsch, das Punkte als Tausendertrennzeichen und Kommas als Dezimaltrennzeichen verwendet:
const locale = 'de-DE';
const numberFormat = new Intl.NumberFormat(locale);
const pluralRules = new Intl.PluralRules(locale);
const forms = new Map([
['one', 'Artikel'],
['other', 'Artikel'],
]);
function formatCount(count) {
const formattedNumber = numberFormat.format(count);
const category = pluralRules.select(count);
const form = forms.get(category);
return `${formattedNumber} ${form}`;
}
formatCount(1); // '1 Artikel'
formatCount(1000); // '1.000 Artikel'
formatCount(1.5); // '1,5 Artikel'
Dieses Muster stellt sicher, dass sowohl die Zahlenformatierung als auch die Textform den Erwartungen der Benutzer für die Locale entsprechen.
Den Nullfall bei Bedarf explizit verarbeiten
Wie Null pluralisiert wird, variiert je nach Sprache. Englisch verwendet typischerweise die Pluralform: "0 items", "0 results". Einige Sprachen verwenden die Singularform für Null. Andere haben eine eigene Nullkategorie.
Die Intl.PluralRules-API gibt die entsprechende Kategorie für Null basierend auf den Sprachregeln zurück. Im Englischen gibt Null 'other' zurück, was der Pluralform entspricht:
const enRules = new Intl.PluralRules('en-US');
enRules.select(0); // 'other'
Im Arabischen hat die Null eine eigene Kategorie:
const arRules = new Intl.PluralRules('ar-EG');
arRules.select(0); // 'zero'
Ihr Text sollte dies berücksichtigen. Für Englisch möchten Sie möglicherweise "No items" anstelle von "0 items" anzeigen, um die Benutzererfahrung zu verbessern. Behandeln Sie dies, bevor Sie die Pluralregeln aufrufen:
function formatItems(count) {
if (count === 0) {
return 'No items';
}
const category = enRules.select(count);
const form = enForms.get(category);
return `${count} ${form}`;
}
Für Arabisch stellen Sie eine spezifische Nullform in Ihren Übersetzungen bereit:
const arForms = new Map([
['zero', 'لا توجد عناصر'],
['one', 'عنصر واحد'],
['two', 'عنصران'],
['few', 'عناصر'],
['many', 'عنصرًا'],
['other', 'عنصر'],
]);
Dies respektiert die linguistischen Konventionen jeder Sprache und ermöglicht es Ihnen gleichzeitig, den Nullfall für eine bessere Benutzererfahrung anzupassen.
PluralRules-Instanzen für bessere Performance wiederverwenden
Das Erstellen einer PluralRules-Instanz umfasst das Parsen der Locale und das Laden von Pluralregeldaten. Führen Sie dies einmal pro Locale durch, nicht bei jedem Funktionsaufruf oder Render-Zyklus.
// Good: create once, reuse
const enRules = new Intl.PluralRules('en-US');
const enForms = new Map([
['one', 'item'],
['other', 'items'],
]);
function formatItems(count) {
const category = enRules.select(count);
const form = enForms.get(category);
return `${count} ${form}`;
}
Wenn Sie mehrere Locales unterstützen, erstellen Sie Instanzen für jede Locale und speichern Sie diese in einer Map oder einem Cache:
const rulesCache = new Map();
function getPluralRules(locale) {
if (!rulesCache.has(locale)) {
rulesCache.set(locale, new Intl.PluralRules(locale));
}
return rulesCache.get(locale);
}
const rules = getPluralRules('en-US');
Dieses Muster amortisiert die Initialisierungskosten über viele Aufrufe hinweg.
Browser-Unterstützung und Kompatibilität
Intl.PluralRules wird seit 2019 in allen modernen Browsern unterstützt. Dazu gehören Chrome 63+, Firefox 58+, Safari 13+ und Edge 79+. Es wird nicht in Internet Explorer unterstützt.
Für Anwendungen, die auf moderne Browser abzielen, können Sie Intl.PluralRules ohne Polyfill verwenden. Wenn Sie ältere Browser unterstützen müssen, sind Polyfills über Pakete wie intl-pluralrules auf npm verfügbar.
Die selectRange()-Methode ist neuer und hat eine etwas eingeschränktere Unterstützung. Sie ist verfügbar in Chrome 106+, Firefox 116+, Safari 15.4+ und Edge 106+. Überprüfen Sie die Kompatibilität, wenn Sie selectRange() verwenden und ältere Browserversionen unterstützen müssen.
Vermeiden Sie das Hardcodieren von Pluralformen in der Logik
Überprüfen Sie nicht die Anzahl und verzweigen Sie im Code, um eine Pluralform auszuwählen. Dieser Ansatz skaliert nicht für Sprachen mit mehr als zwei Formen und koppelt Ihre Logik an englische Regeln.
// Avoid this pattern
function formatItems(count) {
if (count === 1) {
return `${count} item`;
}
return `${count} items`;
}
Verwenden Sie Intl.PluralRules und eine Datenstruktur zur Speicherung von Formen. Dies hält Ihren Code sprachunabhängig und erleichtert das Hinzufügen neuer Sprachen durch Bereitstellung neuer Übersetzungen.
// Prefer this pattern
const rules = new Intl.PluralRules('en-US');
const forms = new Map([
['one', 'item'],
['other', 'items'],
]);
function formatItems(count) {
const category = rules.select(count);
const form = forms.get(category);
return `${count} ${form}`;
}
Dieses Muster funktioniert für jede Sprache identisch. Nur die rules-Instanz und die forms-Map ändern sich.
Mit mehreren Locales und Grenzfällen testen
Pluralregeln haben Grenzfälle, die leicht übersehen werden, wenn nur auf Englisch getestet wird. Testen Sie Ihre Pluralisierungslogik mit mindestens einer Sprache, die mehr als zwei Formen verwendet, wie Polnisch oder Arabisch.
Testen Sie Zählwerte, die verschiedene Kategorien auslösen:
- Null
- Eins
- Zwei
- Einige (3-10 im Arabischen)
- Viele (11-99 im Arabischen)
- Große Zahlen (100+)
- Dezimalwerte (0,5, 1,5, 2,3)
- Negative Zahlen, falls Ihre Benutzeroberfläche diese anzeigt
Wenn Sie Ordinalregeln verwenden, testen Sie Zahlen, die verschiedene Suffixe auslösen: 1, 2, 3, 4, 11, 21, 22, 23. Dies stellt sicher, dass Sie die Sonderfälle korrekt behandeln.
Das frühzeitige Testen mit mehreren Locales verhindert Überraschungen, wenn Sie später neue Sprachen hinzufügen. Es validiert auch, dass Ihre Datenstruktur alle notwendigen Kategorien enthält und dass Ihre Logik diese korrekt verarbeitet.