首页 文章

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

提问于
浏览
117

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

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

代码

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

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

问题

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

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

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

备注

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

问题

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

5 回答

  • 137

    EDIT :请参阅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所做的,所以它不能那么糟糕......

  • 122

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

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

    <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服务还有一个方法,可以使用 $translate.instant() 直接翻译字符串而无需处理承诺:

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

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

    使用提供的过滤器

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

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

    使用提供的指令

    由于@PascalPrecht是这个令人敬畏的库的创建者,我建议使用his advise (see his answer below)并使用提供的指令,它似乎处理非常智能的翻译 .

    该指令负责异步执行,并且如果转换没有动态值,它也足够聪明地监视范围上的转换ID .

  • 4

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

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

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

    但是,如果没有办法,你真的在控制器中使用 $translate 服务,你应该使用 $rootScope$translate.instant() 结合在 $translateChangeSuccess 事件中包装调用,如下所示:

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

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

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

    从版本2.8.0开始,还有 $translate.onReady() ,它会返回一个在转换准备就绪后立即解析的承诺 . See the changelog .

  • 67

    要在控制器中进行翻译,您可以使用 $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,页面的转换一次完成,并且它始终显示带有页面初始渲染的翻译文本 .

    完全披露:我是联合创始人:)

相关问题