AngularJSのクライアントでのテンプレートのローカライズ

画像



AngularJSで多言語Webアプリケーションを開発する場合、おそらく翻訳の問題を何らかの形で解決する必要があります。 今日、これを実装する方法の1つを共有したいと思います。



文字列の単純な辞書を使用して翻訳する機能を提供する特定のサービスが既にあるとします。



/** * @param {Settings} Settings * @constructor */ function Language(Settings) { this.Settings = Settings; } Language.$inject = ['Settings']; app.service('Language', Language); /** * @param {String} string * @returns {String} */ Language.prototype.translate = function(string) { var translation = __lang[this.Settings.getValue('lang')]; if (typeof translation[string] !== 'undefined') { string = translation[string]; } return string; };
      
      







AngularJSについて知っている最初のアイデアは、式の標準機能とフィルターを使用して、フォームの文字列を「オンザフライ」で翻訳することです。



 <span>{{ 'some_english_string' | translate }}</span>
      
      





しかし、このアプローチには欠点があります。

-まず、各$ダイジェストサイクルで実行されるコードの量は依然として増加します。複雑なアプリケーションがある場合は、ページに多数の行が同時に表示されます。 -生産性が低下します。

-次に、角度式の使用は、他の式内の式の実行が機能しないため、すでに式を受け入れている一部のディレクティブの属性内で使用する場合、それほど便利ではなくなります。 この場合、もちろん、フィルタの代わりにグローバル関数を使用してそのような文字列を変換することも可能ですが、それでもこれらは追加の困難です。



彼らが使用することをお勧めする2番目のオプションは、サーバー上のテンプレートを翻訳し、クライアント側からすでにsome_partial_en.htmlsome_partial_ru.htmlの形式のローカライズされたコピーにアクセスできることです 。 この場合、言語を変更するにはアプリケーションを再起動する必要があります。 さらに、これは常に可能というわけではありません。たとえば、私の最後のプロジェクトでは、アプリケーションはサードパーティのサービスからのデータを使用し、バックエンドはまったく記述されていませんでした。



しかし、別の方法があります。つまり、クライアントでテンプレートを翻訳しますが、AngularJSでは翻訳しません。 たとえば、 Lo-Dash / underscorejsのテンプレートエンジンを使用して、次の形式の構造を使用できます。



 <span><%= t('some_english_string') %></span>
      
      





プラスは、この場合、辞書の改行内で角度式を使用できることです



 __lang.ru = { "some_english_string": "    {{string.number}}" };
      
      





逆もまた同様です。たとえば、いくつかのディレクティブで、この構造を他の角度式に置き換えます。



 <div class="input-text-right"> <input type="text" my-num-format="00000.00" my-validate="[ { type: 'notGreaterThen', compareTo: 'somecondition()', message: '<%= t('some_validation_error_message') %>' } ]" ng-model="model.value"> </div>
      
      







これを行うには、テンプレートを言語サービスに翻訳するためのメソッドを追加します。



 ..... /** * @param {String} template * @returns {String} */ Language.prototype.translateTemplate = function(template) { //     this.translate()      Lo-Dash  t() return _.template(template, { t: angular.bind(this, this.translate) }); };
      
      







次に、angleが使用するパターンをインターセプトし、コンパイルを開始する前に変換する必要があります。 AngularJSでテンプレートを取得するための個別のサービスはありませんが、どこでこれが発生しても(ルーティング、ngIncludeディレクティブなど)- $ templateCacheがキャッシュに使用されます。 ここで再定義します。



 //  angular-    ,       app.factory('$templateCache', [ '$cacheFactory', 'Language', function($cacheFactory, Language) { /** * @constructor */ function MyTemplateCache() { /** * @param {String} key * @param {*} value */ this.put = function(key, value) { //   -  promise-,    $http if (typeof value.then !== 'undefined') { //    promise-,       value = value.then(function(response) { response.data = Language.translateTemplate(response.data); return response; }); } //   -  -,  angular      promise- $http else if (value instanceof Array) { value[1] = Language.translateTemplate(value[1]); } //   -    // ( ,        <script type="text/ng-template"></script> //   ) else if (typeof value === 'string') { value = Language.translateTemplate(value); } //    put() MyTemplateCache.prototype.put(key, value); }; } //     $templateCache MyTemplateCache.prototype = $cacheFactory('templates'); return new MyTemplateCache(); } ]);
      
      







それだけです。 ページをリロードせずに言語を変更するには、キャッシュをクリアしてルートをリロードするだけで十分です。



 $templateCache.removeAll(); $route.reload();
      
      





唯一のコメント:ルートを再起動すると、状態に保存されていないすべての変更は破棄されます。テンプレートを再コンパイルすると、すべてのスコープが再作成されるためです。



All Articles