热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CocosCreator中的多语言支持实现

在项目需要国际化处理时,即支持多种语言切换的功能,通常有两种方案:单个包和多个包。本文将重点讨论单个包的实现方法。

在项目需要国际化处理时,即支持多种语言切换的功能,通常有两种方案:

单个包

优点:

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 类似。


推荐阅读
  • 本文探讨了在 Vue 2.0 项目中使用 Axios 获取数据时可能出现的错误,并提供详细的解决方案和最佳实践。 ... [详细]
  • 本文详细介绍了如何在 Windows 环境下使用 node-gyp 工具进行 Node.js 本地扩展的编译和配置,涵盖从环境搭建到代码实现的全过程。 ... [详细]
  • 选择适合生产环境的Docker存储驱动
    本文旨在探讨如何在生产环境中选择合适的Docker存储驱动,并详细介绍不同Linux发行版下的配置方法。通过参考官方文档和兼容性矩阵,提供实用的操作指南。 ... [详细]
  • 本文介绍如何使用 Angular 6 的 HttpClient 模块来获取 HTTP 响应头,包括代码示例和常见问题的解决方案。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文总结了在使用Ionic 5进行Android平台APK打包时遇到的问题,特别是针对QRScanner插件的改造。通过详细分析和提供具体的解决方法,帮助开发者顺利打包并优化应用性能。 ... [详细]
  • 在 ExtJS 中,类的别名(alias)是开发过程中非常有用的一个特性。通过别名,开发者可以使用简短且易于记忆的名称来引用复杂的类名。本文将详细探讨如何在 ExtJS API 中使用和定义别名,并提供实例说明。 ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • This pull request introduces the ability to provide comprehensive paragraph configurations directly within the Create Note and Create Paragraph REST endpoints, reducing the need for additional configuration calls. ... [详细]
  • Kubernetes 持久化存储与数据卷详解
    本文深入探讨 Kubernetes 中持久化存储的使用场景、PV/PVC/StorageClass 的基本操作及其实现原理,旨在帮助读者理解如何高效管理容器化应用的数据持久化需求。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • 本文介绍如何使用 Android 的 Canvas 和 View 组件创建一个简单的绘图板应用程序,支持触摸绘画和保存图片功能。 ... [详细]
  • 如何使用Ping命令来测试网络连接?当网卡安装和有关参数配置完成后,可以使用ping命令来测试一下网络是否连接成功。以winXP为例1、打开XP下DOS窗口具体操作是点击“开始”菜 ... [详细]
  • 微信小程序:授权登录与手机号绑定
    本文详细介绍了微信小程序中用户授权登录及绑定手机号的流程,结合官方指引和实际开发经验,提供了一套完整的实现方案,帮助开发者更好地理解和应用。 ... [详细]
author-avatar
采蘑菇的小熙熙_395
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有