Multilingual apps with CakePHP

Note: If you are looking for a way to set page titles in CakePHP it is here

There are basic two ways to creating a multilingual app in traditional PHP, using a file with variables for each of the phrase which our Coppermine Picture Gallery uses and then there is the gettext series of functions in PHP, which while a very good option for desktop apps can be a pain for web apps because they are dependent on server as well as client LOCALE. CakePHP V1.2 is the framework which allows you to take the quantum leap of using gettext like functionality with minimum of hassles and at the same time address the common problems which a PHP programmer faces while creating multilingual apps

What I outline below is an example of translating a sentence in a view and some tips on working with .po files. The sentence which I want to make multilingual is “Hello Grandma!” starting with the view – you write

  1. <?php __('Hello Grandma') ?>

Thats it! As far as your ‘view’ is concerned it is now multilingual ready, no I am not joking really, if you do not do anything else the ‘Hello Grandma’ will still render properly, do note that you are not required to write echo or print if you use the __() function without the second parameter.

OK, while making the view multilingual ready take less work than your regular echo(ing) making the translations work takes a bit more work. We now want ‘Hello Grandma’ to appear in French – ‘Bonjour grand-maman’.

Start by creating a file /app/locale/fre/LC_MESSAGES/default.po

Note here that the ISO 639-2 language codes are used to name the folder, and you have rightly guessed fre is the code for French, the default.po file is what will contain the translated text and is written in the following simple pattern

  1. msgid  "Hello Grandma"
  2. msgstr "Bonjour grand-maman"

Some people prefer the msgid to be more varaiblish like ‘hello_grandma’ (with a corresponding change in the view) but I rather prefer to give the msgid in plain English, which also happens to be the default language for all of my development.

Now the only step that remains is setting the language to use. For this in your controller write

  1. Configure::write('Config.language', 'fre');

If you write the same key to session then the language code in session will take precedence – I use this trick to allow for user selectable languages.

Since we are now using gettext, if you are on a *nix development machine you get a number of useful CLI tools which ease the process of creating .po files the first among them is xgettext a utility to extract gettext strings from source and create a .po file. If your view files is called hello.ctp then from the commandline while in the same directory as your view file do

  1. xgettext -L php --keyword=__ hello.ctp

this will result in a file called messages.po which will have all the strings which you need to translate as msgid, xgettext is very powerful and can work on entire folders with subfolders. See the xgettext man page for more information.

Two other useful utilities are msgcat and msgattr, msgcat allows you to combine several message catalogs and msgattrib allows for attribute matching and manipulation on message catalog.

An idea for combining several .po files into one without any duplication can be done with something like

  1. msgcat --use-first  general.po [^g]*.po | msgattrib  --no-fuzzy -o default.po

as shown here

If you have any particular trick of your own I would love to hear from you….

Update: Running ./cake extract from the command line allows you to extract all the messages to be translated into a convenient default.pot file

About Tarique Sani

Dr. Tarique Sani is a pediatrician and forensic expert by education. He is a PHP programmer of 'wrote the book' caliber and has to his credit several very popular open source as well as commercial PHP projects. He leads a team of dynamic programmers at SANIsoft who have in-depth understanding of Web development tools and usability practices with strong developmental skills in PHP, MySQL/PostgreSQL, HTML, DHTML, Javascript, and Linux/Apache

