rp_11001/assets/Loading/scripts/manager/I18nManager.ts
TJH 9ad38a43b5
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m16s
资源加载逻辑修改
2025-12-30 12:26:22 +08:00

221 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { resources, JsonAsset, director, SpriteFrame, SpriteAtlas, sp } from 'cc';
export class I18nManager {
private static _instance: I18nManager;
spriteFrameCache: Map<string, SpriteFrame> = new Map();
spineCache: Map<string, sp.SkeletonData> = new Map();
_sfTasks = new Map<string, Promise<SpriteFrame>>();
languageData: Record<string, any> = {};
currentLanguage: string = 'en';
ready: boolean = false;
static get instance() {
return this._instance || (this._instance = new I18nManager());
}
private constructor() { }
// yield/await 风格:谁都可以 await且只加载一次
ensureI18nSprite(lang: string, name: string): Promise<SpriteFrame> {
const key = `${lang}_${name}`;
const path = `i18nSprite/${lang}/${name}/spriteFrame`;
const cached = this.spriteFrameCache.get(key);
if (cached) return Promise.resolve(cached);
const pending = this._sfTasks.get(key);
if (pending) return pending;
const task = new Promise<SpriteFrame>((resolve, reject) => {
resources.load(path, SpriteFrame, (err, sf) => {
this._sfTasks.delete(key);
if (err || !sf) return reject(err);
this.spriteFrameCache.set(key, sf);
resolve(sf);
});
});
this._sfTasks.set(key, task);
return task;
}
/**
* 初始化国际化管理器
* @param language 初始语言代码
* @param languageJson 语言数据JSON资源
*/
public async init(language: string = 'en', languageJson: JsonAsset = null): Promise<void> {
this.currentLanguage = language;
try {
if (languageJson) {
this.languageData = languageJson.json;
}
// 预加载资源(目前资源列表为空,可根据需要添加)
let okSprite = await this.preloadAssets('spriteFrame', [
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15',
'16',
'17',
'18',
'19',
'20',
'21',
'22',
'23',
'24',
'25',
'26',
'27',
'29',
'30',
'98',
'99',
'Buy_5',
'sysgift_completed',
'sysgift_continue',
'sysgift_fbs',
'sysgift_info_fbs',
'sysgift_received',
'sysgift_symbols',
'sysgift_total',
'sysgift_win',
]);
let okAtlas = await this.preloadAssets('atlas', []);
let okSpine = await this.preloadAssets('spine', []);
this.ready = okSprite && okAtlas && okSpine;
} catch (error) {
console.error('I18nManager init failed:', error);
}
}
/**
* 预加载指定类型的资源
* @param type 资源类型
* @param names 资源名称列表
*/
private async preloadAssets(type: 'spriteFrame' | 'atlas' | 'spine', names: string[]): Promise<boolean> {
let results = await Promise.all(names.map(name => this.loadAsset(type, name)));
return results.every(ok => ok);
}
/**
* 加载单个资源
* @param type 资源类型
* @param name 资源名称
*/
private loadAsset(type: 'spriteFrame' | 'atlas' | 'spine', name: string): Promise<boolean> {
return new Promise(resolve => {
let cacheKey = `${this.currentLanguage}_${name}`;
if (type === 'spriteFrame') {
let path = `i18nSprite/${this.currentLanguage}/${name}/spriteFrame`;
resources.load(path, SpriteFrame, (err, asset) => {
if (!err && asset) {
this.spriteFrameCache.set(cacheKey, asset);
resolve(true);
} else {
console.warn(`[i18n] spriteFrame load failed: ${path}`, err?.message || err);
resolve(false);
}
});
} else if (type === 'atlas') {
let path = `i18nSprite/${this.currentLanguage}/${name}`;
resources.load(path, SpriteAtlas, (err, atlas) => {
if (!err && atlas) {
atlas.getSpriteFrames().forEach(frame => {
this.spriteFrameCache.set(`${this.currentLanguage}_${frame.name}`, frame);
});
resolve(true);
} else {
console.warn(`[i18n] atlas load failed: ${path}`, err?.message || err);
resolve(false);
}
});
} else if (type === 'spine') {
let path = `i18nSpine/${this.currentLanguage}/${name}`;
resources.load(path, sp.SkeletonData, (err, asset) => {
if (!err && asset) {
this.spineCache.set(cacheKey, asset);
resolve(true);
} else {
console.warn(`[i18n] spine load failed: ${path}`, err?.message || err);
resolve(false);
}
});
}
});
}
/**
* 设置当前语言
* @param language 语言代码
*/
public setLanguage(language: string): void {
if (this.languageData[language]) {
this.currentLanguage = language;
this.updateSceneRenderers();
}
}
/**
* 翻译文本
* @param key 翻译键
* @returns 翻译后的文本,如果找不到则返回键本身
*/
public t(key: string): string {
return this.languageData[this.currentLanguage]?.[key] || key;
}
public getSpriteFrame(spriteName: string): SpriteFrame {
let cacheKey = `${this.currentLanguage}_${spriteName}`;
let cachedFrame = this.spriteFrameCache.get(cacheKey);
return cachedFrame;
}
/**
* 更新场景中的所有本地化组件
* 在语言切换时调用,刷新所有本地化文本和资源
*/
public updateSceneRenderers(): void {
if (!this.ready) {
console.warn('I18nManager is not ready.');
return;
}
let scene = director.getScene();
if (!scene?.isValid) return;
// 收集所有本地化组件
let allLocalizedLabels = [];
let allLocalizedSprites = [];
scene.children.forEach(node => {
allLocalizedLabels.push(...node.getComponentsInChildren('LocalizedLabel'));
allLocalizedSprites.push(...node.getComponentsInChildren('LocalizedSprite'));
});
// 更新所有激活的本地化组件
[...allLocalizedLabels, ...allLocalizedSprites].forEach(component => {
if (component.node.active) {
// 调用对应的更新方法
component.updateLabel?.() || component.updateSprite?.();
}
});
}
}