Plural management in PHP: my plural functions
If like me you are a bit pedantic as regards orthography, even in texts, blogs, but especially in search results, for sure you have noticed, not to say shocked by, bits like“1 results found”, or even "the selected files image1.jpg have been deleted". Of course there is the usual (s) workaround, as in "1 result(s) found", but it is not the ultimate elegant way, is it? Since we are at coding, it is not much more difficult to have plural management implemented as you write along.
To facilitate the coder’s job, here PHP in this topic, but the principle remains the same regardless of the language used, may I suggest you use my very own collection of plural functions.
What are these plural functions?
Down below is my collection, that I typically have ready in an include file, preloaded in the common header (bootstrap) of all my PHP scripts.
<?php
/**
(c) Fabien Haddadi -- Free to reuse
Please keep this copyright notice as you copy-paste samples.
*/
/*****************************************************************************/
function plural_s($n) {
return $n != 1 ? 's' : '';
}
/*****************************************************************************/
function plural_is($n) {
return $n != 1 ? 'are' : 'is';
}
/*****************************************************************************/
function plural_was($n) {
return $n != 1 ? 'were' : 'was';
}
/*****************************************************************************/
function plural_has($n) {
return $n != 1 ? 'have' : 'has';
}
/*****************************************************************************/
function plural_y($n) {
return $n != 1 ? 'ies' : 'y';
}
/*****************************************************************************/
/**
e.g.
no items
items
an item
*/
function plural_an($n) {
if (!$n) return 'no';
return $n != 1 ? '' : 'an';
}
/*****************************************************************************/
/**
e.g.
no files
files
a file
*/
function plural_a($n) {
if (!$n) return 'no';
return $n != 1 ? '' : 'a';
}
/*****************************************************************************/
function plural_3rd($n) {
return $n != 1 ? '' : 's';
}
/*****************************************************************************/
/**
e.g.
3 deleted.
none deleted.
*/
function plural_none($n) {
return $n != 1 ? $n : 'none';
}
/*****************************************************************************/
/**
e.g.
0 item[s] found
1 item[] found
3 item[s] found.
*/
function plural_no($n) {
return $n != 1 ? $n : 'no';
}
/*****************************************************************************/
/**
e.g.
your other []order
your other [2 ]orders
*/
function plural_n_or_empty($n) {
return $n? $n . ' ' : '';
}
/*****************************************************************************/
function plural_it($n) {
return $n != 1 ? 'them' : 'it';
}
/*****************************************************************************/
function plural_other($n) {
if (!n) return "no other";
return plural_an($n) . 'other';
}
/**
Add more here...
*/
?>
How to use them?
All these functions return strings, that are either suffixes to be added, or suffixes used as substitutes. In all cases, what you need to do is concatenate them, with either the dot . operator ou the sprintf function, my favourite way, as I find it more legible.
Examples:
<?php
// Example 1, trivial case
$msg = sprintf("%d item%s displayed", plural_n($nb), plural_s($nb));
/**
Example 2, still easy
Let $InvalidDetailsList be a comma separated value list of details that have been rejected by a validation routine
e.g. $InvalidDetailsList = "1003,1017,1023";
*/
if ($n = str_word_count($InvalidDetailsList, 0, ',')) {
$_SESSION['message'] = sprintf("%d of the details entered %s not correct. Please correct %s.",
$n,
plural_was($n),
plural_it($n)
);
}
// In this example, $_SESSION['message'] = "3 of the details entered were not correct. Please correct them."
/**
Example 3, a slightly more complicated because it involves "no" if $nb_updated is zero or null.
*/
$_SESSION['message'] .= sprintf("%s name%s %s been updated.",
plural_no($nb_updated),
plural_s($nb_updated),
plural_has($nb_updated)
);
/**
Could lead to
$_SESSION['message'] .= "no names have been updated"
or
$_SESSION['message'] .= "1 name has been updated"
or even
$_SESSION['message'] .= "3 names have been updated"
*/
/**
Example 4 : here is an even more complicated one, since if $n != 1,
we'll display $n between "your" and "other orders".
Let $n be a number of orders (integer)
*/
$warning = sprintf("Your %sother order%s contain%s the same item.",
plural_n_or_empty($n),
plural_s($n),
plural_3rd($n)
);
// Si $n == 1, $warning = "Your order contains the same item."
// Si $n > 1 (e.g. 3), $warning = "Your 3 other orders contain the same item."
?>
What if I need these in French?
Syntax for plural follows a very different rule in French. Any quantity greater than or equal to 2 leads to a plural, otherwise it is singular, even 1.9999999!
Anyway I thought of you. Read on.