i18n-Pluralisierung: CLDR-Pluralregeln, i18next & ICU (Guide 2026)
Pluralisierung ist einer der am meisten unterschätzten Teile der Internationalisierung. Im Englischen wirkt sie trivial, ein Element gegenüber zwei Elementen, sodass die meisten Codebasen mit etwas wie count === 1 ? 'item' : 'items' beginnen. Diese eine Zeile ist in den meisten Sprachen der Welt ein Bug.
Dieser Guide erklärt, wie Plurale über die Sprachen hinweg tatsächlich funktionieren (via CLDR), wie i18next sie umsetzt, und die Handvoll Fehler, die Plural-Ausgaben in Produktion still kaputtmachen.
Inhaltsverzeichnis
- Warum Pluralisierung schwierig ist
- CLDR-Pluralkategorien
- Wie i18next Plurale behandelt
- Den count interpolieren
- i18next v3 vs. v4 Plurale
- Ordinale Plurale (1st, 2nd, 3rd)
- ICU-MessageFormat-Plurale
- Häufige Fehler
- Plurale über Sprachen hinweg verwalten
- Häufig gestellte Fragen
Warum Pluralisierung schwierig ist
Englisch hat zwei Pluralformen: Singular (1 item) und Plural (0 items, 2 items, 100 items). Diese Zweiteilung ist die Ausnahme, nicht die Regel.
- Japanisch, Chinesisch, Koreanisch: eine Form. Substantive ändern sich nicht mit der Menge.
- Französisch: Der Singular deckt 0 und 1 ab, der Plural den Rest, plus eine separate Form für große formatierte Zahlen.
- Polnisch, Russisch, Ukrainisch: Die Form für 2, 3, 4 unterscheidet sich von der für 5-21, die sich wiederum von 22-24 unterscheidet.
- Arabisch: sechs verschiedene Formen, inklusive eigener Formen für 0, 1 und 2.
Das lässt sich nicht mit if (count === 1) ausdrücken. Die Regeln sind sprachspezifisch, nicht offensichtlich und von Linguisten definiert, nicht von Entwicklern. Dieses standardisierte Regelwerk ist CLDR.
CLDR-Pluralkategorien
Das Unicode CLDR definiert bis zu sechs Pluralkategorien. Jede Sprache ordnet jede Zahl genau einer davon zu:
| Kategorie | Bedeutung (variiert je nach Sprache) |
|---|---|
zero | Menge 0 (nur einige Sprachen) |
one | singularartige Menge |
two | Dual (nur einige Sprachen) |
few | kleine Menge (sprachspezifisch) |
many | große Menge (sprachspezifisch) |
other | Auffangkategorie / allgemeiner Plural |
Wie viele eine Sprache tatsächlich nutzt:
| Sprache | Verwendete Kategorien | Anzahl |
|---|---|---|
| Japanisch, Chinesisch, Koreanisch | other | 1 |
| Englisch, Deutsch, Spanisch, Italienisch | one, other | 2 |
| Französisch | one, many, other | 3 |
| Polnisch, Russisch, Ukrainisch | one, few, many, other | 4 |
| Arabisch, Walisisch | zero, one, two, few, many, other | 6 |
Die gute Nachricht: Sie müssen sich das nicht merken. Der Browser bringt es mit. Intl.PluralRules liefert für jede Zahl und Locale die richtige Kategorie:
new Intl.PluralRules('en').select(1) // "one"
new Intl.PluralRules('en').select(2) // "other"
new Intl.PluralRules('pl').select(2) // "few"
new Intl.PluralRules('pl').select(5) // "many"
new Intl.PluralRules('ar').select(0) // "zero"Wie i18next Plurale behandelt
i18next v4 baut direkt auf Intl.PluralRules auf. Sie fügen pro benötigter Pluralkategorie einen JSON-Schlüssel hinzu und nutzen den Kategorienamen als Suffix:
{
"item_one": "{{count}} item",
"item_other": "{{count}} items"
}Dann rufen Sie t() mit einem count auf:
t('item', { count: 1 }) // "1 item"
t('item', { count: 5 }) // "5 items"i18next führt Intl.PluralRules(lng).select(count) aus, erhält die Kategorie (one, other, …) und löst item_<category> auf. Für eine Sprache, die mehr Formen braucht, stellen Sie einfach mehr Schlüssel bereit. Polnisch:
{
"item_one": "{{count}} produkt",
"item_few": "{{count}} produkty",
"item_many": "{{count}} produktów",
"item_other": "{{count}} produktu"
}Im Code schreiben Sie denselben t('item', { count })-Aufruf; die richtige Form wird je nach aktiver Sprache gewählt. Genau das ist der Sinn der i18n-Pluralisierung: Die Logik lebt in den Daten, nicht in Ihren Komponenten.
Den count interpolieren
count dient zugleich als Interpolations-Wert, sodass {{count}} die Zahl in den String einsetzt:
{ "cart_one": "You have {{count}} item in your cart", "cart_other": "You have {{count}} items in your cart" }Das Formatieren der Zahl (Tausendertrennzeichen usw.) ist ein separates, locale-abhängiges Thema und wird mit i18nexts format-Funktion oder Intl.NumberFormat erledigt. Behalten Sie Übersetzungsdateien als .json; siehe die Referenz JSON-Übersetzungsdateien für Struktur-Konventionen.
i18next v3 vs. v4 Plurale
Wenn Sie ältere Tutorials lesen oder ein Legacy-Projekt pflegen, sieht das Pluralformat anders aus. Das ist die mit Abstand häufigste Ursache für „meine Plurale funktionieren nicht mehr":
| i18next v3 | i18next v4 (aktuell) | |
|---|---|---|
| Sprachen mit zwei Formen | key + key_plural | key_one + key_other |
| Sprachen mit mehreren Formen | key_0, key_1, key_2, … | key_one, key_few, key_many, key_other |
| Quelle der Regeln | gebündelte JSON-Regeln | natives Intl.PluralRules |
v4-Schlüssel sind selbsterklärend (das Suffix benennt die Kategorie) und bündeln keine Pluralregeltabelle mehr, was die Runtime kleiner hält. Ein v3-Projekt zu migrieren ist ein mechanisches Umbenennen; der offizielle Migrations-Guide und i18next-cli decken das ab.
Ordinale Plurale (1st, 2nd, 3rd)
Kardinalplurale (1 item) und Ordinalplurale (1st place) nutzen unterschiedliche CLDR-Regeln. i18next unterstützt Ordinalzahlen mit dem ordinal-Flag und _ordinal_*-Schlüsseln:
{
"place_ordinal_one": "{{count}}st place",
"place_ordinal_two": "{{count}}nd place",
"place_ordinal_few": "{{count}}rd place",
"place_ordinal_other": "{{count}}th place"
}t('place', { count: 1, ordinal: true }) // "1st place"
t('place', { count: 3, ordinal: true }) // "3rd place"
t('place', { count: 11, ordinal: true }) // "11th place"ICU-MessageFormat-Plurale
Wenn Sie einen einzelnen Inline-String gegenüber suffixierten Schlüsseln bevorzugen, ergänzt das Plugin i18next-icu ICU-MessageFormat-Unterstützung:
{ "item": "{count, plural, one {# item} other {# items}}" }Beide Stile lösen unter der Haube zu denselben CLDR-Kategorien auf. Suffixierte Schlüssel sind der i18next-Standard (einfachere Diffs, ein String pro Form); ICU hält alles in einem String (dichter, vertraut für Teams, die von FormatJS/react-intl kommen). Wählen Sie einen und bleiben Sie konsistent.
ICU selbst wird von MessageFormat 2 (MF2) abgelöst, dem neuen Unicode-Standard (Final Candidate seit 2025), der Plurale über explizite .match-Selektoren ausdrückt und Kombinationen aus Genus und Plural sauberer behandelt. Die Verbreitung ist noch sehr gering, daher ist es noch nicht der pragmatische Standard. Ob sich der Einsatz heute lohnt, lesen Sie in MessageFormat 2 in i18next: Stand der Migration.
Wie sich i18nexts Format zu ICU, Fluent, Gettext und dem Rest des JS-Ökosystems verhält, zeigt I18N in the Multiverse of Formats.
Häufige Fehler
countals String übergeben.t('item', { count: '5' })wählt nicht korrekt aus.Intl.PluralRulesbraucht eine Zahl.- Fehlende Kategorien. Nur
_oneund_otherfür eine Sprache bereitzustellen, die_fewund_manybraucht (Polnisch, Russisch), fällt still zurück und liest sich für Muttersprachler falsch. - v3/v4-Format-Mismatch. JSON im alten
key_plural/key_0-Format gegen eine v4-Runtime (oder umgekehrt) löst zum Basisschlüssel oder zu nichts auf. Siehe v3 vs. v4. - Englische Regeln überall annehmen.
0ist im Englischen_other, im Arabischen aber_zero. Behandeln Siecount === 0nicht global als Sonderfall. - Ressourcen noch nicht geladen. Wenn Übersetzungen asynchron laden und Sie rendern, bevor sie ankommen, sehen Sie rohe Schlüssel, unabhängig von Pluralen. Siehe Übersetzungen werden nicht geladen.
Aktivieren Sie debug: true in Ihrer i18next-Konfiguration, um bei jedem Aufruf zu protokollieren, welcher Schlüssel aufgelöst wurde.
Plurale über Sprachen hinweg verwalten
Der schwierige Teil ist nicht der Code, sondern das richtige Set an Pluralformen für jede Sprache gefüllt zu halten. Wenn Sie Arabisch hinzufügen, müssen plötzlich sechs Formen pro pluralisiertem Schlüssel übersetzt werden; fügen Sie Japanisch hinzu, sind fünf davon überflüssig.
Genau hier verdient sich ein Translation-Management-System seinen Platz. Locize ist um das i18next-Pluralmodell herum gebaut:
- Der Editor zeigt genau die Pluralformen, die jede Sprache benötigt, nicht mehr und nicht weniger, sodass Übersetzer
_fewfür Polnisch nicht übersehen oder_twofür Arabisch nicht leer lassen. - Plural-bewusste Validierung markiert Schlüssel, bei denen eine erforderliche Kategorie fehlt.
- Neue Schlüssel, die via saveMissing hinzukommen, erhalten das korrekte Plural-Gerüst, bereit für menschliche oder KI-Übersetzung.
Bringen Sie die CLDR-Regeln einmal in Ordnung, und eine Sprache hinzuzufügen wird zur Übersetzungsaufgabe statt zur Engineering-Aufgabe, was das eigentliche Ziel von i18n ist.
Häufig gestellte Fragen
Sie rufen t(key, { count }) auf, und i18next hängt anhand der CLDR-Pluralkategorie dieses count für die aktive Sprache ein Suffix an, mithilfe des browsereigenen Intl.PluralRules. Im Englischen sind das ein _one- und ein _other-Schlüssel; in anderen Sprachen können es bis zu sechs Schlüssel sein (_zero, _one, _two, _few, _many, _other). Sie schreiben nie selbst eine count === 1-Logik.
CLDR (das Unicode Common Locale Data Repository) definiert bis zu sechs Pluralkategorien: zero, one, two, few, many und other. Jede Sprache nutzt eine Teilmenge. Englisch verwendet one und other; Polnisch one, few, many, other; Arabisch alle sechs; Japanisch und Chinesisch nur other. Intl.PluralRules liefert für jede Zahl und Locale die richtige Kategorie.
Zwischen einer und sechs. Japanisch, Chinesisch und Koreanisch haben eine (kein grammatischer Plural). Englisch, Deutsch, Spanisch und die meisten westeuropäischen Sprachen haben zwei. Französisch hat drei. Slawische Sprachen wie Polnisch und Russisch haben vier. Arabisch und Walisisch haben sechs. Deshalb scheitert eine boolesche Singular/Plural-Prüfung außerhalb des Englischen.
i18next v4 wechselte von numerischen Suffixen (key_0, key_1, key_2) und key_plural zu den CLDR-Kategorienamen (key_one, key_two, key_few, key_many, key_other), angetrieben von Intl.PluralRules. Damit sind Plural-Schlüssel selbsterklärend und konsistent mit dem Rest der Plattform. Bestehende v3-Projekte lassen sich mit dem offiziellen Migrations-Tooling umstellen.
Die üblichen Ursachen: Sie haben count als String statt als Zahl übergeben; dem Schlüssel fehlt das richtige CLDR-Suffix für die aktive Sprache (z. B. nur _one und _other, obwohl die Sprache _few und _many braucht); Ihr JSON ist noch im i18next-v3-Format, während die Runtime v4 ist (oder umgekehrt); oder die Sprachressourcen sind noch nicht fertig geladen. Aktivieren Sie debug: true, um zu sehen, welchen Schlüssel i18next aufgelöst hat.
Ja. Übergeben Sie ordinal: true an t() und stellen Sie Ordinal-Schlüssel bereit (key_ordinal_one, key_ordinal_two, key_ordinal_few, key_ordinal_other). Im Englischen entsprechen sie 1st, 2nd, 3rd und 4th+. i18next nutzt Intl.PluralRules mit dem Typ "ordinal", um die richtige Form zu wählen.
Ja, über das Plugin i18next-icu. Damit können Sie ICU-Syntax wie {count, plural, one {# item} other {# items}} inline in einem einzigen String schreiben, statt suffixierte Schlüssel zu verwenden. Beide Ansätze nutzen dieselben zugrunde liegenden CLDR-Regeln; suffixierte Schlüssel sind der i18next-Standard, ICU ist optional.
Für Sprachen, deren CLDR-Regeln eine zero-Kategorie enthalten (Arabisch, Lettisch, Walisisch), definieren Sie einen _zero-Schlüssel; er wird für count 0 automatisch verwendet. Für Sprachen ohne zero-Kategorie (wie Englisch, wo 0 zu _other aufgelöst wird) fügen Sie einen expliziten _zero-Schlüssel für eine dedizierte „Keine Einträge"-Meldung hinzu oder verzweigen vor dem t()-Aufruf über count === 0.