使用$ translateProvider.useStaticFilesLoader进行Angular Translate异步计时问题

时间:2015-04-10 00:31:58

标签: javascript angularjs angularjs-directive angular-services angular-translate

我正在使用优秀的Angular Translate($translate)指令/服务来处理多种语言环境语言,因为我有多个语言环境文件,所以我使用方便的$translateProvider.useStaticFilesLoader通过结构加载我的翻译文件localeAbbr.json,例如en.jsones.json等...我构建了一个Plunker来显示我的开源项目,该项目通过Git原始文件使用语言环境(指向实际的Github存储库) ,意思不是plunker demo的本地化)。我的项目是作为指令和服务构建的,我制作了一个小的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');
}]);

通过Controller致电我的服务:

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">&times;</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;并尝试过,但似乎没有帮助。< / p>

这里再次是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;
});

3 个答案:

答案 0 :(得分:2)

在使用AngularJS或JavaScript时,您确实需要采用异步范例。为了减少处理异步代码的麻烦,可以使用Promises。 Angular为您提供了一个名为$ q的服务,它为您提供了繁重的工作

https://docs.angularjs.org/api/ng/service/$q

让人们了解Promises可能需要时间,但从长远来看非常值得付出努力。

基本上你需要对validationService做的是使用$ translate的promise api,它可以根据提供的密钥为你提供所需的翻译。这可以归结为你要求翻译所有翻译的翻译,并且当你获取所有翻译时,你用你的消息填充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中使用翻译过滤器。请注意,如果您有一个大型DOM,这可能会被证明是昂贵的,因为Angular会调用每个摘要翻译每个键。要考虑的方法是为vm提供标签对象,并使用$ filter服务在控制器实例化时填充它们。

答案 1 :(得分:1)

我发现我的问题的答案是将额外的参数传递给promise的匿名函数是使用Closures,这样变量在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);

现在最后,我的变量是正确的,并保持该时间点的值:)

答案 2 :(得分:0)

虽然$translateProvider.useStaticFilesLoader确实没有返回承诺,但我查看了$ translate服务,发现它提供了一个方便的回调onReady(),它确实返回了一个承诺。当$translate服务加载了当前选定的语言时,将调用此回调,这对于确保在页面初始化后即时翻译将按预期工作非常有用:

$translate.onReady(function () {
    // perform your instant translations here
    var translatedMsg = $translate.instant('INVALID_ALPHA');
});