我已经更新了这个答案以反映我目前对这个问题的解决方案。删除模板中的文本数据依赖是我觉得的一个重要问题,我已经为此编写了自己的小模块。如果你想使用所有的文本插入选项(状态文本和相关文本),你需要使用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(文本数据)
});
有四个基于属性的指令用于从模板中检索文本。属性名称是:
-
atext
- “绝对文本”
-
stext
- “状态文本”
-
rtext
——《相对文本》
-
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)
更新()
}
}
})