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