feat(i18n): 统一国际化系统架构,支持插件独立翻译 (#301)

* feat(i18n): 统一国际化系统架构,支持插件独立翻译

## 主要改动

### 核心架构
- 增强 LocaleService,支持插件命名空间翻译扩展
- 新增 editor-runtime/i18n 模块,提供 createPluginLocale/createPluginTranslator
- 新增 editor-core/tokens.ts,定义 LocaleServiceToken 等服务令牌
- 改进 PluginAPI 类型安全,使用 ServiceToken<T> 替代 any

### 编辑器本地化
- 扩展 en.ts/zh.ts 翻译文件,覆盖所有 UI 组件
- 新增 es.ts 西班牙语支持
- 重构 40+ 组件使用 useLocale() hook

### 插件本地化系统
- behavior-tree-editor: 新增 locales/ 和 useBTLocale hook
- material-editor: 新增 locales/ 和 useMaterialLocale hook
- particle-editor: 新增 locales/ 和 useParticleLocale hook
- tilemap-editor: 新增 locales/ 和 useTilemapLocale hook
- ui-editor: 新增 locales/ 和 useUILocale hook

### 类型安全改进
- 修复 Debug 工具使用公共接口替代 as any
- 修复 ChunkStreamingSystem 添加 forEachChunk 公共方法
- 修复 blueprint-editor 移除不必要的向后兼容代码

* fix(behavior-tree-editor): 使用 ServiceToken 模式修复服务解析

- 创建 BehaviorTreeServiceToken 遵循"谁定义接口,谁导出Token"原则
- 使用 ServiceToken.id (symbol) 注册服务到 ServiceContainer
- 更新 PluginSDKRegistry.resolveService 支持 ServiceToken 检测
- BehaviorTreeEditorPanel 现在使用类型安全的 PluginAPI.resolve

* fix(behavior-tree-editor): 使用 ServiceContainer.resolve 获取类注册的服务

* fix: 修复多个包的依赖和类型问题

- core: EntityDataCollector.getEntityDetails 使用 HierarchySystem 获取父实体
- ui-editor: 添加 @esengine/editor-runtime 依赖
- tilemap-editor: 添加 @esengine/editor-runtime 依赖
- particle-editor: 添加 @esengine/editor-runtime 依赖
This commit is contained in:
YHH
2025-12-09 18:04:03 +08:00
committed by GitHub
parent 995fa2d514
commit 1b0d38edce
103 changed files with 8015 additions and 1633 deletions

View File

@@ -22,7 +22,7 @@ export class ComponentDataCollector {
};
}
const entityList = (scene as any).entities;
const entityList = scene.entities;
if (!entityList?.buffer) {
return {
componentTypes: 0,
@@ -98,7 +98,7 @@ export class ComponentDataCollector {
if (!scene) return 64;
const entityList = (scene as any).entities;
const entityList = scene.entities;
if (!entityList?.buffer) return 64;
let calculatedSize = 64;
@@ -174,7 +174,7 @@ export class ComponentDataCollector {
public calculateDetailedComponentMemory(typeName: string, scene?: IScene | null): number {
if (!scene) return this.getEstimatedComponentSize(typeName, scene);
const entityList = (scene as any).entities;
const entityList = scene.entities;
if (!entityList?.buffer) return this.getEstimatedComponentSize(typeName, scene);
try {

View File

@@ -8,18 +8,25 @@ import { HierarchySystem } from '../../ECS/Systems/HierarchySystem';
/**
* 实体数据收集器
* Entity data collector
*
* 收集实体的调试信息,通过公共接口访问数据。
* Collects entity debug information through public interfaces.
*/
export class EntityDataCollector {
/**
* 收集实体数据
* @param scene 场景实例
* Collect entity data
*
* @param scene 场景实例 | Scene instance
*/
public collectEntityData(scene?: IScene | null): IEntityDebugData {
if (!scene) {
return this.getEmptyEntityDebugData();
}
const entityList = (scene as any).entities;
// 使用公共接口 | Use public interface
const entityList = scene.entities;
if (!entityList) {
return this.getEmptyEntityDebugData();
}
@@ -56,7 +63,9 @@ export class EntityDataCollector {
/**
* 获取原始实体列表
* @param scene 场景实例
* Get raw entity list
*
* @param scene 场景实例 | Scene instance
*/
public getRawEntityList(scene?: IScene | null): Array<{
id: number;
@@ -74,7 +83,8 @@ export class EntityDataCollector {
}> {
if (!scene) return [];
const entityList = (scene as any).entities;
// 使用公共接口 | Use public interface
const entityList = scene.entities;
if (!entityList?.buffer) return [];
const hierarchySystem = scene.getSystem(HierarchySystem);
@@ -110,15 +120,21 @@ export class EntityDataCollector {
try {
if (!scene) return null;
const entityList = (scene as any).entities;
const entityList = scene.entities;
if (!entityList?.buffer) return null;
const entity = entityList.buffer.find((e: any) => e.id === entityId);
if (!entity) return null;
// 使用 HierarchySystem 获取父实体
// Use HierarchySystem to get parent entity
const hierarchySystem = scene.getSystem(HierarchySystem);
const parent = hierarchySystem?.getParent(entity);
const parentName = parent?.name ?? null;
const baseDebugInfo = entity.getDebugInfo
? entity.getDebugInfo()
: this.buildFallbackEntityInfo(entity, scene);
: this.buildFallbackEntityInfo(entity, scene, hierarchySystem);
const componentDetails = this.extractComponentDetails(entity.components);
@@ -129,7 +145,7 @@ export class EntityDataCollector {
scene: sceneInfo.name,
sceneName: sceneInfo.name,
sceneType: sceneInfo.type,
parentName: entity.parent?.name || null,
parentName,
components: componentDetails || [],
componentCount: entity.components?.length || 0,
componentTypes: entity.components?.map((comp: any) => getComponentInstanceTypeName(comp)) || []
@@ -180,7 +196,7 @@ export class EntityDataCollector {
return this.getEmptyEntityDebugData();
}
const entityList = (scene as any).entities;
const entityList = scene.entities;
if (!entityList) {
return this.getEmptyEntityDebugData();
}
@@ -769,13 +785,14 @@ export class EntityDataCollector {
try {
if (!scene) return {};
const entityList = (scene as any).entities;
const entityList = scene.entities;
if (!entityList?.buffer) return {};
const entity = entityList.buffer.find((e: any) => e.id === entityId);
if (!entity || componentIndex >= entity.components.length) return {};
const component = entity.components[componentIndex];
if (!component) return {};
const properties: Record<string, any> = {};
const propertyKeys = Object.keys(component);
@@ -970,7 +987,7 @@ export class EntityDataCollector {
try {
if (!scene) return null;
const entityList = (scene as any).entities;
const entityList = scene.entities;
if (!entityList?.buffer) return null;
// 找到对应的实体

View File

@@ -3,13 +3,19 @@ import { IScene } from '../../ECS/IScene';
/**
* 场景数据收集器
* Scene data collector
*
* 收集场景的调试信息,通过公共接口访问数据。
* Collects scene debug information through public interfaces.
*/
export class SceneDataCollector {
private sceneStartTime: number = Date.now();
/**
* 收集场景数据
* @param scene 场景实例
* Collect scene data
*
* @param scene 场景实例 | Scene instance
*/
public collectSceneData(scene?: IScene | null): ISceneDebugData {
if (!scene) {
@@ -26,15 +32,15 @@ export class SceneDataCollector {
const currentTime = Date.now();
const runTime = (currentTime - this.sceneStartTime) / 1000;
const entityList = (scene as any).entities;
const entityProcessors = (scene as any).entityProcessors;
// 使用公共接口获取数据 | Use public interface to get data
const stats = scene.getStats();
return {
currentSceneName: (scene as any).name || 'Unnamed Scene',
isInitialized: (scene as any)._didSceneBegin || false,
currentSceneName: scene.name || 'Unnamed Scene',
isInitialized: true, // 如果 scene 存在,则认为已初始化 | If scene exists, consider initialized
sceneRunTime: runTime,
sceneEntityCount: entityList?.buffer?.length || 0,
sceneSystemCount: entityProcessors?.processors?.length || 0,
sceneEntityCount: stats.entityCount,
sceneSystemCount: stats.processorCount,
sceneUptime: runTime
};
}

View File

@@ -4,12 +4,18 @@ import { IScene } from '../../ECS/IScene';
/**
* 系统数据收集器
* System data collector
*
* 收集系统的调试信息,通过公共接口访问数据。
* Collects system debug information through public interfaces.
*/
export class SystemDataCollector {
/**
* 收集系统数据
* @param performanceMonitor 性能监视器实例
* @param scene 场景实例
* Collect system data
*
* @param performanceMonitor 性能监视器实例 | Performance monitor instance
* @param scene 场景实例 | Scene instance
*/
public collectSystemData(performanceMonitor: any, scene?: IScene | null): ISystemDebugData {
if (!scene) {
@@ -19,15 +25,8 @@ export class SystemDataCollector {
};
}
const entityProcessors = (scene as any).entityProcessors;
if (!entityProcessors) {
return {
totalSystems: 0,
systemsInfo: []
};
}
const systems = entityProcessors.processors || [];
// 使用公共接口 | Use public interface
const systems = scene.systems || [];
// 获取性能监控数据
let systemStats: Map<string, any> = new Map();