Internationalizing controller and view texts

In this recipe, we will learn how to internationalize text that is located in our application views, and have that content ready for translation.

Getting ready

To go through this recipe, we need some data to work with. Create a table named articles with the following SQL statement:

CREATE TABLE `articles`(
`id` INT UNSIGNED AUTO_INCREMENT NOT NULL,
`title` VARCHAR(255) NOT NULL,
`body` TEXT NOT NULL,
`created` DATETIME NOT NULL,
`modified` DATETIME NOT NULL,
PRIMARY KEY(`id`)
);

Now add some sample data to this table with the following statement:

INSERT INTO `articles`(`title`, `body`, `created`, `modified`) VALUES
('First Article', 'Body for first article', NOW(), NOW()),
('Second Article', 'Body for second article', NOW(), NOW()),
('Third Article', 'Body for third article', NOW(), NOW());

Create the controller for this table in a file named articles_controller.php and place it in your app/controllers folder, with the following contents:

<?php
class ArticlesController extends AppController {
public function index() {
$this->paginate['limit'] = 2;
$articles = $this->paginate();
$this->set(compact('articles'));
}
public function add() {
if (!empty($this->data)) {
$this->Article->create();
if ($this->Article->save($this->data)) {
$this->Session->setFlash('Article saved'),
$this->redirect(array('action'=>'index'));
} else {
$this->Session->setFlash('Please correct the errors'),
}
}
}
public function view($id) {
$article = $this->Article->find('first', array(
'conditions' => array('Article.id' => $id)
));
if (empty($article)) {
$this->cakeError('error404'),
}
$this->set(compact('article'));
}
}
?>

Create a file named article.php and place it in your app/models folder, with the following contents:

<?php
class Article extends AppModel {
public $validate = array(
'title' => 'notEmpty',
'body' => 'notEmpty'
);
}
?>

Create a folder named articles in your app/views folder, and inside that folder create a file named index.ctp with the following contents:

<h1>Articles</h1>
<p>
<?php echo $this->Paginator->counter(); ?>
&nbsp;-&nbsp;
<?php echo $this->Paginator->prev(); ?>
&nbsp;
<?php echo $this->Paginator->numbers(); ?>
&nbsp;
<?php echo $this->Paginator->next(); ?>
</p>
<p>
<?php echo count($articles) . ' articles: '; ?>
</p>
<ul>
<?php foreach($articles as $article) { ?>
<li><?php echo $this->Html->link(
$article['Article']['title'],
array('action'=>'view', $article['Article']['id'])
); ?></li>
<?php } ?>
</ul>
<p><?php echo $this->Html->link('Create article', array('action'=>'add')); ?></p>

Create a file named add.ctp and place it in your app/views/articles folder, with the following contents:

<?php
echo $this->Form->create();
echo $this->Form->inputs(array(
'title',
'body'
));
echo $this->Form->end('Save'),
?>

Create a file named view.ctp and place it in your app/views/articles folder, with the following contents:

<h1><?php echo $article['Article']['title']; ?></h1>
<?php echo $article['Article']['body']; ?>

How to do it...

  1. Edit the articles_controller.php file located in your app/controllers folder and make the following changes to the add() method:
    public function add() {
    if (!empty($this->data)) {
    $this->Article->create();
    if ($this->Article->save($this->data)) {
    $this->Session->setFlash(__('Article saved', true));
    $this->redirect(array('action'=>'index'));
    } else {
    $this->Session->setFlash(__('Please correct the errors', true));
    }
    }
    }
    
  2. Edit the file add.ctp located in your app/views/articles folder and make the following changes:
    <?php
    echo $this->Form->create();
    echo $this->Form->inputs(array(
    'legend' => __('New Article', true),
    'title' => array('label' => __('Title:', true)),
    'body' => array('label' => __('Body:', true))
    ));
    echo $this->Form->end(__('Save', true));
    ?>
    
  3. Finally, edit the file index.ctp located in your app/views/articles folder and make the following changes:
    <h1><?php __('Articles'), ?></h1>
    <p>
    <?php echo $this->Paginator->counter(__('Showing records %start%-%end% in page %page% out of %pages%', true)); ?>
    &nbsp;-&nbsp;
    <?php echo $this->Paginator->prev(__('<< Previous', true)); ?>
    &nbsp;
    <?php echo $this->Paginator->numbers(); ?>
    &nbsp;
    <?php echo $this->Paginator->next(__('Next >>', true)); ?>
    </p>
    <p>
    <?php
    $count = count($articles);
    echo $count . ' ' . __n('article', 'articles', $count, true) . ': ';
    ?>
    </p>
    <ul>
    <?php foreach($articles as $article) { ?>
    <li><?php echo $this->Html->link(
    $article['Article']['title'],
    array('action'=>'view', $article['Article']['id'])
    ); ?></li>
    <?php } ?>
    </ul>
    <p><?php echo $this->Html->link(__('Create article', true), array('action'=>'add')); ?></p>
    

