Alle verfügbaren Pluralformen in einem Gebietsschema abrufen
Entdecken Sie, für welche Pluralkategorien Sie Übersetzungen bereitstellen müssen
Einführung
Beim Erstellen mehrsprachiger Anwendungen müssen Sie unterschiedliche Textformen für verschiedene Mengen bereitstellen. Im Englischen schreibt man "1 item" und "2 items". Das erscheint einfach, bis Sie beginnen, andere Sprachen zu unterstützen.
Russisch verwendet drei verschiedene Formen, abhängig von der Anzahl. Arabisch verwendet sechs. Einige Sprachen verwenden dieselbe Form für alle Anzahlen. Bevor Sie Übersetzungen für diese Formen bereitstellen können, müssen Sie wissen, welche Formen in jeder Sprache existieren.
JavaScript bietet eine Möglichkeit, herauszufinden, welche Pluralkategorien ein Gebietsschema verwendet. Die resolvedOptions()-Methode einer PluralRules-Instanz gibt eine pluralCategories-Eigenschaft zurück, die alle Pluralformen auflistet, die das Gebietsschema benötigt. Dies teilt Ihnen genau mit, welche Übersetzungen Sie bereitstellen müssen, ohne raten zu müssen oder sprachspezifische Regeltabellen pflegen zu müssen.
Was Pluralkategorien sind
Pluralkategorien sind standardisierte Bezeichnungen für verschiedene Pluralformen, die sprachübergreifend verwendet werden. Das Unicode CLDR (Common Locale Data Repository) definiert sechs Kategorien: zero, one, two, few, many und other.
Nicht jede Sprache verwendet alle sechs Kategorien. Englisch verwendet nur zwei: one und other. Die Kategorie one gilt für die Anzahl 1, und other gilt für alles andere.
Arabisch verwendet alle sechs Kategorien. Die Kategorie zero gilt für 0, one für 1, two für 2, few für Anzahlen wie 3-10, many für Anzahlen wie 11-99 und other für Anzahlen wie 100 und darüber.
Russisch verwendet drei Kategorien: one für Anzahlen, die auf 1 enden (außer 11), few für Anzahlen, die auf 2-4 enden (außer 12-14), und many für alles andere.
Japanisch und Chinesisch verwenden nur die Kategorie other, da diese Sprachen nicht zwischen Singular und Plural unterscheiden.
Diese Kategorien spiegeln die sprachlichen Regeln jeder Sprache wider. Wenn Sie Übersetzungen bereitstellen, erstellen Sie für jede von der Sprache verwendete Kategorie eine eigene Zeichenkette.
Pluralkategorien mit resolvedOptions abrufen
Die Methode resolvedOptions() auf einer PluralRules-Instanz gibt ein Objekt mit Informationen zu den Regeln zurück, einschließlich der Pluralkategorien, die die jeweilige Locale verwendet.
const enRules = new Intl.PluralRules('en-US');
const options = enRules.resolvedOptions();
console.log(options.pluralCategories);
// Output: ["one", "other"]
Die Eigenschaft pluralCategories ist ein Array von Zeichenketten. Jede Zeichenkette ist einer der sechs Standardkategorienamen. Das Array enthält nur die Kategorien, die die jeweilige Locale tatsächlich verwendet.
Für Englisch enthält das Array one und other, da Englisch zwischen Singular und Plural unterscheidet.
Für eine Sprache mit komplexeren Regeln enthält das Array mehr Kategorien:
const arRules = new Intl.PluralRules('ar-EG');
const options = arRules.resolvedOptions();
console.log(options.pluralCategories);
// Output: ["zero", "one", "two", "few", "many", "other"]
Arabisch verwendet alle sechs Kategorien, daher enthält das Array alle sechs Werte.
Pluralkategorien für verschiedene Locales anzeigen
Verschiedene Sprachen haben unterschiedliche Pluralregeln, das heißt, sie verwenden unterschiedliche Kategorien. Vergleichen Sie mehrere Sprachen, um die Unterschiede zu sehen:
const locales = ['en-US', 'ar-EG', 'ru-RU', 'pl-PL', 'ja-JP', 'zh-CN'];
locales.forEach(locale => {
const rules = new Intl.PluralRules(locale);
const categories = rules.resolvedOptions().pluralCategories;
console.log(`${locale}: [${categories.join(', ')}]`);
});
// Output:
// en-US: [one, other]
// ar-EG: [zero, one, two, few, many, other]
// ru-RU: [one, few, many, other]
// pl-PL: [one, few, many, other]
// ja-JP: [other]
// zh-CN: [other]
Englisch hat zwei Kategorien. Arabisch hat sechs. Russisch und Polnisch haben jeweils vier. Japanisch und Chinesisch haben nur eine, da sie keine Pluralformen unterscheiden.
Diese Unterschiede zeigen, warum Sie nicht davon ausgehen können, dass jede Sprache wie Englisch funktioniert. Sie müssen prüfen, welche Kategorien jede Locale verwendet, und für jede passende Übersetzungen bereitstellen.
Was die Kategorien für jede Locale bedeuten
Der gleiche Kategoriename bedeutet in verschiedenen Sprachen Unterschiedliches. Die Kategorie one gilt im Englischen nur für die Zahl 1. Im Russischen gilt one für Zahlen, die auf 1 enden, außer 11, also z. B. 1, 21, 31, 101 usw.
Testen Sie, welche Zahlen in verschiedenen Locales welchen Kategorien zugeordnet werden:
const enRules = new Intl.PluralRules('en-US');
const ruRules = new Intl.PluralRules('ru-RU');
const numbers = [0, 1, 2, 3, 5, 11, 21, 22, 100];
console.log('English:');
numbers.forEach(n => {
console.log(` ${n}: ${enRules.select(n)}`);
});
console.log('Russian:');
numbers.forEach(n => {
console.log(` ${n}: ${ruRules.select(n)}`);
});
// Output:
// English:
// 0: other
// 1: one
// 2: other
// 3: other
// 5: other
// 11: other
// 21: other
// 22: other
// 100: other
// Russian:
// 0: many
// 1: one
// 2: few
// 3: few
// 5: many
// 11: many
// 21: one
// 22: few
// 100: many
Im Englischen verwendet nur 1 die Kategorie one. Im Russischen verwenden sowohl 1 als auch 21 die Kategorie one, da sie auf 1 enden. Die Zahlen 2, 3 und 22 verwenden few, da sie auf 2-4 enden. Die Zahlen 0, 5, 11 und 100 verwenden many.
Dies zeigt, dass Sie nicht vorhersagen können, welche Kategorie auf eine Zahl zutrifft, ohne die Sprachregeln zu kennen. Das pluralCategories-Array gibt an, welche Kategorien existieren, und die select()-Methode gibt an, welche Kategorie auf jede Zahl zutrifft.
Kategorien für Ordinalzahlen abrufen
Ordinalzahlen wie 1., 2., 3. haben eigene Pluralregeln, die sich von Kardinalzahlen unterscheiden. Erstellen Sie eine PluralRules-Instanz mit type: 'ordinal', um die Kategorien für Ordinalzahlen zu erhalten:
const enCardinalRules = new Intl.PluralRules('en-US', { type: 'cardinal' });
const enOrdinalRules = new Intl.PluralRules('en-US', { type: 'ordinal' });
console.log('Cardinal:', enCardinalRules.resolvedOptions().pluralCategories);
// Output: Cardinal: ["one", "other"]
console.log('Ordinal:', enOrdinalRules.resolvedOptions().pluralCategories);
// Output: Ordinal: ["one", "two", "few", "other"]
Englische Kardinalzahlen verwenden zwei Kategorien. Englische Ordinalzahlen verwenden vier Kategorien, da Ordinalzahlen zwischen 1st, 2nd, 3rd und allen anderen unterscheiden müssen.
Die Ordinalkategorien entsprechen Ordinalsuffixen:
const enOrdinalRules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const numbers = [1, 2, 3, 4, 11, 21, 22, 23];
numbers.forEach(n => {
const category = enOrdinalRules.select(n);
console.log(`${n}: ${category}`);
});
// Output:
// 1: one
// 2: two
// 3: few
// 4: other
// 11: other
// 21: one
// 22: two
// 23: few
Die Kategorie one entspricht dem Suffix st (1st, 21st), two dem Suffix nd (2nd, 22nd), few dem Suffix rd (3rd, 23rd) und other dem Suffix th (4th, 11th).
Verschiedene Sprachen haben unterschiedliche Ordinalkategorien:
const locales = ['en-US', 'es-ES', 'fr-FR'];
locales.forEach(locale => {
const rules = new Intl.PluralRules(locale, { type: 'ordinal' });
const categories = rules.resolvedOptions().pluralCategories;
console.log(`${locale}: [${categories.join(', ')}]`);
});
// Output:
// en-US: [one, two, few, other]
// es-ES: [other]
// fr-FR: [one, other]
Spanisch verwendet nur eine Ordinalkategorie, da spanische Ordinalzahlen einem einfacheren Muster folgen. Französisch verwendet zwei Kategorien, um die erste Position von allen anderen zu unterscheiden.
Verwendung von Pluralkategorien zum Erstellen von Übersetzungsmaps
Wenn Sie wissen, welche Kategorien ein Locale verwendet, können Sie eine Übersetzungsmap mit genau der richtigen Anzahl von Einträgen erstellen:
function buildTranslationMap(locale, translations) {
const rules = new Intl.PluralRules(locale);
const categories = rules.resolvedOptions().pluralCategories;
const map = new Map();
categories.forEach(category => {
if (translations[category]) {
map.set(category, translations[category]);
} else {
console.warn(`Missing translation for category "${category}" in locale "${locale}"`);
}
});
return map;
}
const enTranslations = {
one: 'item',
other: 'items'
};
const arTranslations = {
zero: 'لا توجد عناصر',
one: 'عنصر واحد',
two: 'عنصران',
few: 'عناصر',
many: 'عنصرًا',
other: 'عنصر'
};
const enMap = buildTranslationMap('en-US', enTranslations);
const arMap = buildTranslationMap('ar-EG', arTranslations);
console.log(enMap);
// Output: Map(2) { 'one' => 'item', 'other' => 'items' }
console.log(arMap);
// Output: Map(6) { 'zero' => 'لا توجد عناصر', 'one' => 'عنصر واحد', ... }
Diese Funktion überprüft, ob Sie Übersetzungen für alle erforderlichen Kategorien bereitgestellt haben, und warnt Sie, falls welche fehlen. Dies verhindert Laufzeitfehler, wenn eine Kategorie verwendet wird, aber keine Übersetzung vorhanden ist.
Validierung der Übersetzungsvollständigkeit
Verwenden Sie Pluralkategorien, um zu überprüfen, ob Ihre Übersetzungen alle notwendigen Formen enthalten, bevor Sie in die Produktion gehen:
function validateTranslations(locale, translations) {
const rules = new Intl.PluralRules(locale);
const requiredCategories = rules.resolvedOptions().pluralCategories;
const providedCategories = Object.keys(translations);
const missing = requiredCategories.filter(cat => !providedCategories.includes(cat));
const extra = providedCategories.filter(cat => !requiredCategories.includes(cat));
if (missing.length > 0) {
console.error(`Locale ${locale} is missing categories: ${missing.join(', ')}`);
return false;
}
if (extra.length > 0) {
console.warn(`Locale ${locale} has unused categories: ${extra.join(', ')}`);
}
return true;
}
const enTranslations = {
one: 'item',
other: 'items'
};
const incompleteArTranslations = {
one: 'عنصر واحد',
other: 'عنصر'
};
validateTranslations('en-US', enTranslations);
// Output: true
validateTranslations('ar-EG', incompleteArTranslations);
// Output: Locale ar-EG is missing categories: zero, two, few, many
// Output: false
Diese Validierung erkennt fehlende Übersetzungen während der Entwicklung, anstatt sie zu entdecken, wenn Benutzer auf nicht übersetzten Text stoßen.
Erstellen dynamischer Übersetzungsschnittstellen
Beim Erstellen von Tools für Übersetzer fragen Sie die Pluralkategorien ab, um genau anzuzeigen, welche Formen übersetzt werden müssen:
function generateTranslationForm(locale, key) {
const rules = new Intl.PluralRules(locale);
const categories = rules.resolvedOptions().pluralCategories;
const form = document.createElement('div');
form.className = 'translation-form';
const heading = document.createElement('h3');
heading.textContent = `Translate "${key}" for ${locale}`;
form.appendChild(heading);
categories.forEach(category => {
const label = document.createElement('label');
label.textContent = `${category}:`;
const input = document.createElement('input');
input.type = 'text';
input.name = `${key}.${category}`;
input.placeholder = `Enter ${category} form`;
const wrapper = document.createElement('div');
wrapper.appendChild(label);
wrapper.appendChild(input);
form.appendChild(wrapper);
});
return form;
}
const enForm = generateTranslationForm('en-US', 'items');
const arForm = generateTranslationForm('ar-EG', 'items');
document.body.appendChild(enForm);
document.body.appendChild(arForm);
Dies generiert ein Formular mit der korrekten Anzahl von Eingabefeldern für jede Locale. Englisch erhält zwei Felder (one und other), während Arabisch sechs Felder erhält (zero, one, two, few, many und other).
Vergleich von Kategorien über Locales hinweg
Beim Verwalten von Übersetzungen für mehrere Locales vergleichen Sie, welche Kategorien sie verwenden, um die Übersetzungskomplexität zu verstehen:
function compareLocalePluralCategories(locales) {
const comparison = {};
locales.forEach(locale => {
const rules = new Intl.PluralRules(locale);
const categories = rules.resolvedOptions().pluralCategories;
comparison[locale] = categories;
});
return comparison;
}
const locales = ['en-US', 'es-ES', 'ar-EG', 'ru-RU', 'ja-JP'];
const comparison = compareLocalePluralCategories(locales);
console.log(comparison);
// Output:
// {
// 'en-US': ['one', 'other'],
// 'es-ES': ['one', 'other'],
// 'ar-EG': ['zero', 'one', 'two', 'few', 'many', 'other'],
// 'ru-RU': ['one', 'few', 'many', 'other'],
// 'ja-JP': ['other']
// }
Dies zeigt, dass Englisch und Spanisch dieselben Pluralkategorien haben, was es einfach macht, Übersetzungsstrukturen zwischen ihnen wiederzuverwenden. Arabisch erfordert deutlich mehr Übersetzungsarbeit, da es sechs Kategorien verwendet.
Überprüfen, ob eine Locale eine bestimmte Kategorie verwendet
Bevor Sie eine bestimmte Pluralkategorie in Ihrem Code verwenden, überprüfen Sie, ob die Locale sie tatsächlich verwendet:
function localeUsesCategory(locale, category) {
const rules = new Intl.PluralRules(locale);
const categories = rules.resolvedOptions().pluralCategories;
return categories.includes(category);
}
console.log(localeUsesCategory('en-US', 'zero'));
// Output: false
console.log(localeUsesCategory('ar-EG', 'zero'));
// Output: true
console.log(localeUsesCategory('ja-JP', 'one'));
// Output: false
Dies verhindert, dass Sie davon ausgehen, dass jede Locale eine zero-Kategorie oder one-Kategorie hat. Verwenden Sie diese Überprüfung, um kategoriespezifische Logik sicher zu implementieren.
Verständnis der other-Kategorie
Jede Sprache verwendet die other-Kategorie. Diese Kategorie dient als Standardfall, wenn keine andere Kategorie zutrifft.
Im Englischen deckt „other" alle Zahlen außer 1 ab. Im Arabischen deckt „other" große Zahlen wie 100 und darüber ab. Im Japanischen deckt „other" alle Zahlen ab, da Japanisch keine Pluralformen unterscheidet.
Stellen Sie immer eine Übersetzung für die Kategorie „other" bereit. Diese Kategorie ist garantiert in jedem Gebietsschema vorhanden und wird verwendet, wenn keine spezifischere Kategorie zutrifft.
const locales = ['en-US', 'ar-EG', 'ru-RU', 'ja-JP'];
locales.forEach(locale => {
const rules = new Intl.PluralRules(locale);
const categories = rules.resolvedOptions().pluralCategories;
const hasOther = categories.includes('other');
console.log(`${locale} uses "other": ${hasOther}`);
});
// Output:
// en-US uses "other": true
// ar-EG uses "other": true
// ru-RU uses "other": true
// ja-JP uses "other": true
Alle aufgelösten Optionen zusammen abrufen
Die Methode resolvedOptions() gibt mehr als nur Pluralkategorien zurück. Sie enthält Informationen über das Gebietsschema, den Typ und Zahlenformatierungsoptionen:
const rules = new Intl.PluralRules('de-DE', {
type: 'cardinal',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const options = rules.resolvedOptions();
console.log(options);
// Output:
// {
// locale: 'de-DE',
// type: 'cardinal',
// pluralCategories: ['one', 'other'],
// minimumIntegerDigits: 1,
// minimumFractionDigits: 2,
// maximumFractionDigits: 2,
// minimumSignificantDigits: undefined,
// maximumSignificantDigits: undefined
// }
Die Eigenschaft pluralCategories ist eine Information im Objekt der aufgelösten Optionen. Die anderen Eigenschaften geben Ihnen die exakte Konfiguration an, die die Instanz PluralRules verwendet, einschließlich aller Optionen, die auf Standardwerte gesetzt wurden.
Caching von Pluralkategorien für Performance
Das Erstellen von Instanzen von PluralRules und das Aufrufen von resolvedOptions() hat einen Kostenfaktor. Cachen Sie die Ergebnisse für jedes Gebietsschema, anstatt sie wiederholt abzufragen:
const categoriesCache = new Map();
function getPluralCategories(locale, type = 'cardinal') {
const key = `${locale}:${type}`;
if (categoriesCache.has(key)) {
return categoriesCache.get(key);
}
const rules = new Intl.PluralRules(locale, { type });
const categories = rules.resolvedOptions().pluralCategories;
categoriesCache.set(key, categories);
return categories;
}
const enCardinal = getPluralCategories('en-US', 'cardinal');
const enOrdinal = getPluralCategories('en-US', 'ordinal');
const arCardinal = getPluralCategories('ar-EG', 'cardinal');
console.log('en-US cardinal:', enCardinal);
console.log('en-US ordinal:', enOrdinal);
console.log('ar-EG cardinal:', arCardinal);
// Subsequent calls use cached results
const enCardinal2 = getPluralCategories('en-US', 'cardinal');
// No new PluralRules instance created
Dieses Muster ist besonders wichtig in Anwendungen, die viele pluralisierte Strings formatieren oder viele Gebietsschemata unterstützen.
Browser-Unterstützung und Kompatibilität
Die Eigenschaft pluralCategories auf resolvedOptions() wurde 2020 zu JavaScript hinzugefügt. Sie wird in Chrome 106+, Firefox 116+, Safari 15.4+ und Edge 106+ unterstützt.
Ältere Browser, die Intl.PluralRules unterstützen, aber nicht pluralCategories, geben für diese Eigenschaft undefined zurück. Prüfen Sie deren Existenz, bevor Sie sie verwenden:
function getPluralCategories(locale) {
const rules = new Intl.PluralRules(locale);
const options = rules.resolvedOptions();
if (options.pluralCategories) {
return options.pluralCategories;
}
// Fallback for older browsers
return ['one', 'other'];
}
Dieser Fallback geht von einem einfachen Zwei-Kategorien-System aus, das für Englisch und viele europäische Sprachen funktioniert, aber möglicherweise nicht korrekt für Sprachen mit komplexeren Regeln ist. Für bessere Kompatibilität stellen Sie sprachspezifische Fallbacks bereit oder verwenden Sie ein Polyfill.