@spaceflow/core 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaceflow/core",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Spaceflow 核心能力库",
5
5
  "license": "MIT",
6
6
  "author": "Lydanne",
@@ -81,7 +81,6 @@
81
81
  "@rspack/core": "^1.7.4",
82
82
  "chalk": "^5.6.2",
83
83
  "dotenv": "^16.4.5",
84
- "i18next": "^25.8.4",
85
84
  "json-stringify-pretty-compact": "^4.0.0",
86
85
  "jsonrepair": "^3.13.1",
87
86
  "log-update": "^7.1.0",
@@ -109,6 +108,7 @@
109
108
  "typescript": "^5.7.3",
110
109
  "typescript-eslint": "^8.20.0",
111
110
  "@vitest/coverage-v8": "^4.0.18",
111
+ "i18next": "^25.8.4",
112
112
  "unplugin-swc": "^1.5.9",
113
113
  "vitest": "^4.0.18"
114
114
  },
@@ -85,7 +85,6 @@ export class SchemaGeneratorService {
85
85
 
86
86
  // 写入文件
87
87
  fs.writeFileSync(outputPath, JSON.stringify(fullSchema, null, 2), "utf-8");
88
- console.log(`✅ JSON Schema 已生成: ${outputPath}`);
89
88
 
90
89
  // 自动添加到 .gitignore
91
90
  this.addToGitignore(dir, path.basename(outputPath));
@@ -7,5 +7,7 @@
7
7
  "common.options.ci": "Run in CI environment",
8
8
  "config.parseWarning": "Warning: unable to parse config file {{path}}",
9
9
  "config.validationFailed": "Spaceflow config validation failed:\n{{errors}}",
10
- "extensionLoader.loadFailed": "⚠️ Failed to load Extension {{name}}: {{error}}"
10
+ "extensionLoader.loadFailed": "⚠️ Failed to load Extension {{name}}: {{error}}",
11
+ "extensionLoader.autoInstalling": "📦 Auto-installing missing extensions: {{packages}}",
12
+ "extensionLoader.autoInstallFailed": "⚠️ Auto-install failed, please run spaceflow install manually"
11
13
  }
@@ -7,5 +7,7 @@
7
7
  "common.options.ci": "是否在 CI 环境中运行",
8
8
  "config.parseWarning": "警告: 无法解析配置文件 {{path}}",
9
9
  "config.validationFailed": "Spaceflow 配置验证失败:\n{{errors}}",
10
- "extensionLoader.loadFailed": "⚠️ 加载 Extension {{name}} 失败: {{error}}"
10
+ "extensionLoader.loadFailed": "⚠️ 加载 Extension {{name}} 失败: {{error}}",
11
+ "extensionLoader.autoInstalling": "📦 自动安装缺失的扩展: {{packages}}",
12
+ "extensionLoader.autoInstallFailed": "⚠️ 自动安装扩展失败,请手动执行 spaceflow install"
11
13
  }
@@ -1,72 +1,70 @@
1
- import * as i18nextModule from "i18next";
2
- import type { TOptions, i18n } from "i18next";
1
+ /** globalThis 上的 key */
2
+ const GLOBAL_T_KEY = "__spaceflow_t__";
3
+ const GLOBAL_ADD_LOCALE_KEY = "__spaceflow_add_locale__";
3
4
 
4
- // 兼容 CJS/ESM 混合环境
5
- const i18next: i18n =
6
- (i18nextModule as unknown as { default: i18n }).default || (i18nextModule as unknown as i18n);
7
- import { detectLocale } from "./locale-detect";
8
- import zhCN from "../../locales/zh-cn/translation.json";
9
- import en from "../../locales/en/translation.json";
5
+ /** 翻译函数类型 */
6
+ export type TranslateFn = (key: string, options?: Record<string, unknown>) => string;
10
7
 
11
- /** 默认命名空间 */
12
- const DEFAULT_NS = "translation";
8
+ /** 注册翻译资源函数类型 */
9
+ export type AddLocaleResourcesFn = (
10
+ ns: string,
11
+ resources: Record<string, Record<string, unknown>>,
12
+ ) => void;
13
13
 
14
- /** 是否已初始化 */
15
- let initialized = false;
14
+ /**
15
+ * 设置全局翻译函数
16
+ * 由 CLI 在启动时调用,将 i18next 的 t 函数挂载到 globalThis
17
+ */
18
+ export function setGlobalT(fn: TranslateFn): void {
19
+ (globalThis as Record<string, unknown>)[GLOBAL_T_KEY] = fn;
20
+ }
16
21
 
17
22
  /**
18
- * 初始化 i18n
19
- * 当提供 resources 且无后端加载器时,i18next.init() 同步完成
20
- * @param lang 指定语言,不传则自动检测
23
+ * 设置全局翻译资源注册函数
24
+ * CLI 在启动时调用
21
25
  */
