Множественное число на Android

В амазонских джунглях живет племя, в языке которого есть всего три слова для обозначения чисел — «один», «два» и «много»

Фактрум

В нашей жизни (а особенно — в интерфейсе наших программ!) очень часто встречаются числительные. Цена чего-либо? Число. Количество записей или комментариев к ним? Всё числа. Продолжительность какого-либо периода? Это зачастую даже несколько чисел: например, дни, часы и минуты. В общем, без чисел — никуда.

И чем важнее представленная числом информация, тем неприятнее человеку видеть на экране что-нибудь такое:

21 комментариев
21 комментариев. Без комментариев.

Бросается в глаза, согласитесь? Сразу видно: текст «механический». Взгляд спотыкается на такой строчке, мозг фиксирует грубую грамматическую ошибку. Вот сравните, например, со скриншотом из популярной социальной сети:

21 комментарий
А вот тут глазу цепляться не за что

Осознавая эти тонкости, многие пытаются выводить числа просто в скобочках или после двоеточия («комментарии: 21»). Это не самый плохой компромисс: текст хоть и веет всё той же механистичностью, но по крайней мере остаётся согласованным при любом числе. Однако же — зачем нам компромиссы? Правильное склонение — одно из требований к современному приложению, и больших усилий его реализация не потребует — всё уже написано до нас!

Собственно, нужный нам механизм лежит на самой поверхности, да и называется без особых изысков — Quantity Strings (plurals). Появился он ещё в самых первых версиях Android, но не пользовался у наших разработчиков большой популярностью, поскольку реализован был с ошибками. Однако же теперь, начиная с Honeycomb, ошибки исправлены, а для более старых версий — написана и свободно доступна исправляющая ошибки библиотечка.

Как оно работает?

В идеале — всё очень просто. В файле строковых ресурсов (обычно strings.xml) задаётся набор правил склонения для какой-либо строки; затем, в java-коде, мы просим Android подобрать верную строку для согласования с некоторым числом. Элегантно и со вкусом!

Нужный ресурс называется plurals, каждая строка описывается в нём дочерним элементом item, имеющим обязательный атрибут quantity — квантификатор, «количественность» этой строки. Иначе говоря — диапазон чисел, к которому строка относится. Возможные значения у этого атрибута полностью соответствуют стандарту unicode.org:

  • zero — строка для нуля, отсутствия чего-либо; в некоторых языках — ещё и для чисел, оканчивающихся нулём;
  • one —  строка для чисел, заканчивающихся на единицу; в некоторых языках — только для единицы;
  • two — для чисел, заканчивающихся на двойку, или только для двойки;
  • few — здесь, под словом «несколько», уже не скрывается конкретики, обработка полностью зависит от языковых правил; например, для русского языка это относится к числам, оканчивающимся на 2, 3 и 4 (именно так, несмотря на наличие правила «two»);
  • many — аналогично, «неконкретная» категория, можно понимать её как «нечто побольше few»; в русском языке — от пятёрки и выше;
  • other — всё остальное.

В коде же мы используем метод Resources.getQuantityString(int id, int quantity, Object... formatArgs), где id — идентификатор нашего ресурса plurals (R.plurals.something), quantity — число, для которого нужно найти словоформу, и, как в случае с обычным getString() — дополнительные параметры formatArgs позволяют делать подстановки в строку по шаблону.

Попробуем применить эти знания в условиях, приближенных к боевым. Создадим новый Android Project, и в нём добавим в русскоязычный strings.xml парочку plural-ресурсов:

И прямо в методе onCreate() главной Activity приложения мы протестируем вывод чисел от нуля до тридцати; для простоты мы выведем результаты просто в LogCat:

Код, я полагаю, достаточно тривиален — в цикле получаем из ресурсов строку, согласующуюся (по мнению системы) со счётчиком цикла, в неё же, на место шаблона %1$d, подставляем значение этого счётчика. Нетривиальные вещи ещё ждут нас впереди.

Итак, запустим это всё на аппарате с системой Honeycomb и выше. Вот что выдаст нам в лог Android версии 4.0.4:

Полностью правильный результат по стандарту, хотя и хотелось бы чтоб в случае нуля использовалась строчка из «zero». Но это уже вопросы удобства и не более того: строка в любом случае грамматически правильная, а отдельно сравнить число с нулём — это, при необходимости, совсем не архисложная задача. Что ж, здесь всё в порядке — за владельцев новых телефонов мы можем быть спокойны.

Но запустим этот же код на старой версии системы — например, на Android 2.2:

Да, это не случайная ошибка: версии до Honeycomb обрабатывают русские (и не только русские) множественные числа по правилам английского языка — используя one для числа 1 и other для всех остальных. Но не спешите отчаиваться, вспоминать старую шутку про точность остановившихся часов и ждать пока отомрёт линейка 2.х.

Что делать, шеф?

Итак, нас категорически не устраивают склонения на старых андроидах, равно как могут смущать «нулевые» нюансы в свежих версиях системы. Что ж — мы не одни, и мир не без добрых людей: беглый поиск на Google Code немедленно выдаёт нам проект android-i18n-plurals, любезно выложенный под одной из самых либеральных лицензий — MIT.

Суть проекта — создание крошечной обёртки над классом Resources, умеющей наконец-то правильно вытаскивать языковые данные из ресурса plurals. В остальном же — наш код никак не изменяется в .xml, а добавления внутри .java — минимальны. Нужно всего лишь создать экземпляр класса PluralResources, «заворачивающий» системный Resources, и далее работать уже с ним. Для нашего примера это будет выглядеть так (естественно, не забываем сперва добавить исходные коды android-i18n-plurals к своему проекту):

Для чистоты (и для усложнения) эксперимента запускаем приложение на том самом проблемном телефоне с версией 2.2 — и…

Вот он — идеал! И правильные склонения, и, на десерт, даже специальная обработка нуля — мы видим заветную строчку «нет андроидов»!

Выводы

Вывод из всего сказанного напрашивается простой: можно и нужно переформулировать сообщения своих android-приложений в более «человечную» форму. Радуйте пользователя формулировками в духе «ваш пост получил 71 оценку и 23 комментария», уберите унылые IT-канцеляризмы. Инструментарий для всего этого — найдётся, и никуда не исчезнет в будущем.

Начиная с API level 11 и выше можно использовать системные функции. Хороший и гарантированно работающий код может выглядеть так:

Ну а для проектов, изначально ориентированных на Honeycomb+, нет никакого смысла добавлять лишний код, всего-то отличающийся от системного дополнительной обработкой нуля — которая, к тому же, не прописана в документации unicode.org для русского языка и является в значительной мере эдакой удобной «отсебятиной». Кушать ли этот «синтаксический сахар», или же не отходить от стандарта — каждый решает сам.

Русский язык требует указать строки для one, few, many и other (на всякий случай). По стандарту не используется zero, и никем не используется two — но, разумеется, ничего страшного в указании этих строк нет. На всякий случай можно даже рекомендовать их всё-таки указывать — кто знает, а вдруг что-то необъяснимо поменяется в системных механизмах? Да и переводчику могут понадобиться эти варианты, уже заботливо подготовленные в ресурсном файле.

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

Множественное число на Android
5, голосов: 10


Комментарии:

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Капча (решите пример) *