Библиотека Pluralization для единиц измерения

Наверное многие не раз сталкивались с проблемой выхода единиц измерения: 1 час, 3 часа, 5 часов… А какое слово использовать для неизвестного заранее значения?

Если если добавить к этому еще локализацию, то кажется, что без профессионального переводчика не обойтись. Но все гораздо проще и зачастую будет достаточно Bing, Google и т.п.

Для решения подобной задачи можно воспользоваться библиотекой Moveax.Pluralization (лицензия MS-PL). Разберемся с её использованием на простом примере: будем считать число символов с пробелами в введенном тексте и печатать результат на 2-х языках.

Создаем приложение

Создадим консольное приложение PluralizationDemo и подключим саму библиотеку:

Install-Package Moveax.Pluralization.Core -IncludePrerelease

Стоит отметить, что это Portable Class Library, которая минимально требует .NET 4, WP7, SL4. В данный момент поддерживается работа с русским, украинским, белорусским, английским, французским, немецким, итальянским и испанским языками.

Добавляем слова

Все что нужно сделать – задать используемые слова или фразы в формах, которые соответствуют следующему количеству:

  • Zero – ноль;
  • One – один;
  • Two – два;
  • Few – несколько;
  • Many – много;
  • Other – форма по умолчанию;

В большинстве случаев все они требуются. Так для русского, украинского, белорусского необходимо описать 4 формы, а для большинства европейских – всего 2. Таблицу, с их указанием для каждого языка можно найти на сайте unicode.org.

Moveax.Pluralization "из коробки" может работать со строками из ресурсов приложения. Однако при необходимости можно подставить реализацию интерфейса ILocalizedStringsSource, загружающую ресурсы из собственного источника данных.

В демонстрационном приложении воспользуемся готовым ResourceStringsSource. У него есть соглашение для именования ресурсов: после имени строки необходимо добавить название его формы. Поэтому создадим в тестовом проекте следующие resx-файлы со строками:

  • PhrasesResource.resx (английский язык по умолчанию)
    • CharsOne: character
    • CharsOther: characters
  • PhrasesResource.ru-RU.resx
    • CharsFew: символа
    • CharsMany: символов
    • CharsOne: символ
    • CharsOther: символа

Код приложения

Осталось написать немного кода. Необходимо создать

  • экземпляр класса ResourceStringsSource, который будет указывать на ресурсы приложения;
  • непосредственно, сам Pluralizer для заданного языка.
static void Main(string[] args)
{
    Console.Write("Type some text:");
    string line = Console.ReadLine();

    var count = line != null ? line.Count() : 0;

    var enPluralizer = new Pluralizer(new CultureInfo("en-US"),
        new ResourceStringsSource(PhrasesResource.ResourceManager));
    var units = enPluralizer.Pluralize("Chars", count);
    Console.WriteLine("{0} {1}", count, units);

    var ruPluralizer = new Pluralizer(new CultureInfo("ru-RU"), 
        new ResourceStringsSource(PhrasesResource.ResourceManager));
    units = ruPluralizer.Pluralize("Chars", count);
    Console.WriteLine("{0} {1}", count, units);

    Console.WriteLine("Press any key...");
    Console.ReadKey(true);
}

Можно запускать и пробовать.

Коллекция часто используемых слов

Кроме того, в библиотеки планируется собрать наиболее часто используемые в перечислениях слова. Они доступны в отдельном установочном пакете:

Install-Package Moveax.Pluralization.Common -IncludePrerelease

В данный момент доступны только единицы измерения времени на русском и английском языках. Например:

var dtPluralizer = new DateTimePluralizer(new CultureInfo("ru-RU"));
Console.WriteLine("{0} {1}", count, dtPluralizer.GetStringFor(count, DateTimeUnit.Hours));

Обратная связь

Вопросы, советы, предложения принимаются по почте или на сайте проекта.

Комментарии (7) -

Алексей 05.07.2013 13:13:53

задача проще решается, зачем хранить отдельно разные формы слов?

посмотрите на такой вариант https://github.com/hVostt/PawnHunter.Numerals проще и универсальней, по мне Smile

Install-Package PawnHunter.Numerals

Алексей 05.07.2013 13:15:59

еденицы еще могут быть разных родов, кстати вариант решения хорошо укладывается в ресурсы, нужно только подключить форматтер.

@ Алексей: При локализации строки все равно окажутся в ресурсах (стандартных resx или своем формате). Но ваше решение тоже интересное.

Алексей 05.07.2013 14:49:22

@ Andrey:

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

"{0} ваших писем было доставлено {1} адресатам, получено {2} уведомления о доставке"

с форматтером такая строка также по всем правилам запихивается в ресурсы, но уже с поддержкой числовых и порядковых форм. просто в указанной библиотеке поддерживается всего 2 языка (с возможностью расширения конечно же), и ни о каких-либо ещё возможностях речи нет. можете взять идею на вооружение Smile

@ Алексей: С другой стороны - все эти "адресатам" (само слово) как правило не раз встречается в приложении. Плюс имена все же помогают вспоминать что за формы слов. Но это уже мелочь и наверное вопрос привычки.

@ Алексей: Хотя добавить поддержку такого формата можно, но нужно подумать как удобнее будет Smile

Алексей 05.07.2013 15:22:16

даже если и так. один стринг "{0:W;адресат(у,ам)}" против шести (!). вы могли бы внедрить поддержку такой формы (с форматтером), и получилась бы добротная либа вкупе с остальными фичами Smile

Добавить комментарий