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


121

AngularJS 응용 프로그램에서 i18n에 대해 angular-translate 를 사용 하고 있습니다.

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

암호

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'; , 번역 작품은 처음부터 완벽. 문제는 항상 번역을 사용하고 싶지 않다는 것입니다 (예 : 두 번째 컨트롤러의 경우 원시 문자열을 전달하고 싶습니다).

질문

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

답변:


69

편집 : 더 나은 솔루션을 위해 PascalPrecht (angular-translate의 저자)의 답변을 참조하십시오.


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

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

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

그러나 이것은 모든 다이제스트주기에서 관찰 된 표현식을 실행합니다. 이는 차선책이며 눈에 띄는 성능 저하를 유발할 수도 있고 그렇지 않을 수도 있습니다. 어쨌든 Angular가하는 일이므로 그렇게 나쁠 수는 없습니다.


감사합니다! View 또는 Controller에서 필터를 사용하면 정확히 동일하게 작동 할 것으로 예상합니다. 여기서는 그렇지 않은 것 같습니다.
ndequeker 2013

$scope.$watchAngular Translate가 컨트롤러에서 사용할 서비스를 제공하기 때문에 a를 사용하는 것은 다소 과잉 이라고 말하고 싶습니다 . 아래 내 대답을 참조하십시오.
Robin van Baalen 2014-06-20

1
Angular Translate 필터는 $translate.instant()서비스와 동일한 기능을 제공하므로 필요하지 않습니다 . 이 외에도 Pascal의 답변에 주목하십시오.
knalli

동의합니다. $ watch를 사용하는 것은 과잉입니다. 아래 답변은 더 적절한 사용법입니다.
jpblancoder 2014

141

권장 : 컨트롤러에서 번역하지 말고보기에서 번역하세요.

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

<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;
        });
});

번역 서비스에는 다음을 사용하여 promise를 처리 할 필요없이 문자열을 직접 번역하는 방법도 있습니다 $translate.instant().

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

using의 단점 $translate.instant()은 비동기로로드하는 경우 언어 파일이 아직로드되지 않는다는 것입니다.

제공된 필터 사용

이런 식으로 promise를 처리 할 필요가 없기 때문에 이것이 제가 선호하는 방법입니다. 필터의 출력은 범위 변수로 직접 설정할 수 있습니다.

