Как использовать plural ресурсы в Android?
Что проверяют
Знаете ли вы, что форма множественного числа выбирается по правилам языка, а не по самому числу. Для русского это главный подвох: «1 яблоко», «3 яблока», «5 яблок», «21 яблоко». Следом часто спрашивают, почему для нуля не срабатывает zero и как вывести такую строку в Compose.
Как отвечать
Ресурс объявляется в res/values/strings.xml тегом <plurals>, внутри элементы <item quantity="..."> с категориями CLDR: zero, one, two, few, many, other. Какие из них нужны, зависит от языка:
- русский:
oneдля 1, 21, 101, но не для 11;fewдля 2, 3, 4, 22, 23, 24;manyдля 0, 5, 11, 12, 25;otherдля дробных; - английский: только
oneиother.zeroдля нуля в английском не выбирается никогда, «0 apples» берётся изother; - обязательный минимум: если нужной категории нет, система берёт
other, а безotherбросаетResources.NotFoundException.
В коде: resources.getQuantityString(R.plurals.apples, count, count). Число передаётся дважды: первое выбирает форму, второе подставляется в %d. Если в строке нет плейсхолдера, второй аргумент не нужен. В Compose то же самое делает pluralStringResource(R.plurals.apples, count, count).
Переводы кладутся в values-ru, values-en и так далее, и в каждой локали свой набор категорий. Проверку берёт на себя Lint: MissingQuantity сообщает о пропущенных формах, UnusedQuantity о лишних. Для сложных фраз с несколькими числами есть ICU MessageFormat из android.icu.text.
Где спотыкаются
Используют one как «ровно один» и пишут в нём «Один файл» без %d. В русском эта строка покажется и для 21, Lint отмечает такое как ImpliedQuantity.
Рассчитывают на zero для «Нет сообщений». Ни в русском, ни в английском эта категория для нуля не выбирается, пустое состояние делают отдельной строкой через проверку count == 0.
Переводят только базовую локаль. Если в values английские one и other, а в values-ru забыли few и many, русский интерфейс покажет «3 файлов», и никакой ошибки при этом не будет.