$compile を独自に使用しない限り、アプリケーションのブートストラップ中に AngularJS テンプレートが 1 回しかコンパイルされないことに注意してください。
AngularJS のコンパイルとリンクのフェーズ
コードが機能しない理由を理解するには、AngularJS のコンパイルとリンクのフェーズを理解する必要があります。アプリケーションをロードすると、AngularJS は ng-app 属性を含む HTML 要素を $compile サービスでコンパイルします。
<html ng-app="MyApp"></html>
コンパイル段階
$compile は、各ディレクティブのコンパイル関数を呼び出す HTML テンプレート内のすべてのディレクティブを識別し、Angular ルート要素 ($rootElement) から html dom ツリーを介して上に向かって動作します。
リンクフェーズ
各コンパイル関数は、リンク後の関数と、オプションでリンク前の関数を返します。AngularJS がルート要素の下の dom 全体をコンパイルすると、以前にコンパイル関数を呼び出したのと同じ方法で、リンク前関数の呼び出しが開始されます。dom のリーフに到達すると、ディレクティブのリンク後関数が呼び出され、ルート要素に戻ります。
補間
{{ と }} の間の式を含む文字列は、補間ディレクティブと呼ばれる特別なディレクティブとして AngularJS によって処理されます。他のディレクティブと同様に、これらは $interpolate サービスを使用してコンパイル中に作成されます。$interpolate サービスは、多数の式で補間された文字列を受け取り、補間関数を返します。補間ディレクティブのリンク後関数は、補間関数にウォッチを作成し、補間された文字列の式が変更されたときに html ノードを更新できるようにします。
翻訳モジュール
コードを見ると、ディレクティブのポストリンク関数で {{ と }} で囲まれた式を使用して、HTML 要素のテキストを AngularJS 補間文字列に実際に設定しています。
上記で説明したように、この時点で AngularJS は既にテンプレートをコンパイルしているため、補間された文字列を式でコンパイルすることはありません。
コードからわかるように、ある種の変換ディレクティブを実装しようとしています。そのようなディレクティブは、翻訳された文字列で補間された文字列と他の AngluarJS テンプレート コードを考慮する必要がある場合、 $compile 関数を呼び出す必要があります。
directive('translate', ['$compile','translate', function factory($compile, translate) {
return {
priority: 10, // Should be evaluated before e. g. pluralize
restrict: 'ECMA',
link: function postLink(scope, el, attrs) {
if (el.contents().length) {
el.html(translate(el.text()));
$compile(el.contents())(scope); // This is only necessary if your translations contain AngularJS templates
}
},
};
}]).
translate ディレクティブは、翻訳サービスを使用して実際の翻訳を取得します。translateProvider には、言語バンドルなどから翻訳を追加するために使用できる add メソッドがあります。
.provider('translate', function() {
var localizedStrings = {};
var translateProvider = this;
this.add = function(translations) {
angular.extend(localizedStrings, translations);
};
this.$get = ['$log', '$rootScope', function ($log, $rootScope) {
var translate = function translate(sourceString) {
if (!sourceString) {
return '';
}
sourceString = sourceString.trim();
if (localizedStrings[sourceString]) {
return localizedStrings[sourceString];
} else {
$log.warn('Missing localization for "' + sourceString + '"');
return sourceString;
}
};
return translate;
}];
}).
config(function(translateProvider) {
translateProvider.add({'My name is {{name}}': 'Mi nombre es {{name}}'}); // This might come from a bundle
}).
モジュールの使用
モジュールを次のように使用できるようになりました。
<div ng-app="myApp" ng-controller="MyCtrl">
<span data-translate>My name is {{name}}</span>
</div>
完全な例でjsFiddleを作成しました:http://jsfiddle.net/jupiter/CE9V4/2/