Skip to content

Pluralization _ PluralLocalizationFormatter

axunonb edited this page Jan 15, 2024 · 3 revisions

The PluralFormatter uses language-specific pluralization rules to choose different text for singular and plural forms. Some languages can have as many as 5 different forms.

The rules used in PluralFormatter are inferred from the Langue Plural Rules published on unicode.org.

Syntax Details

{ Number : plural(lang) : singular | plural | more... }

Number :plural (lang) singular plural more...
Any Number "plural" or implicit language code the singular text the plural text more plural forms

Number: can be short, ushort, int, uint, long, ulong, float, double, decimal

Plural forms: Specify all plural forms, in smallest-to-largest order (eg. zero|one|two|few|many)

  • English has two plural forms: 1 is singular, everything else is plural.
  • However, some languages have complex rules, with as many as 6 plural forms! Special cases for 0, 2-4, or singular used for 21, 31, etc. So, for these languages, you should specify all plural forms.

Language Code: optional 2-letter ISO language code

  • Language (culture, respectively) is determined in this sequence:
    a) Get the culture from the FormattingInfo.FormatterOptions like this: {0:plural(ru):банан|банана|бананов}
    b) Get the culture from the IFormatProvider argument (which may be a CultureInfo) to SmartFormatter.Format(IFormatProvider, string, object?[])
    c) The CultureInfo.CurrentUICulture

Configuration:

string Name: default is plural
The name to use a named formatter

char SplitChar: default is '|'

Examples

Simple Singular/Plural

var number = 1; // or: 2
Smart.Format("There {0:plural:is 1 item|are {} items}.", number);
// outputs "There is 1 item." or "There are 2 items."

Zero/One/Many

Note: Depending on the locale, expected arguments may be 2 or 3.

// In English - 2 arguments are required
Smart.Format("{0:plural(en):zero|one|many}", number);
// outputs by number:
// 0 => "zero", 1 => "one", 5 => "many"

// In Polish - 3 arguments are expected
Smart.Format("{0:plural(pl):miesiąc|miesiące|miesięcy}", number);
// outputs by number:
// 0 => "miesięcy", 1 => "miesiąc", 5 => "miesięcy"

Use a CustomPluralRuleProvider

English:

var custom = new CustomPluralRuleProvider(PluralRules.GetPluralRule("en"));
Smart.Format(custom, "{0:plural:person|people}", 5);
// Outputs: "5 people"

French:

var custom = new CustomPluralRuleProvider(PluralRules.GetPluralRule("fr"));
Smart.Format(custom, "{0:plural:une personne|deux personnes|plusieurs personnes|beaucoup de personnes}", 99);
// Outputs: "beaucoup de personnes"

Modify a PluralRuleDelegate for a specific language globally

Dictionary<string, PluralRuleDelegate> PluralRule.IsoLangToDelegate holds delegates with the pluralization rule per language. Changing a value of this dictionary will change the pluralization rules globally. This is not recommended, but possible.

After a change calling PluralRules.RestoreDefault() will restore the default rules.

// Note: This example changes a default rule delegate *globally*.
//       It is not recommended, but possible.
PluralRules.IsoLangToDelegate["en"] = (value, wordsCount) =>
{
    if (wordsCount != 6) return -1;

    return value switch
    {
        <= 0 => 0,
        > 0 and < 2 => 1,
        >= 2 and < 3 => 2,
        > 2 and < 10 => 3,
        >= 10 and < 20 => 4,
        >= 20 => 5
    };
};

var ciEnglish = CultureInfo.GetCultureInfo("en");
var count = 6;

Smart.Format(ciEnglish, "{0:plural:nobody|{} person|{} people|a couple of people|many people|a lot of people}", count);
// Outputs: "a lot of people" for count == 6, "nobody" for count == 0

// Restore default rule delegates:
PluralRules.RestoreDefault();
Clone this wiki locally