Webtools:Mozparty/L10n
Contents
Localization
Starting with CakePHP 1.2 localization functions are included the library. GNU gettext is not required nor are any of the gettext tools.
Static Strings
If you're already familiar with gettext, Cake's __()
and __n()
(note the double underscore) functions from basics.php should help you feel right at home. These are Cake's equivalents of the aliases for the traditional gettext()
and ngettext()
functions - though there are a few differences.
Singular Strings
Say we want to display simple string like "Needs more pie". To do this we want to pass a key that represents our string to the __()
function:
-
__('error_need_pie');
Note that as apposed to the gettext equivalent there is no need to use echo
as it's assumed that that's what you want to do by default.
"That's handy, but what about when I need to assign to a variable or use it within a function?"
__()
takes two parameters: your string key and a boolean indicating whether to return instead of echoing the result (false by default). For this example let's cover both this and string replacement using sprintf
. We'll also take our simple string from before and change it to "Needs more %s pie":
-
echo sprintf(__('error_need_pie', true), 'apple');
Plural Strings
Let's again morph our simple string into "Needs 1 more pie". This string is fine if we're only ever going to need one more pie, but if we want to make the number of pies variable, we're going to need our string to change between plural and singular forms based on the number of pies - this is where __n()
comes in. __n()
takes 4 arguments: the singular string key, the plural string key (we'll be using the same key for both), the number of items and a boolean indicating whether to return or echo:
-
__n('error_need_x_pies', 'error_need_x_pies', $num_pies);
Updating PO files
Say goodbye to the msginit
and msgfmt
gettext tools as you're not going to need them anymore! Cake (almost) automatically takes care of the extracting and compiling steps of a traditional gettext setup for you.
Extracting
To extract localizable strings from the application, move to the /cake/console/ directory and run php cake.php i18n
on the commandline and follow the prompts:
Welcome to CakePHP v1.2 Console --------------------------------------------------------------- What is the full path you would like to extract? Example: /mozparty/myapp [Q]uit [Q] > /mozparty/app What is the full path you would like to output? Example: /mozparty/app/locale [Q]uit [/mozparty/app/locale] > (enter) I18n Shell --------------------------------------------------------------- [E]xtract POT file from sources [I]nitialize i18n database table [H]elp [Q]uit What would you like to do? (E/I/H/Q) > E Extracting... --------------------------------------------------------------- Path: /mozparty/app Output Directory: /mozparty/app/locale/ --------------------------------------------------------------- Would you like to merge all translations into one file? (y/n) [y] > (enter) What should we name this file? [default] > (enter) Processing... Error: default.pot already exists in this location. Overwrite? (y/n/q) [n] > y Done.
Merging
Now that we've created a PO template (.pot) from our source we need to update our PO file using it. To do this, we'll use poEdit:
- Open the locale's default.po file in poEdit
- Select Catalog > Update from POT file
- Select the default.pot file in app/locale/
poEdit simply calls its own bundled copy of msgmerge
- so if you have it handy, it's a perfect poEdit alternative.
Compiling
Fuhgeddaboutit!
In production mode (Config::write('debug', 0)
in app/config/core.php), Cake will automatically generate MO files using any PO files present in the locale. In any of the debug modes, Cake will read directly from the PO files and any changes made to the PO files will be reflected immediately in the app.
Dynamic Strings
In any model that needs to have fields saved as translated strings simply use the Translation behavior and indicate which fields will contain translated content:
class Pie extends AppModel { var $actsAs = array('Translate' => array('flavor', 'description')); }
Caveat: Cake ticket 3680 means that using a translatable model from another (by way of any of the associations) won't work. You'll need to fetch data directly from the translated model and do any necessary association footwork manually.