Самый элегантный способ борьбы с одиночками / множественными числами?

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

[Entry title]
[Content........]
[ <?php print($numComments;) ?> Comments]

Что может привести к:

[Entry title]
[Content........]
5 Comments

Но если запись содержит только 1 комментарий, я хочу, чтобы в строке было написано "Комментарий", а не "Комментарии". И в линии if/elseуродливые и повторяющиеся.

Какой лучший способ справиться с этим?

7 ответов

Решение

Пожалуйста, используйте ngettext функция для таких вещей, как это. Это позволяет вам раз и навсегда разобраться с множественным числом на английском и других языках. Вы используете это так:

printf(ngettext("%d Comment", "%d Comments", $numComments), $numComments);

ngettext функция вернет первую строку формата ("%d Comment") если есть только один комментарий и вторая строка формата ("%d Comments") если есть еще. printf Функция поместит число в строку.

Это может показаться большой работой, но она очень мощная: она работает с языками, которые имеют более чем одну форму множественного числа (!) - они действительно существуют. В руководстве по PHP приведен пример слова "окно", которое на некоторых экзотических языках, которые я не узнаю, становится "1 окно", "2 окна" и " 5 окен ".

Если вы используете ngettext, тогда ваши будущие пользователи из дальних стран будут вам очень благодарны:-)

Изменить: как предлагается в комментариях, есть одна функция, чтобы сделать выше:

function pluralize($num, $singleWord, $pluralWord) {
    return printf(ngettext($singleWord, $pluralWord, $num), $num);
}

По умолчанию, xgettext не будет распознавать эту новую функцию, но вы можете добавить ее с помощью --keyword флаг. Данный файл test.php с

echo ngettext("foo", "foos", 1);
echo pluralize(2, "bar", "bars");

Вы можете извлечь строки с

xgettext --keyword=pluralize:2,3 test.php 

Результирующий messages.po В файле есть такие записи:

#: test.php:7
msgid "foo"
msgid_plural "foos"
msgstr[0] ""
msgstr[1] ""

#: test.php:8
msgid "bar"
msgid_plural "bars"
msgstr[0] ""
msgstr[1] ""

Переводчик заполняет каждую форму множественного числа, и с правильно сформированной строкой "Plural-Forms" в заголовке каталога сообщений вы сможете поддерживать все языки.

Почему бы не потратить время, чтобы очеловечить вещи еще больше....

switch ($numComments)
{
    case 0:
        echo "Be the first to write a comment";
        break;
    case 1:
        echo "Just one comment so far";
        break;
    default:
        echo "There are $numComments comments";

}

Меня удивляет, что никто еще не предлагал этого, но я обычно использую условный оператор:

string commentWord = numComments != 1 ? "Comments" : "Comment"; 

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

// should load "{0} Comments" or "{0} Comment" if we run in an English locale
string comments = string.Format(
        numComments != 1 ? GetResource("Comments") : GetResource("Comment"),
        numComments);

Создайте функцию, которая принимает число и слово и возвращает строку, содержащую оба. Он добавит "s" (или сверится со словарем, который вы строите), когда число больше 1.

Не самый элегантный, но самый простой - вывести "Комментарий (и)".

[Entry title]
[Content........]
1 Comment(s)

В C/C++ вы можете сделать следующее. Вы можете сделать что-то подобное в PHP.

printf("%d %s\n", numComments, numComments == 1 ? "Comment" : "Comments");

Следующее также работает, но вы можете столкнуться с проблемами с \b (backspace) неправильно обрабатывается в разных реализациях.

printf("%d Comment%s\n", numComments, numComments == 1 ? " \b" : "s");

С помощью \0 (нулевой символ), чтобы ничего не печатать, вместо этого напечатал пробел в моей реализации.

Посмотрите на модуль инфлектора Rails. Это обеспечивает хорошее, централизованное и настраиваемое решение этой проблемы.

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