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

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

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

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

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

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

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

Ответ 1

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

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

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

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

Если вы связаны с использованием 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" в заголовке каталога сообщений, вы будете способный поддерживать все языки.

Ответ 2

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

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";

}

Ответ 3

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

Ответ 4

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

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);

Ответ 5

Не самый элегантный, но самый легкий для вывода "Comment (s)".

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

Ответ 6

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

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

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

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

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

Ответ 7

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