Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct use for angular-translate in controllers

I'm using angular-translate for i18n in an AngularJS application.

For every application view, there is a dedicated controller. In the controllers below, I set the value to be shown as the page title.

Code

HTML

<h1>{{ pageTitle }}</h1> 

JavaScript

.controller('FirstPageCtrl', ['$scope', '$filter', function ($scope, $filter) {         $scope.pageTitle = $filter('translate')('HELLO_WORLD');     }])  .controller('SecondPageCtrl', ['$scope', '$filter', function ($scope, $filter) {         $scope.pageTitle = 'Second page title';     }]) 

I'm loading the translation files using the angular-translate-loader-url extension.

Problem

On the initial page load, the translation key is shown instead of the translation for that key. The translation is Hello, World!, but I'm seeing HELLO_WORLD.

The second time I go to the page, all is well and the translated version is shown.

I assume the issue has to do with the fact that maybe the translation file is not yet loaded when the controller is assigning the value to $scope.pageTitle.

Remark

When using <h1>{{ pageTitle | translate }}</h1> and $scope.pageTitle = 'HELLO_WORLD';, the translation works perfect from the first time. The problem with this is that I don't always want to use translations (eg. for the second controller I just want to pass a raw string).

Question

Is this a known issue / limitation? How can this be solved?

like image 929
ndequeker Avatar asked Dec 12 '13 10:12

ndequeker


People also ask

Why we use translate in Angular?

NGX-Translate is an internationalization library for Angular. It lets you translate for your content in different languages and switch between them easily.

What is the use of NGX translate?

What is ngx-translate? ngx-translate is the library for internationalization (i18n) and localization in Angular. It simplifies your Angular application to work for localization. It's easy to set up and use in an Angular application.

What are controllers used for in Angular?

All the AngularJS application mainly relies on the controllers to control the flow of data in that application. Basically, it controls the data of AngularJS applications and the controller is a Javascript object, created by a standard JavaScript object constructor.

What is translate in AngularJS?

angular-translate is an AngularJS module that provides filters and directives, along with the ability to load i18n data asynchronously. It supports pluralization through MessageFormat , and is designed to be highly extensible and configurable.


2 Answers

Recommended: don't translate in the controller, translate in your view

I'd recommend to keep your controller free from translation logic and translate your strings directly inside your view like this:

<h1>{{ 'TITLE.HELLO_WORLD' | translate }}</h1> 

Using the provided service

Angular Translate provides the $translate service which you can use in your Controllers.

An example usage of the $translate service can be:

.controller('TranslateMe', ['$scope', '$translate', function ($scope, $translate) {     $translate('PAGE.TITLE')         .then(function (translatedValue) {             $scope.pageTitle = translatedValue;         }); }); 

The translate service also has a method for directly translating strings without the need to handle a promise, using $translate.instant():

.controller('TranslateMe', ['$scope', '$translate', function ($scope, $translate) {     $scope.pageTitle = $translate.instant('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined }); 

The downside with using $translate.instant() could be that the language file isn't loaded yet if you are loading it async.

Using the provided filter

This is my preferred way since I don't have to handle promises this way. The output of the filter can be directly set to a scope variable.

.controller('TranslateMe', ['$scope', '$filter', function ($scope, $filter) {     var $translate = $filter('translate');      $scope.pageTitle = $translate('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined }); 

Using the provided directive

Since @PascalPrecht is the creator of this awesome library, I'd recommend going with his advise (see his answer below) and use the provided directive which seems to handle translations very intelligent.

The directive takes care of asynchronous execution and is also clever enough to unwatch translation ids on the scope if the translation has no dynamic values.

like image 188
Robin van Baalen Avatar answered Sep 18 '22 17:09

Robin van Baalen


Actually, you should use the translate directive for such stuff instead.

<h1 translate="{{pageTitle}}"></h1> 

The directive takes care of asynchronous execution and is also clever enough to unwatch translation ids on the scope if the translation has no dynamic values.

However, if there's no way around and you really have to use $translate service in the controller, you should wrap the call in a $translateChangeSuccess event using $rootScope in combination with $translate.instant() like this:

.controller('foo', function ($rootScope, $scope, $translate) {   $rootScope.$on('$translateChangeSuccess', function () {     $scope.pageTitle = $translate.instant('PAGE.TITLE');   }); }) 

So why $rootScope and not $scope? The reason for that is, that in angular-translate's events are $emited on $rootScope rather than $broadcasted on $scope because we don't need to broadcast through the entire scope hierarchy.

Why $translate.instant() and not just async $translate()? When $translateChangeSuccess event is fired, it is sure that the needed translation data is there and no asynchronous execution is happening (for example asynchronous loader execution), therefore we can just use $translate.instant() which is synchronous and just assumes that translations are available.

Since version 2.8.0 there is also $translate.onReady(), which returns a promise that is resolved as soon as translations are ready. See the changelog.

like image 31
Pascal Precht Avatar answered Sep 17 '22 17:09

Pascal Precht