developing cakephp multilingual website

To develop any multilingual website (Translated database content only) using cakephp framework all basic steps are discussed below. If you want fully multilingual website with translated button text or label text then go forward with Internationalizing your application
To manage multiple language translated content for any specific models specific field cakephp has a core behavior named TranslateBehavior.
Suppose we want a website with multiple number of language support and site administrator can add/edit/delete any language and front-end user can choose any language to visit the website.
Here are the list of steps given below.
Step 1: Create a db language table

CREATE TABLE `languages` (
  `id` int(11) NOT NULL auto_increment,
  `title` varchar(120) NOT NULL,
  `flag` varchar(100) default NULL,
  `code_2_digit` varchar(2) NOT NULL,
  `code_4_digit` varchar(6) NOT NULL,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

now do a management for languages db table for site administrator

Step 2: Add a language as default on cakephp core

Configure::write('Config.language', 'en_us');

Step 3: Create a db table i18n

CREATE TABLE `i18n` (
  `id` int(10) NOT NULL auto_increment,
  `locale` varchar(6) NOT NULL,
  `model` varchar(255) NOT NULL,
  `foreign_key` int(10) NOT NULL,
  `field` varchar(255) NOT NULL,
  `content` mediumtext,
  PRIMARY KEY  (`id`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

Suppose you want to add this multilingual features for db pages table and the translateable field will be title and description here
Step 4: Create a db pages table

CREATE TABLE `pages` (
    `id` int(11) unsigned NOT NULL auto_increment,
    `title` varchar(255) default NULL,
    `identifier` varchar(255) default NULL,
    `description` text,
    `meta_key` text,
    `meta_desc` text,
  PRIMARY KEY  (`id`),
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

and then on page.php model you need to add The translate behavior as below

var $actsAs = array(
        'Translate' => array(
            'title'=>'titleTranslate', 'description'=>'descriptionTranslate'
        )
    );

Basically that’s all, now if you add or save this Page model with data on i18n table there will be added 2 new row or update existing row as:
i18n table data samle:

id: auto id
locale:	Configure::read('Config.language'); //'en_us'
model: Page
foreign_key: page_id from Page model
field: title
content: new or updated content for title field

and

id: auto id
locale:	Configure::read('Config.language'); //'en_us'
model: Page
foreign_key: page_id from Page model
field: description
content: new or updated content for description field

now if you change the configuration value with es_mx like

Configure::write('Config.language', 'es_mx');

then when saving Page model all fields value will be same but locale filed value will be es_mx.

So if you want to save Page models data with another language like Spanish (Mexico)
you can use below code on controller before same the Page model

$this->Page->locale = 'es_mx';
$this->Page->save($this->data);

Additional Steps: Saving all languages content at a time.
if you go for edit Page model and load specific row by id and debug it’s value like

$this->data=$this->Page->read();
pr($this->data);

the pr() output will be look like

Array
(
    [Page] => Array
        (
            [id] => 14
            [title] => Terms & Condition
            [identifier] => terms-condition
            [description] => Terms & Condition Description will goes here
            [meta_key] =>
            [meta_desc] =>
            [locale] => en_us
        )

     [titleTranslate] => Array
        (
            [0] => Array
                (
                    [id] => 15
                    [locale] => en_us
                    [model] => Page
                    [foreign_key] => 14
                    [field] => title
                    [content] => Terms & Condition
                )

            [1] => Array
                (
                    [id] => 132
                    [locale] => es_mx
                    [model] => Page
                    [foreign_key] => 14
                    [field] => title
                    [content] => Terms & Condition
                )

        )

    [descriptionTranslate] => Array
        (
            [0] => Array
                (
                    [id] => 16
                    [locale] => en_us
                    [model] => Page
                    [foreign_key] => 14
                    [field] => description
                    [content] => Terms & Condition Description will goes here

                )

            [1] => Array
                (
                    [id] => 133
                    [locale] => es-mx
                    [model] => Page
                    [foreign_key] => 14
                    [field] => description
                    [content] => Terms & Condition Description will goes here

                )

        )

)

So that means you can save all languages i18n entry at a time with cakephp saveAll method!

Our target is to save all languages(which all is already available on languages db table) translated content at a time for Page model.
To do it, create a translate method on pages_controller.php like

function admin_translate($id=null) {
        if($id==null){
            $this->redirect($this->referer());
            exit;
        }

        if(!empty($this->data)){
            if($this->Page->saveAll($this->data)) {
                $this->Session->write('Success',true);
                $this->Session->setFlash('Page has been seved successfully!');
                $this->redirect(array('controller' => 'pages', 'action' => 'index'));
                exit;
            }
        } elseif($id) {
            $this->Page->id=$id;
            $this->data=$this->Page->read();
            $this->set('id',$id);
        }

       $this->paginate = array('Language' => array('limit' => $this->admin_page_factor));
       $languages = $this->paginate('Language');
       $this->set(compact('languages'));
}

now create a admin_translate.ctp for Page model and create a form to save Page model and it’s sub entry like numtiple titleTranslate and descriptionTranslate with all fields and submit that form on admin_translate method!

Final step: Management for front-end visitor
For front-end landing page show the list of languages from languages db table.
When visitor click on any language to choose it then redirect him/her on a page and save visitor chosen language code on SESSION and redirect him/her on site home page like

function choose($identifier){
        $this->Session->write('language',$identifier);
        $this->redirect(array('controller' => 'pages', 'action' => 'display', 'home'));
        exit;
 }

and on site home page load the page content like

$this->Page->locale = $this->_get_language();
$identifier=='home';
$details=$this->Page->findByIdentifier($identifier);

where _get_language(); is a method from app_controller.php to get current SESSION 4 digit language code like

    /**
    * If it is defined the language in session using landing page then it will return language
    * other wise it will return en_us as default
    *
    * @return String
    * @access public
    */
    public function _get_language(){
        $language = $this->Session->read('language');
        if(empty($language)){
            $language = 'en_us';
        }
        return $language;
    }
 

8 thoughts on “developing cakephp multilingual website

  1. Hi,

    A good starting point however for people just getting involved in full-app localization, you seemed to leave out your most crucial part.

    “now create a admin_translate.ctp for Page model and create a form to save Page model and it’s sub entry like numtiple titleTranslate and descriptionTranslate with all fields and submit that form on admin_translate method!”

    Could you please elaborate on this with an example?

    Thank you.

    Like

  2. Hey,

    finally I found a really good article on that subject. But right now I’m stuck at creating the admin_translate.ctp. To be specifig, how the input fields for the translations should be created.

    Could you post the code of the ctp here?

    Thanks in advance!

    Like

  3. Hi,

    either I’m too stupid or the comment view here is broken. I can only see the speech bubble and “2 comments” but I don’t see the actual comments.

    Like

  4. Hi,
    I couldn’t understand the mean of ‘now do a management for languages db table for site administrator’. Do i need to insert the languages in db by phpMyAdmin?

    Thanks

    Like

  5. Hi,

    What you mean by ‘now do a management for languages db table for site administrator’ and how can i get the data for all languages?

    Thanks

    Like

    1. Please see my attachment on this post, where I have added 2 screenshot for language management, 1 controller, 1 model and the view folder from one of my live projects, You are advised to just follow the steps and idea. Thanks

      Like

  6. Hello.
    I’m building a multilingual app with CakePHP and I “took advantage” of your tutorial.
    In the app I want administrator to add and edit subpage in all available languages within one form.

    The add function works fine, the problem is when I want to edit
    subpage and all translations at one time with the use of one form – one of the fields does not want to update in i18n table with translations.

    My Subpage model:
    http://pastebin.com/Mas1aciu

    admin_add function in subpages_controller.php (works fine, adds record to “subpages” table and records to “i18n” table containing title, link and content in every language):
    http://pastebin.com/N61WLwNQ

    admin_add view:
    http://pastebin.com/Y6a1WquA

    admin_edit function:
    http://pastebin.com/1ZdumqUe

    admin_edit view:
    http://pastebin.com/BWcXvGKY

    The “link” field is created on the basis of entered title. Saving changes after editing the title and content in every language affects only the translations of fields “link” and “content” in i18n table. The “title” field just doesn’t want to change.

    I have a Polish – pol – and German – ger – languages in my app.
    The var_dump($this->request->data) after submiting edit form, called before Subpage->saveAll, returns:

    array(1) {
    [“Subpage”]=>
    array(8) {
    [“id”]=>
    string(1) “1”
    [“title”]=>
    array(2) {
    [“pol”]=>
    string(15) “Title in Polish”
    [“ger”]=>
    string(15) “Title in German”
    }
    [“content”]=>
    array(2) {
    [“pol”]=>
    string(34) ”

    Test content in Polish


    [“ger”]=>
    string(34) ”

    Test content in German


    }
    [“only_footer”]=>
    string(1) “0”
    [“only_logged”]=>
    string(1) “0”
    [“link”]=>
    array(2) {
    [“pol”]=>
    string(15) “title-in-polish”
    [“ger”]=>
    string(15) “title-in-german”
    }
    }
    }
    Even that in var_dump both [title] versions values are updated (AND the “link” fields are correctly transformed on the basis on the titles) – “title”s don’t update in ‘i18n’ table.

    I’ve also build another model – Category. Same issue here, although I
    translate only two fields (name and link, based on the name). The same
    situation with saving changes after edit – only “link” translation is being updated, and “name” isn’t.

    Do you have a clue what could be the problem?

    Regards,
    Anna

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.