.controller('TranslateMe', ['$scope', '$filter', function ($scope, $filter) {
    var $translate = $filter('translate');

    $scope.pageTitle = $translate('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined
});

제공된 지시문 사용

@PascalPrecht는이 멋진 라이브러리의 제작자이므로 그의 조언 (아래 답변 참조) 과 함께 이동하여 매우 지능적인 번역을 처리하는 것처럼 보이는 지침을 사용하는 것이 좋습니다 .

이 지시문은 비동기 실행을 처리하며 번역에 동적 값이없는 경우 범위에서 번역 ID를 관찰 할 수있을만큼 영리합니다.


관련없는 댓글을 작성하는 대신 시도해 본다면 지금 쯤이면 답을 알 수있을 것입니다. 짧은 대답 : 예. 가능합니다.
Robin van Baalen 2015 년

1
컨트롤러의 필터로 예제에서 : instant ()과 같이 언어 파일이로드되지 않으면 제대로 작동하지 않습니까? 이 경우 시계를 사용하면 안되나요? 아니면 '번역이로드 된 것을 아는 경우에만 필터를 사용 하시겠습니까?
Bombinosh

@Bombinosh 번역이로드 된 것을 알고 있다면 필터 방법을 사용하십시오. 개인적으로 필요하지 않은 경우 번역을 동적으로로드하지 않는 것이 좋습니다. 애플리케이션의 필수 부분이므로 사용자가 기다리지 않도록하는 것이 좋습니다. 그러나 그것은 개인적인 의견입니다.
Robin van Baalen 15.07.07

번역의 요점은 사용자 선호도 또는 사용자 작업에서도 변경할 수 있다는 것입니다. 따라서 일반적으로 동적으로로드해야합니다. 적어도 번역 할 문자열의 수가 중요하거나 번역이 많은 경우.
PhiLho

4
HTML에서 번역이 완료되면 다이제스트주기가 두 번 실행되지만 컨트롤러에서는 한 번만 실행됩니다. 99 %의 경우 이것은 아마도 중요하지 않을 것입니다. 그러나 많은 셀에 번역이있는 각도 UI 그리드에서 끔찍한 성능 문제가있었습니다. 물론, 뭔가에 대한 에지 케이스는 알고 있어야합니다
tykowale

123

사실, 대신에 이러한 항목에 대해 translate 지시문을 사용해야합니다.

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

이 지시문은 비동기 실행을 처리하며 번역에 동적 값이없는 경우 범위에서 번역 ID를 관찰 할 수있을만큼 영리합니다.

이 주위에 방법이 없습니다 당신이 정말 그러나, 에있는 사용 $translate컨트롤러의 서비스, 당신은에 전화를 포장해야 $translateChangeSuccess사용하여 이벤트 $rootScope와 함께 $translate.instant()다음과 같습니다 :

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

그렇다면 왜 $rootScope그렇지 $scope않습니까? 그 이유 는 전체 범위 계층 구조를 통해 브로드 캐스트 할 필요가 없기 때문에 angular-translate의 이벤트가 $emited on $rootScope이 아닌 $broadcasted on $scope이기 때문입니다.

$translate.instant()비동기가 $translate()아닌가? 때 $translateChangeSuccess이벤트가 시작되고, 따라서 우리가 사용할 수 있으며, 필요한 변환 데이터가 더 비동기 실행 (예 : 비동기 로더 실행을 위해) 발생되지 않도록 확실한 $translate.instant()동기 인 단지 번역을 사용할 수 있다고 가정합니다.

버전 2.8.0 이후에는 $translate.onReady()번역이 준비되는 즉시 해결되는 promise를 반환하는 도 있습니다 . 변경 로그를 참조하십시오 .


필터 대신 번역 지시문을 사용하면 성능 문제가 발생할 수 있습니까? 또한 내부적으로는 instant ()의 반환 값을 감시한다고 생각합니다. 그렇다면 현재 범위가 파괴되면 시계를 제거합니까?
Nilesh

귀하의 제안을 사용해 보았지만 범위 변수의 값이 동적으로 변경되면 작동하지 않습니다.
Nilesh

10
실제로는 항상 새 시계를 설정하기 때문에 앱 속도가 느려지므로 가능한 경우 필터를 피하는 것이 좋습니다. 그러나 지침은 조금 더 나아갑니다. 번역 ID의 값을 주시해야하는지 확인합니다. 그러면 앱 성능이 향상됩니다. 좀 더 살펴볼 수 있도록 링크를 만들어 주시겠습니까?
Pascal Precht 2014-06-12

Plunk : plnkr.co/edit/j53xL1EdJ6bT20ldlhxr 아마도 내 예에서 지시문은 가치를 보지 않기로 결정하고 있습니다. 또한 별도의 문제로 키를 찾을 수없는 경우 내 사용자 지정 오류 처리기가 호출되지만 반환 된 문자열이 표시되지 않습니다. 나는 그것을 위해 또 다른 플렁크를 만들 것이다.
Nilesh 2014-06-12

2
@PascalPrecht 질문입니다. 번역과 함께 bind-once를 사용하는 것이 좋은 습관입니까? 이렇게 {{::'HELLO_WORLD | translate}}'.
Zunair Zubair 2015

5

컨트롤러에서 번역을하려면 $translate서비스를 사용할 수 있습니다 .

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

이 명령문은 컨트롤러 활성화에 대한 번역 만 수행하지만 언어의 런타임 변경을 감지하지 않습니다. 이 동작을 달성하기 위해 $rootScope이벤트를 수신 $translateChangeSuccess하고 동일한 번역을 수행 할 수 있습니다.

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

물론, $translate서비스를 메서드에 캡슐화 하고 컨트롤러와 $translateChangeSucess리스너 에서 호출 할 수 있습니다.


1

무슨 일이 일어나고 있는지 Angular-translate가 이벤트 기반 시스템으로 표현식을 감시하고 있으며 다른 바인딩 또는 양방향 바인딩의 경우와 마찬가지로 데이터가 검색되고 값이 변경되면 이벤트가 발생합니다. 분명히 번역을 위해 작동하지 않습니다. 물론 페이지의 다른 동적 데이터와 달리 번역 데이터는 사용자에게 즉시 표시되어야합니다. 페이지가로드 된 후에는 튀어 나올 수 없습니다.

이 문제를 성공적으로 디버깅 할 수 있더라도 더 큰 문제는 관련된 개발 작업이 거대하다는 것입니다. 개발자는 사이트의 모든 문자열을 수동으로 추출하여 .json 파일에 넣고 문자열 코드 (이 경우 'pageTitle')로 수동으로 참조해야합니다. 대부분의 상업 사이트에는 이런 일이 발생해야하는 수천 개의 문자열이 있습니다. 그리고 그것은 시작에 불과합니다. 이제 일부 텍스트의 기본 텍스트가 변경 될 때 번역을 동기화 상태로 유지하는 시스템, 번역 파일을 다양한 번역자에게 보내고, 빌드에 다시 통합하고, 번역자가 볼 수 있도록 사이트를 재배포하는 시스템이 필요합니다. 상황에 따른 변화, 그리고 계속해서.

또한 이것은 '바인딩', 이벤트 기반 시스템이므로 페이지의 모든 단일 문자열에 대해 이벤트가 발생합니다. 이는 페이지를 변환하는 속도가 느릴뿐만 아니라 페이지의 모든 작업을 느리게 할 수 있습니다. 많은 이벤트를 추가하기 시작하면

어쨌든 후 처리 번역 플랫폼을 사용하는 것이 더 의미가 있습니다. 예를 들어, GlobalizeIt을 사용하면 번역가는 사이트의 페이지로 이동하여 해당 언어 페이지에서 직접 텍스트를 편집 할 수 있습니다. https://www.globalizeit.com/HowItWorks . 프로그래밍이 필요하지 않습니다 (프로그래밍 방식으로 확장 할 수 있지만) Angular : https://www.globalizeit.com/Translate/Angular 와 쉽게 통합 되며 페이지 변환이 한 번에 이루어지며 항상 다음과 같이 번역 된 텍스트를 표시합니다. 페이지의 초기 렌더링.

전체 공개 : 저는 공동 설립자입니다. :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.