22
- export function initI18n(lang?: string): void {
23
- if (initialized) return;
24
- const lng = lang || detectLocale();
25
- // i18next v25+ 移除了 initSync,但提供内联 resources 时 init() 同步完成
26
- void i18next.init({
27
- lng,
28
- fallbackLng: "zh-CN",
29
- defaultNS: DEFAULT_NS,
30
- ns: [DEFAULT_NS],
31
- resources: {
32
- "zh-CN": { [DEFAULT_NS]: zhCN },
33
- en: { [DEFAULT_NS]: en },
34
- },
35
- interpolation: {
36
- escapeValue: false,
37
- },
38
- returnNull: false,
39
- returnEmptyString: false,
40
- // 确保 init 同步完成(默认 initImmediate: true 会将加载推到 setTimeout)
41
- initImmediate: false,
42
- // i18next v25.8+ 会在 init 时输出 locize.com 推广日志
43
- showSupportNotice: false,
44
- });
45
- initialized = true;
26
+ export function setGlobalAddLocaleResources(fn: AddLocaleResourcesFn): void {
27
+ (globalThis as Record<string, unknown>)[GLOBAL_ADD_LOCALE_KEY] = fn;
46
28
  }
47
29
 
48
30
  /**
49
- * 重置 i18n 状态(仅用于测试)
31
+ * 获取全局翻译函数
50
32
  */
51
- export function resetI18n(): void {
52
- initialized = false;
33
+ function getGlobalT(): TranslateFn | undefined {
34
+ return (globalThis as Record<string, unknown>)[GLOBAL_T_KEY] as TranslateFn | undefined;
35
+ }
36
+
37
+ /**
38
+ * 简单的模板插值(fallback 用)
39
+ * 支持 {{key}} 格式
40
+ */
41
+ function interpolate(template: string, options?: Record<string, unknown>): string {
42
+ if (!options) return template;
43
+ return template.replace(/\{\{(\w+)\}\}/g, (_, k: string) => {
44
+ const val = options[k];
45
+ return val !== undefined ? String(val) : `{{${k}}}`;
46
+ });
53
47
  }
54
48
 
55
49
  /**
56
50
  * 翻译函数
57
- * 装饰器和运行时均可使用
51
+ * 优先使用 CLI 通过 setGlobalT 挂载的翻译函数
52
+ * 未挂载时回退到返回 key(带插值)
58
53
  * @param key 翻译 key
59
54
  * @param options 插值参数
60
55
  */
61
- export function t(key: string, options?: TOptions): string {
62
- if (!initialized) {
63
- initI18n();
56
+ export function t(key: string, options?: Record<string, unknown>): string {
57
+ const globalT = getGlobalT();
58
+ if (globalT) {
59
+ return globalT(key, options);
64
60
  }
65
- return i18next.t(key, options) as string;
61
+ // fallback: 直接返回 key(带插值)
62
+ return interpolate(key, options);
66
63
  }
67
64
 
68
65
  /**
69
66
  * 为外部 Extension 注册语言资源
67
+ * 委托给 CLI 通过 setGlobalAddLocaleResources 挂载的实际实现
70
68
  * @param ns 命名空间(通常为 Extension name)
71
69
  * @param resources 语言资源,key 为语言代码,值为翻译对象
72
70
  */
@@ -74,15 +72,18 @@ export function addLocaleResources(
74
72
  ns: string,
75
73
  resources: Record<string, Record<string, unknown>>,
76
74
  ): void {
77
- if (!initialized) {
78
- initI18n();
79
- }
80
- for (const [lng, translations] of Object.entries(resources)) {
81
- i18next.addResourceBundle(lng, ns, translations, true, true);
82
- }
83
- if (!i18next.options.ns) {
84
- i18next.options.ns = [DEFAULT_NS, ns];
85
- } else if (Array.isArray(i18next.options.ns) && !i18next.options.ns.includes(ns)) {
86
- i18next.options.ns.push(ns);
75
+ const fn = (globalThis as Record<string, unknown>)[GLOBAL_ADD_LOCALE_KEY] as
76
+ | AddLocaleResourcesFn
77
+ | undefined;
78
+ if (fn) {
79
+ fn(ns, resources);
87
80
  }
88
81
  }
82
+
83
+ /**
84
+ * 重置全局翻译函数(仅用于测试)
85
+ */
86
+ export function resetI18n(): void {
87
+ (globalThis as Record<string, unknown>)[GLOBAL_T_KEY] = undefined;
88
+ (globalThis as Record<string, unknown>)[GLOBAL_ADD_LOCALE_KEY] = undefined;
89
+ }
@@ -1 +1,14 @@
1
- export { initI18n, t, addLocaleResources } from "./i18n";
1
+ export {
2
+ t,
3
+ setGlobalT,
4
+ setGlobalAddLocaleResources,
5
+ addLocaleResources,
6
+ resetI18n,
7
+ type TranslateFn,
8
+ type AddLocaleResourcesFn,
9
+ } from "./i18n";
10
+ export { detectLocale } from "./locale-detect";
11
+
12
+ // 导出 core 基础翻译资源,供 CLI 注册
13
+ export { default as coreZhCN } from "../../locales/zh-cn/translation.json";
14
+ export { default as coreEn } from "../../locales/en/translation.json";