Handelbarsヘルパーといくつかの正規表現を組み合わせることで、非常にエレガントなソリューションを作成できると思います。
これが私が提案するものです:
- メッセージキーのJSON配列を受け取り、JSONオブジェクトを返すサービスを作成します。ここで、キーはメッセージキーであり、値はローカライズされたテキストです。
- メッセージキー(サーバー上のメッセージキーと一致する)を受け取り、翻訳されたテキストを出力するハンドルバーヘルパーを定義します。のようなもの
{{localize "messageKey"}}
。すべてのテンプレートのローカリゼーションにこのヘルパーを使用します。
- テンプレートからメッセージキーを取得し、サービスを要求するテンプレートプリプロセッサを作成します。プリプロセッサは、取得したすべてのメッセージキーをキャッシュし、まだ持っていないメッセージキーのみを要求します。
- テンプレートをレンダリングする必要があるときにこのプリプロセッサをオンデマンドで呼び出すか、事前に呼び出してメッセージキーをキャッシュすることで、必要なときにすぐに使用できるようにすることができます。
- さらに最適化するために、キャッシュをブラウザのローカルストレージに永続化できます。
これが概念実証です。ローカルストレージの永続性や、キャッシュ目的で複数のテンプレートのテキストを一度にフェッチするためのサポートはまだありませんが、ハッキングするのは簡単だったので、さらにいくつかの作業を行うとうまくいくと思います。
クライアントAPIは次のようになります。
var localizer = new HandlebarsLocalizer();
//compile a template
var html = $("#tmpl").html();
localizer.compile(html).done(function(template) {
//..template is now localized and ready to use
});
怠惰な読者の情報源は次のとおりです。
var HandlebarsLocalizer = function() {
var _templateCache = {};
var _localizationCache = {};
//fetches texts, adds them to cache, resolves deferred with template
var _fetch = function(keys, template, deferred) {
$.ajax({
type:'POST',
dataType:'json',
url: '/echo/json',
data: JSON.stringify({
keys: keys
}),
success: function(response) {
//handle response here, this is just dummy
_.each(keys, function(key) { _localizationCache[key] = "(" + key + ") localized by server"; });
console.log(_localizationCache);
deferred.resolve(template);
},
error: function() {
deferred.reject();
}
});
};
//precompiles html into a Handlebars template function and fetches all required
//localization keys. Returns a promise of template.
this.compile = function(html) {
var cacheObject = _templateCache[html],
deferred = new $.Deferred();
//cached -> return
if(cacheObject && cacheObject.ready) {
deferred.resolve(cacheObject.template);
return deferred.promise();
}
//grep all localization keys from template
var regex = /{{\s*?localize\s*['"](.*)['"]\s*?}}/g, required = [], match;
while((match = regex.exec(html))) {
var key = match[1];
//if we don't have this key yet, we need to fetch it
if(!_localizationCache[key]) {
required.push(key);
}
}
//not cached -> create
if(!cacheObject) {
cacheObject = {
template:Handlebars.compile(html),
ready: (required.length === 0)
};
_templateCache[html] = cacheObject;
}
//we have all the localization texts ->
if(cacheObject.ready) {
deferred.resolve(cacheObject.template);
}
//we need some more texts ->
else {
deferred.done(function() { cacheObject.ready = true; });
_fetch(required, cacheObject.template, deferred);
}
return deferred.promise();
};
//translates given key
this.localize = function(key) {
return _localizationCache[key] || "TRANSLATION MISSING:"+key;
};
//make localize function available to templates
Handlebars.registerHelper('localize', this.localize);
}