如何在AngularJS中处理多种语言以获取表单验证消息/警报?

时间:2013-08-09 23:04:16

标签: javascript angularjs

我正在尝试使用AngularJS开发一个应用程序,它应该可以在多种用户选择的语言中使用。我将我的观点放在views/enviews/fr等中,因此如果用户正在查看英文,那么所有控制器的模板网址都将为views/en/someFile.html,而对于法语,它将为{ {1}},等等。

问题是,如何处理显示javascript显示的随机表单验证消息/警报,以正确的语言显示?

例如,在我的所有控制器中,我有一个/views/fr/someFile.html变量,用于在浏览器中设置$scope.title。如果用户选择其他语言,我希望<title>更新为以他选择的语言显示。

实现这一目标的最佳方式是什么?

1 个答案:

答案 0 :(得分:2)

textService

我已更新此答案,以反映我目前解决此问题的方法。删除模板中的文本数据依赖性是我感觉到的一个重要问题,我已经为此编写了自己的小模块。如果要使用所有文本插入选项(状态文本和相关文本),则需要使用ui-router来配置路由。

这是用法。我将把模块放在答案的最后。

  • 在angular之后但在模块定义之前包含text-service.js  
  • 将其声明为依赖项:angular.module("app", ["textService"]  
  • 将文本数据对象绑定到它。文本数据对象应该模仿您的状态层次结构。 e.g:

    var textData = {
      home: { // 'home' state
        // text data for home state here
        child { // 'home.child' state
          // text data for child state
        }
      }
    }
    

    文本对象应该是对象文字,语言名称为键:

    var textData = {
      home: {
          title: {
            en: "Home",
            fr: "Maison"
          }
        }
      }
    }
    

    设置语言并将文本对象绑定到textService:

    app.run(function(textService) {
      var textData = ...
      textService
        .setLanguage("en")
        .bindText(textData)
    });
    

    在运行函数中包含所有文本数据可能并不合适 - 因此,如果用户想要使用工厂或多个工厂来注入它,则由用户决定:

    app.factory("textData", function() {
      var textData = ...
      return textData
    }
    app.run(function(textService, textData) {
      textService
        .setLanguage("en")
        .bindText(textData)
    });
    

  • 有四种基于属性的指令用于从模板中检索文本。属性名称为:

       
    1. atext - “绝对文字”
    2.  
    3. stext - “州文字”
    4.  
    5. rtext - “相对文字”
    6.  
    7. text - “文字”
    8. 要在模板中使用,请添加atext作为属性,并将其值设置为一个字符串,找到您感兴趣的文本数据:

      <h1 atext="home.title.en"></h1>
      

      所有指令都会将您添加的任何DOM元素的innerHtml替换为文本数据,因此请确保它没有您关心的子DOM元素。

      指令的差异主要与定位文本字符串有关。假设我们有以下文本数据对象:

      var textData = {
        title: {
          en: "Index",
          fr: "Index"
        },
        // home state
        home: {
          title: {en: "Home",fr: "Maison"},
          header: {en: "Heading", fr: ""}
          child: { // home.child
            title: {en: "Child",fr: "Enfant"},
              intro: {
                en: "Welcome to child",
                fr: "Bienvenue à l'enfant"
              }
          }
          lonelychild: {
            // no text data
          }
        }
      };
      

      atext指的是字符串的绝对位置。所以atext="title.en"获取“索引”,其中atext="title"会抛出错误(暂时)。

      stext指的是相对于当前状态的字符串。例如,如果处于“home”状态,stext="title"将获取“Home”。如果你根本不处于任何状态,它将获取“索引”。如果您要导航到'home.child'状态,它将获取“Child”。 (注意:如果您已将语言设置为“en”)

      ,则均为这些

      rtext指的是相对文字位置。它的行为与stext类似,不同之处在于它会搜索状态层次,寻找文本数据以匹配。这对于根据状态动态更改标题非常方便:

      <title rtext="title"></title>
      

      这将用最近的'title'文本数据替换标题DOM元素的innerHtml。因此,如果你处于'home.lonelychild'状态,那么标题仍会绑定到“Home”(因为它位于父状态的文本数据中)。

      text此指令的工作方式与atext类似,但您不需要指定语言。

      在语言变化时动态变化的指令是stext,rtext和text。 您可以使用更改语言,例如textService.setLanguage("fr")。这将向所有文本指令广播一个“languageChange”事件,指示它们应该更新。如果要取消更新,请传递第二个参数,指示是否应进行更新:textService.setLanguage("fr", false) /

      在状态变化时动态变化的指令是stext和rtext。

      您可以使用textService.update()

      强制进行更新

      我已尽一切努力尽快制作这个插件。作为一般经验法则,每个文本指令将产生大约1ms的初始处理时间。我认为这很大一部分来自角度初始化每个文本数据的指令。但是,即使你在一个页面上有100个左右的文本指令,动态更新也很快。


      这是模块和github repo

      的链接
      /*
       * text-service.js
       * Author: Ian Haggerty - iahag001@yahoo.co.uk
       * Last Edit: 17/08/2013
       */
      
      angular.module("textService", [])
          .factory("textService", function ($rootScope, $log) {
      
              /* Internal Implementation */
              var textService;
              textService = {
                  language: "",
                  state: "",
                  textData: {},
      
                  /* text(request) - Text request
                   * @request Absolute path to text without language appended - e.g. 'home.title'
                   */
                  text: function (request) {
                      return (new Function(
                          "return arguments[0].textData." + request +
                              ((textService.language) ? ("." + textService.language) : "")
                      ))(textService);
                  },
      
                  /* absText(request)- Absolute text request
                   * @request Absolute path to text with language appended - e.g. 'home.title.en'
                   */
                  absText: function (request) {
                      return (new Function(
                          "return arguments[0].textData." + request
                      ))(textService);
                  },
      
                  /* relText(request, cut) - Scoped text request, will search up the state heirarchy
                   * @request Relative path to text without language appended - e.g. 'title'
                   * @state State to test for textual data - defaults to the current state, used recursively
                   */
                  relText: function (request, state) {
                      if(state === undefined) {
                          // initial call to function
                          state = textService.state
                      }
                      try { return textService.text((state?state+".":"") + request)}
                      catch(e) {
                          if(!state) return "" // terminate to avoid infinite recursion
                          return textService.relText(request, state.split(".")).slice(0,-1).join(".");
                      }
                  },
      
                  /* stateText - request a string in the current state(e.g. stateText('title')
                   * @request - Relative path to string in current state
                   */
                  stateText: function (request) {
                      return (textService.state) ?
                          textService.text(textService.state + "." + request) : "";
                  }
              }
      
              // Register handler for state changes
              $rootScope.$on("$stateChangeSuccess", function (event, toState) {
                  textService.state = toState.name;
              });
      
              /* Public API */
              var textServiceApi = {
                  /* bindText - Bind the entire textual data to a new object
                   * @textData - The text data object to be bound to
                   */
                  bindText: function (textData) {
                      textService.textData = textData;
                      $rootScope.$broadcast("textDataChange")
                      return textServiceApi;
                  },
                  /* setText() - function to set textual data and update text directives
                   * @request The request string, e.g. 'home.title', 'home.title.en'
                   * @textData The textual data. Could be a literal string or an object with textual data
                   * @doUpdate Boolean indicating whether to update text directives. Defaults to FALSE.
                   * Example usage 1: setText('home.title.en', "Title") - set a text string without update
                   * Example usage 2: setText('home.title', {en:"Title", fr:"Maison"}, true)
                   * - set a text object with update to the page
                   */
                  setText: function(request, textData, doUpdate) {
                      (new Function(
                          "arguments[0].textData." + request + "=arguments[1]"
                      ))(textService, textData)
                      if(!doUpdate) $rootScope.$broadcast("textDataChange")
                      return textServiceApi
                  },
                  /* getText() - Function returning textual data
                   * @request An absolute reference to the text
                   * Example usage: getText('home.title.en'), getText('home.title') // this returns a text object
                   */
                  getText: function(request) {
                      if(!request)
                          return textService.textData
                      else {
                          return (new Function(
                              "return arguments[0].textData." + request
                          ))(textService)
                      }
                  },
                  /* setLanguage() - Set the current language
                   * @langauge  - The new language. e.g. "fr", "en"
                   * @doUpdate - Boolean indicating whether to update text directives, defaults to TRUE
                   * Example usage: setLanguage("fr") // change to french and update the page
                   */
                  setLanguage: function (language, doUpdate) {
                      if(doUpdate === undefined) doUpdate = true;
                      textService.language = language
                      $rootScope.$broadcast("languageChange")
                      return textServiceApi;
                  },
                  getLanguage: function () {
                      return textService.language;
                  },
                  /* update() - Requests all text directives to update themselves
                   */
                  update: function() {
                      $rootScope.$broadcast("textDataChange")
                      return textServiceApi
                  },
                  /* Used by text directives */
                  text: textService.text,
                  absText: textService.absText,
                  relText: textService.relText,
                  stateText: textService.stateText
              }
              return textServiceApi
          })
          /* Text directive */
          .directive("text", function (textService) {
              return {
                  restrict: "A",
                  link: function (scope, element, attrs) {
                      function update() {
                          element.html(textService.text(attrs.text))
                      }
      
                      scope.$on("languageChange", update)
                      scope.$on("textDataChange", update)
      
                      update()
                  }
              }
          })
          /* Absolute text directive */
          .directive("atext", function (textService) {
              return {
                  restrict: "A",
                  link: function (scope, element, attrs) {
                      function update() {
                          element.html(textService.absText(attrs.atext))
                      }
      
                      scope.$on("textDataChange", update)
      
                      update()
                  }
              }
          })
          /* State text directive */
          .directive("stext", function (textService) {
              return {
                  restrict: "A",
                  link: function (scope, element, attrs) {
                      function update() {
                          element.html(textService.stateText(attrs.stext))
                      }
      
                      scope.$on("languageChange", update)
                      scope.$on("textDataChange", update)
                      scope.$on("$stateChangeSuccess", update)
      
                      update()
                  }
              }
          })
          /* Relative text directive */
          .directive("rtext", function (textService, $log) {
              return {
                  restrict: "A",
                  link: function (scope, element, attrs) {
                      function update(event, request) {
                          element.html(textService.relText(attrs.rtext))
                      }
      
                      scope.$on("languageChange", update)
                      scope.$on("textDataChange", update)
                      scope.$on("$stateChangeSuccess", update)
      
                      update()
                  }
              }
          })