I really love the following approach:
one file is the translator itself:
class Translator{
private static $strs = array();
private static $currlang = 'en';
public static function loadTranslation($lang, $strs){
if (empty(self::$strs[$lang]))
self::$strs[$lang] = array();
self::$strs[$lang] = array_merge(self::$strs[$lang], $strs);
}
public static function setDefaultLang($lang){
self::$currlang = $lang;
}
public static function translate($key, $lang=""){
if ($lang == "") $lang = self::$currlang;
$str = self::$strs[$lang][$key];
if (empty($str)){
$str = "$lang.$key";
}
return $str;
}
public static function freeUnused(){
foreach(self::$strs as $lang => $data){
if ($lang != self::$currlang){
$lstr = self::$strs[$lang]['langname'];
self::$strs[$lang] = array();
self::$strs[$lang]['langname'] = $lstr;
}
}
}
public static function getLangList(){
$list = array();
foreach(self::$strs as $lang => $data){
$h['name'] = $lang;
$h['desc'] = self::$strs[$lang]['langname'];
$h['current'] = $lang == self::$currlang;
$list[] = $h;
}
return $list;
}
public static function &getAllStrings($lang){
return self::$strs[$lang];
}
}
function generateTemplateStrings($arr){
$trans = array();
foreach($arr as $totrans){
$trans[$totrans] = Translator::translate($totrans);
}
return $trans;
}
the language-files can be simply include()
d and look like this:
en.php:
Translator::loadTranslation('en', array(
'textfield_1' => 'This is some Textfield',
'another_textfield ' => 'This is a longer Text showing how this is used',
));
de.php:
Translator::loadTranslation('de', array(
'textfield_1' => 'Dies ist ein Textfeld',
'another_textfield ' => 'Dies ist ein längerer Text, welcher aufzeigt, wie das hier funktioniert.',
));
in you app you can do either translate one string like this:
$string = Translator::translate('textfield_1')
or even a bunch of strings:
$strings = generateTemplateStrings(array('textfield_1', 'another_textfield'));
Because the language-files can just be included, you can stack the very easily and, say, include a global file first and then include files from submodules which can either add new strings or replace already defined ones (which doesn't work with the define()
-method).
Because it's pure PHP, it can even be opcode-cached very easily.
I even have scripts around which generate CSV-files containing untranslated strings from a file and even better: convert the translated CSV-file back to the language file.
I have this solution in productive use since 2004 and I'm so very happy with this.
Of course, you can even extend it with conventions for pluralizing for example. Localizing number formats is something you'd have to do using other means though - the intl-extension comes to mind.