2

我正在尝试使用 AngularJS 开发一个应用程序,它应该以多种用户选择的语言工作。我将我的视图放在views/enandviews/fr等中,所以如果用户正在查看英文,那么所有控制器的模板 URL 将是views/en/someFile.html,而对于法语它将是/views/fr/someFile.html,依此类推。

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

例如,在我所有的控制器中,我都有一个在浏览器$scope.title中设置的变量。<title>如果用户选择不同的语言,我希望<title>更新以他选择的语言显示。

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

4

1 回答 1

2

文本服务

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

这是用法。我会将模块放在答案的末尾。

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

    var textData = {
      home: { // '家' 状态
        // 这里是家庭状态的文本数据
        child { // 'home.child' 状态
          //子状态的文本数据
        }
      }
    }
    

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

    var textData = {
      家: {
          标题: {
            zh: "家",
            fr:“梅森”
          }
        }
      }
    }
    

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

    应用程序运行(功能(文​​本服务){
      var 文本数据 = ...
      文本服务
        .setLanguage("en")
        .bindText(文本数据)
    });
    

    将所有文本数据包含在 run 函数中可能是不可取的 - 因此,如果他们想使用一个工厂或多个工厂来注入这个,这取决于用户:

    app.factory("textData", function() {
      var 文本数据 = ...
      返回文本数据
    }
    app.run(function(textService, textData) {
      文本服务
        .setLanguage("en")
        .bindText(文本数据)
    });
    

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

    1. atext- “绝对文本”
    2. stext- “状态文本”
    3. rtext——《相对文本》
    4. text- “文本”

    要从模板中使用,请添加,例如,atext作为属性并将其值设置为定位您感兴趣的文本数据的字符串:

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

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

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

    var textData = {
      标题: {
        zh: "索引",
        fr:“索引”
      },
      // 老家
      家: {
        标题:{en:“家”,fr:“Maison”},
        标题:{en:“标题”,fr:“”}
        child: { // home.child
          标题:{en:“儿童”,fr:“Enfant”},
            介绍: {
              zh: "欢迎来到孩子",
              fr: "Bienvenue à l'enfant"
            }
        }
        孤儿:{
          // 没有文本数据
        }
      }
    };
    

    atext指的是字符串的绝对位置。所以在会抛出错误的atext="title.en"地方获取“索引” (现在)。atext="title"

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

    rtext指相对文本位置。它的行为就像stext除了它会搜索状态层次结构以查找要匹配的文本数据。这对于根据状态动态更改标题非常方便:

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

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

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

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

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

    您可以使用强制更新textService.update()

    我已经竭尽全力使这个插件尽可能快。作为一般经验法则,每个文本指令都会产生大约 1 毫秒的初始处理时间。我认为大部分内容来自为每条文本数据的角度初始化指令。但在此之后,动态更新很快,即使您在一页上有 100 个左右的文本指令。


    这是模块和github 存储库的链接

    /*
     * 文本服务.js
     * 作者:伊恩·哈格蒂 - iahag001@yahoo.co.uk
     * 最后编辑:2013 年 8 月 17 日
     */
    
    angular.module("textService", [])
        .factory("textService", function ($rootScope, $log) {
    
            /* 内部实现 */
            var 文本服务;
            文本服务 = {
                语: ””,
                状态: ””,
                文本数据:{},
    
                /* text(request) - 文本请求
                 * @request 没有附加语言的文本的绝对路径 - 例如'home.title'
                 */
                文本:函数(请求){
                    返回(新功能(
                        “返回参数 [0].textData。” + 请求 +
                            ((textService.language) ? ("." + textService.language) : "")
                    ))(文本服务);
                },
    
                /* absText(request)- 绝对文本请求
                 * @request 附加语言的文本的绝对路径 - 例如'home.title.en'
                 */
                absText:函数(请求){
                    返回(新功能(
                        “返回参数 [0].textData。” + 请求
                    ))(文本服务);
                },
    
                /* relText(request, cut) - 范围文本请求,将搜索状态层次结构
                 * @request 没有附加语言的文本的相对路径 - 例如“标题”
                 * @state 测试文本数据的状态 - 默认为当前状态,递归使用
                 */
                relText:函数(请求,状态){
                    如果(状态 === 未定义){
                        // 初始调用函数
                        状态 = textService.state
                    }
                    尝试 { 返回 textService.text((state?state+".":"") + request)}
                    抓住(e){
                        if(!state) return "" // 终止以避免无限递归
                        return textService.relText(request, state.split(".")).slice(0,-1).join(".");
                    }
                },
    
                /* stateText - 请求当前状态的字符串(例如 stateText('title')
                 * @request - 当前状态下字符串的相对路径
                 */
                stateText:函数(请求){
                    返回(文本服务状态)?
                        textService.text(textService.state + "." + request) : "";
                }
            }
    
            // 注册状态改变的处理程序
            $rootScope.$on("$stateChangeSuccess", function (event, toState) {
                textService.state = toState.name;
            });
    
            /* 公共 API */
            var textServiceApi = {
                /* bindText - 将整个文本数据绑定到一个新对象
                 * @textData - 要绑定的文本数据对象
                 */
                绑定文本:函数(文本数据){
                    textService.textData = 文本数据;
                    $rootScope.$broadcast("textDataChange")
                    返回文本服务接口;
                },
                /* setText() - 设置文本数据和更新文本指令的函数
                 * @request 请求字符串,例如 'home.title', 'home.title.en'
                 * @textData 文本数据。可以是文字字符串或带有文本数据的对象
                 * @doUpdate 布尔值,指示是否更新文本指令。默认为假。
                 * 示例用法1:setText('home.title.en', "Title") - 设置文本字符串而不更新
                 * 示例用法2:setText('home.title', {en:"Title", fr:"Maison"}, true)
                 * - 设置一个更新到页面的文本对象
                 */
                setText:函数(请求,文本数据,doUpdate){
                    (新功能(
                        “参数[0].textData。” +请求+“=参数[1]”
                    ))(文本服务,文本数据)
                    if(!doUpdate) $rootScope.$broadcast("textDataChange")
                    返回文本ServiceApi
                },
                /* getText() - 返回文本数据的函数
                 * @request 对文本的绝对引用
                 * 示例用法:getText('home.title.en'), getText('home.title') // 这会返回一个文本对象
                 */
                获取文本:函数(请求){
                    如果(!请求)
                        返回 textService.textData
                    别的 {
                        返回(新功能(
                            “返回参数 [0].textData。” + 请求
                        ))(文本服务)
                    }
                },
                /* setLanguage() - 设置当前语言
                 * @langauge - 新语言。例如“fr”、“en”
                 * @doUpdate - 指示是否更新文本指令的布尔值,默认为 TRUE
                 * 示例用法:setLanguage("fr") // 更改为法语并更新页面
                 */
                setLanguage:函数(语言,doUpdate){
                    如果(doUpdate === 未定义)doUpdate = true;
                    textService.language = 语言
                    $rootScope.$broadcast("languageChange")
                    返回文本服务接口;
                },
                获取语​​言:函数(){
                    返回文本服务.语言;
                },
                /* update() - 请求所有文本指令更新自己
                 */
                更新:函数(){
                    $rootScope.$broadcast("textDataChange")
                    返回文本ServiceApi
                },
                /* 由文本指令使用 */
                文本:textService.text,
                absText:textService.absText,
                relText:textService.relText,
                stateText:textService.stateText
            }
            返回文本ServiceApi
        })
        /* 文本指令 */
        .directive("text", function (textService) {
            返回 {
                限制:“A”,
                链接:函数(范围、元素、属性){
                    函数更新(){
                        element.html(textService.text(attrs.text))
                    }
    
                    scope.$on("languageChange", 更新)
                    scope.$on("textDataChange", 更新)
    
                    更新()
                }
            }
        })
        /* 绝对文本指令 */
        .directive("atext", function (textService) {
            返回 {
                限制:“A”,
                链接:函数(范围、元素、属性){
                    函数更新(){
                        element.html(textService.absText(attrs.atext))
                    }
    
                    scope.$on("textDataChange", 更新)
    
                    更新()
                }
            }
        })
        /* 状态文本指令 */
        .directive("stext", function (textService) {
            返回 {
                限制:“A”,
                链接:函数(范围、元素、属性){
                    函数更新(){
                        element.html(textService.stateText(attrs.stext))
                    }
    
                    scope.$on("languageChange", 更新)
                    scope.$on("textDataChange", 更新)
                    scope.$on("$stateChangeSuccess", update)
    
                    更新()
                }
            }
        })
        /* 相对文本指令 */
        .directive("rtext", function (textService, $log) {
            返回 {
                限制:“A”,
                链接:函数(范围、元素、属性){
                    功能更新(事件,请求){
                        element.html(textService.relText(attrs.rtext))
                    }
    
                    scope.$on("languageChange", 更新)
                    scope.$on("textDataChange", 更新)
                    scope.$on("$stateChangeSuccess", update)
    
                    更新()
                }
            }
        })
    
    
  • 于 2013-08-10T01:55:55.237 回答