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

我在AngularJS应用程序中使用i18n的angular-translate 。

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

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> <h1>{{ pageTitle | translate }}</h1>$scope.pageTitle = 'HELLO_WORLD'; ,翻译从第一次就完美了。 这个问题是,我不总是要使用翻译(例如,我只是想传递一个原始string的第二个控制器)。

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

编辑 :请参阅PascalPrecht(angular-translate的作者)的答案,以获得更好的解决scheme。


加载的asynchronous性质导致问题。 你看, {{ pageTitle | translate }} {{ pageTitle | translate }} ,Angular会观看表情; 当加载本地化数据时,expression式的值改变并且屏幕被更新。

所以,你可以自己做:

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

但是,这将在每个摘要循环中运行监视的expression式。 这是不理想的,可能会或可能不会导致可见的性能下降。 无论如何,这是什么angular,所以它不能是坏…

build议:不要在控制器中翻译,翻译你的看法

我build议让你的控制器免于翻译逻辑,并直接在你的视图内翻译你的string,如下所示:

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

使用提供的服务

angular度翻译提供$translate服务,您可以在您的控制器中使用。

$translate服务的一个示例用法是:

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

翻译服务还有一个直接翻译string的方法,不需要处理promise,使用$translate.instant()

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

使用$translate.instant()的缺点可能是语言文件没有加载,如果你正在加载asynchronous。

使用提供的filter

这是我喜欢的方式,因为我不必这样处理承诺。 filter的输出可以直接设置为范围variables。

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

使用提供的指令

由于@PascalPrecht是这个真棒图书馆的创build者,所以我build议去看他的build议(见下面的答案),并使用提供的指令来处理翻译非常聪明。

该指令负责asynchronous执行,并且在翻译没有dynamic值的情况下也足够聪明,可以解释范围上的翻译id。

其实,你应该使用translate指令代替这些东西。

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

该指令负责asynchronous执行,并且在翻译没有dynamic值的情况下也足够聪明,可以解释范围上的翻译id。

但是,如果没有办法解决,并且真的必须在控制器中使用$translate服务,则应该使用$rootScope$translate.instant()组合使用$rootScope $translateChangeSuccess事件来包装调用,如下所示:

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

那么为什么$rootScope而不是$scope ? 原因是,在angular-translate的事件中$emit放在$rootScope而不是$scope$scope因为我们不需要通过整个范围层次来广播。

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

自2.8.0版本以来,还有$translate.onReady() ,它将返回一个在翻译准备就绪后立即解决的承诺。 查看更新日志 。

要在控制器中进行翻译,您可以使用$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监听器中调用它。

正在发生的事情是,Angular-translate正在用基于事件的系统来观察expression式,就像在任何其他绑定或双向绑定的情况下一样,当数据被检索时,事件被触发,并且值发生改变显然不适合翻译。 翻译数据,不同于页面上的其他dynamic数据,当然必须立即显示给用户。 页面加载后无法popup。

即使你能成功地debugging这个问题,更大的问题是涉及到的开发工作是巨大的。 开发人员必须手动提取网站上的每个string,把它放在一个.json文件中,通过string代码手动引用它(例如,在这种情况下是“pageTitle”)。 大多数商业网站有成千上万的string,这需要发生。 而这仅仅是一个开始。 现在,您需要一个系统,在底层文本发生变化时保持翻译同步,将翻译文件发送给各个翻译人员,将其重新整合到翻译版本中,重新部署翻译站点,以便翻译人员可以看到他们在上下文中的变化,等等。

另外,由于这是一个基于事件的“绑定”系统,因此页面上的每个string都会触发一个事件,这不仅是转换页面的较慢方式,而且会减慢页面上的所有操作,如果你开始添加大量的事件。

无论如何,使用后处理翻译平台对我来说更有意义。 例如,使用GlobalizeIt,翻译人员可以直接访问网站上的一个页面,并直接在页面上为他们的语言编辑文本,就是这样: https : //www.globalizeit.com/HowItWorks 。 不需要编程(虽然它可以通过编程扩展),它可以轻松地与Angular集成: https : //www.globalizeit.com/Translate/Angular ,页面转换一次完成,并且总是显示翻译后的文本页面的初始渲染。

充分披露:我是一个联合创始人:)