• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Internationalizing CakePHP Applications
 

Internationalizing CakePHP Applications

on

  • 12,449 views

Slides from the talk given by Mariano Iglesias during the CakeFest #3 - July 2009...

Slides from the talk given by Mariano Iglesias during the CakeFest #3 - July 2009

Note: the original pdf and the code related to this talk can be found on cakephp.org (http://cakephp.org/downloads/CakeFest/CakeFest%203%20-%20Berlin%202009/Mariano%20Iglesias%20-%20Internationalizing%20CakePHP%20Applications)

Statistics

Views

Total Views
12,449
Views on SlideShare
12,390
Embed Views
59

Actions

Likes
5
Downloads
130
Comments
2

5 Embeds 59

http://www.slideshare.net 45
http://www.pierre-martin.fr 8
http://www.apurva.com 3
http://www.php.rk.edu.pl 2
http://coderwall.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

12 of 2 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Great slides. This is a right method for a site with high traffic?
    Are you sure you want to
    Your message goes here
    Processing…
  • Loved it, answered all my questions about cakephp internationalization.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Internationalizing CakePHP Applications Internationalizing CakePHP Applications Presentation Transcript

    • Internacionalization Building multi-language applications with CakePHP
    • Who am I? ● The argentinean in the Cake team ● A C++ developer that turned to Java, then PHP ● Working exclusively with CakePHP for 3 years
    • Oh, BTW Tomorrow is my birthday
    • Why do we need i18n? ● Expand your audience ● CakePHP makes it simple ● Translators don't have to know our application ● Works with files (views, models, controllers), and database records ● Think about your future needs
    • This could get you killed ● The switch lover switch ($language) { case 'en': echo 'My message'; break; case 'es': echo 'Mi mensaje'; break; } ● The table lover $terms = $this->Term->find('all'); $terms = Set::combine($terms, '/Term/code', '/Term/text'); $this->set(compact('terms')); // ... echo $term['my_message'];
    • The CakePHP way ● Methods ● __() -> __('My message') ● __n() -> __n('An element', 'Several elements', $count) ● Configure::write('Config.language', 'en') ● Translate behavior ● i18n extractor
    • The CakePHP way ● Multibyte ● 1 letter != 1 byte ● 8 bits -> 256 ● wchar_t (L'w') ● mb_strlen(), mb_strpos(), mb_substr(), ... ● Multibyte::checkMultibyte() -> ord($char) > 128 ● Multibyte::utf8($string) -> array (values higher than 128 allowed) ● Multibyte::ascii($array) -> string
    • The CakePHP way <p><?php __('Welcome to my page'); ?></p> <?php echo $html->link(__('Home', true), '/'); ?> <p><?php echo sprintf(__('Your name is %s', true), $name); ?></p> $ cake i18n extract -output app/locale locale/eng/LC_MESSAGES locale/ default.po default.pot POEDIT default.mo
    • Let's go to work ● Our own example ● Modify the view ● Run the extractor ● Look at the generated template file ● Run POEDIT → nplurals=2; plural=(n != 1); ● Look at the translated files ● Some tips when using POEDIT
    • Translate Behavior ● Internationalization for our database records ● All translations in the same table ● Automatically filters the records to fetch them in the current language
    • Translate Behavior class Post extends AppModel { public $actsAs = array('Translate' => array( 'title', 'body' )); public $belongsTo = array('User'); } CREATE TABLE `posts`( CREATE TABLE `posts`( `id` INT NOT NULL AUTO_INCREMENT, `id` INT NOT NULL AUTO_INCREMENT, `user_id` INT NOT NULL, `user_id` INT NOT NULL, `title` VARCHAR(255) NOT NULL, `title` VARCHAR(255) NOT NULL, `body` TEXT, `body` TEXT, `created` DATETIME, `created` DATETIME, `modified` DATETIME, `modified` DATETIME, PRIMARY KEY(`id`) PRIMARY KEY(`id`) ); );
    • Translate Behavior mysql> desc i18n; +-------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+----------------+ | id | int(10) | NO | PRI | NULL | auto_increment | | locale | varchar(6) | NO | MUL | NULL | | | model | varchar(255) | NO | MUL | NULL | | | foreign_key | int(10) | NO | MUL | NULL | | | field | varchar(255) | NO | MUL | NULL | | | content | text | YES | | NULL | | +-------------+--------------+------+-----+---------+----------------+ mysql> select * from i18n; +----+--------+-------+-------------+-------+------------------------------------------+ | id | locale | model | foreign_key | field | content | +----+--------+-------+-------------+-------+------------------------------------------+ | 1 | eng | Post | 1 | title | Pre-registration opened | | 2 | spa | Post | 1 | title | Pre-inscripciones abiertas | | 3 | eng | Post | 1 | body | Body for Pre-registration opened | | 4 | spa | Post | 1 | body | Cuerpo para Pre-inscripciones abiertas | +----+--------+-------+-------------+-------+------------------------------------------+ 4 rows in set (0.00 sec)
    • Translate Behavior $posts = $this->Post->find('all', array( 'recursive' => -1, 'fields' => array('title', 'body') )); $posts = Set::combine($posts, '/Post/title', '/Post/body'); SELECT `I18n__title`.`content`, `I18n__body`.`content` FROM `posts` AS `Post` LEFT JOIN `i18n` AS `I18n__title` ON (`Post`.`id` = `I18n__title`.`foreign_key` AND `I18n__title`.`model` = 'Post' AND `I18n__title`.`field` = 'title') LEFT JOIN `i18n` AS `I18n__body` ON (`Post`.`id` = `I18n__body`.`foreign_key` AND `I18n__body`.`model` = 'Post' AND `I18n__body`.`field` = 'body') WHERE `I18n__title`.`locale` = 'eng' AND `I18n__body`.`locale` = 'eng' array( [Pre-registration opened] => Body for Pre-registration opened [Site Updates] => Body for Site Updates )
    • Translate Behavior $this->Post->create(); $this->Post->save(array('Post' => array( 'user_id' => 1, 'title' => array('eng' => 'ENG 1', 'spa' => 'spa1'), 'body' => array('eng' => 'Body for ENG 1', 'spa' => 'Cuerpo para spa1') ))); $this->Post->create(); $this->Post->save(array('Post' => array( 'user_id' => 1, 'title' => array('eng' => 'ENG 1'), 'body' => array('eng' => 'Body for ENG 1') ))); $this->Post->save(array('Post' => array( 'id' => $this->Post->id, 'title' => array('spa' => 'spa1'), 'body' => array('spa' => 'Cuerpo para spa1') )));
    • Changing the language class AppController extends Controller { public $components = array('Cookie'); public function beforeFilter() { $lang = null; if (!empty($this->params['url']['lang'])) { $lang = $this->params['url']['lang']; $this->Cookie->write('CakeFestLanguage', $lang, false, '+365 days'); } else { $lang = $this->Cookie->read('CakeFestLanguage'); } if (empty($lang)) { $lang = Configure::read('CakeFest.defaultLanguage'); } Configure::write('Config.language', $lang); } function beforeRender() { $this->set('currentLanguage', Configure::read('Config.language')); } }
    • Changing the language class AppHelper extends Helper { Public function url($url = null, $full = false) { if (!empty($url) && !is_array($url) && $url[0] == '/') { $urlRoute = Router::parse($url); if (!empty($urlRoute['controller'])) { $url = array_merge(array_intersect_key($urlRoute, array_flip(array('admin', 'controller', 'action', 'plugin'))), $urlRoute['pass'], $urlRoute['named']); } } if (is_array($url)) { if (!isset($url['lang']) && Configure::read('Config.language') != Configure::read('CakeFest.defaultLanguage')) { $url['lang'] = Configure::read('Config.language'); } } return parent::url($url, $full); } }
    • Caching i18n elements $this->element('news', array('cache' => array( 'time' => '+1 day', 'key' => $currentLanguage ))); tmp/cache/views element_eng_news element_spa_news
    • And we are done Questions?