Translation2 is a class for multilingual applications management. It provides an easy way to retrieve all the strings for a multilingual site from a data source (i.e. db). The API is designed to be clean, simple to use, yet powerful and extensible. A Translation2_Admin class is provided to easily manage translations (add/remove a language, add/remove a string).
The following containers (data source drivers) are provided:
PEAR::DB
PEAR::MDB
PEAR::MDB2
gettext
PEAR::DB_DataObject (experimental, used by PEAR:: HTML_Template_Flexy)
XML
Some decorator classes will help in various tasks. They can be layered/stacked one on top of the other, in any number. This approach should suit everyone's needs. Currently, the following decorators are provided:
CacheLiteFunction (for fast file-based caching)
CacheMemory (for memory-based caching)
DefaultText (to replace empty strings with their keys or a default text)
ErrorText (to replace empty strings with an "error_text" fallback message)
Iconv (to switch from/to different encodings)
Lang (resort to fallback languages for empty strings)
SpecialChars (replace html entities with their hex codes)
UTF-8 (convert UTF-8 strings to ISO-8859-1)
Translation2 can use different storage containers. Have a look in the /docs/examples dir of the package for some example setups (gettext ini files, SQL DDLs, PHP configuration files, etc).
This simple example will show how you can instanciate a Translation2 object and use it to retrieve your translated strings from a db, using the MDB2 driver:
<?php
// set the parameters to connect to your db
$dbinfo = array(
'hostspec' => 'host',
'database' => 'dbname',
'phptype' => 'mysql',
'username' => 'user',
'password' => 'pwd'
);
define('TABLE_PREFIX', 'mytable_');
// tell Translation2 about your db-tables structure,
// if it's different from the default one.
// NB: the default db structure is:
//
// Table "langs" (available languages and meta info)
// +----+------+------+----------+------------+
// | ID | name | meta | encoding | error_text |
// +----+------+------+----------+------------+
//
// Table "strings" (translations)
// +----+---------+----+----+----+-----+
// | ID | page_id | en | de | it | ... |
// +----+---------+----+----+----+-----+
// You can have one table per translation, instead
// of one table for all the languages
//
$params = array(
'langs_avail_table' => TABLE_PREFIX.'langs_avail',
'lang_id_col' => 'ID',
'lang_name_col' => 'name',
'lang_meta_col' => 'meta',
'lang_errmsg_col' => 'error_text',
'strings_tables' => array(
'en' => TABLE_PREFIX.'i18n',
'it' => TABLE_PREFIX.'i18n',
'de' => TABLE_PREFIX.'i18n'
),
'string_id_col' => 'ID',
'string_page_id_col' => 'pageID',
'string_text_col' => '%s' //'%s' will be replaced by the lang code
);
$driver = 'MDB2';
require_once 'Translation2.php';
$tr =& Translation2::factory($driver, $dbinfo, $params);
//always check for errors. In this examples, error checking is omitted
//to make the example concise.
if (PEAR::isError($tr)) {
//deal with it
}
// you can set the charset that the database must use, for instance 'utf8'
$tr->setCharset('iso-8859-1');
// set primary language
$tr->setLang('it');
// set the group of strings you want to fetch from
$tr->setPageID('defaultGroup');
// add a Lang decorator to provide a fallback language
$tr =& $tr->getDecorator('Lang');
$tr->setOption('fallbackLang', 'en');
// add another Lang decorator to provide another fallback language,
// in case some strings are not translated in Italian or English
$tr =& $tr->getDecorator('Lang');
$tr->setOption('fallbackLang', 'de');
// fetch the string with the 'test' stringID
echo $tr->get('test');
// fetch a string not translated into Italian (test fallback language)
echo $tr->get('only_english');
// fetch the whole group of strings, without resorting to the fallback lang
// and without any "decoration"
$rawPage = $tr->getRawPage();
print_r($rawPage);
// fetch the whole group of strings, but applying the decorators
$page = $tr->getPage();
print_r($page);
// you can force the lang and the group of the string you're requesting
echo $tr->get('month_01', 'calendar', 'it');
// the same is true for getRawPage() and getPage()
$page = $tr->getPage('calendar', 'de');
print_r($page);
?>
As you can see, the main methods are get(), getPage() and getRawPage(). The full syntax is
<?php
get($stringID, $pageID, $langID);
?>
but if you set the pageID and the langID beforehand, you won't need to specify them at each get() invocation.
NB: you have to check for errors at least on the first invocation of one of these methods, since the db connection is only estabilished at this point, so the chances of failures are higher here.
Now let's see how we can extract some meta info from the db:
<?php
$tr->getLang(); // no langID => get current lang
$tr->getLang('it'); // same as above, if the current lang is Italian
// the first parameter is the lang code,
// with the second parameter you can filter the info you need
$tr->getLang('it', 'error_text');
$tr->getLang('en', 'name');
$tr->getLang('de', 'meta');
$tr->getLang('de', 'encoding');
?>
Translation2 uses decorators to filter/change the retrieved strings. You can have a chain of decorators (filters), and you can also add yours.
<?php
$tr =& Translation2::factory($driver, $dbinfo, $params);
$tr->setLang('en');
$tr->setPageID('calendar');
// add a memory-based cache decorator, to do some basic prefetching and
// reduce the load on the db
$tr = & $tr->getDecorator('CacheMemory');
// add a file-based cache decorator, to cache the query results through pages
$tr =& $tr->getDecorator('CacheLiteFunction');
$tr->setOption('cacheDir', 'cache/');
$tr->setOption('lifeTime', 3600*24);
// add a fallback lang decorator
$tr = & $tr->getDecorator('Lang');
$tr->setOption('fallbackLang', 'it');
// add a special chars decorator to replace special characters with the html entity
$tr = & $tr->getDecorator('SpecialChars');
// control the charset to use
$tr->setOption('charset', 'ISO-8859-2');
// add a UTF-8 decorator to automatically decode UTF-8 strings
$tr = & $tr->getDecorator('UTF8');
// add a default text decorator to deal with empty strings
$tr = & $tr->getDecorator('DefaultText');
// replace the empty string with its stringID
echo $tr->get('emptyString');
// use a custom fallback text
echo $tr->get('emptyString', 'stringGroup', 'en', 'show this default text');
?>
The getStringID() method is the reverse of get(). If you want to translate a string to another language, but you don't know the associated stringID, you can retrieve it with this method:
<?php
$tr->setLang('it');
// translate the Italian string "gennaio" into the English "january"
$stringID = $tr->getStringID('gennaio', 'calendar');
echo $translatedString = $tr->get($stringID, 'calendar', 'en');
?>
Translation2 can handle parametric strings, and replace them with parameters passed at runtime (they can be numeric or associative arrays).
<?php
// "hello_user" = "hello &&user&&, today is &&weekday&&, &&day&&th &&month&& &&year&&"
$tr->setParams(array(
0 => '',
'user' => 'Joe',
'day' => '15',
'month' => $tr->get('month_01', 'calendar', 'en'),
'year' => '2004',
'weekday' => $tr->get('day_5', 'calendar', 'en')
));
echo $tr->get('hello_user');
// the above line will print "hello Joe, today is Friday, 15th January 2004"
?>
If your site structure is organized in sections, like a header, a body and a footer, you may use those units as "pages" (or groups of translations), and then fetch them one by one:
<?php
$header_trans = $tr->getPage('header');
$body_trans = $tr->getPage('body');
$footer_trans = $tr->getPage('footer');
?>
If you want them all in a single result, just merge them into a single array:
<?php
$translations = array_merge(
$tr->getPage('header'),
$tr->getPage('body'),
$tr->getPage('footer')
);
?>