正确使用控制器中的角度平移

nde*_*ker 118 javascript angularjs angular-translate

我在AngularJS应用程序中使用angular-translate for i18n.

对于每个应用程序视图,都有一个专用控制器.在下面的控制器中,我将值设置为页面标题.

HTML

<h1>{{ pageTitle }}</h1>
Run Code Online (Sandbox Code Playgroud)

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';
    }])
Run Code Online (Sandbox Code Playgroud)

我正在使用angular-translate-loader-url扩展名加载翻译文件.

问题

在初始页面加载时,将显示翻译键,而不是该键的翻译.翻译是Hello, World!,但我看到了HELLO_WORLD.

我第二次去页面,一切都很好,并显示翻译版本.

我假设问题与控制器分配值时可能尚未加载转换文件的事实有关$scope.pageTitle.

备注

使用<h1>{{ pageTitle | translate }}</h1>和时$scope.pageTitle = 'HELLO_WORLD';,翻译工作从第一次起完美.这个问题是我并不总是想要使用翻译(例如,对于第二个控制器,我只想传递一个原始字符串).

这是一个已知的问题/限制吗?怎么解决这个问题?

Rob*_*len 139

推荐:不要在控制器中翻译,在你的视图中翻译

我建议让你的控制器免于翻译逻辑,并直接在你的视图中翻译你的字符串,如下所示:

<h1>{{ 'TITLE.HELLO_WORLD' | translate }}</h1>
Run Code Online (Sandbox Code Playgroud)

使用提供的服务

Angular Translate提供$translate您可以在控制器中使用的服务.

$translate服务的示例用法可以是:

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

translate服务还有一个直接翻译字符串的方法,无需处理promise,使用$translate.instant():

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

使用的缺点$translate.instant()可能是,如果您正在加载异步,则尚未加载语言文件.

使用提供的过滤器

这是我的首选方式,因为我不必以这种方式处理承诺.过滤器的输出可以直接设置为范围变量.

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

    $scope.pageTitle = $translate('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined
});
Run Code Online (Sandbox Code Playgroud)

使用提供的指令

由于@PascalPrecht是这个令人敬畏的库的创建者,我建议继续他的建议(参见下面的答案)并使用提供的指令,它似乎处理非常聪明的翻译.

该指令负责异步执行,并且在转换没有动态值的情况下也非常聪明地监视范围上的转换ID.

  • 在HTML中完成转换时,摘要周期运行两次,但仅在控制器中运行一次.99%的情况可能无关紧要,但我在角度ui网格中遇到了一个问题,在许多单元格中都有翻译.一个边缘的情况肯定,只是要注意的事情 (4认同)

Pas*_*cht 122

实际上,你应该使用translate指令代替这些东西.

<h1 translate="{{pageTitle}}"></h1>
Run Code Online (Sandbox Code Playgroud)

该指令负责异步执行,并且在转换没有动态值的情况下也非常聪明地监视范围上的转换ID.

但是,如果没有办法,你真的必须$translate在控制器中使用服务,你应该在一个$translateChangeSuccess事件中使用这样$rootScope的组合来包装调用$translate.instant():

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

那么为什么$rootScope$scope呢?原因在于,在angular-translate的事件中$emit编辑$rootScope而不是$broadcast编辑,$scope因为我们不需要通过整个范围层次结构进行广播.

为什么$translate.instant()而不仅仅是异步$translate()?当$translateChangeSuccess事件被触发时,它确保所需的转换数据存在并且没有发生异步执行(例如异步加载器执行),因此我们可以使用$translate.instant()哪个是同步的并且只是假设转换可用.

从版本2.8.0开始,还会$translate.onReady()返回一个在转换准备就绪后立即解决的承诺.请参阅更改日志.

  • 实际上,尽可能避免过滤器总是更好,因为它们会减慢你的应用程序,因为它们总是设置新的手表.然而,该指令更进一步.它会检查是否必须查看翻译ID的值.这样可以更好地执行您的应用.你能不能把它连接起来,所以我可以再看看了吗? (10认同)
  • @PascalPrecht只是一个问题,将bind-once与翻译一起使用是一种好习惯吗?像这样`{{::'HELLO_WORLD | 翻译}}'`. (2认同)

Nik*_*los 68

编辑:请参阅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; }
    );
});
Run Code Online (Sandbox Code Playgroud)

但是,这将在每个摘要周期运行观察表达式.这是次优的,可能会也可能不会导致可见的性能下降.无论如何它是Angular所做的,所以它不能那么糟糕......


Mac*_*eod 5

要在控制器中进行翻译,您可以使用$translateservice:

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

该语句仅在激活控制器时执行转换,但不会检测语言的运行时更改。为了实现该行为,您可以监听$rootScope事件:$translateChangeSuccess,并在该处执行相同的翻译:

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

当然,您可以将$translate服务封装在一个方法中,然后在控制器和$translateChangeSucess侦听器中调用它。