Question

Say you're making a blog software, and want to show the number of comments an entry got. You might do it this way:

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

Which might result in:

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

But if an entry had only 1 comment, I want the line to say 'Comment' rather than 'Comments'. And in-line if/elses are ugly and repetitive.

What's the best way to deal with this?

Was it helpful?

Solution

Please use the ngettext function for things like this. It allows you to deal correctly with plurals in English and other languages, once and for all. You use it like this:

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

The ngettext function will return the first format string ("%d Comment") if there is just a single comment and the second format string ("%d Comments") if there are more. The printf function will then put the number into the string.

This might seem like a lot of work, but it is very powerful: it works with languages that have more than one plural form(!) -- they actually exist. The PHP manual gives an example for the word "window" which becomes "1 okno", "2 okna" and "5 oken" in some exotic language I don't recognize...

If you are consequent about using ngettext, then your future users from far-away countries will be very grateful to you :-)

Edit: As suggested in the comments, there is a single function to do the above:

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

By default, xgettext wont recognize this new function, but you can add it with the --keyword flag. Given a file test.php with

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

you can extract the strings with

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

The resulting messages.po file has entries like these:

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

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

The translator will fill in each plural form and with a correctly formed "Plural-Forms" line in the message catalog header, you will be able to support all languages.

OTHER TIPS

Why not take the time to humanize things even more....

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

}

Create a function that takes a number and a word, and returns a string containing both. It will append an "s" (or consult a dictionary that you build) when the number is bigger than 1.

It surprises me that nobody suggested that yet, but what I usually do is to use the conditional operator:

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

Note: the string should of course not be hard coded like this at all, but rather loaded from some resource repository, where it is stored with a formatting placeholder for the number, so that you can handle languages where the number should appear last (or in the middle):

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

Not the most elegant, but the easiest it to output "Comment(s)".

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

In C/C++, you can do the following. You may be able to do something similar in PHP.

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

The following also works, but you may run into issues with \b (backspace) being handled incorrectly in different implementations.

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

Using \0 (null character) to print nothing, instead, printed a space in my implementation.

Check out the Rails inflector module. This provides a nice, centralized and configurable solution to this problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top