Javascript 在控制器中正确使用角度平移
我正在AngularJS应用程序中使用i18n 对于每个应用程序视图,都有一个专用控制器。在下面的控制器中,我将值设置为显示为页面标题 代码 HTML 我正在使用扩展名加载翻译文件 问题 在初始页面加载时,将显示翻译键,而不是该键的翻译。翻译是Javascript 在控制器中正确使用角度平移,javascript,angularjs,angular-translate,Javascript,Angularjs,Angular Translate,我正在AngularJS应用程序中使用i18n 对于每个应用程序视图,都有一个专用控制器。在下面的控制器中,我将值设置为显示为页面标题 代码 HTML 我正在使用扩展名加载翻译文件 问题 在初始页面加载时,将显示翻译键,而不是该键的翻译。翻译是你好,世界,但我看到了你好_WORLD 我第二次进入页面时,一切都很好,并且显示了翻译版本 我假设问题与以下事实有关:当控制器将值分配给$scope.pageTitle时,翻译文件可能尚未加载 评论 使用{pageTitle | translate}和$s
你好,世界代码>,但我看到了你好_WORLD
我第二次进入页面时,一切都很好,并且显示了翻译版本
我假设问题与以下事实有关:当控制器将值分配给$scope.pageTitle
时,翻译文件可能尚未加载
评论
使用{pageTitle | translate}
和$scope.pageTitle='HELLO_WORLD'代码>,译文从第一次开始就完美无瑕。问题是我并不总是想使用翻译(例如,对于第二个控制器,我只想传递一个原始字符串)
问题:
这是已知的问题/限制吗?如何解决这个问题?编辑:请参阅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就是这么做的,所以不会那么糟糕…建议:不要在控制器中进行转换,而是在您的视图中进行转换
我建议让您的控制器不受转换逻辑的影响,并在视图中直接转换字符串,如下所示:
<h1>{{ 'TITLE.HELLO_WORLD' | translate }}</h1>
.controller('foo', function ($rootScope, $scope, $translate) {
$rootScope.$on('$translateChangeSuccess', function () {
$scope.pageTitle = $translate.instant('PAGE.TITLE');
});
})
translate服务还有一种方法,可以使用$translate.instant()
:
使用$translate.instant()
的缺点是,如果以异步方式加载语言文件,则该文件可能尚未加载
使用提供的过滤器
这是我的首选方式,因为我不必用这种方式处理承诺。过滤器的输出可以直接设置为范围变量
.controller('TranslateMe', ['$scope', '$filter', function ($scope, $filter) {
var $translate = $filter('translate');
$scope.pageTitle = $translate('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined
});
使用提供的指令
由于@PascalPrecht是这个很棒的库的创建者,我建议使用提供的指令,它似乎可以非常智能地处理翻译
该指令负责异步执行,并且如果转换没有动态值,它还足够聪明,可以在作用域上取消匹配转换ID
实际上,您应该使用translate指令来处理这些内容
<h1 translate="{{pageTitle}}"></h1>
那么为什么$rootScope
而不是$scope
?原因是,在angular translate中,事件是$rootScope
上的$emit
ed,而不是$broadcast
上的$broadcast
ed,因为我们不需要通过整个范围层次结构进行广播
为什么$translate.instant()
而不仅仅是异步$translate()
?当触发$translateChangeSuccess
事件时,可以确定所需的翻译数据在那里,并且没有发生异步执行(例如异步加载程序执行),因此我们可以只使用同步的$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
服务封装在一个方法中,并在控制器和$translateChangeSuccess
侦听器中调用它。现在发生的是,Angular translate使用基于事件的系统监视表达式,就像任何其他绑定或双向绑定情况一样,当检索到数据并更改了值时,会触发一个事件,这显然不适用于转换。当然,与页面上的其他动态数据不同,翻译数据必须立即显示给用户。页面加载后,它无法弹出
即使您能够成功地调试这个问题,更大的问题是所涉及的开发工作是巨大的。开发人员必须手动提取站点上的每个字符串,将其放入.json文件中,并通过字符串代码手动引用(本例中为“pageTitle”)。大多数商业网站都有数千个字符串,需要这样做。这仅仅是开始。现在,您需要一个在某些翻译中的底层文本发生更改时保持翻译同步的系统,一个将翻译文件发送给各个翻译人员、将其重新整合到构建中、重新部署站点以便翻译人员可以在上下文中看到其更改的系统,等等
此外,由于这是一个基于事件的“绑定”系统,因此会为页面上的每个字符串触发一个事件,这不仅是转换页面的较慢方式,而且如果开始向页面添加大量事件,还会减慢页面上的所有操作
无论如何,使用后处理翻译平台对我来说更有意义。例如,使用GlobalizeIt,翻译人员只需转到网站上的某个页面,就可以开始直接在页面上编辑文本,以供其使用
<h1 translate="{{pageTitle}}"></h1>
.controller('foo', function ($rootScope, $scope, $translate) {
$rootScope.$on('$translateChangeSuccess', function () {
$scope.pageTitle = $translate.instant('PAGE.TITLE');
});
})
$translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
vm.si = translations['COMMON.SI'];
vm.no = translations['COMMON.NO'];
});
$rootScope.$on('$translateChangeSuccess', function () {
$translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
vm.si = translations['COMMON.SI'];
vm.no = translations['COMMON.NO'];
});
});