I started implementing i18n for my upcoming KO3 application, and implemented a quick patch so that I don’t need to manually find and type translation strings.
What this code does
What the code below does is it checks whether the translation string exists, if not then it saves it into the translation file with the English equivalent. This updated version of the translation string file is saved into /application/i18n/languagename.php, and the old file is saved with a new name containing the current date and time.
Hope this helps!
How to set it up
First set the language using i18n::lang(‘xy-xx’) in bootstrap.php.
Also, add the following as the last line in bootstrap.php:
// Write the updated language file, if necessary i18n::write();
Finally, add the file /application/classes/i18n.php which overrides i18n::get():
<?php /** * A patch for the Internationalization (i18n) class. * * @package I18n * @author Mikito Takada */ class I18n extends Kohana_I18n { // Cache of missing strings protected static $_cache_missing = array(); /** * Returns translation of a string. If no translation exists, the original * string will be returned. * * @param string text to translate * @return string */ public static function get($string) { if ( ! isset(I18n::$_cache[I18n::$lang])) { // Load the translation table I18n::load(I18n::$lang); } // Return the translated string if it exists if(isset(I18n::$_cache[I18n::$lang][$string])) { return I18n::$_cache[I18n::$lang][$string]; } else { // Translated string does not exist // Store the original string as missing - still makes sense to store the English string so that loading the untranslated file will work. I18n::$_cache_missing[I18n::$lang][$string] = $string; return $string; } } public static function write() { // something new must be added for anything to happen if(!empty(I18n::$_cache_missing)) { $contents = '<?php defined(\'SYSPATH\') or die(\'No direct script access.\'); /** * Translation file in language: '.I18n::$lang.' * Automatically generated from previous translation file. */ return '.var_export(array_merge(I18n::$_cache_missing[I18n::$lang], I18n::$_cache[I18n::$lang]), true).';'; // save string to file $savepath = APPPATH.'/i18n/'; $filename = I18n::$lang.'.php'; // check that the path exists if(!file_exists($savepath)) { // if not, create directory mkdir($savepath, 0777, true); } // rename the old file - if the file size is different. if(file_exists($savepath.$filename) && ( filesize($savepath.$filename) != strlen($contents) ) ) { $result = rename($savepath.$filename, $savepath.I18n::$lang.'_'.date('Y_m_d_H_i_s').'.php'); if(!$result) { // Rename failed! Don't write the file. return; } } // save the file file_put_contents($savepath.$filename, $contents); } } }
Caveats and notes
There are two things that have to be taken into account:
- First, this is would obviously be inefficient for a production site, since actual files are being rewritten on each request that finds new translation strings.
- Why this is not a problem: My recommendation is that you shouldn’t run this code in production mode, since there is no point and it is very easy to remove the code after developement is completed.
- Second, this approach is less comprehensive than using something like the gettext tools that are available – those tools scan all of the source code, while my approach depends on run-time detection of new strings. This means that a small percentage of strings will not be found automatically (ex. rare errors that never get triggered).
- Why this is not a problem: This approach will still get the vast majority of the strings without requiring any manual hunting for strings, so I think it’ll save you quite a bit of time.