Programming

컨트롤러에서 각도 변환에 대한 올바른 사용

procodes 2020. 7. 16. 20:33
반응형

컨트롤러에서 각도 변환에 대한 올바른 사용


AngularJS 응용 프로그램에서 i18n에 각도 변환사용 하고 있습니다.

모든 애플리케이션보기에는 전용 컨트롤러가 있습니다. 아래 컨트롤러에서 페이지 제목으로 표시 할 값을 설정했습니다.

암호

HTML

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

자바 스크립트

.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';
    }])

angular-translate-loader-url 확장명을 사용하여 번역 파일을로드하고 있습니다.

문제

초기 페이지로드시 해당 키의 번역 대신 번역 키가 표시됩니다. 번역은 Hello, World!있지만보고 HELLO_WORLD있습니다.

두 번째로 페이지를 방문하면 모든 것이 잘되고 번역 된 버전이 표시됩니다.

컨트롤러가 값을에 할당 할 때 변환 파일이 아직로드되지 않았기 때문에 문제와 관련이 있다고 가정합니다 $scope.pageTitle.

<h1>{{ pageTitle | translate }}</h1>및을 사용할 때 $scope.pageTitle = 'HELLO_WORLD';번역은 처음부터 완벽하게 작동합니다. 이것의 문제는 항상 번역을 사용하고 싶지 않다는 것입니다 (예 : 두 번째 컨트롤러의 경우 원시 문자열을 전달하고 싶습니다).

질문

알려진 문제 / 제한 사항입니까? 이 문제를 어떻게 해결할 수 있습니까?


편집 : 더 나은 솔루션을 얻으려면 PascalPrecht (각도 변환 작성자)의 답변을 참조하십시오.


로딩의 비동기 특성으로 인해 문제가 발생합니다. 과 함께 {{ pageTitle | translate }}Angular는 표현을 볼 것입니다. 현지화 데이터가로드되면 표현식 값이 변경되고 화면이 업데이트됩니다.

따라서 직접 할 수 있습니다.

.controller('FirstPageCtrl', ['$scope', '$filter', function ($scope, $filter) {
    $scope.$watch(
        function() { return $filter('translate')('HELLO_WORLD'); },
        function(newval) { $scope.pageTitle = newval; }
    );
});

그러나 이렇게하면 모든 다이제스트주기마다 감시식이 실행됩니다. 이는 차선책이며 눈에 띄는 성능 저하를 유발하거나 유발하지 않을 수 있습니다. 어쨌든 그것은 Angular 가하는 일이므로 그렇게 나쁠 수는 없습니다 ...


권장 사항 : 컨트롤러에서 번역하지 말고보기에서 번역하십시오.

컨트롤러를 번역 논리에서 자유롭게 유지하고 다음과 같이 뷰 내부에서 직접 문자열을 번역하는 것이 좋습니다.

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

제공된 서비스 사용

Angular Translate는 $translate컨트롤러에서 사용할 수 있는 서비스를 제공합니다 .

$translate서비스 사용법의 예 는 다음과 같습니다.

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

또한 번역 서비스에는 다음을 사용하여 약속을 처리 할 필요없이 문자열을 직접 번역하는 방법이 있습니다 $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.


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.


To make a translation in the controller you could use $translate service:

$translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
    vm.si = translations['COMMON.SI'];
    vm.no = translations['COMMON.NO'];
});

That statement only does the translation on controller activation but it doesn't detect the runtime change in language. In order to achieve that behavior, you could listen the $rootScope event: $translateChangeSuccess and do the same translation there:

    $rootScope.$on('$translateChangeSuccess', function () {
        $translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
            vm.si = translations['COMMON.SI'];
            vm.no = translations['COMMON.NO'];
        });
    });

Of course, you could encapsulate the $translateservice in a method and call it in the controller and in the $translateChangeSucesslistener.


What is happening is that Angular-translate is watching the expression with an event-based system, and just as in any other case of binding or two-way binding, an event is fired when the data is retrieved, and the value changed, which obviously doesn't work for translation. Translation data, unlike other dynamic data on the page, must, of course, show up immediately to the user. It can't pop in after the page loads.

Even if you can successfully debug this issue, the bigger problem is that the development work involved is huge. A developer has to manually extract every string on the site, put it in a .json file, manually reference it by string code (ie 'pageTitle' in this case). Most commercial sites have thousands of strings for which this needs to happen. And that is just the beginning. You now need a system of keeping the translations in synch when the underlying text changes in some of them, a system for sending the translation files out to the various translators, of reintegrating them into the build, of redeploying the site so the translators can see their changes in context, and on and on.

Also, as this is a 'binding', event-based system, an event is being fired for every single string on the page, which not only is a slower way to transform the page but can slow down all the actions on the page, if you start adding large numbers of events to it.

Anyway, using a post-processing translation platform makes more sense to me. Using GlobalizeIt for example, a translator can just go to a page on the site and start editing the text directly on the page for their language, and that's it: https://www.globalizeit.com/HowItWorks. No programming needed (though it can be programmatically extensible), it integrates easily with Angular: https://www.globalizeit.com/Translate/Angular, the transformation of the page happens in one go, and it always displays the translated text with the initial render of the page.

Full disclosure: I'm a co-founder :)

참고URL : https://stackoverflow.com/questions/20540877/correct-use-for-angular-translate-in-controllers

반응형