26

I'm looking for a function that given a string it switches the string to singular/plural. I need it to work for european languages other than English.

Are there any functions that can do the trick? (Given a string to convert and the language?)

Thanks

Marty
  • 146
  • 1
  • 13
dynamic
  • 46,985
  • 55
  • 154
  • 231
  • 4
    What other European language? – Gumbo Jan 18 '11 at 21:00
  • 4
    Here ya go: `$result = (preg_match('~s$~i', $string) > 0) ? rtrim($string, 's') : sprintf('%ss', $string);`. :P – Alix Axel Jan 18 '11 at 21:11
  • 3
    The trick with many languages is that a plural isn't just made on the noun, like how English adds an 's', the article and adjectives are also pluralized. Given the difficulties in parsing natural language to associate nouns with the correct modifiers, most software that I'm aware of just stores manual translations of both plural and non-plural versions. – Karl Bielefeldt Jan 18 '11 at 21:18
  • 1
    @Alix Axel: ... fails for things like `box`, `loss` and many more ;) – nico Jan 18 '11 at 21:36
  • @nico: I was being ironic. =P This clearly depends on the language, and the OP didn't specify any... – Alix Axel Jan 18 '11 at 22:57
  • 1
    This one is for the English laguage, but it might give you some inspiration: https://github.com/flourishlib/flourish-classes/blob/master/fGrammar.php – Lutsen Mar 07 '14 at 11:55
  • for the record, not all forms of plural end in 's' – Radu May 26 '16 at 07:39
  • 1
    @AlixAxel: "depends on the language, and the OP didn't specify any..." -- I know it's old, but just FTR: there was no need to be ironic, since OP *did specify clearly* that the language should be an *input of the function* s/he was looking for. (E.g. as any locale-aware L10/I18N APIs work, i.e. the same way irrespective of the specific language.) – Sz. Oct 29 '18 at 02:53

10 Answers10

50

Here is my handy function:

function plural( $amount, $singular = '', $plural = 's' ) {
    if ( $amount === 1 ) {
        return $singular;
    }
    return $plural;
}

By default, it just adds the 's' after the string. For example:

echo $posts . ' post' . plural( $posts );

This will echo '0 posts', '1 post', '2 posts', '3 posts', etc. But you can also do:

echo $replies . ' repl' . plural( $replies, 'y', 'ies' );

Which will echo '0 replies', '1 reply', '2 replies', '3 replies', etc. Or alternatively:

echo $replies . ' ' . plural( $replies, 'reply', 'replies' );

And it works for some other languages too. For example, in Spanish I do:

echo $comentarios . ' comentario' . plural( $comentarios );

Which will echo '0 comentarios', '1 comentario', '2 comentarios', '3 comentarios', etc. Or if adding an 's' is not the way, then:

echo $canciones . ' canci' . plural( $canciones, 'ón', 'ones' );

Which will echo '0 canciones', '1 canción', '2 canciones', '3 canciones', etc.

Sophivorus
  • 3,008
  • 3
  • 33
  • 43
10

This is not easy: each language has its own rules for forming plurals of nouns. In English it tends to be that you put "-s" on the end of a word, unless it ends in "-x", "-s", "-z", "-sh", "-ch" in which case you add "-es". But then there's "mouse"=>"mice", "sheep"=>"sheep" etc.

The first thing to do, then, is to find out what the rule(s) are for forming the plural from the singular noun in the language(s) you want to work with. But that's not the whole solution. Another problem is recognising nouns. If you are given a noun, and need to convert it from singular to plural that's not too hard, but if you are given a piece of free text and you have to find the singular nouns and convert them to plural, that's a lot harder. You can get lists of nouns, but of course some words can be nouns and verbs ("hunt", "fish", "break" etc.) so then you need to parse the text to identify the nouns.

It's a big problem. There's probably an AI system out there that would do what you need, but I don't imagine there'll be anything free that does it all.

Ben
  • 66,838
  • 37
  • 84
  • 108
  • 2
    Another problem is that in some European languages nouns can be masculine and feminine, and the rules for pluralising them change depending on their gender. And to make things more complicated, there is no rule to determine whether a word is masculine or feminine, you'll have to look it up in a dictionary. – nico Jan 18 '11 at 21:42
  • well googling it there are a coulpe of function that does the trick in php, the problem is they work only for english. I need it for other european language. – dynamic Jan 18 '11 at 22:27
  • @yes123: I coded one for Portuguese, it correctly handles feminine / masculine inflations. – Alix Axel Jan 18 '11 at 23:10
  • @Alix Axel: I don't know Portuguese, is there a clear rule to determine if a word is masculine or feminine? – nico Jan 18 '11 at 23:12
  • @nico: A clear rule? I wouldn't say so, no. I had to buy a "prontuário" (translation "chart" - more or less a dictionary for grammar rules) to discover that some pluralizations depend on the type of closing diphthongs. My implementation isn't perfect - I only managed to inflate most of the words, not *all* words - that would be an extremely hard task. – Alix Axel Jan 19 '11 at 00:41
  • @Alix Axel: OK, I was just wondering because I tried to do it for Italian a while ago and I found it quite hard. – nico Jan 19 '11 at 07:12
10

There is no function built into PHP for this type of operation. There are, however, some tools that you may be able to use to help accomplish your goal.

There is an unofficial Google Dictionary API which contains information on plurals. You can read more about that method here. You'll need to parse a JSON object to find the appropriate items and this method tends to be a little bit slow.

The other method that comes to mind is to use aspell, or one of its relatives. I'm not sure how accurate the dictionaries are for languages other than English but I've used aspell to expand words into their various forms.

I know this is not the most helpful answer, but hopefully it gives you a general direction to search in.