17 Responses to Multilingual apps with CakePHP

  1. Andrew June 12, 2007 at 7:47 pm #

    Hi,

    I’m interested to know how you set up your URL strucutre.

    I’ve done it a few ways, mod-rewritten sub-domains

    en.domain.com/store/shirts/

    and first url segment

    domain.com/en/store/shirts/

    last url segment

    domain.com/store/shirts/en/

    and query string

    domain.com/store/shirts.php?lang=en

    I’ve never really decided what is the best semantically. For big apps I now use sub-domain, for smaller I use first url segment … it’s easier to ID it, vs using last url segment which can confuse dispatching (if all URL’s in the site do not have the same number of segments … which is normal, then you have to test the last segment of each url etc …)

    But what is more meaningful … to imply that there be two “stores”

    domain.com/fr/store/
    domain.com/en/store/

    ? or would there be one store, with sub page per lang
    domain.com/stores/shirts/fr/
    domain.com/stores/shirts/en/

    domain.com/home/en/

    I’m really interested to know what others think.

  2. Tarique Sani June 12, 2007 at 8:33 pm #

    I prefer doing domain.com/fr/store/ or domain.com/en/store/ would be most appropriate as it indicates a clear hierarchy in URL with two stores one French and one English

  3. Jelka July 4, 2007 at 1:00 am #

    Do you by any chance know how to only get the string but not to output in the new cakePHP?

    I tried setting page title
    $this->pageTitle = __(‘My page title’);

    but this only echos my translated string to output (where it shouldn’t) and my page title is not what I want it to be.

    Any ideas ?
    I was searching tutorials but this does not seem to be covered at so well.

  4. Tarique Sani July 4, 2007 at 10:21 am #

    Try $this->pageTitle = __(‘My page title’,true); Note the second parameter, sending the second parameter as ‘true’ returns the translated string.

  5. Bido November 28, 2007 at 10:08 pm #

    Hi all!
    I just start a new site with cakephp 1.2 and while searching for “Multilingual” example I found this really useful post.

    I’d like to implement the “domain.com/en/store/shirts/” web link solution but I’m not able to found a clear tutorial about this…

    I just use the admin routing from cakephp manual but I think is not applicable in this situation…

    Can you help me? Do you know any tutorial about this procedure?
    Tnx!

  6. Fistro March 7, 2008 at 7:32 pm #

    hi!

    nice article, very helpful for me.

    A little correction: I’ve found that to extract the messages to be translated should be executed the ./cake i18n command.

    Thank you again.

  7. Tarique Sani March 8, 2008 at 11:07 am #

    @Fistro yes cake i18n it the current command

  8. suman November 11, 2008 at 1:26 pm #

    Hi, in default.po file i have writen
    msgid “Hello Grandma”
    msgstr “Bonjour grand-maman”

    now i want to display the text of msgstr using msgid. Could I get the details stape.
    Thanks

  9. Tarique Sani November 11, 2008 at 2:07 pm #

    @Suman – the above tutorial explains exactly what you are asking…. please let me know which part you did not understand?

  10. Shaun October 15, 2009 at 5:06 pm #

    What about localized validation errors in the model? I am trying to move the errors inside the view according to the documentation here:
    http://book.cakephp.org/view/133/Multiple-Rules-per-Field

    Instead of getting localized errors, it just outputs the name of my validation rule.

    In 2009, CakePHP documentation is still crap.

  11. Tarique Sani October 15, 2009 at 6:50 pm #

    @Shaun Localized errors work as advertised in the page you are quoting….

  12. Julia November 13, 2009 at 6:57 pm #

    I have an issue with l18n and accented characters (e.g. é,ö,è .etc…) Looks like a bug to me, could you guys have a look at this point on cakephp group:-

    http://groups.google.com/group/cake-php/browse_thread/thread/3760347ce8b689eb/6a10c164fca71a1c?lnk=gst&q=extended+characters#6a10c164fca71a1c

    Thanks-

  13. jar atc December 2, 2009 at 1:55 pm #

    This is not very clear, i do not know if cakephp is still developing this feature, or it is just well documented, but each place tells one thing apart on how to do it…. It is just starting to be like ACL some months ago… getting crazy…

Trackbacks/Pingbacks

  1. developercast.com » Sanisoft Blog: Multilingual apps with CakePHP - June 11, 2007

    [...] the Sanisoft blog today, there’s a quick tutorial demonstrating how to create a multilingual application with the CakePHP framework: There are [...]

  2. DuperMag » Archivo » Que fácil es hacer sitios multi-idioma con CakePHP 1.2 - June 13, 2007

    [...] (¿klingon quizá?). Las instrucciones más exactas de como lograrlo están en el sitio de sanisoft Por sosa en [...]

  3. Blog Dot Php With cakePHP » Полезные ссылки по cakePHP - January 26, 2008

    [...] Создание мультиязычного приложения [...]

  4. AmZ: Witaj! - August 29, 2008

    [...] Multilingual apps with CakePHP [...]

Leave a Reply