4

There are a lot of questions explaining how to echo a singular or plural variable, but none answer my question as to how one sets a variable to contain said singular or plural value.

I would have thought it would work as follows:

$bottom="You have favourited <strong>$count</strong> " . $count == 1 ? 'user':'users';

This however does not work.

Can someone advise how I achieve the above?

pb2q
  • 58,613
  • 19
  • 146
  • 147
Thomas Clowes
  • 4,529
  • 8
  • 41
  • 73
  • 2
    Explain the outcome a bit more detailed than "it does not work". – mario Oct 08 '12 at 17:47
  • 2
    possible duplicate of [Ternary operator and string concatenation quirk?](http://stackoverflow.com/questions/1317383/ternary-operator-and-string-concatenation-quirk) – mario Oct 08 '12 at 17:49
  • mario, I believe his problem is $bottom is always equal to only 'users' regardless of the ternary operation and concatenation – anditpainsme Oct 08 '12 at 17:50
  • This link contains the most usable function i could find http://www.kavoir.com/2011/04/php-class-converting-plural-to-singular-or-vice-versa-in-english.html – aye Sep 20 '13 at 01:50
  • Symfony now offers a the Inflector component converts English words between their singular and plural forms. https://symfony.com/doc/master/components/inflector.html – ya.teck May 25 '19 at 18:08

10 Answers10

37

You can try this function I wrote:

/**
 * Pluralizes a word if quantity is not one.
 *
 * @param int $quantity Number of items
 * @param string $singular Singular form of word
 * @param string $plural Plural form of word; function will attempt to deduce plural form from singular if not provided
 * @return string Pluralized word if quantity is not one, otherwise singular
 */
public static function pluralize($quantity, $singular, $plural=null) {
    if($quantity==1 || !strlen($singular)) return $singular;
    if($plural!==null) return $plural;

    $last_letter = strtolower($singular[strlen($singular)-1]);
    switch($last_letter) {
        case 'y':
            return substr($singular,0,-1).'ies';
        case 's':
            return $singular.'es';
        default:
            return $singular.'s';
    }
}

Usage:

pluralize(4, 'cat'); // cats
pluralize(3, 'kitty'); // kitties
pluralize(2, 'octopus', 'octopii'); // octopii
pluralize(1, 'mouse', 'mice'); // mouse

There's obviously a lot of exceptional words that this function will not pluralize correctly, but that's what the $plural argument is for :-)

Take a look at Wikipedia to see just how complicated pluralizing is!

mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • 3
    @Francesco Sure it does. Usage: `pluralize(3, 'Ranch', 'Ranches')`. The 3rd argument is only optional for the most basic words. – mpen Mar 05 '16 at 21:03
27

You might want to look at the gettext extension. More specifically, it sounds like ngettext() will do what you want: it pluralises words correctly as long as you have a number to count from.

print ngettext('odor', 'odors', 1); // prints "odor"
print ngettext('odor', 'odors', 4); // prints "odors"
print ngettext('%d cat', '%d cats', 4); // prints "4 cats"

You can also make it handle translated plural forms correctly, which is its main purpose, though it's quite a lot of extra work to do.

  • 5
    actually it would be `printf(ngettext('%d cat', '%d cats', 4), 4); // prints "4 cats"` – Bot Mar 04 '13 at 23:16
  • That's not cool in combination with printf. Maybe PHP has something new today? :-) – Alex2php Mar 09 '15 at 20:58
  • This answer is not correct. `ngettext` is a plural version of `gettext`; essentially, this is a transation function; in many cases this is not appropriate solution. – Georgy Ivanov Jun 09 '21 at 21:18
7

The best way IMO is to have an array of all your pluralization rules for each language, i.e. array('man'=>'men', 'woman'=>'women'); and write a pluralize() function for each singular word.

You may want to take a look at the CakePHP inflector for some inspiration.

https://github.com/cakephp/cakephp/blob/master/src/Utility/Inflector.php

Jesse Kochis
  • 766
  • 3
  • 10
  • 1
    That link is currently dead; source can be found here: https://github.com/cakephp/cakephp/blob/c2f298a8b7b461584dfdbe6a1c3feb81ba47e525/lib/Cake/Utility/Inflector.php – mpen Feb 03 '15 at 19:16
6

Enjoy: https://github.com/ICanBoogie/Inflector

Multilingual inflector that transforms words from singular to plural, underscore to camel case, and more.

Gerry
  • 10,584
  • 4
  • 41
  • 49
5

This will solve your issue, thanks to mario and Ternary operator and string concatenation quirk?

$bottom = "You have favourited <strong>$count</strong> " . ($count == 1 ? 'user':'users');
Community
  • 1
  • 1
anditpainsme
  • 601
  • 1
  • 7
  • 14
4

If you're going to go down the route of writing your own pluralize function then you might find this algorithmic description of pluralisation helpful:

http://www.csse.monash.edu.au/~damian/papers/HTML/Plurals.html

Or the much easier approach would probably be to use one of the ready-made pluralize functions available on the Internet:

http://www.eval.ca/2007/03/03/php-pluralize-method/

Reality
  • 613
  • 1
  • 8
  • 8
1

For $count = 1:

    "You have favourited <strong>$count</strong> " . $count == 1 ? 'user' : 'users';
=>               "You have favourited <strong>1</strong> 1" == 1 ? 'user' : 'users';
=>                                                        1 == 1 ? 'user' : 'users';
=>                                                          true ? 'user' : 'users';
// output: 'user'

The PHP parser (rightly) assumes everything to the left of the question mark is the condition, unless you change the order of precedence by adding in parenthesis of your own (as stated in other answers).

deizel.
  • 11,042
  • 1
  • 39
  • 50
1

Custom, transparent and extension-free solution. Not sure about its speed.

/**
 * Custom plural
 */
function splur($n,$t1,$t2,$t3) {
    settype($n,'string');
    $e1=substr($n,-2);
    if($e1>10 && $e1<20) { return $n.' '.$t3; } // "Teen" forms
    $e2=substr($n,-1);
    switch($e2) {
        case '1': return $n.' '.$t1; break;
        case '2': 
        case '3':
        case '4': return $n.' '.$t2; break;
        default:  return $n.' '.$t3; break;
    }
}

Usage in Ukrainian / Russian:

splur(5,'сторінка','сторінки','сторінок') // 5 сторінок
splur(4,'сторінка','сторінки','сторінок') // 4 сторінки
splur(1,'сторінка','сторінки','сторінок') // 1 сторінка
splur(12,'сторінка','сторінки','сторінок') // 12 сторінок

splur(5,'страница','страницы','страниц') // 5 страниц
splur(4,'страница','страницы','страниц') // 4 страницы
splur(1,'страница','страницы','страниц') // 1 страница
splur(12,'страница','страницы','страниц') // 12 страниц
K.Alex
  • 91
  • 3
0

You can try using $count < 2 because $count can also be 0

$count =1;
$bottom = sprintf("You have favourited <strong>%d %s</strong>", $count, ($count < 2 ? 'user' : 'users'));
print($bottom);

Output

You have favourited 1 user
Baba
  • 94,024
  • 28
  • 166
  • 217
0

This is one way to do it.

$usersText = $count == 1 ? "user" : "users";
$bottom = "You have favourited <strong>" . $count . "</strong> " , $usersText;
thescientist
  • 2,906
  • 1
  • 20
  • 15