If you build a PHP application using the CakePHP framework, it is easy to localize the application into multiple languages, provided you have the proper translations for those languages. If you want to internationalize your application to a global market, it is important to localize it for each language and region you want to target.
Fortunately, CakePHP and PHP itself provide us with some easy mechanisms to provide translations and localize our code without much effort. You do not have to make copies of HTML or PHP files. Everything will be done with the PHP files you already have, and the translated text strings will dynamically be inserted at render time, ready for the user in their localized language and format.
In this example, we will localize a CakePHP application that was written in English into Japanese. Let’s assume we have a menu for e-mail functions that we want to localize. This example assumes CakePHP version 2.0 (But earlier and perhaps later versions of CakePHP will work in a similar manner).
Wrapping Translatable Text in __() Functions
The first step in the localization process is to identify the text strings that will need to be translated, and replace them with CakePHP’s localized string __() function. Supposing our menu looked like the following:
<ul> <li>Send</li> <li>Reply</li> <li>Forward</li> <li>Delete</li> </ul>
We would wrap each text string inside the __() function like as follows:
<ul> <li><?php echo __('Send') ?></li> <li><?php echo __('Reply') ?></li> <li><?php echo __('Forward') ?></li> <li><?php echo __('Delete') ?></li> </ul>
The __() function identifies these strings as translatable text that will differ by language locale and uses the text within the __() function as the message ID. If we define the translations for a certain language, those translations will appear in place of these functions. If we do not define the translations for that language, the text within the __() function will display instead by default.
Creating the Localized PO Files
The next step is to create the PO files which will contain the translations for each language to be dynamically inserted in each of the __() functions. CakePHP has two ways you can do this: automatically using the console shell; or manually.
Using the I18N Shell
CakePHP has some console shell programs that you can run on the command line, including one to generate the PO file to use as the original language source file for translations. In our case it will be a file with all the English text strings.
To run the i18n shell command, type the following on the Linux command line in your CakePHP application directory:
./Console/cake i18n extract
Then follow the onscreen menu.
The shell command will examine all of your application files for instances of the __() function and generate a PO file for the original source language that you can use to create the PO files for each of the translations you are going to use.
Creating the PO Files Manually
If you want to do this manually—for example you don’t have many translatable text strings like in our example—you can create the PO files by hand in a text editor.
First we will create the original source language English version here:
/app/Locale/eng/LC_MESSAGES/default.po
The default.po file will have this format:
msgid "ID" msgstr "STRING"
Where msgid is the ID within the __() function; msgstr is the localized translation that should appear as output.
Our full English source PO file will look like this:
msgid "Send" msgstr "Send" msgid "Reply" msgstr "Reply" msgid "Forward" msgstr "Forward" msgid "Delete" msgstr "Delete"
To create the Japanese localized version, we copy the English PO file to the Japanese directory, and then replace the English strings in the msgstr field with the Japanese translations. (If you have a large application being localized into dozens of languages, it is at this point that you send the PO files to a language service provider to translate the localized strings.)
Our localized PO file with Japanese translations will go here:
/app/Locale/jpn/LC_MESSAGES/default.po
Our final localized Japanese PO file will look like this.
msgid "Send" msgstr "送信" msgid "Reply" msgstr "返信" msgid "Forward" msgstr "転送" msgid "Delete" msgstr "削除"
That’s it. The translations for English and Japanese will display appropriately for the proper locale. If you want to add translations for other languages, you do the same process and put the new PO file in the directory that corresponds with that language code. CakePHP uses the ISO 639-2 standard for naming locales. Follow that standard for naming your localized directories. Make sure you save these files at UTF-8.
Detecting and Changing Languages and Locales
Having the translations ready is nice, but you still have to detect and change to the proper language in your PHP code to get the translations to appear. Detecting the user’s language is tricky. You could do it in JavaScript or try to use something like the following PECL function:
locale_accept_from_http($_SERVER['HTTP_ACCEPT_LANGUAGE']);
In either case, you have to trust the user agent to report back the right language.
Another option is to simply have a button or menu for the user to select their language. Flag icons usually work well for this. Then you can set the language manually. In CakePHP it is easy to do with the CakeSession class:
CakeSession::write('Config.language', 'jpn);
Finally, you also have to set the locale in PHP. Since you already know this from however you determined the language above, you can use PHP’s setlocale function to do this. This is important for localization of date, time, money, and numeric separator formats among others.
setlocale("LC_ALL", "ja_JP.utf8");
That’s all there is to localizing a CakePHP application with proper translations and other locale-specific customizations.
Thank you for the awesome tutorial! Saved my day
Thanks for this tutorial! It just might be what I’ve been looking for all day — localization with CakePHP 2.x. I have the .po files and flag icons ready to go. However, I am stuck on the last part. Where do you place the code for CakeSession and setlocale?
I appreciate your help!
Hi Dee,
A natural place to work with CakeSession is in the beforeFilter() function of your controller, so that it is called before anything else.
For setlocale, you could probably put this at the very top of your view since that is where you might be using PHP functions to display things like dates and times, etc.
[…] I found this article: http://www.localizingjapan.com/blog/2011/11/10/localizing-a-cakephp-application/comment-page-1/#comm…. Does anyone know where you place the code for CakeSession::write('Config.language', 'fre'); and […]
I use https://poeditor.com/ to localize po files. It will surely be useful for you too.
Please give us a localization example for cakephp 3.
The default domain is default , therefore the locale folder should at least contain the default.po file as shown above. A domain refers to any arbitrary grouping of translation messages. When no group is used, then the default group is selected.