If you now browse to http://localhost/articles, you should see a paginated list of articles, as shown in the following screenshot:

How to do it...

How it works...

CakePHP offers two main methods (amongst others) to allow developers to specify content that can be translated: __() and __n(). The naming of these methods may seem a bit odd, but they are largely influenced by Perl's implementation of gettext, a tool that is part of the GNU Translation Project.

The __() method is used to translate static text, and takes up to two arguments:

Argument

Purpose

singular

Text that should be translated to the current language.

return

If set to true, the translated text will be returned instead of echoed to the client. Defaults to false.

The __n() method is used to translate static text that could change if a certain value is either singular or plural, and takes up to four arguments:

Argument

Purpose

singular

Text that should be used if the given value in count is singular, and that will be translated to the current language when used.

plural

Text that should be used if the given value in count is plural, and that will be translated to the current language when used.

count

A variable or numeric value that holds the value that should be used to determine if either the singular or plural text is to be used.

return

If set to true, the translated text will be returned instead of echoed to the client. Defaults to false.

We start by changing the flash messages in the ArticlesController class to use the __() method, specifying that the translated string should be returned rather than echoed to the client. We continue by modifying the add.ctp view so that all labels and the form legend can be translated.

Similarly, we wrap the title in the index.ctp view with the translator function. We then use the first parameter of the counter(), next(), and prev() methods that are part of the PaginatorHelper class to pass the translated version of the appropriate pagination text. Finally, we use the __n() function to choose the correct translated text depending on the value of the count variable.

Note

When using the __n() function you should only use a variable as its third parameter. Using expressions (including array indexes) may produce unexpected results when running CakePHP's extractor shell, which is covered in the recipe Extracting and translating text.

Domains and categories

The translation functions used in this recipe are actually wrappers around the translate() method of CakePHP's built-in I18n class. This method not only allows simple translations, but also allows the developer to specify the domain from which translated texts are obtained, and the category to which the text to be translated belongs to.

Domains allow you to separate groups of translation text into separate files. By default, when no domain is specified, CakePHP assumes a domain named default. If you want to specify the domain in which a translated text should be looked for, use the __d() and __dn() translation functions. For example, to look for a translated text in the my_plugin domain, you would do:

$translated = __d('my_plugin', 'Hello World', true);

Categories allow for a further grouping of translated texts by grouping the translation files into separate directories, and provide further meaning to the translated text. By default, CakePHP will assume that translated texts belong to the LC_MESSAGES category. If you wish to change the category, use the __dc() and __dcn() translator functions, by setting its next-to-last argument, return, to the desired category, which can be any of the following defined constants with the respective fixed value:

  • LC_ALL: 0
  • LC_COLLATE: 1
  • LC_CTYPE: 2
  • LC_MONETARY: 3
  • LC_NUMERIC: 4
  • LC_TIME: 5
  • LC_MESSAGES: 6

For example, to look for a translated text in the default domain and the LC_MESSAGES category you would do:

$translated = __dc('default', 'Hello World', 6, true);

Note

When looking forward to using categories, always use the category value previously given in the list rather than the constant name, as this constant is platform-dependent.

See also

  • Internationalizing model validation messages
  • Extracting and translating text
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.29.145