$translateProvider.useStaticFilesLoader的Angular Translate异步定
Angular Translate async timing issue with $translateProvider.useStaticFilesLoader
我使用出色的Angular Translate($translate
)指令/服务来处理多种语言环境,由于我有多个语言环境文件,我使用方便的$translateProvider.useStaticFilesLoader
通过localeAbbr.json结构加载翻译文件,例如en.json
、es.json
,等等。我构建了一个Plunker来展示我的开源项目,该项目通过Git原始文件使用区域设置(指向实际的Github存储库,意味着不是Plunker演示的本地存储库)。我的项目是作为指令和服务构建的,我制作了一个小的Plunker来显示JSON文件加载的时间问题。
也就是说,$translateProvider.useStaticFilesLoader
似乎是asynchronous
,而我真的需要它是synchronous
,因为当plunker运行时,JSON文件还没有解析,而我已经在消息中调用了$translate.instant()
。
我有一个Plunker显示问题。
这是我快速服务演示的一部分:
app.factory('validationService', ['$filter', '$translate', function ($filter, $translate) {
var service = this;
var validationSummary = [];
var errorMessages = [
'INVALID_ALPHA',
'INVALID_ALPHA_SPACE',
'INVALID_ALPHA_NUM',
'INVALID_BOOLEAN'
];
//var $translate = $filter('translate');
for(var i=0, ln=errorMessages.length; i < ln; i++) {
validationSummary.push({
field: i,
message: $translate.instant(errorMessages[i])
});
}
// attach public functions
service.getValidationSummary = getValidationSummary;
return service;
// function declaration
function getValidationSummary() {
return validationSummary;
}
}]);
$translateProvider配置
app.config(['$translateProvider', function ($translateProvider) {
$translateProvider.useStaticFilesLoader({
prefix: 'https://rawgit.com/ghiscoding/angular-validation/master/locales/validation/',
suffix: '.json'
});
// load English ('en') table on startup
$translateProvider.preferredLanguage('en').fallbackLanguage('en');
}]);
通过控制器呼叫我的服务:
app.controller("TestController", function($scope, validationService) {
var vm = this;
vm.displayValidationSummary = true;
vm.validationSummary = validationService.getValidationSummary();
});
最后是使用控制器的HTML:
<div class="alert alert-danger alert-dismissable" ng-show="vm.displayValidationSummary">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true" ng-click="displayValidationSummary = false">×</button>
<h4><strong>{{ 'ERRORS' | translate }}!</strong></h4>
<ul>
<li ng-repeat="item in vm.validationSummary">{{item.field }}: {{item.message}}</li>
</ul>
</div>
由于我使用的是AngularJS 1.3+,我还发现$translate
只翻译一次,所以作者建议使用translateFilter.$stateful = true;
,我尝试过,但似乎没有帮助。
这里是Plunker
我花了好几个星期的时间试图找到并编写各种解决方案,但我一直没有成功,看到我的原始翻译代码我真的很难过:(
请帮忙!!!
编辑
我意识到我的问题并没有涵盖与我的问题相关的所有内容。除了翻译延迟问题之外,我还必须传递额外的参数,这是一个将它们传递给翻译匿名函数的巨大问题。当承诺完成时,我的论点已经改变了。例如:
$translate(validator.message).then(function(translation) {
// only log the invalid message in the $validationSummary
addToValidationSummary(formElmObj, translation);
// error Display
if(!isValid) {
updateErrorMsg(translation, isValid);
}else if(!!formElmObj && formElmObj.isValid) {
addToValidationSummary(formElmObj, '');
}
}, function(data) {
throw 'Failed to translate' + data;
});
在使用AngularJS或JavaScript时,您确实需要接受异步范式。为了减少处理异步代码的麻烦,可以使用Promises。Angular为您提供了一项名为$q的服务,它为您提供
https://docs.angularjs.org/api/ng/service/$q
实现承诺可能需要时间,但从长远来看,这是值得的。
从本质上讲,您需要使用validationService来使用$translate的promise api,当它能够做到这一点时,它将根据提供的密钥为您提供所需的翻译。归根结底,您需要$translates来获得您希望获得翻译的所有translationId,当所有的translationId都被提取后,您将填充validationSummary数组中包含您的消息。
app.factory('validationService', ['$q', '$translate', function ($q, $translate) {
var translationsPromises = [],
validationSummary = [],
errorMessages = [
'INVALID_ALPHA',
'INVALID_ALPHA_SPACE',
'INVALID_ALPHA_NUM',
'INVALID_BOOLEAN'
];
angular.forEach(errorMessages, function(val, key) {
translationsPromises.push($translate(val));
});
$q.all(translationsPromises)
.then(function(translations) {
angular.forEach(translations, function(val, key) {
validationSummary.push({
filed: key,
message: val
});
});
})
.catch(function (err) {
console.error('Failed to translate error messages for validation summary', err);
});
// function declaration
function getValidationSummary() {
return validationSummary;
}
return {
getValidationSummary: getValidationSummary
};
}]);
我已经分叉了你的plunker,并对其进行了修改,以包括上面的样品
http://plnkr.co/edit/7DCwvY9jloXwfetKtcDA?p=preview
另一个观察结果是,您在HTML中使用了translate过滤器。请注意,如果您有一个大型DOM,这可能会被证明是昂贵的,因为Angular将调用来翻译每个摘要上的每个键。一种需要考虑的方法是为vm提供一个labels对象,并在控制器实例化时使用$filter服务来填充它们。
我发现,将额外参数传递给promise的匿名函数的问题的答案是使用闭包,这样一来,promise之前和内部的变量都是相同的。因此,我基本上必须将我的$translate
调用封装到闭包中,如下所示:
(function(formElmObj, isValid, validator) {
$translate(validator.message).then(function(translation) {
message = message.trim();
// only log the invalid message in the $validationSummary
addToValidationSummary(formElmObj, message);
// error Display
if(!isValid) {
updateErrorMsg(message, isValid);
}else if(!!formElmObj && formElmObj.isValid) {
addToValidationSummary(formElmObj, '');
}
}, function(data) {
throw 'Failed to translate' + data;
});
})(formElmObj, isValid, validator);
最后,我的变量是正确的,并保持该时间点的值:)
虽然$translateProvider.useStaticFilesLoader
确实不返回promise,但我查看了$translate服务内部,发现它提供了一个方便的回调onReady()
,它确实返回了promise。当$translate
服务完成加载当前选定的语言时,会调用此回调,它有助于确保即时翻译在页面初始化后按预期工作:
$translate.onReady(function () {
// perform your instant translations here
var translatedMsg = $translate.instant('INVALID_ALPHA');
});
- 偶尔结结巴巴地说“;堆叠的”;translate()上的转换(v4.0.0-alpha40)
- esri javascript异步打印
- JavaScript异步问题
- $translateProvider.useStaticFilesLoader的Angular Translate异步定
- 异步facebook功能
- 异步并行错误
- 在Redux中,我应该在哪里编写复杂的异步流
- 角度异步http自动完成
- 如何从SeleniumWebdriver获取异步Javascript响应
- 如何使用异步调用更改工厂的变量
- 在等待异步任务时永久循环
- 如何在异步函数中使用javascript对象
- 调用后不异步Ajax忽略函数
- learnyounode#9杂耍异步
- 异步获取数据使用JavaScript同步获取数据
- Meteor:异步回调问题
- 如何以异步方式打印q中的项目
- javascript函数中的异步与同步.(Node.js)
- Fresh Spark Install+Homestead上的Vue异步堆栈跟踪错误
- Meteor:异步函数回调异常:onAfterAction