Sunday, February 3, 2013

Handling plurals with the Yii PHP framework


Yii (which stands for Yes, it is) is a free, open-source PHP framework started by Qiang Xue in 2008. Aimed at performance, based on MVC architecture, and following the event-driven programming paradigm, it also supports message translation, date and time formatting, number formatting, and interface localization. We will focus here on the way Yii handles the plural form format in its message translation feature in its current release (1.1.13).

Internationalization with Yii


We will set up a minimal implementation of the Yii framework that will only have one controller with one method.

The internationalization of texts in Yii can be performed from multiple sources:
  • an associative array of keys/values in a set of directories: this is the default option that uses the class CPhpMessageSource
  • a database containing a source table and a message table: this solution uses the class CDbMessageSource
  • a GNU Gettext source based on .po files or their .mo binary counterpart: this solution is defined by the class CGettextMessageSource
Each of these methods can use cachingDuration, a parameter that will cache the result of the translation for the indicated time.

In our example, we will use an associative array in PHP.

The architecture of the files will be the following:
framework/
test/protected/controllers/SiteController.php
test/protected/messages/fr/test.php
test/index.php
To correctly display the accented characters encoded in UTF-8, the language file protected/messages/fr/test.php of course needs to be encoded in UTF-8 as well, and the index file of your application (test/index.php) should indicates the character encoding with the following line:
header("Content-Type: text/html; charset=utf-8");
The file test/protected/messages/fr/test.php contains the associative array of the translation keys in the source language (which is English by default) and their translated values.
return array (
    'You have a message.' => 'Vous avez un message.',
);
In the controller, we first indicate the language of consultation (here, French), then we use the method t of the YiiBase class (defined in the file YiiBase.php) which takes as parameters the message category (here, the name of the file containing the associative array in messages/fr/, hence test), then the key (or the string in the source language).
echo Yii::t('test','You have a message.')
We get: Vous avez un message.

Pluralization with Yii


Let's go back to our problem of message pluralization as explained in a previous post (Quite singular plurals). To sum it up, some languages have different forms of grammatical numbers, and not only one singular and one plural as in English.

The example we would like to cover is this one: an interface can display 0 message (or No message), 1 message (or One message), or else n messages, n being a placeholder to be replaced on the fly during processing.

The CChoiceFormat helper (we can find in the directory framework/i18n/) is useful for expressing in a simple way the different possible values of a message thanks to the rules of languages pluralization already supported by the framework, which we can find in the directory framework/i18n/data/, in the files dedicated to each language and locale.

Those for French can be found for example in fr.php:
'pluralRules' =>
    array (
        0 => '(n>=0&&n<=2)&&n!=2',
        1 => 'true',
    ),
This is the CLocale class that accesses it via its method getPluralRules(). This method is called by the method t (used above) of the class YiiBase of which you can appreciate the code.

For more information on the types of plural by language, I refer you to the Unicode Common Locale Data Repository. The rules of pluralization are explicited there, and help writing the above formulas.

The compactness of use of these rules is illustrated here with one word.
for ($i=0; $i<3; $i++)
{
    echo Yii::t('test', "message|messages", $i);
}
Display for the values 0 to 2:
message.
message.
messages.
But a more meaningful expression can also be used.
for ($i=0; $i<4; $i++)
{
    echo Yii::t('test', "Vous avez {n} message.|Vous avez {n} messages.", $i);
}
Displays:
Vous avez 0 message.
Vous avez 1 message.
Vous avez 2 messages.
Vous avez 3 messages.
It is also possible to refine the messages by directly using a PHP expression or a value.
for ($i=0; $i<3; $i++)
{
    echo Yii::t('test', "0#Vous n'avez aucun message.|1#Vous avez un message.|n>1#Vous avez plusieurs messages.", $i);
}
Displays:
Vous n'avez aucun message.
Vous avez un message.
Vous avez plusieurs messages.

Internationalization and pluralization


The next step is of course to manage both internationalization and pluralization at the same time. To do so, we just have to use the full message with its variations of expressions in the source language (here, English) and to use it as a key in the language array.

With a language file such as this one:
return array (
    "0#You don't have any message.|1#You have one message.|n>1#You have many messages." => "0#Vous n'avez aucun message.|1#Vous avez un message.|n>1#Vous avez plusieurs messages.",
);
The following controller:
for ($i=0; $i<3; $i++)
{
    echo Yii::t('test', "0#You don't have any message.|1#You have one message.|n>1#You have many messages.", $i);
}
Still displays in French:
Vous n'avez aucun message.
Vous avez un message.
Vous avez plusieurs messages.
And in English (by commenting out the line Yii::app()->setLanguage('fr');) :
You don't have any message.
You have one message.
You have many messages.

Conclusion


As you can see from these few examples, the Yii framework developers have implemented a very elegant solution to handle plurals, allowing to express a great complexity due to the variety of possible cases while maintaining a relative ease of use. It covers a part of the different types of plurals between languages with different grammatical numbers, and it also easily manages different contextual displays for the same language.

Some reading


To go further in the understanding of the Yii framework, I recommend you these two books:
Yii Rapid Application Development

Yii Rapid Application Development, by Lauren J. O'Meara and James R. Hamilton III (2012, 340 pages)

You will discover there the development of a complete application in the form of projects and missions focused on features and key issues of both the framework and a real world application.
Web Application Development with Yii and PHP

Web Application Development with Yii and PHP, by Jeffrey Winesett (2012, 332 pages)

You will find in it an introduction to the framework, but above all the step by step development of a complete web application.

Photo credit: gringer


Gestion des pluriels avec le framework PHP Yii (in French)
Gestão dos plurais com o framework PHP Yii (in Spanish)
Gestión de los plurales con el framework PHP Yii (in Portuguese)

No comments:

Post a Comment