Интернационализация Java (i18n) с правильными множественными числами

Я собирался использовать стандартную систему Java i18n с классом ChoiceFormat для множественного числа, но потом понял, что она не обрабатывает сложные правила множественного числа некоторых языков (например, польского). Если он работает только с языками, похожими на английский, то это кажется немного бессмысленным.

Какие есть варианты для достижения правильных форм множественного числа? Каковы плюсы и минусы их использования?

2 ответа

Решение

Ну, вы уже пометили вопрос правильно, поэтому я предполагаю, что вы знаете кое-что об ICU.

С ICU у вас есть два варианта правильной обработки множественных форм:

  • PluralRules, который дает вам правила для данной локали
  • PluralFormat, который использует вышеупомянутые правила, чтобы разрешить форматирование

Какой использовать? Лично я предпочитаю использовать PluralRules напрямую, чтобы выбрать подходящее сообщение из комплекта ресурсов.

ULocale uLocale = ULocale.forLanguageTag("pl-PL");
ResourceBundle resources = ResourceBundle.getBundle( "path.to.messages",
                               uLocale.toLocale());
PluralRules pluralRules = PluralRules.forLocale(uLocale);

double[] numbers = { 0, 1, 1.5, 2, 2.5, 3, 4, 5, 5.5, 11, 12, 23 };
for (double number : numbers) { 
  String resourceKey = "some.message.plural_form." + pluralRules.select(number);
  String message = "!" + resourceKey + "!";
  try {
    message = resources.getString(resourceKey);
    System.out.println(format(message, uLocale, number));
   } catch (MissingResourceException e) { // Log this } 
}

Конечно, вам (или переводчику) потребуется добавить правильные формы в файл свойств, в этом примере скажем:

some.message.plural_form.one=Znaleziono {0} plik
some.message.plural_form.few=Znaleziono {0} pliki
some.message.plural_form.many=Znaleziono {0} plików
some.message.plural_form.other=Znaleziono {0} pliku

Для других языков (например, арабского) вам также может понадобиться использовать ключевые слова "ноль" и "два", подробности см. В правилах множественного числа языков CLDR.

В качестве альтернативы вы можете использовать PluralFormat, чтобы выбрать правильную форму. Обычные примеры показывают прямую реализацию, что, на мой взгляд, не имеет смысла. Проще использовать его с MessageFormat ICU:

String pattern = "Znaleziono {0,plural,one{# plik}" +
                 "few{# pliki}" +
                 "many{# plików}" +
                 "other{# pliku}}";
MessageFormat fmt = new MessageFormat(pattern, ULocale.forLanguageTag("pl-PL"));
StringBuffer result = new StringBuffer();
FieldPosition zero = new FieldPosition(0);
double[] theNumber = { number };
fmt.format(theNumber, result, zero);

Конечно, реально вы не жестко закодировали бы строку шаблона, но поместили бы что-то вроде этого в файл свойств:

some.message.pattern=Found {0,plural,one{# file}other{# files}}

Единственная проблема с этим подходом состоит в том, что переводчик должен знать формат заполнителя. Другая проблема, которую я пытался показать в приведенном выше коде, заключается в том, что метод статического формата (), который легко использовать в MessageFormat, всегда форматирует для локали по умолчанию. Это может быть реальной проблемой в веб-приложениях, где локаль по умолчанию обычно означает серверную. Таким образом, я должен был отформатировать для определенной локали (числа с плавающей запятой, обратите внимание), и код выглядит довольно некрасиво...

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

ChoiceFormat, как объясняется здесь, кажется достаточно гибким, чтобы справиться с любым типом плюрализации, который вы можете использовать.

РЕДАКТИРОВАТЬ: как отметил д-р Харибо в своем комментарии, ChoiceFormat недостаточно для польской плюрализации. Но продолжение того же блога предлагает ICU4J, который обрабатывает более сложные правила плюрализации

Другие вопросы по тегам