218 lines
6.7 KiB
TypeScript
218 lines
6.7 KiB
TypeScript
import { resources, JsonAsset, director, SpriteFrame, Sprite, Node, SpriteAtlas, sp } from 'cc';
|
|
import { LocalizedSprite } from '../i18n/LocalizedSprite';
|
|
|
|
export class I18nManager {
|
|
private static _instance: I18nManager = null;
|
|
spriteFrameCache: Map<string, SpriteFrame> = new Map();
|
|
spineCache: Map<string, sp.SkeletonData> = new Map();
|
|
languageData: Record<string, any> = {};
|
|
currentLanguage: string = 'en';
|
|
ready: boolean = false;
|
|
|
|
static get instance() {
|
|
if (this._instance) {
|
|
return this._instance;
|
|
}
|
|
this._instance = new I18nManager();
|
|
return this._instance;
|
|
}
|
|
|
|
private constructor() { }
|
|
|
|
/**
|
|
* 初始化语言管理器
|
|
* @param language 初始语言
|
|
*/
|
|
public async init(language: string = 'en', languageJson: JsonAsset): Promise<void> {
|
|
this.currentLanguage = language;
|
|
try {
|
|
this.languageData = languageJson.json;
|
|
|
|
// 预加载并缓存图片资源
|
|
await this.preloadSpriteFrames();
|
|
await this.preloadSpriteFrameAltas();
|
|
await this.preloadSpineAssets(); // 新增预加载 spine 资源
|
|
this.ready = true;
|
|
} catch (error) {
|
|
|
|
}
|
|
}
|
|
|
|
getIsReady() {
|
|
return this.ready;
|
|
}
|
|
|
|
/**
|
|
* 预加载并缓存图片资源
|
|
*/
|
|
private async preloadSpriteFrames(): Promise<void> {
|
|
const imageNames = [
|
|
'loadingBg',
|
|
'sysgift_completed',
|
|
'sysgift_continue',
|
|
'sysgift_fbs',
|
|
'sysgift_info_fbs',
|
|
'sysgift_received',
|
|
'sysgift_symbols',
|
|
'sysgift_total',
|
|
'sysgift_win',
|
|
];
|
|
|
|
for (const name of imageNames) {
|
|
const path = `i18nSprite/${this.currentLanguage}/${name}/spriteFrame`;
|
|
const cacheKey = `${this.currentLanguage}_${name}`;
|
|
|
|
if (!this.spriteFrameCache.has(cacheKey)) {
|
|
await new Promise<void>((resolve) => {
|
|
resources.load(path, SpriteFrame, (err, spriteFrame) => {
|
|
if (!err && spriteFrame) {
|
|
this.spriteFrameCache.set(cacheKey, spriteFrame);
|
|
}
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
private async preloadSpriteFrameAltas(): Promise<void> {
|
|
const altasNames = [
|
|
`FreeSpinINOUT_${this.currentLanguage}`,
|
|
`BuyFeature_${this.currentLanguage}`,
|
|
`Others_${this.currentLanguage}`,
|
|
`SymbolsInfo_${this.currentLanguage}`,
|
|
]
|
|
|
|
for (const altasName of altasNames) {
|
|
const atlasPath = `i18nSprite/${this.currentLanguage}/${altasName}`;
|
|
// 加载图集并缓存其中的多个 SpriteFrame
|
|
await new Promise<void>((resolve) => {
|
|
resources.load(atlasPath, SpriteAtlas, (err, atlas) => {
|
|
if (!err && atlas) {
|
|
const spriteFrames = atlas.getSpriteFrames();
|
|
spriteFrames.forEach((frame, index) => {
|
|
let name = frame.name;
|
|
const cacheKey = `${this.currentLanguage}_${name}`;
|
|
this.spriteFrameCache.set(cacheKey, frame);
|
|
});
|
|
}
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
// 添加预加载 Spine 资源的方法
|
|
private async preloadSpineAssets(): Promise<void> {
|
|
const spineNames = [
|
|
`WinWinWin_${this.currentLanguage}`,
|
|
];
|
|
|
|
for (const name of spineNames) {
|
|
const path = `i18nSprite/${this.currentLanguage}/${name}`;
|
|
const cacheKey = `${this.currentLanguage}_${name}`;
|
|
|
|
if (!this.spineCache.has(cacheKey)) {
|
|
await new Promise<void>((resolve) => {
|
|
resources.load(path, sp.SkeletonData, (err, spineData) => {
|
|
if (!err && spineData) {
|
|
this.spineCache.set(cacheKey, spineData);
|
|
}
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
setSpriteFrame(node: Node, name: string) {
|
|
// 先尝试从缓存获取
|
|
const cacheKey = `${this.currentLanguage}_${name}`;
|
|
const cachedFrame = this.spriteFrameCache.get(cacheKey);
|
|
|
|
if (cachedFrame) {
|
|
const sprite = node.getComponent(Sprite);
|
|
if (sprite) {
|
|
sprite.spriteFrame = cachedFrame;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 如果缓存中没有,则使用原有逻辑
|
|
let spriteNode = node.getComponent(LocalizedSprite);
|
|
if (spriteNode) {
|
|
spriteNode.setSpriteName(name);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 设置当前语言
|
|
* @param language 语言代码
|
|
*/
|
|
public setLanguage(language: string): void {
|
|
if (this.languageData[language]) {
|
|
this.currentLanguage = language;
|
|
this.updateSceneRenderers();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 翻译文本
|
|
* @param key 翻译键
|
|
*/
|
|
public t(key: string): string {
|
|
const translation = this.languageData[this.currentLanguage]?.[key];
|
|
if (!translation) {
|
|
return key; // Return the key itself if translation is not found
|
|
}
|
|
return translation;
|
|
}
|
|
|
|
/**
|
|
* 更新场景中的本地化组件
|
|
*/
|
|
public updateSceneRenderers(): void {
|
|
if (!this.ready) {
|
|
console.warn('I18nManager is not ready.');
|
|
return;
|
|
}
|
|
|
|
let scene = director.getScene();
|
|
if (!scene || !scene.isValid) return;
|
|
|
|
const rootNodes = director.getScene()?.children || [];
|
|
const allLocalizedLabels: any[] = [];
|
|
const allLocalizedSprites: any[] = [];
|
|
|
|
rootNodes.forEach(node => {
|
|
allLocalizedLabels.push(...node.getComponentsInChildren('LocalizedLabel'));
|
|
allLocalizedSprites.push(...node.getComponentsInChildren('LocalizedSprite'));
|
|
});
|
|
|
|
allLocalizedLabels.forEach(label => {
|
|
if (label.node.active) {
|
|
label.updateLabel();
|
|
}
|
|
});
|
|
|
|
allLocalizedSprites.forEach(sprite => {
|
|
if (sprite.node.active) {
|
|
sprite.updateSprite();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// // 供插件查询当前语言使用
|
|
// const win = window as any;
|
|
// win._languageData = {
|
|
// get language() {
|
|
// return I18nManager.instance.currentLanguage;
|
|
// },
|
|
// init(lang: string) {
|
|
// I18nManager.instance.init(lang);
|
|
// },
|
|
// updateSceneRenderers() {
|
|
// I18nManager.instance.updateSceneRenderers();
|
|
// },
|
|
// };
|