Creator有个本地化的示例项目i18n-example,LabelLocazlized组件可以根据当前语言读取相应的文字。可是使用过程中发现一个很不方便的地方是:用到的文字往往在我们做界面的时候才定下来,根本没写到对应语言文件(如zh.js)中。意味着我们要来回切换代码编辑器、Creator编辑器才能新加、修改文字。很不爽,得优化下。
需求
我们希望是直接在Creator编辑器中新加字段、修改文本,然后直接写到对应的语言文件(zh.js)中。
解决方案
文件结构
i18n/LabelLocalized.js
本地化的组件,主要是修改string
字段的get
方法,从语言文件中读取相应字段(textKey)的文本。i18n/polyglot.js
一个工具类,将语言文件内容暂存,并提供一些格式化文本的方法。i18n/i18n.js
前面两个的中间层,只是传递了一下数据
写入文件
主要的问题是如何在编辑器中写入到本地文件。Creator是使用浏览器内核,同时支持nodeJs。那没啥了,直接百度大法:nodeJs如何写入文件
。找出一个fs
的库,在i18n.js
中加入const Fs = require('fs')
。保存,好的编译成功,说明是有这个库的。是时候表现一下复制粘帖的功力了。
//i18n.js@H_404_43@
const@H_404_43@ Polyglot = require@H_404_43@('polyglot'@H_404_43@);
//language修改为var方便设值@H_404_43@
var@H_404_43@ language = require@H_404_43@('zh'@H_404_43@);
const@H_404_43@ Fs = require@H_404_43@("fs"@H_404_43@);
let@H_404_43@ polyglot = new@H_404_43@ Polyglot({phrases: language});
module.exports = {
init (language) {
let@H_404_43@ data = require@H_404_43@(language);
polyglot.replace(data);
},t (key,opt) {
return@H_404_43@ polyglot.t(key,opt);
},save (key,value) {
//修改require缓存的值@H_404_43@
language[key] = value;
polyglot.replace(language);
//写入文件@H_404_43@
let@H_404_43@ text = "module.exports = "@H_404_43@ + JSON@H_404_43@.stringify(language,null@H_404_43@,"\t"@H_404_43@);
Fs.writeFile("YOUR_PROJECT_PATH/assets/i18n/data/zh.js"@H_404_43@,text);
}
};
现在是路径是写死的,协作开发显然是不行的。继续百度NodeJs 文件路径,得到以下几种写法:
cc.log@H_404_43@("__dirname:"@H_404_43@,__dirname);@H_404_43@
cc.log@H_404_43@("__filename:"@H_404_43@,__filename);@H_404_43@
cc.log@H_404_43@("process.cwd():"@H_404_43@,process.cwd@H_404_43@());@H_404_43@
赶紧喝口水冷静一下,我只是要拿到编辑器打开的项目路径,这东西理论上它编辑器自己的插件应该也会经常用到,肯定有某个地方保存着。翻翻插件开发教程,好多方法都是在Editor
中,啧啧,看这名字就有希望。我马上机智的想起了直播视频中有个小哥用编辑器>开发者工具
查看方法名的画面。果断照着试试,打开开发者工具,输入Editor。点开一路找,好的,抓到一只importPath
libraryPath
。感觉不对,怎么也得有个ProjectPath吧。点开继续找找,没错,就是你了:Editor.projectInfo.path
。修改一下
Fs.writeFile("YOUR_PROJECT_PATH/assets/i18n/data/zh.js",text);
—>
let path = Editor.projectInfo@H_404_43@.path@H_404_43@ + "/assets/i18n/data/"@H_404_43@ + cc.sys@H_404_43@.language@H_404_43@ + ".js"@H_404_43@;@H_404_43@
Fs.writeFile@H_404_43@(path,text);@H_404_43@
修改组件
保存写入文件有了,是时候修改组件了。先想一下编辑器上怎么操作更方便。个人觉得是以下操作流程更方便:
- 创建组件,直接修改文本,修改完成填写TextKey时保存到文件
- 有TextKey时修改文本后保存到文件
- 为了防止拼写错误将错误的字段写入文件,应该有个删除字段的方法。可以判断文本是空的时候视为删除字段
//LabelLocalized.js@H_404_43@
const@H_404_43@ i18n = require('i18n'@H_404_43@);
cc.Class({
extends: cc.Label,properties: {
textKey: {
default@H_404_43@: ''@H_404_43@,notify: function () {
//设置string@H_404_43@
let@H_404_43@ text = i18n.t(this@H_404_43@.textKey);
//相同说明没找到字段@H_404_43@
if@H_404_43@ (text !== this@H_404_43@.textKey) {
this@H_404_43@.string@H_404_43@ = text;
}
//写入文件@H_404_43@
if@H_404_43@ (this@H_404_43@.textKey !== ""@H_404_43@) {
if@H_404_43@ (this@H_404_43@.string@H_404_43@ !== ""@H_404_43@) {
i18n.save(this@H_404_43@.textKey,this@H_404_43@.string@H_404_43@);
} else@H_404_43@ {
//string为空视为删除字段@H_404_43@
i18n.save(this@H_404_43@.textKey,null@H_404_43@);
}
}
}
},string@H_404_43@: {
override@H_404_43@: true@H_404_43@,default@H_404_43@: ''@H_404_43@,notify: function () {
//textKey有值,修改string后写入文件@H_404_43@
if@H_404_43@ (this@H_404_43@.textKey !== ""@H_404_43@) {
if@H_404_43@ (this@H_404_43@.string@H_404_43@ !== ""@H_404_43@) {
i18n.save(this@H_404_43@.textKey,null@H_404_43@);
}
}
//From engine/cocos/core/components/CCLabel.js@H_404_43@
if@H_404_43@ (this@H_404_43@._sgNode) {
if@H_404_43@ (CC_EDITOR) {
if@H_404_43@(this@H_404_43@.overflow === cc.Label.Overflow.SHRINK) {
this@H_404_43@.fontSize = this@H_404_43@._userDefinedFontSize;
}
this@H_404_43@._debouncedUpdateSgNodeString();
} else@H_404_43@ {
this@H_404_43@._updateSgNodeString();
}
}
}
},}
});
保存、编译。添加组件,修改文本,修改textKey,再打开zh.js检查。诶呦我去,这是每输入TextKey一个字符都保存了一下啊。
仔细想了一下,考虑用定时器,组件的schedule编辑器里不会运行,只好用setTimeOut了,修改后:
//LabelLocalized.js@H_404_43@
const@H_404_43@ i18n = require@H_404_43@('i18n'@H_404_43@);
var@H_404_43@ saveTimer = null@H_404_43@;
cc.Class({
extends: cc.Label,notify: function@H_404_43@ ()@H_404_43@ {@H_404_43@
//设置string@H_404_43@
let@H_404_43@ text = i18n.t(this@H_404_43@.textKey);
//相同说明没找到字段@H_404_43@
if@H_404_43@ (text !== this@H_404_43@.textKey) {
this@H_404_43@.string = text;
}
if@H_404_43@ (saveTimer) {
clearTimeout(saveTimer);
}
//延时写入,时间可以自己实验调整,太小的话会保存没输完时候的值@H_404_43@
saveTimer = setTimeout(function@H_404_43@ ()@H_404_43@ {@H_404_43@
saveTimer = null@H_404_43@;
//写入文件@H_404_43@
if@H_404_43@ (this@H_404_43@.textKey !== ""@H_404_43@) {
if@H_404_43@ (this@H_404_43@.string !== ""@H_404_43@) {
i18n.save(this@H_404_43@.textKey,this@H_404_43@.string);
} else@H_404_43@ {
//string为空视为删除字段@H_404_43@
i18n.save(this@H_404_43@.textKey,null@H_404_43@);
}
}
}.bind(this@H_404_43@),5000@H_404_43@);
}
},string: {
override: true@H_404_43@,notify: function@H_404_43@ ()@H_404_43@ {@H_404_43@
if@H_404_43@ (saveTimer) {
clearTimeout(saveTimer);
}
//延时写入,防止文件读写太过频繁@H_404_43@
saveTimer = setTimeout(function@H_404_43@ ()@H_404_43@ {@H_404_43@
saveTimer = null@H_404_43@;
//textKey有值时修改string写入文件@H_404_43@
if@H_404_43@ (this@H_404_43@.textKey !== ""@H_404_43@) {
if@H_404_43@ (this@H_404_43@.string !== ""@H_404_43@) {
i18n.save(this@H_404_43@.textKey,1000@H_404_43@);
//From engine/cocos/core/components/CCLabel.js@H_404_43@
if@H_404_43@ (this@H_404_43@._sgNode) {
if@H_404_43@ (CC_EDITOR) {
if@H_404_43@(this@H_404_43@.overflow === cc.Label.Overflow.SHRINK) {
this@H_404_43@.fontSize = this@H_404_43@._userDefinedFontSize;
}
this@H_404_43@._debouncedUpdateSgNodeString();
} else@H_404_43@ {
this@H_404_43@._updateSgNodeString();
}
}
}
},}
});
基本功能已经实现,但是因为string
的get
方法没重写,切换语言的话文本还是用的之前设置的,加个__preload
:
__preload: function@H_404_43@ ()@H_404_43@ {@H_404_43@
this@H_404_43@._super();
//设置string@H_404_43@
let@H_404_43@ text = i18n.t(this@H_404_43@.textKey);
//相同说明没找到字段@H_404_43@
if@H_404_43@ (text !== this@H_404_43@.textKey) {
this@H_404_43@.string = text;
}
}
最后再加上CC_EDITOR
判断,完整版本附件: Cocos Creator LabelLocalized优化