Ответ 1
Ну, вы уже правильно пометили вопрос, поэтому я предполагаю, что вы знаете кое-что о ICU.
В ICU у вас есть два варианта правильной обработки множественных форм:
- PluralRules, который дает вам правила для данного Locale
- PlurarFormat, который использует вышеупомянутые правила, чтобы разрешить форматирование
Какой из них использовать? Лично я предпочитаю использовать 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 для выбора допустимой формы. Обычные примеры показывают прямую конкретизацию, которая, на мой взгляд, совершенно не имеет смысла. Легче использовать его с ICU MessageFormat:
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 static format() (тот, который прост в использовании) всегда форматирует для локали по умолчанию. Это может быть реальной проблемой в веб-приложениях, где по умолчанию Locale обычно означает серверные. Таким образом, мне пришлось отформатировать для определенного Locale (числа с плавающей запятой, заметьте), и код выглядит довольно уродливым...
Я по-прежнему предпочитаю подход PluralRules, который для меня намного чище (хотя ему нужно использовать тот же стиль форматирования сообщений, только обернутый вспомогательным методом).