多语言配置化
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
import { _decorator, Component, Node, Button, Label, instantiate, Prefab, ScrollView, Layout, Color, Sprite } from 'cc';
|
||||
import li_BaseView from '../../Main/Common/li_BaseView';
|
||||
import LanguageUtils, { LanguageType } from '../../Main/Common/LanguageUtils';
|
||||
import Utils from '../../Main/Common/Utils';
|
||||
import AudioManager from '../../Main/Manager/AudioManager';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('LanguageSelectPanel')
|
||||
export class LanguageSelectPanel extends li_BaseView {
|
||||
@property(Node)
|
||||
private contentNode: Node = null;
|
||||
|
||||
@property(Node)
|
||||
private itemTemplate: Node = null;
|
||||
|
||||
@property(Button)
|
||||
private closeBtn: Button = null;
|
||||
|
||||
@property(Label)
|
||||
private titleLabel: Label = null;
|
||||
|
||||
private languageItems: Map<LanguageType, Node> = new Map();
|
||||
private currentSelectedLang: LanguageType = null;
|
||||
|
||||
onLoadCT() {
|
||||
super.onLoadCT();
|
||||
this.initUI();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.currentSelectedLang = LanguageUtils.CurrentLanguage;
|
||||
this.createLanguageItems();
|
||||
this.updateSelection();
|
||||
}
|
||||
|
||||
private initUI() {
|
||||
if (this.titleLabel) {
|
||||
this.titleLabel.string = "Select Language / 选择语言";
|
||||
}
|
||||
|
||||
if (this.itemTemplate) {
|
||||
this.itemTemplate.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bindEvents() {
|
||||
if (this.closeBtn) {
|
||||
this.closeBtn.node.on(Button.EventType.CLICK, this.onCloseBtnClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
private createLanguageItems() {
|
||||
if (!this.contentNode || !this.itemTemplate) {
|
||||
console.error("LanguageSelectPanel: contentNode or itemTemplate is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// 清除旧的语言项
|
||||
this.languageItems.clear();
|
||||
this.contentNode.removeAllChildren();
|
||||
|
||||
const availableLanguages = LanguageUtils.getAvailableLanguages();
|
||||
|
||||
availableLanguages.forEach((lang, index) => {
|
||||
const item = instantiate(this.itemTemplate);
|
||||
item.active = true;
|
||||
|
||||
// 设置语言名称
|
||||
const nameLabel = item.getChildByName("NameLabel");
|
||||
if (nameLabel) {
|
||||
const label = nameLabel.getComponent(Label);
|
||||
if (label) {
|
||||
label.string = LanguageUtils.getLanguageDisplayName(lang);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置语言代码
|
||||
const codeLabel = item.getChildByName("CodeLabel");
|
||||
if (codeLabel) {
|
||||
const label = codeLabel.getComponent(Label);
|
||||
if (label) {
|
||||
label.string = `(${lang.toUpperCase()})`;
|
||||
label.color = new Color(150, 150, 150);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置选中标记
|
||||
const checkMark = item.getChildByName("CheckMark");
|
||||
if (checkMark) {
|
||||
checkMark.active = false;
|
||||
}
|
||||
|
||||
// 绑定点击事件
|
||||
const button = item.getComponent(Button);
|
||||
if (!button) {
|
||||
item.addComponent(Button);
|
||||
}
|
||||
|
||||
item.on(Button.EventType.CLICK, () => {
|
||||
this.onLanguageItemClick(lang);
|
||||
}, this);
|
||||
|
||||
this.contentNode.addChild(item);
|
||||
this.languageItems.set(lang, item);
|
||||
});
|
||||
}
|
||||
|
||||
private onLanguageItemClick(language: LanguageType) {
|
||||
if (this.currentSelectedLang === language) {
|
||||
return;
|
||||
}
|
||||
|
||||
AudioManager.I.playSfx("click");
|
||||
|
||||
this.currentSelectedLang = language;
|
||||
LanguageUtils.setLanguage(language);
|
||||
this.updateSelection();
|
||||
|
||||
// 延迟关闭面板,让用户看到选择效果
|
||||
this.scheduleOnce(() => {
|
||||
this.close();
|
||||
}, 0.3);
|
||||
}
|
||||
|
||||
private updateSelection() {
|
||||
this.languageItems.forEach((item, lang) => {
|
||||
const checkMark = item.getChildByName("CheckMark");
|
||||
if (checkMark) {
|
||||
checkMark.active = lang === this.currentSelectedLang;
|
||||
}
|
||||
|
||||
// 更新背景色或边框来表示选中状态
|
||||
const bg = item.getChildByName("Bg");
|
||||
if (bg) {
|
||||
const sprite = bg.getComponent(Sprite);
|
||||
if (sprite) {
|
||||
if (lang === this.currentSelectedLang) {
|
||||
sprite.color = new Color(100, 200, 100, 255);
|
||||
} else {
|
||||
sprite.color = new Color(255, 255, 255, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onCloseBtnClick() {
|
||||
AudioManager.I.playSfx("click");
|
||||
this.close();
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
if (this.closeBtn) {
|
||||
this.closeBtn.node.off(Button.EventType.CLICK, this.onCloseBtnClick, this);
|
||||
}
|
||||
|
||||
this.languageItems.forEach((item) => {
|
||||
item.targetOff(this);
|
||||
});
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "a9f8c2d1-7e6b-4a3c-9d5f-2b1e8c7f9a4d",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import { _decorator, Component, Node, Button, Label, Sprite } from 'cc';
|
||||
import LanguageUtils, { LanguageType } from '../../Main/Common/LanguageUtils';
|
||||
import { ViewManager } from '../../Main/Manager/ViewManager';
|
||||
import AudioManager from '../../Main/Manager/AudioManager';
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
@ccclass('LanguageToggleButton')
|
||||
export class LanguageToggleButton extends Component {
|
||||
@property(Label)
|
||||
private languageLabel: Label = null;
|
||||
|
||||
@property(Sprite)
|
||||
private flagIcon: Sprite = null;
|
||||
|
||||
@property({
|
||||
displayName: "Panel Prefab Path",
|
||||
tooltip: "语言选择面板的预制体路径"
|
||||
})
|
||||
private panelPath: string = "prefabs/UI/SimpleLanguagePanel";
|
||||
|
||||
private button: Button = null;
|
||||
|
||||
onLoad() {
|
||||
this.button = this.node.getComponent(Button);
|
||||
if (!this.button) {
|
||||
this.button = this.node.addComponent(Button);
|
||||
}
|
||||
|
||||
this.bindEvents();
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.updateDisplay();
|
||||
LanguageUtils.onLanguageChanged(this.onLanguageChanged, this);
|
||||
}
|
||||
|
||||
onDisable() {
|
||||
LanguageUtils.offLanguageChanged(this.onLanguageChanged, this);
|
||||
}
|
||||
|
||||
private bindEvents() {
|
||||
if (this.button) {
|
||||
this.button.node.on(Button.EventType.CLICK, this.onClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
private onClick() {
|
||||
AudioManager.I.playSfx("click");
|
||||
|
||||
// 快速切换模式(循环切换语言)
|
||||
if (this.isQuickToggleMode()) {
|
||||
this.quickToggleLanguage();
|
||||
} else {
|
||||
// 打开语言选择面板
|
||||
this.openLanguagePanel();
|
||||
}
|
||||
}
|
||||
|
||||
private isQuickToggleMode(): boolean {
|
||||
// 可以通过按住Shift键或其他条件来判断是否快速切换
|
||||
return false;
|
||||
}
|
||||
|
||||
private quickToggleLanguage() {
|
||||
const languages = LanguageUtils.getAvailableLanguages();
|
||||
const currentLang = LanguageUtils.CurrentLanguage;
|
||||
const currentIndex = languages.indexOf(currentLang);
|
||||
const nextIndex = (currentIndex + 1) % languages.length;
|
||||
|
||||
LanguageUtils.setLanguage(languages[nextIndex]);
|
||||
}
|
||||
|
||||
private openLanguagePanel() {
|
||||
// 使用ViewManager打开语言选择面板
|
||||
if (this.panelPath && this.panelPath.length > 0) {
|
||||
ViewManager.I.openView(this.panelPath);
|
||||
} else {
|
||||
console.warn("Language panel path not set!");
|
||||
// 如果没有设置面板路径,使用快速切换
|
||||
this.quickToggleLanguage();
|
||||
}
|
||||
}
|
||||
|
||||
private onLanguageChanged(language: LanguageType) {
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
private updateDisplay() {
|
||||
const currentLang = LanguageUtils.CurrentLanguage;
|
||||
|
||||
if (this.languageLabel) {
|
||||
// 显示当前语言的缩写或名称
|
||||
this.languageLabel.string = this.getLanguageDisplay(currentLang);
|
||||
}
|
||||
|
||||
// 如果有旗帜图标,可以在这里更新
|
||||
if (this.flagIcon) {
|
||||
// 需要根据语言加载对应的旗帜图标
|
||||
// this.loadFlagIcon(currentLang);
|
||||
}
|
||||
}
|
||||
|
||||
private getLanguageDisplay(language: LanguageType): string {
|
||||
// 可以选择显示缩写或完整名称
|
||||
const useAbbreviation = true;
|
||||
|
||||
if (useAbbreviation) {
|
||||
return language.toUpperCase();
|
||||
} else {
|
||||
return LanguageUtils.getLanguageDisplayName(language);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
if (this.button) {
|
||||
this.button.node.off(Button.EventType.CLICK, this.onClick, this);
|
||||
}
|
||||
LanguageUtils.offLanguageChanged(this.onLanguageChanged, this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "c4e7b9d2-8a3f-4c5e-b7d1-6e9f8a2c5b4d",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ export class PreloadUI extends Component {
|
||||
|
||||
this.jinduFilled.fillRange = 0;
|
||||
//this.btnLogin.node.active = false;
|
||||
|
||||
|
||||
this.preloadFiles();
|
||||
|
||||
LanguageUtils.setLanguage(LanguageType.CN);
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
import {
|
||||
_decorator,
|
||||
Component,
|
||||
Node,
|
||||
Button,
|
||||
Label,
|
||||
Color,
|
||||
Sprite,
|
||||
tween,
|
||||
Vec3,
|
||||
} from "cc";
|
||||
import li_BaseView from "../../Main/Common/li_BaseView";
|
||||
import LanguageUtils, { LanguageType } from "../../Main/Common/LanguageUtils";
|
||||
import AudioManager from "../../Main/Manager/AudioManager";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
interface LanguageButton {
|
||||
button: Button;
|
||||
label: Label;
|
||||
checkMark: Node;
|
||||
bg: Sprite;
|
||||
language: LanguageType;
|
||||
}
|
||||
|
||||
@ccclass("SimpleLanguagePanel")
|
||||
export class SimpleLanguagePanel extends li_BaseView {
|
||||
@property(Button)
|
||||
private closeBtn: Button = null;
|
||||
|
||||
@property(Label)
|
||||
private titleLabel: Label = null;
|
||||
|
||||
@property(Button)
|
||||
private btnEnglish: Button = null;
|
||||
|
||||
@property(Button)
|
||||
private btnChinese: Button = null;
|
||||
|
||||
@property(Button)
|
||||
private btnHindi: Button = null;
|
||||
|
||||
@property(Button)
|
||||
private btnFrench: Button = null;
|
||||
|
||||
@property(Button)
|
||||
private btnGerman: Button = null;
|
||||
|
||||
@property(Node)
|
||||
private panelBg: Node = null;
|
||||
|
||||
private languageButtons: LanguageButton[] = [];
|
||||
private currentSelectedLang: LanguageType = null;
|
||||
|
||||
onLoadCT() {
|
||||
super.onLoadCT();
|
||||
this.initUI();
|
||||
this.bindEvents();
|
||||
this.playEnterAnimation();
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.currentSelectedLang = LanguageUtils.CurrentLanguage;
|
||||
this.updateSelection();
|
||||
}
|
||||
|
||||
private initUI() {
|
||||
if (this.titleLabel) {
|
||||
this.titleLabel.string = this.getMultiLangTitle();
|
||||
}
|
||||
|
||||
// 初始化语言按钮数组
|
||||
this.initLanguageButton(this.btnEnglish, LanguageType.EN, "English");
|
||||
this.initLanguageButton(this.btnChinese, LanguageType.CN, "中文");
|
||||
this.initLanguageButton(this.btnHindi, LanguageType.HI, "हिंदी");
|
||||
this.initLanguageButton(this.btnFrench, LanguageType.FR, "Français");
|
||||
this.initLanguageButton(this.btnGerman, LanguageType.DE, "Deutsch");
|
||||
}
|
||||
|
||||
private getMultiLangTitle(): string {
|
||||
const titles = [
|
||||
"Select Language",
|
||||
"选择语言",
|
||||
"भाषा चुनें",
|
||||
"Choisir la langue",
|
||||
"Sprache wählen",
|
||||
];
|
||||
return titles.join(" / ");
|
||||
}
|
||||
|
||||
private initLanguageButton(
|
||||
button: Button,
|
||||
language: LanguageType,
|
||||
displayName: string
|
||||
) {
|
||||
if (!button) return;
|
||||
|
||||
const node = button.node;
|
||||
|
||||
// 查找或创建标签
|
||||
let labelNode = node.getChildByName("Label");
|
||||
if (!labelNode) {
|
||||
labelNode = node.getChildByName("label");
|
||||
}
|
||||
|
||||
let label: Label = null;
|
||||
if (labelNode) {
|
||||
label = labelNode.getComponent(Label);
|
||||
if (label) {
|
||||
label.string = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
// 查找或创建选中标记
|
||||
let checkMark = node.getChildByName("CheckMark");
|
||||
if (!checkMark) {
|
||||
checkMark = node.getChildByName("checkmark");
|
||||
}
|
||||
if (checkMark) {
|
||||
checkMark.active = false;
|
||||
}
|
||||
|
||||
// 获取背景
|
||||
let bg = node.getComponent(Sprite);
|
||||
if (!bg) {
|
||||
const bgNode = node.getChildByName("Bg");
|
||||
if (bgNode) {
|
||||
bg = bgNode.getComponent(Sprite);
|
||||
}
|
||||
}
|
||||
|
||||
this.languageButtons.push({
|
||||
button,
|
||||
label,
|
||||
checkMark,
|
||||
bg,
|
||||
language,
|
||||
});
|
||||
}
|
||||
|
||||
private bindEvents() {
|
||||
if (this.closeBtn) {
|
||||
this.closeBtn.node.on(Button.EventType.CLICK, this.onCloseBtnClick, this);
|
||||
}
|
||||
|
||||
// 绑定语言按钮事件
|
||||
this.languageButtons.forEach((langBtn) => {
|
||||
if (langBtn.button) {
|
||||
langBtn.button.node.on(
|
||||
Button.EventType.CLICK,
|
||||
() => {
|
||||
this.onLanguageSelect(langBtn.language);
|
||||
},
|
||||
this
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onLanguageSelect(language: LanguageType) {
|
||||
if (this.currentSelectedLang === language) {
|
||||
return;
|
||||
}
|
||||
|
||||
//AudioManager.I.playSfx("click");
|
||||
|
||||
this.currentSelectedLang = language;
|
||||
LanguageUtils.setLanguage(language);
|
||||
this.updateSelection();
|
||||
|
||||
// 播放选中动画
|
||||
const selectedBtn = this.languageButtons.find(
|
||||
(btn) => btn.language === language
|
||||
);
|
||||
if (selectedBtn && selectedBtn.button) {
|
||||
this.playSelectAnimation(selectedBtn.button.node);
|
||||
}
|
||||
|
||||
// 延迟关闭面板
|
||||
this.scheduleOnce(() => {
|
||||
this.playExitAnimation(() => {
|
||||
this.close();
|
||||
});
|
||||
}, 0.5);
|
||||
}
|
||||
|
||||
private updateSelection() {
|
||||
this.languageButtons.forEach((langBtn) => {
|
||||
const isSelected = langBtn.language === this.currentSelectedLang;
|
||||
|
||||
// 更新选中标记
|
||||
if (langBtn.checkMark) {
|
||||
langBtn.checkMark.active = isSelected;
|
||||
}
|
||||
|
||||
// 更新背景色
|
||||
if (langBtn.bg) {
|
||||
if (isSelected) {
|
||||
langBtn.bg.color = new Color(150, 255, 150, 255);
|
||||
} else {
|
||||
langBtn.bg.color = new Color(255, 255, 255, 255);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新按钮交互性
|
||||
if (langBtn.button) {
|
||||
langBtn.button.interactable = !isSelected;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private playSelectAnimation(node: Node) {
|
||||
tween(node)
|
||||
.to(0.1, { scale: new Vec3(1.1, 1.1, 1) })
|
||||
.to(0.1, { scale: new Vec3(1, 1, 1) })
|
||||
.start();
|
||||
}
|
||||
|
||||
private playEnterAnimation() {
|
||||
if (this.panelBg) {
|
||||
this.panelBg.scale = new Vec3(0.8, 0.8, 1);
|
||||
tween(this.panelBg)
|
||||
.to(0.3, { scale: new Vec3(1, 1, 1) }, { easing: "backOut" })
|
||||
.start();
|
||||
}
|
||||
}
|
||||
|
||||
private playExitAnimation(callback: () => void) {
|
||||
if (this.panelBg) {
|
||||
tween(this.panelBg)
|
||||
.to(0.2, { scale: new Vec3(0.8, 0.8, 1) }, { easing: "backIn" })
|
||||
.call(callback)
|
||||
.start();
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
private onCloseBtnClick() {
|
||||
//AudioManager.I.playSfx("click");
|
||||
this.playExitAnimation(() => {
|
||||
this.close();
|
||||
});
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
// if (this.closeBtn) {
|
||||
// this.closeBtn.node.off(
|
||||
// Button.EventType.CLICK,
|
||||
// this.onCloseBtnClick,
|
||||
// this
|
||||
// );
|
||||
// }
|
||||
|
||||
// this.languageButtons.forEach((langBtn) => {
|
||||
// if (langBtn.button) {
|
||||
// langBtn.button.node.targetOff(this);
|
||||
// }
|
||||
// });
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "775ab74f-0a20-4218-9c6e-9e30bfc91635",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user