Active Records may be internationalized by prefixing column names with a locale, then using certain AkActiveRecord functions to process them. This section will provide a detailed explanation with an example. The example will take a field from a non-internationalized table and write it's value in an internationalized table in a project called esimerkki (Finnish for example).
The first thing we should do is to define AK_ACTIVE_RECORD_DEFAULT_LOCALES in config/config.php. Originally, mine looked like this:
define('AK_ACTIVE_RECORD_DEFAULT_LOCALES', 'en,en_us');
I changed it to look like this:
define('AK_ACTIVE_RECORD_DEFAULT_LOCALES', 'en,fi,sv');
I said “should” because, if AK_ACTIVE_RECORD_DEFAULT_LOCALES isn't defined, AkActiveRecord::getAvailableLocales() will try to get values from Ak::langs().
This is done by creating and running a migration. The code for doing so is shown in the linked section. Running the migration will give you two tables, mono_langs and multi_langs.
We need to create models for the two tables: Change the directory (if necessary) to your project's root.
./script/generate model MonoLang
./script/generate model MultiLang
We are going to create app/controllers/refmt_controller.php. To access it, though, we need to change the first line in config/routes.php to reference it:
$Map->connect('/:controller/:action/:id', array('controller' => 'refmt', 'action' => 'index'));
The first things we'll do are to reference the models, write the index function and, then write the code to populate the non-internationalized mono_langs table
<?php class RefmtController extends ApplicationController { var $models = 'mono_lang, multi_lang'; function index() { if($this->MonoLang->count() == 0) { $this->populate_mono_lang(); } $this->display_func_results(); $this->populate_multi_lang(); exit; // This is to keep from trying to access a view }
We're not commenting on how to populate this table because we assume that you know how to do that. We're showing the code so that you know what the input table contains.
function populate_mono_lang() { $mono = new $this->MonoLang(array('lang' => 'en','name' => 'municipality')); $mono->save(); $mono = new $this->MonoLang(array('lang' => 'fi','name' => 'kunta')); $mono->save(); $mono = new $this->MonoLang(array('lang' => 'sv','name' => 'kommun')); $mono->save(); }
To understand what Active Record thinks we have, we'll display the results of locale related “get” functions as shown by Page Source.
function display_func_results() { $result = array(); $result['available_locales'] = $this->MultiLang->getAvailableLocales(); $result['internationalized_columns'] = $this->MultiLang->getInternationalizedColumns(); $result['locales_for_name_attribute'] = $this->MultiLang->getAttributeLocales('name'); $result['current_locale'] = $this->MultiLang->getCurrentLocale(); print_r($result); }
Array
(
[available_locales] => Array
(
[0] => en
[1] => fi
[2] => sv
)
[internationalized_columns] => Array
(
[name] => Array
(
[0] => en
[1] => fi
[2] => sv
)
)
The multi_langs table has the fields id, en_name, fi_name, sv_name, updated_at and created_at. What we see here is that en_name, fi_name and sv_name are interpreted as internationalized columns. The columns id, updated_at and created_at are not recognized as internationalized columns. Notice that Active Record stores the related internationalized columns as an array.
[locales_for_name_attribute] => Array
(
[en] =>
[fi] =>
[sv] =>
)
[current_locale] => en
)
This function reads the non-internationalized table and writes a record to an internationalized table.
function populate_multi_lang() { $mono_langs = $this->MonoLang->find('all'); // $mono_langs is an array of objects $multi = $this->MultiLang; // $multi is an instance of the internationalized table foreach($mono_langs as $mono_lang) { $multi->setAttributeByLocale('name', $mono_lang->name, $mono_lang->lang); } $multi->save(); // The following code shows that the data was written to the table. // The real reason for including it is to demonstrate the getAttributebyLocale function. $result = array(); $result['name_by_locale-en'] = $multi->getAttributeByLocale('name','en'); $result['name_by_locale-fi'] = $multi->getAttributeByLocale('name','fi'); $result['name_by_locale-sv'] = $multi->getAttributeByLocale('name','sv'); print_r($result); } } ?>
Following is the code to do this conversion in one block. Comments and code not needed to do the job have been removed.
<?php class RefmtController extends ApplicationController { var $models = 'mono_lang, multi_lang'; function index() { if($this->MonoLang->count() == 0) { $this->populate_mono_lang(); } $this->populate_multi_lang(); exit; } function populate_mono_lang() { $mono = new $this->MonoLang(array('lang' => 'en','name' => 'municipality')); $mono->save(); $mono = new $this->MonoLang(array('lang' => 'fi','name' => 'kunta')); $mono->save(); $mono = new $this->MonoLang(array('lang' => 'sv','name' => 'kommun')); $mono->save(); } function populate_multi_lang() { $mono_langs = $this->MonoLang->find('all'); $multi = $this->MultiLang; foreach($mono_langs as $mono_lang) { $multi->setAttributeByLocale('name', $mono_lang->name, $mono_lang->lang); } $multi->save(); } } ?>
The locale is established by appending the locale to the project name in the URL. You might open a non-internationalized application with
http://<host>/esimerkki
The internationalized application might be opened with
http://<host>/esimerkki/en http://<host>/esimerkki/fi or http://<host>/esimerkki/sv
You may also open the internationalized application as a non-internationalized one and set the language within the program with this:
Ak::lang('fi'); $_SESSION['lang'] = 'fi';
where 'fi' is the new current locale. The second line is apparently necessary to get text strings to reflect the new language. (I found this on the forum.) Of course, if you do this, you will have to make all locale changes programmatically; you won't be able to access different languages by appending the locale onto the URL.
In this example, this code would be put right at the beginning of the index() function.
An ActiveRecord locale-related function not discussed here is
setAttributeLocales($attribute [, $values = array()]);
I haven't tried to use it, but I suppose that it might be used in an installer to create i18n columns.
Go internationalize yourself.