Интернационализация 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, который обрабатывает более сложные правила плюрализации