我正在尝试使用AngularJS开发一个应用程序,它应该可以在多种用户选择的语言中使用。我将我的观点放在views/en
和views/fr
等中,因此如果用户正在查看英文,那么所有控制器的模板网址都将为views/en/someFile.html
,而对于法语,它将为{ {1}},等等。
问题是,如何处理显示javascript显示的随机表单验证消息/警报,以正确的语言显示?
例如,在我的所有控制器中,我有一个/views/fr/someFile.html
变量,用于在浏览器中设置$scope.title
。如果用户选择其他语言,我希望<title>
更新为以他选择的语言显示。
实现这一目标的最佳方式是什么?
答案 0 :(得分:2)
我已更新此答案,以反映我目前解决此问题的方法。删除模板中的文本数据依赖性是我感觉到的一个重要问题,我已经为此编写了自己的小模块。如果要使用所有文本插入选项(状态文本和相关文本),则需要使用ui-router来配置路由。
这是用法。我将把模块放在答案的最后。
angular.module("app", ["textService"]
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) });
atext
- “绝对文字”stext
- “州文字”rtext
- “相对文字”text
- “文字”要在模板中使用,请添加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() } } })