thetaiko
  • 7,816
  • 2
  • 33
  • 49
8

For anyone still stumbling across this in 2021, I suggest using the Inflector package from Doctrine.

Doctrine Inflector is a small library that can perform string manipulations with regard to uppercase/lowercase and singular/plural forms of words.

At time of writing, it supports English, French, Norwegian (bokmal), Portuguese, Spanish and Turkish.

Simply install it using composer: composer require doctrine/inflector and use it like this:

<?php
// Composer autoloading (your project probably already does this)
require __DIR__ . '/vendor/autoload.php';

// Build the inflector:
$inflector = \Doctrine\Inflector\InflectorFactory::create()->build();

// Singularize a word:
$inflector->singularize('houses'); // house
$inflector->singularize('vertices');  // vertex
Harold
  • 1,372
  • 1
  • 14
  • 25
7

English Only Solution

Here is a PHP class that has worked flawlessly for me thus far: http://kuwamoto.org/2007/12/17/improved-pluralizing-in-php-actionscript-and-ror/

Here it is as a Gist in case that site goes away: https://gist.github.com/tbrianjones/ba0460cc1d55f357e00b

This is a small class and could easily and quickly be converted to other languages.

T. Brian Jones
  • 13,002
  • 25
  • 78
  • 117
4

Here is a quick function that I usually use for less complex scenarios:

public static function getPluralPrase($phrase,$value){
    $plural='';
    if($value>1){
        for($i=0;$i<strlen($phrase);$i++){
            if($i==strlen($phrase)-1){
                $plural.=($phrase[$i]=='y')? 'ies':(($phrase[$i]=='s'|| $phrase[$i]=='x' || $phrase[$i]=='z' || $phrase[$i]=='ch' || $phrase[$i]=='sh')? $phrase[$i].'es' :$phrase[$i].'s');
            }else{
                $plural.=$phrase[$i];
            }
        }
        return $plural;
    }
    return $phrase;
}

Although for a more complex solution you can go with @T. Brian Jones' Solution

user28864
  • 3,375
  • 1
  • 25
  • 19
2

I like the answer of James Constantino. Simple and efficient, and you're sure to master every case, in any language. Though one must write more code (twice the common part of the word, namely).

I also like, of course, the TBrianJones solution, but it works only with English (as is. I can easily enhance it for my usual European languages, German, French, Spanish, Italian and Portuguese). Thanks for it. If you know the frequency of the words that will be used, you can optimize it by reorganizing the lines.

Also Felipe's proposal is good, and btw plebiscited.

But in every solution, I found what I consider as a bug: each of you use the singular form only for the value 1, and the plural form for every other case. Which is obviously wrong for negative values, but also --at least in French-- for values strictly lower than 2.

So here is my proposal, taking James's code as the base, optimized:

function singleOrPlural($amount, $singular, $plural) {
  return (abs($amount)>=2
    ? $amount.' '.$plural 
    : $amount.' '.$singular
  );
}

So a code like

echo "We bought ".singleOrPlural(1.5, "pound", "pounds")
    ." of apples and ".singleOrPlural(2, "pound", "pounds")." of bread.";

will give

We bought 1.5 pound of apples and 2 pounds of bread.

which is correct.

For the zero value, I cannot understand the reason of a plural, since there is none of the object, but maybe anglosaxon natives are used with that.

HTH, M.

Madmarsu
  • 41
  • 1
1

I came up with a rather easy solution for something like this. However, this depends on some prior knowledge of general PHP as well as a custom mySQLi class, that can be found here (which explains my use of num_rows.

In my case, I needed to pull up a number of notes from a database and say "1 note" and then the word "notes" for everything after 1, as well as something to say "0 notes".

To pull from the database and do a count, I had to use: $total_notes = $database->num_rows("SELECT notes_id FROM $notes_db");

And then the code to echo the value...

<?php
 if($total_notes === 1){
 echo '<strong>1</strong> note.';
 }elseif($total_notes > 1){
 echo '<strong>'.$total_notes.'</strong> notes.';                                                                           
 }elseif($total_notes === 0){
 echo '<strong>0</strong> notes.';                                                                      
 }
?>
Robert Dewitt
  • 324
  • 5
  • 17
0

I have a multilanguage solution.

 function howmany($number,$singular,$plural) {
      if($number==1) return $number.' '.$singular;
      else return $number.' '.$plural;
 }

Call the function like so:

echo howmany($variablenumber,upcase('kaibigan'),upcase('ng kaibigan'));

Hope this helps!

  • If you view my solution as pragmatic rather than pedantic, it solves ALL multilanguage problems with singular and plural by relying on the programmer to supply the correct singular and plural forms, such as in english '1 property' and '2 properties', a use case for a web page listing real estate portfolios I have coded. Therefore, as a pragmatic solution, LIGHTWEIGHT, bug-free, and easy to implement, I would personally rate it as the most useful solution, if not the most pedantically correct solution. Cheers! – James Constantino Nov 10 '14 at 03:24
  • 1
    Your condition is not correct for many languages) Russian, for example, uses third form (genitive) for 5-19 :) [1 сайт, 2 сайта, 5 сайтов] – vp_arth Mar 31 '15 at 12:03
  • Aside from many languages have [*far* more complex plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html), this code ironically also doesn't work for Filipino, as in your example... – leo Apr 28 '15 at 10:14
0

You can try the following,

if ( !function_exists('pluralize') ) {
    function pluralize( $amount, $singular, $plural, $show=false ) {
        $OP = $show ? $amount.' ' : '';
        $OP .= ( $amount == 1 ) ? $singular : $plural;
        return $OP;
    }
}
Vinoth Krishnan
  • 2,925
  • 6
  • 29
  • 34
Miguel Peniche
  • 981
  • 10
  • 20