How to deal with javascript internationalization
Is there any mechanism in yii framework to translate messages in javascript source开发者_开发技巧 files.
For example with:
yiic message config-message.php
I can generate translation .php files for all Yii::t().
Is it possible to generate .js files with the same mechanism. Currently I'm including to my javascript json data with table returned by translation file.
An alternate solution would be to make Yii include translated messages in the DOM, that will be later accessed by your JS code, so:
- You do not need to repeat JS code.
- Translation is centralized in the PHP/Yii framework.
I've created an extension that should handle this:
http://www.yiiframework.com/extension/jstrans/
It's a really problem. Multi languages sites is always problem. YII solve the problem for php code. But js code problem still on place.
I do not very elegant solution but it's works. Create controller/component and generate js code with localization on the fly using t().
/js/get/?file=some-js-file in layout:
Of course, every JS need to be rewrite. If use small pieces of code (cs()->RegisterScript) I use t() as well.
I just stumbled over this problem and using a controller to generate js code on the fly is not an option because you will waste resources because of starting an additional PHP process on every request. This may be a problem on high traffic sites. So I implemented a different approach: In the .js messages are stored in Variables e.g.
var MyJsClass = {
lang:
{
foo: 'Foo',
bar: 'Bar',
},
doSomething: function()
{
console.log(this.lang.foo);
},
};
in the view you add the translation if the current language is different to the sourceLanguage of the App:
<?php
$cs = Yii::app()->clientScript;
$cs->registerScriptFile($this->module->assetsUrl.'/js/myjsclass.js');
if (Yii::app()->sourceLanguage != Yii::app()->language) {
$cs->registerScript('MyScriptID', '
MyJsClass.lang.foo = \''.Yii::t('TranslationCategory', 'Translated Foo').'\';
MyJsClass.lang.bar = \''.Yii::t('TranslationCategory', 'Translated Bar').'\';
');
}
?>
There is no specific way to deal with that issue.
You can for example generate file with an array in with 'message-id' => 'translation' and include the correct one and then do stuff like alert($messages['itemDeleted']) or something.
An alternative could be to make views of your javascript and use the Yii::t() function on it.
Here's my way of doing it.
Little context for my application :
- Available languages differ from one section to another, and is available through the
$availableLanguages
variable. - I have created very small message files to be able to make public some of them without any security issue. I then created a variable called
$langFiles
that I can change within the controller.
use yii\helpers\Json;
use yii\helpers\FileHelper;
$files = FileHelper::findFiles(\Yii::getAlias('@app/messages/'));
$translations = [];
// Loop into all the available languages
foreach($availableLanguages as $lang) {
$translations[$lang] = [];
// Get all the available message files
foreach ($langFiles as $file) {
// Import the php file if it exists
$filePath = \Yii::getAlias("@app/messages/{$lang}/{$file}.php");
$key = "app/{$file}";
$translations[$lang][$key] = file_exists($filePath) ? include($filePath) : [];
// Replace '.' by '_' to use the get method
foreach($translations[$lang][$key] as $msg => $value) {
unset($translations[$lang][$key][$msg]);
$msg = str_replace('.', '_', $msg);
$translations[$lang][$key][$msg] = $value;
}
}
}
?>
<script>
var translations = <?= Json::encode($translations) ?>;
var lang = document.getElementsByTagName('html')[0].getAttribute('lang');
function t(category, message) {
// Get method thats works exactly like lodash
const get = (value, path, defaultValue) => {
return String(path).split('.').reduce((acc, v) => {
try {
acc = acc[v];
if(typeof acc === 'undefined') {
throw "Undefined";
}
} catch (e) {
return defaultValue;
}
return acc;
}, value)
}
// Replace '.' by '_' to use the get method.
var key = message.replace('.', '_');
// If the translation is not found, return the original message
console.log(lang+'.'+category+'.'+key, message);
return get(translations, lang+'.'+category+'.'+key, message);
}
</script>
I can now get the translation directly into my scripts by using the same syntax as in Yii2. Example :
t('app/quotes', 'Hello World. Captain speaking!')
精彩评论