在项目需要国际化处理时,即支持多种语言切换的功能,通常有两种方案:
单个包
优点:
1. 可以动态切换语言(需要代码支持)
2. 只有一个版本,便于维护
缺点:
1. 安装包较大
多个包
优点:
1. 安装包较小
2. 可以对不同语言进行深度本地化(如功能差异)
缺点:
1. 需要多次提交审核
2. 多个版本的维护成本较高
下面我们重点讨论单个包的实现方法
由于 CocosCreator 内置的 i18n 功能可能不够灵活,因此我们需要自定义一个多语言处理系统。具体实现需要以下几个文件:
1. LanguageMgr.ts
2. LanguageSprite.ts
3. LanguageLabel.ts
4. language.json
以下是各文件的具体实现:
LanguageMgr.ts:
/*
多语言管理类,主要功能是加载多语言的图片和文字
*/
import { EventMgr } from "./EventMgr";
import { GlobalEvent } from "../model/EventType";
import { config } from "./config";
import { CallNative } from "./CallNative";
import { LanguageEnum } from "./Enum";
export class LanguageMgr {
static languageJson = null;
static kind = "EN";
/**
* 加载多语言json
*/
static initLanguageJson() {
this.languageJson = config.getOneConfig("language");
}
static init() {
this.initLanguageJson();
let kind = "EN";
if (cc.sys.localStorage.getItem("lanAndCountry")) {
kind = cc.sys.localStorage.getItem("lanAndCountry");
} else {
let lanAndCountry = CallNative.getLanguage();
if (lanAndCountry.substr(0, 2) === "zh") {
kind = LanguageEnum.tc;
} else {
kind = LanguageEnum.en;
}
}
this.setKind(kind);
}
/**
* 设置语言类型
* @param kind
*/
static setKind(kind: string) {
this.kind = kind;
}
/**
* 获取当前语言类型
* @param kind
*/
static getKind() {
return this.kind;
}
/**
* 修改语言
* @param kind
*/
static changeLanguage = function (kind: string) {
if (this.kind !== kind) {
this.setKind(kind);
cc.sys.localStorage.setItem("lanAndCountry", kind);
EventMgr.sendNormalEvent(GlobalEvent.CHANGE_LANGUAGE);
}
}
/**
* 获取语言包的key
* @param text
* @param param
*/
static getText = function (text: string, param?: { "$param1": string | number }) {
if (this.languageJson && this.languageJson[text]) {
let str: string = this.languageJson[text][this.kind] || "";
if (param) {
if (param["$param1"] !== undefined) str = str.replace("$param1", param["$param1"].toString());
}
return str;
} else if (text === "") {
return "";
} else {
console.log("文本 " + text + " 没有多语言");
return text;
}
}
}
LanguageSprite.ts:
import { LanguageMgr } from "../common/LanguageMgr";
import { GlobalEvent } from "../model/EventType";
const { ccclass, property, menu, requireComponent, disallowMultiple } = cc._decorator;
/**
* 多语言的图片初始化
*/
@ccclass
@menu("多语言/sprite")
@requireComponent(cc.Sprite)
@disallowMultiple
export default class LanguageSprite extends cc.Component {
@property(cc.SpriteFrame)
en: cc.SpriteFrame = null;
@property(cc.SpriteFrame)
sc: cc.SpriteFrame = null;
@property(cc.SpriteFrame)
tc: cc.SpriteFrame = null;
start() {
cc.director.on(GlobalEvent.CHANGE_LANGUAGE, this.changeLanguage, this);
this.changeLanguage();
}
/**
* 监听切换语言事件
*/
changeLanguage() {
if (LanguageMgr.getKind() === "EN") {
this.getComponent(cc.Sprite).spriteFrame = this.en;
} else if (LanguageMgr.getKind() === "TC") {
this.getComponent(cc.Sprite).spriteFrame = this.tc;
} else {
if (this.sc) {
this.getComponent(cc.Sprite).spriteFrame = this.sc;
} else {
this.getComponent(cc.Sprite).spriteFrame = this.tc;
}
}
}
}
LanguageLabel.ts:
import { GlobalEvent } from "../model/EventType";
import { LanguageMgr } from "../common/LanguageMgr";
const { ccclass, property, menu, requireComponent, disallowMultiple } = cc._decorator;
@ccclass
@menu("多语言/label")
@requireComponent(cc.Label)
@disallowMultiple
export default class LanguageLabel extends cc.Component {
// LIFE-CYCLE CALLBACKS:
@property
prefix: string = "";
@property
suffix: string = "";
@property
text: string = "";
start() {
cc.director.on(GlobalEvent.CHANGE_LANGUAGE, this.changeLanguage, this);
this.changeLanguage();
}
/**
* 监听切换语言事件
*/
changeLanguage() {
var label = this.getComponent(cc.Label);
if (label) {
label.string = this.prefix + LanguageMgr.getText(this.text) + this.suffix;
} else {
console.log(this.node.name + " 挂载的节点没有label组件!");
}
}
}
language.json:
{
"TEST_VERSION": {
"EN": "Test Version",
"TC": "測試版本",
"SC": "测试版本"
},
"SERVER_IS_DISCONNTECTED_LOGIN_IN_AGAIN": {
"EN": "The Server is Disconnected, Please Log In Again!",
"TC": "伺服器已斷開鏈接,請重新登錄!",
"SC": "服务器已断开连接,请重新登录!"
},
"DAILY_TASK": {
"EN": "Daily Quest",
"TC": "每日任務!",
"SC": "每日任务!"
},
"OCCUPIED": {
"EN": "Occupied",
"TC": "使用中",
"SC": "使用中"
}
}
各个脚本的主要用法:
例如,LanguageMgr.getText("TEST_VERSION"); 当文本是动态变化时,需要使用 LanguageMgr.getText 方法。
如果是静态文本显示,则将 LanguageLabel 组件挂载到相应节点。
LanguageSprite 的使用方式与 LanguageLabel 类似。