Как организовать работу с числительными (плюрализация) при локализации приложения на C#?

«Как организовать работу с числительными (плюрализация) при локализации приложения на C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Правильная плюрализация — это не просто добавление 's'. В разных языках разное количество форм для множественного числа (например, в русском 3, в арабском — 6). Решение должно быть основано на стандартах ICU (Unicode).

1. Использование библиотеки Humanizer (Рекомендуемый подход) Humanizer поддерживает множество языков и склонений, предоставляя простой API.

// Установите пакет: Install-Package Humanizer
using Humanizer;

// Плюрализация на английском
"apple".Pluralize(1); // "apple"
"apple".Pluralize(2); // "apples"

// Плюрализация на русском (требует установки культуры)
var culture = new System.Globalization.CultureInfo("ru-RU");
"сообщение".Pluralize(1, culture); // "сообщение"
"сообщение".Pluralize(2, culture); // "сообщения"
"сообщение".Pluralize(5, culture); // "сообщений"

// Форматирование строк с числительными
"Message".ToQuantity(5, ShowQuantityAs.Words); // "five messages" (en)

2. Использование .resx файлов с выбором формы по правилам Для полного контроля можно хранить шаблоны в ресурсах, а выбор осуществлять по формуле. Для русского языка часто используется формула:

string GetRussianPluralForm(int number, string form1, string form2, string form5)
{
    number = Math.Abs(number) % 100;
    int n1 = number % 10;
    if (number > 10 && number < 20) return form5;
    if (n1 > 1 && n1 < 5) return form2;
    if (n1 == 1) return form1;
    return form5;
}

// В ресурсном файле Messages.ru.resx:
// PluralForm1: "{0} сообщение"
// PluralForm2: "{0} сообщения"
// PluralForm5: "{0} сообщений"

int count = 5;
string form = GetRussianPluralForm(count, PluralForm1, PluralForm2, PluralForm5);
string result = string.Format(form, count); // "5 сообщений"

3. Использование IStringLocalizer и Plural в ASP.NET Core В современных приложениях ASP.NET Core фреймворк предоставляет встроенные средства.

// В ресурсном файле (например, Resources.ru.resx) можно использовать параметризованные ключи.
// На практике часто используют библиотеки, подобные `SmartFormat` или `MessageFormatter`,
// которые поддерживают плюрализацию по стандарту ICU прямо в строке шаблона.

// Пример со SmartFormat (пакет SmartFormat.NET)
using SmartFormat;

var message = Smart.Format("{0} {0:сообщение|сообщения|сообщений}", count);

4. Ключевые принципы:

  • Не изобретайте велосипед: Для поддержки многих языков используйте проверенные библиотеки (Humanizer, SmartFormat).
  • Отделяйте данные от шаблона: Число и строковый шаблон должны быть независимы.
  • Тестируйте на пограничных значениях: 0, 1, 2, 5, 11, 21, 101.
  • Учитывайте контекст: Иногда фраза "1 file(s) processed" лучше, чем сложная система склонений для редких языков в MVP.