Wie wählt man die richtige Pluralform für verschiedene Sprachen?
Verwenden Sie JavaScript's Intl.PluralRules, um zwischen einem Element, zwei Elementen, wenigen Elementen und vielen Elementen basierend auf sprachspezifischen Regeln zu unterscheiden
Einführung
Wenn Sie Text mit Mengenangaben anzeigen, benötigen Sie unterschiedliche Nachrichten für verschiedene Anzahlen. Im Englischen schreibt man "1 file" aber "2 files". Der einfachste Ansatz verkettet eine Zahl mit einem Wort und fügt bei Bedarf ein "s" hinzu.
function formatFileCount(count) {
return count === 1 ? `${count} file` : `${count} files`;
}
Dieser Ansatz scheitert in dreifacher Hinsicht. Erstens erzeugt er falsches Englisch für Null ("0 files" sollte argumentierbar "no files" sein). Zweitens funktioniert er nicht bei komplexen Pluralformen wie "1 child, 2 children" oder "1 person, 2 people". Drittens und am kritischsten: Andere Sprachen haben völlig unterschiedliche Pluralregeln, die dieser Code nicht verarbeiten kann.
JavaScript bietet Intl.PluralRules, um dieses Problem zu lösen. Diese API bestimmt, welche Pluralform für jede Zahl in jeder Sprache zu verwenden ist, gemäß dem Unicode CLDR-Standard, der von professionellen Übersetzungssystemen weltweit verwendet wird.
Warum verschiedene Sprachen unterschiedliche Pluralformen benötigen
Englisch verwendet zwei Pluralformen. Man schreibt "1 book" und "2 books". Das Wort ändert sich, wenn die Anzahl genau eins ist, im Gegensatz zu jeder anderen Zahl.
Andere Sprachen funktionieren anders. Polnisch verwendet drei Formen basierend auf komplexen Regeln. Russisch verwendet vier Formen. Arabisch verwendet sechs Formen. Einige Sprachen verwenden nur eine Form für alle Mengen.
Hier sind Beispiele, die zeigen, wie sich das Wort für "Apfel" je nach Menge in verschiedenen Sprachen ändert:
Englisch: 1 apple, 2 apples, 5 apples, 0 apples
Polnisch: 1 jabłko, 2 jabłka, 5 jabłek, 0 jabłek
Russisch: 1 яблоко, 2 яблока, 5 яблок, 0 яблок
Arabisch: Verwendet sechs verschiedene Formen, abhängig davon, ob Sie null, eins, zwei, einige, viele oder andere Mengen haben
Das Unicode CLDR definiert die genauen Regeln, wann jede Form in jeder Sprache zu verwenden ist. Sie können diese Regeln nicht auswendig lernen oder in Ihre Anwendung fest einprogrammieren. Sie benötigen eine API, die diese kennt.
Was sind CLDR-Pluralkategorien
Der Unicode CLDR-Standard definiert sechs Pluralkategorien, die alle Sprachen abdecken:
zero: Wird in einigen Sprachen für genau null Elemente verwendetone: Wird für Singularformen verwendettwo: Wird in Sprachen mit Dualform verwendetfew: Wird in einigen Sprachen für kleine Mengen verwendetmany: Wird für größere Mengen oder Bruchteile in einigen Sprachen verwendetother: Die Standardform, die verwendet wird, wenn keine andere Kategorie zutrifft
Jede Sprache verwendet die Kategorie other. Die meisten Sprachen verwenden insgesamt nur zwei oder drei Kategorien. Die Kategorien entsprechen nicht direkt den Mengen. Zum Beispiel verwendet im Polnischen die Zahl 5 die Kategorie many, aber auch 0, 25 und 1,5.
Die spezifischen Regeln, welche Zahlen zu welchen Kategorien gehören, unterscheiden sich je nach Sprache. JavaScript behandelt diese Komplexität durch die Intl.PluralRules API.
Wie man bestimmt, welche Pluralform zu verwenden ist
Das Intl.PluralRules-Objekt bestimmt, zu welcher Pluralkategorie eine Zahl in einer bestimmten Sprache gehört. Sie erstellen ein PluralRules-Objekt mit einem Gebietsschema und rufen dann dessen select()-Methode mit einer Zahl auf.
const rules = new Intl.PluralRules('en-US');
console.log(rules.select(0)); // "other"
console.log(rules.select(1)); // "one"
console.log(rules.select(2)); // "other"
console.log(rules.select(5)); // "other"
Im Englischen gibt select() für die Zahl 1 "one" zurück und für alles andere "other".
Polnisch verwendet drei Kategorien mit komplexeren Regeln:
const rules = new Intl.PluralRules('pl-PL');
console.log(rules.select(0)); // "many"
console.log(rules.select(1)); // "one"
console.log(rules.select(2)); // "few"
console.log(rules.select(5)); // "many"
console.log(rules.select(22)); // "few"
console.log(rules.select(25)); // "many"
Arabisch verwendet sechs Kategorien:
const rules = new Intl.PluralRules('ar-EG');
console.log(rules.select(0)); // "zero"
console.log(rules.select(1)); // "one"
console.log(rules.select(2)); // "two"
console.log(rules.select(3)); // "few"
console.log(rules.select(11)); // "many"
console.log(rules.select(100)); // "other"
Die select()-Methode gibt eine Zeichenfolge zurück, die die Kategorie identifiziert. Sie verwenden diese Zeichenfolge, um die entsprechende Nachricht für die Anzeige auszuwählen.
Wie man Pluralkategorien auf Nachrichten abbildet
Nach der Bestimmung der Pluralkategorie müssen Sie die korrekte Nachricht auswählen, die dem Benutzer angezeigt werden soll. Erstellen Sie ein Objekt, das jede Kategorie ihrer Nachricht zuordnet, und verwenden Sie dann den Kategorie-String, um die Nachricht nachzuschlagen.
const messages = {
one: '{count} file',
other: '{count} files'
};
function formatFileCount(count, locale) {
const rules = new Intl.PluralRules(locale);
const category = rules.select(count);
const message = messages[category];
return message.replace('{count}', count);
}
console.log(formatFileCount(1, 'en-US')); // "1 file"
console.log(formatFileCount(5, 'en-US')); // "5 files"
Dieses Muster funktioniert für jede Sprache. Für Polnisch stellen Sie Nachrichten für alle drei Kategorien bereit, die die Sprache verwendet:
const messages = {
one: '{count} plik',
few: '{count} pliki',
many: '{count} plików'
};
function formatFileCount(count, locale) {
const rules = new Intl.PluralRules(locale);
const category = rules.select(count);
const message = messages[category];
return message.replace('{count}', count);
}
console.log(formatFileCount(1, 'pl-PL')); // "1 plik"
console.log(formatFileCount(2, 'pl-PL')); // "2 pliki"
console.log(formatFileCount(5, 'pl-PL')); // "5 plików"
console.log(formatFileCount(22, 'pl-PL')); // "22 pliki"
Die Codestruktur bleibt über alle Sprachen hinweg identisch. Nur das messages-Objekt ändert sich. Diese Trennung ermöglicht es Übersetzern, die korrekten Nachrichten für ihre Sprache bereitzustellen, ohne den Code zu modifizieren.
Wie man fehlende Pluralkategorien behandelt
Ihr messages-Objekt enthält möglicherweise nicht alle sechs möglichen Kategorien. Die meisten Sprachen verwenden nur zwei oder drei. Wenn select() eine Kategorie zurückgibt, die nicht in Ihrem messages-Objekt enthalten ist, greifen Sie auf die Kategorie other zurück.
function formatFileCount(count, locale, messages) {
const rules = new Intl.PluralRules(locale);
const category = rules.select(count);
const message = messages[category] || messages.other;
return message.replace('{count}', count);
}
const englishMessages = {
one: '{count} file',
other: '{count} files'
};
console.log(formatFileCount(1, 'en-US', englishMessages)); // "1 file"
console.log(formatFileCount(5, 'en-US', englishMessages)); // "5 files"
Dieses Muster stellt sicher, dass Ihr Code auch dann funktioniert, wenn das messages-Objekt unvollständig ist. Die Kategorie other existiert immer in jeder Sprache, was sie zu einem sicheren Fallback macht.
So verwenden Sie Pluralregeln mit Ordnungszahlen
Der Intl.PluralRules-Konstruktor akzeptiert eine type-Option, die ändert, wie Kategorien bestimmt werden. Der Standardtyp ist "cardinal", der zum Zählen von Elementen verwendet wird. Setzen Sie type: "ordinal", um Pluralformen für Ordnungszahlen wie "1st", "2nd", "3rd" zu bestimmen.
const cardinalRules = new Intl.PluralRules('en-US', { type: 'cardinal' });
console.log(cardinalRules.select(1)); // "one"
console.log(cardinalRules.select(2)); // "other"
console.log(cardinalRules.select(3)); // "other"
const ordinalRules = new Intl.PluralRules('en-US', { type: 'ordinal' });
console.log(ordinalRules.select(1)); // "one"
console.log(ordinalRules.select(2)); // "two"
console.log(ordinalRules.select(3)); // "few"
console.log(ordinalRules.select(4)); // "other"
Kardinalregeln bestimmen "1 Element, 2 Elemente". Ordnungsregeln bestimmen "1. Platz, 2. Platz, 3. Platz, 4. Platz". Die zurückgegebenen Kategorien unterscheiden sich, da die grammatikalischen Muster unterschiedlich sind.
So formatieren Sie Bruchmengen
Die Methode select() funktioniert mit Dezimalzahlen. Verschiedene Sprachen haben spezifische Regeln dafür, wie Brüche Pluralkategorien zugeordnet werden.
const rules = new Intl.PluralRules('en-US');
console.log(rules.select(1)); // "one"
console.log(rules.select(1.0)); // "one"
console.log(rules.select(1.5)); // "other"
console.log(rules.select(0.5)); // "other"
Im Englischen verwendet 1.0 die Singularform, aber 1.5 die Pluralform. Einige Sprachen haben unterschiedliche Regeln für Brüche und behandeln sie als eigene Kategorie.
const messages = {
one: '{count} Datei',
other: '{count} Dateien'
};
const rules = new Intl.PluralRules('en-US');
const count = 1.5;
const category = rules.select(count);
const message = messages[category];
console.log(message.replace('{count}', count)); // "1.5 Dateien"
Übergeben Sie die Dezimalzahl direkt an select(). Die Methode wendet automatisch die korrekten Sprachregeln an.
So erstellen Sie einen wiederverwendbaren Plural-Formatter
Anstatt dasselbe Muster in Ihrer Anwendung zu wiederholen, erstellen Sie eine wiederverwendbare Funktion, die die Logik der Pluralauswahl kapselt.
class PluralFormatter {
constructor(locale) {
this.locale = locale;
this.rules = new Intl.PluralRules(locale);
}
format(count, messages) {
const category = this.rules.select(count);
const message = messages[category] || messages.other;
return message.replace('{count}', count);
}
}
const formatter = new PluralFormatter('en-US');
const fileMessages = {
one: '{count} Datei',
other: '{count} Dateien'
};
const itemMessages = {
one: '{count} Element',
other: '{count} Elemente'
};
console.log(formatter.format(1, fileMessages)); // "1 Datei"
console.log(formatter.format(5, fileMessages)); // "5 Dateien"
console.log(formatter.format(1, itemMessages)); // "1 Element"
console.log(formatter.format(3, itemMessages)); // "3 Elemente"
Diese Klasse erstellt das PluralRules-Objekt einmal und verwendet es für mehrere Formatierungsoperationen wieder. Sie können es erweitern, um fortgeschrittenere Funktionen zu unterstützen, wie z. B. das Formatieren der Anzahl mit Intl.NumberFormat, bevor sie in die Nachricht eingefügt wird.
Wie man Pluralregeln in Übersetzungssysteme integriert
Professionelle Übersetzungssysteme speichern Nachrichten mit Platzhaltern für Pluralkategorien. Wenn Sie Text übersetzen, stellen Sie alle Pluralformen bereit, die Ihre Sprache benötigt.
const translations = {
'en-US': {
fileCount: {
one: '{count} file',
other: '{count} files'
},
downloadComplete: {
one: 'Download of {count} file complete',
other: 'Download of {count} files complete'
}
},
'pl-PL': {
fileCount: {
one: '{count} plik',
few: '{count} pliki',
many: '{count} plików'
},
downloadComplete: {
one: 'Pobieranie {count} pliku zakończone',
few: 'Pobieranie {count} plików zakończone',
many: 'Pobieranie {count} plików zakończone'
}
}
};
class Translator {
constructor(locale, translations) {
this.locale = locale;
this.translations = translations[locale] || {};
this.rules = new Intl.PluralRules(locale);
}
translate(key, count) {
const messages = this.translations[key];
if (!messages) return key;
const category = this.rules.select(count);
const message = messages[category] || messages.other;
return message.replace('{count}', count);
}
}
const translator = new Translator('en-US', translations);
console.log(translator.translate('fileCount', 1)); // "1 file"
console.log(translator.translate('fileCount', 5)); // "5 files"
console.log(translator.translate('downloadComplete', 1)); // "Download of 1 file complete"
console.log(translator.translate('downloadComplete', 5)); // "Download of 5 files complete"
const polishTranslator = new Translator('pl-PL', translations);
console.log(polishTranslator.translate('fileCount', 1)); // "1 plik"
console.log(polishTranslator.translate('fileCount', 2)); // "2 pliki"
console.log(polishTranslator.translate('fileCount', 5)); // "5 plików"
Dieses Muster trennt Übersetzungsdaten von der Codelogik. Übersetzer stellen die Nachrichten für jede Pluralkategorie bereit, die ihre Sprache verwendet. Ihr Code wendet die Regeln automatisch an.
Wie man prüft, welche Pluralkategorien eine Locale verwendet
Die Methode resolvedOptions() gibt Informationen über das PluralRules-Objekt zurück, listet jedoch nicht auf, welche Kategorien die Locale verwendet. Um alle Kategorien zu finden, die eine Locale verwendet, testen Sie eine Reihe von Zahlen und sammeln Sie die zurückgegebenen eindeutigen Kategorien.
function getPluralCategories(locale) {
const rules = new Intl.PluralRules(locale);
const categories = new Set();
for (let i = 0; i <= 100; i++) {
categories.add(rules.select(i));
categories.add(rules.select(i + 0.5));
}
return Array.from(categories).sort();
}
console.log(getPluralCategories('en-US')); // ["one", "other"]
console.log(getPluralCategories('pl-PL')); // ["few", "many", "one"]
console.log(getPluralCategories('ar-EG')); // ["few", "many", "one", "other", "two", "zero"]
Diese Technik testet ganze Zahlen und Halbwerte über einen Bereich hinweg. Sie erfasst die Kategorien, die Ihr Nachrichtenobjekt für eine bestimmte Locale enthalten muss.