Yii 1.1: How to translate and do the translations the easy way

21 followers

Introduction

I wanted to keep all the I18N related translations in separate files, so that I would not need to modify the view files or the model files every time I need to update or fix the translations of application's source language.

So I figured out I can do it this way - it is 100% Yii compatible.

Set Configuration Parameters (Step 1)

First set the value of sourceLanguage parameter to 2 zeroes. Numbers are not allowed in ISO language codes, so they make excellent use as null values. Then set the value of language parameter to your default language.

For example, I use en as default language.

In the file protected/config/main.cfg:

'sourceLanguage'=>'00',
'language'=>'en',

A good idea is to implement application's language management in a base controller, overriding init() method. Language must be set on every controller's execution, or else application's multilingual features do not work as expected.

Another idea is to create and configure a language management behavior for your application.

Use Message Labels (Step 2)

Now you can call and write all Yii::t() functions with message labels, instead of meaningful text.

For example, I have a model Person with a last_name attribute, and I modify attributeLabels() method.

In the file protected/models/Person.php:

public function attributeLabels {
    return array(
        'last_name'=>Yii::t('app','model.person.last_name'),
    );
}

Create Translation Files (Step 3)

Now create message file app.php in all language folders that you are going to use.

For example, I use en, fr, de languages and I need to create the following files:

protected/messages/de/app.php
protected/messages/en/app.php
protected/messages/fr/app.php

And in all of those files you need to write the translated messages labels.

In the file protected/messages/en/app.php:

'model.person.last_name' => 'Last name',

In the file protected/messages/fr/app.php:

'model.person.last_name' => 'Nom de famille',

In the file protected/messages/de/app.php:

'model.person.last_name' => 'Nachname',

Modify Yii Framework Translations (Optional)

Optionally, if you want to modify framework's translations, you can configure application's coreMessages component to set basePath to null. This way the framework searches for translation files in protected/messages folder.

In the file protected/config/main.php:

'coreMessages'=>array(
    'basePath'=>null,
),

Now you can, for example, copy framework/messages/de/yii.php and framework/messages/de/zii.php files to protected/messages/en, protected/messages/de and protected/messages/fr folders, use some regular expression patterns on those files to replace array values with nulls, and they are ready to use.

Now you can modify the following files to suit your needs:

protected/messages/de/yii.php
protected/messages/de/zii.php
protected/messages/en/yii.php
protected/messages/en/zii.php
protected/messages/fr/yii.php
protected/messages/fr/zii.php

Modify Yii Framework Code (Optional)

Optionally, if you want to make use of empty translation strings, then you can modify translateMessage() method in CMessageSource class to comment out empty string check.

NB! Remember this when you upgrade your Yii distribution!

In the file framework/i18n/CMessageSource.php, line 104 (Yii version 1.1.15):

if(isset($this->_messages[$key][$message]) /*&& $this->_messages[$key][$message]!==''*/)

This is not recommended, unless it is absolutely necessary.

A better way would be to create your own class to handle this case, but since $_messages is a private property you need to reimplement the translateMessage() method.

Create Gii Code Generation Templates (Optional)

You can also create your own code generation templates now.

For example, I use Gii module and I use tmpl1 as my code generation template name.

In the file protected/gii/model/templates/tmpl1/model.php:

public function attributeLabels() {
    return array(
<?php foreach($labels as $name=>$label): ?>
        <?php echo "'$name'=>Yii::t('app','model.$tableName.$name'),\n"; ?>
<?php endforeach; ?>
    );
}

Great Success!

Now you can manage all your translations in one place - under messages folder.

Total 3 comments

#7503 report it
drsimonz at 2012/03/26 04:54pm
Seems like a good compromise

This is great, good idea... it's super annoying having the source language messages in the view files. That makes perfect sense for a simple app, but when you have 10 languages and hundreds of files, not to mention dynamic user-editable messages, it becomes impossible to stay on top of I18N using the normal Yii style. I had to write a very complex tool to make it easier to add and edit translations for all languages. This will save further time once we convert. And it looks like the performance cost of translating for the source language is minuscule.

#5243 report it
redguy at 2011/09/26 06:54am
modifying any code provided by others

Not only it is not recommended to change framework code (like Say_Ten already posted), but also any code from other providers (i.e. giix templates). Such modyfication leads to problems with upgrading code when new versions are published. Instead - there is always possibility to configure components to use our own code with our modyfications.

For CPhpMessageSource - you can extend this class and configure 'components' section in config file. For Giix templates you can provide your own templates directory:

'modules'=>array(
  'gii'=>array(
     'class'=>'system.gii.GiiModule',
     'generatorPaths'=>array(
       'ext.myGiixTemplates',
       'ext.giix-core',
     ),
  ),
)

and in ext.myGiixTemplates you copy needed templates directory from giix and apply custom modyfications. If you rename the directory (i.e. extensions/myGiixTemplates/crud/templates/[myCrudTemplate]) Giix will allow you to choose template you want to use during code generation of crud. You do not need to copy generators code, just templates.

#5230 report it
Say_Ten at 2011/09/24 04:38pm
Re: Modifying the Framework

I wouldn't recommend modifying the framework at all. We did something similar for falling back with translations, i.e. no fr_FR look in fr. Our solution was to create a new message source that extends CPhpMessageSource, overrides the method in question and configured the application to use this new message source.

return array(
    ...
    'components' => array(
        'message' => array(
            'source' => 'MPhpMessageSource'
        )
    )
);

iirc

Leave a comment

Please to leave your comment.

Write new article
  • Written by: Roman Solomatin
  • Category: How-tos
  • Yii Version: 1.1
  • Votes: +26 / -2
  • Viewed: 43,117 times
  • Created on: Sep 24, 2011
  • Last updated: Jul 1, 2014
  • Tags: i18n