@geekron/strapi 0.2.8 → 0.2.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"handle-missing-translations.d.ts","sourceRoot":"","sources":["../../../../admin/src/boot/handle-missing-translations.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,yBAAyB,YAwBrC,CAAA"}
1
+ {"version":3,"file":"handle-missing-translations.d.ts","sourceRoot":"","sources":["../../../../admin/src/boot/handle-missing-translations.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,yBAAyB,YAyBrC,CAAA"}
@@ -36,44 +36,88 @@ module.exports = __toCommonJS(exports_i18n);
36
36
  // i18n/translations/index.ts
37
37
  var exports_translations = {};
38
38
  __export(exports_translations, {
39
+ translations: () => translations,
39
40
  default: () => translations_default
40
41
  });
41
- var loadTranslations = (locale) => {
42
- const allModules = import.meta.glob("./*/**/*.json", { eager: true, import: "default" });
43
- const handlePrefix = (translations, prefix) => {
44
- return Object.keys(translations).reduce((acc, key) => {
45
- acc[`${prefix}.${key}`] = translations[key];
42
+ var addPrefix = (translations, prefix) => {
43
+ return Object.keys(translations).reduce((acc, key) => {
44
+ acc[`${prefix}.${key}`] = translations[key];
45
+ return acc;
46
+ }, {});
47
+ };
48
+ var isNestedFile = (modulePath, baseDepth = 3) => {
49
+ return modulePath.split("/").length > baseDepth;
50
+ };
51
+ var extractFileName = (modulePath) => {
52
+ const match = modulePath.match(/\/([^/]+)\.json$/);
53
+ return match?.[1] || "";
54
+ };
55
+ var processLocaleModules = (modules, locale, basePath = ".") => {
56
+ const localePrefix = `${basePath}/${locale}/`;
57
+ return Object.keys(modules).reduce((acc, modulePath) => {
58
+ if (!modulePath.startsWith(localePrefix)) {
46
59
  return acc;
47
- }, {});
48
- };
49
- const processModules = (modules) => {
50
- return Object.keys(modules).reduce((acc, modulePath) => {
51
- if (!modulePath.startsWith(`./${locale}/`)) {
52
- return acc;
53
- }
54
- const fileNameMatch = modulePath.match(/\/([^/]+)\.json$/);
55
- const fileName = fileNameMatch?.[1] || "";
56
- if (fileName) {
57
- console.log();
58
- const isPrefixFile = modulePath.split("/").length > 3;
59
- if (isPrefixFile) {
60
- return {
61
- ...acc,
62
- ...handlePrefix(modules[modulePath], fileName)
63
- };
64
- } else {
65
- return {
66
- ...acc,
67
- ...modules[modulePath]
68
- };
69
- }
70
- }
60
+ }
61
+ const fileName = extractFileName(modulePath);
62
+ if (!fileName) {
71
63
  return acc;
72
- }, {});
73
- };
74
- return processModules(allModules);
64
+ }
65
+ const translation = modules[modulePath];
66
+ if (isNestedFile(modulePath)) {
67
+ return {
68
+ ...acc,
69
+ ...addPrefix(translation, fileName)
70
+ };
71
+ }
72
+ return {
73
+ ...acc,
74
+ ...translation
75
+ };
76
+ }, {});
77
+ };
78
+ var discoverLocales = (modules, basePath = ".") => {
79
+ const locales = new Set;
80
+ const pattern = new RegExp(`^${basePath.replace(".", "\\.")}/([^/]+)/`);
81
+ Object.keys(modules).forEach((modulePath) => {
82
+ const match = modulePath.match(pattern);
83
+ if (match?.[1]) {
84
+ locales.add(match[1]);
85
+ }
86
+ });
87
+ return Array.from(locales);
75
88
  };
76
- var translations_default = {
77
- en: loadTranslations("en"),
78
- "zh-Hans": loadTranslations("zh-Hans")
89
+ var deepMerge = (target, source) => {
90
+ const result = { ...target };
91
+ for (const key in source) {
92
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
93
+ const sourceValue = source[key];
94
+ const targetValue = result[key];
95
+ const shouldDeepMerge = typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue);
96
+ if (shouldDeepMerge) {
97
+ result[key] = deepMerge(targetValue, sourceValue);
98
+ } else {
99
+ result[key] = sourceValue;
100
+ }
101
+ }
102
+ }
103
+ return result;
104
+ };
105
+ var translations = (config) => {
106
+ const { extensions = [], locales: specifiedLocales } = config || {};
107
+ const defaultModules = import.meta.glob("./*/**/*.json", { eager: true, import: "default" });
108
+ const allModuleSources = [
109
+ { modules: defaultModules, basePath: "." },
110
+ ...extensions
111
+ ];
112
+ const allLocales = specifiedLocales || [
113
+ ...new Set(allModuleSources.flatMap(({ modules, basePath = "." }) => discoverLocales(modules, basePath)))
114
+ ];
115
+ return allLocales.reduce((result, locale) => {
116
+ result[locale] = allModuleSources.reduce((acc, { modules, basePath = "." }) => {
117
+ const localeTranslations = processLocaleModules(modules, locale, basePath);
118
+ return deepMerge(acc, localeTranslations);
119
+ }, {});
120
+ return result;
121
+ }, {});
79
122
  };
123
+ var translations_default = translations();
@@ -12,47 +12,91 @@ var __export = (target, all) => {
12
12
  // i18n/translations/index.ts
13
13
  var exports_translations = {};
14
14
  __export(exports_translations, {
15
+ translations: () => translations,
15
16
  default: () => translations_default
16
17
  });
17
- var loadTranslations = (locale) => {
18
- const allModules = import.meta.glob("./*/**/*.json", { eager: true, import: "default" });
19
- const handlePrefix = (translations, prefix) => {
20
- return Object.keys(translations).reduce((acc, key) => {
21
- acc[`${prefix}.${key}`] = translations[key];
18
+ var addPrefix = (translations, prefix) => {
19
+ return Object.keys(translations).reduce((acc, key) => {
20
+ acc[`${prefix}.${key}`] = translations[key];
21
+ return acc;
22
+ }, {});
23
+ };
24
+ var isNestedFile = (modulePath, baseDepth = 3) => {
25
+ return modulePath.split("/").length > baseDepth;
26
+ };
27
+ var extractFileName = (modulePath) => {
28
+ const match = modulePath.match(/\/([^/]+)\.json$/);
29
+ return match?.[1] || "";
30
+ };
31
+ var processLocaleModules = (modules, locale, basePath = ".") => {
32
+ const localePrefix = `${basePath}/${locale}/`;
33
+ return Object.keys(modules).reduce((acc, modulePath) => {
34
+ if (!modulePath.startsWith(localePrefix)) {
22
35
  return acc;
23
- }, {});
24
- };
25
- const processModules = (modules) => {
26
- return Object.keys(modules).reduce((acc, modulePath) => {
27
- if (!modulePath.startsWith(`./${locale}/`)) {
28
- return acc;
29
- }
30
- const fileNameMatch = modulePath.match(/\/([^/]+)\.json$/);
31
- const fileName = fileNameMatch?.[1] || "";
32
- if (fileName) {
33
- console.log();
34
- const isPrefixFile = modulePath.split("/").length > 3;
35
- if (isPrefixFile) {
36
- return {
37
- ...acc,
38
- ...handlePrefix(modules[modulePath], fileName)
39
- };
40
- } else {
41
- return {
42
- ...acc,
43
- ...modules[modulePath]
44
- };
45
- }
46
- }
36
+ }
37
+ const fileName = extractFileName(modulePath);
38
+ if (!fileName) {
47
39
  return acc;
48
- }, {});
49
- };
50
- return processModules(allModules);
40
+ }
41
+ const translation = modules[modulePath];
42
+ if (isNestedFile(modulePath)) {
43
+ return {
44
+ ...acc,
45
+ ...addPrefix(translation, fileName)
46
+ };
47
+ }
48
+ return {
49
+ ...acc,
50
+ ...translation
51
+ };
52
+ }, {});
53
+ };
54
+ var discoverLocales = (modules, basePath = ".") => {
55
+ const locales = new Set;
56
+ const pattern = new RegExp(`^${basePath.replace(".", "\\.")}/([^/]+)/`);
57
+ Object.keys(modules).forEach((modulePath) => {
58
+ const match = modulePath.match(pattern);
59
+ if (match?.[1]) {
60
+ locales.add(match[1]);
61
+ }
62
+ });
63
+ return Array.from(locales);
51
64
  };
52
- var translations_default = {
53
- en: loadTranslations("en"),
54
- "zh-Hans": loadTranslations("zh-Hans")
65
+ var deepMerge = (target, source) => {
66
+ const result = { ...target };
67
+ for (const key in source) {
68
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
69
+ const sourceValue = source[key];
70
+ const targetValue = result[key];
71
+ const shouldDeepMerge = typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue);
72
+ if (shouldDeepMerge) {
73
+ result[key] = deepMerge(targetValue, sourceValue);
74
+ } else {
75
+ result[key] = sourceValue;
76
+ }
77
+ }
78
+ }
79
+ return result;
80
+ };
81
+ var translations = (config) => {
82
+ const { extensions = [], locales: specifiedLocales } = config || {};
83
+ const defaultModules = import.meta.glob("./*/**/*.json", { eager: true, import: "default" });
84
+ const allModuleSources = [
85
+ { modules: defaultModules, basePath: "." },
86
+ ...extensions
87
+ ];
88
+ const allLocales = specifiedLocales || [
89
+ ...new Set(allModuleSources.flatMap(({ modules, basePath = "." }) => discoverLocales(modules, basePath)))
90
+ ];
91
+ return allLocales.reduce((result, locale) => {
92
+ result[locale] = allModuleSources.reduce((acc, { modules, basePath = "." }) => {
93
+ const localeTranslations = processLocaleModules(modules, locale, basePath);
94
+ return deepMerge(acc, localeTranslations);
95
+ }, {});
96
+ return result;
97
+ }, {});
55
98
  };
99
+ var translations_default = translations();
56
100
  export {
57
101
  exports_translations as translations
58
102
  };
@@ -1,6 +1,56 @@
1
- declare const _default: {
2
- en: Record<string, any>;
3
- 'zh-Hans': Record<string, any>;
4
- };
1
+ /**
2
+ * 翻译加载器配置接口
3
+ */
4
+ interface TranslationsConfig {
5
+ /** 扩展翻译目录配置数组(自定义目录的值会覆盖默认目录的值) */
6
+ extensions?: Array<{
7
+ /** 扩展目录的模块对象(使用 import.meta.glob 导入) */
8
+ modules: Record<string, any>;
9
+ /** 扩展目录的基础路径(用于路径匹配) */
10
+ basePath?: string;
11
+ }>;
12
+ /** 指定要加载的语言列表,如果不指定则自动发现 */
13
+ locales?: string[];
14
+ }
15
+ /**
16
+ * 创建多语言翻译对象
17
+ * @param config - 翻译加载器配置(可选)
18
+ * @returns 以语言为 key 的翻译对象
19
+ *
20
+ * @description
21
+ * 该方法实现了多目录翻译文件的深度合并机制:
22
+ * 1. 自动加载默认目录 (translations/) 下的 JSON 文件
23
+ * 2. 支持扩展自定义目录,可以添加多个自定义来源
24
+ * 3. 合并顺序:默认目录 → 自定义目录 1 → 自定义目录 2 → ...
25
+ * 4. 覆盖机制:后面的目录会 **深度覆盖**前面目录的值
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // 基础用法:只加载默认目录
30
+ * const t = translations();
31
+ *
32
+ * // 高级用法:加载默认目录 + 自定义扩展目录(自定义目录会深度覆盖默认目录)
33
+ * const t = translations({
34
+ * extensions: [
35
+ * {
36
+ * modules: import.meta.glob('../custom/ * \/ ** \/ *.json', { eager: true, import: 'default' }),
37
+ * basePath: '../custom'
38
+ * }
39
+ * ]
40
+ * });
41
+ *
42
+ * // 指定语言列表
43
+ * const t = translations({
44
+ * locales: ['en', 'zh-Hans', 'zh-Hant']
45
+ * });
46
+ *
47
+ * // 深度覆盖示例:
48
+ * // 默认目录的 en.json: { common: { hello: "Hello", world: "World" }, home: { title: "Home" } }
49
+ * // 自定义目录的 en.json: { common: { hello: "Hi" }, about: { title: "About" } }
50
+ * // 最终结果: { common: { hello: "Hi", world: "World" }, home: { title: "Home" }, about: { title: "About" } }
51
+ * ```
52
+ */
53
+ export declare const translations: (config?: TranslationsConfig) => Record<string, Record<string, any>>;
54
+ declare const _default: Record<string, Record<string, any>>;
5
55
  export default _default;
6
56
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../i18n/translations/index.ts"],"names":[],"mappings":";;;;AAiDA,wBAGC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../i18n/translations/index.ts"],"names":[],"mappings":"AAiJA;;GAEG;AACH,UAAU,kBAAkB;IAC3B,mCAAmC;IACnC,UAAU,CAAC,EAAE,KAAK,CAAC;QAClB,wCAAwC;QACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,wBAAwB;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,4BAA4B;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,YAAY,GAAI,SAAS,kBAAkB,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA+B5F,CAAC;;AAGF,wBAA8B"}
@@ -1 +1 @@
1
- {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../server/src/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AA4C3C,QAAA,MAAM,SAAS,EAAE,MAAM,CAAC,YAAY,CAAC,WAAW,CA6B/C,CAAA;AAED,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../server/src/bootstrap.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AA0C3C,QAAA,MAAM,SAAS,EAAE,MAAM,CAAC,YAAY,CAAC,WAAW,CA6B/C,CAAA;AAED,eAAe,SAAS,CAAA"}
@@ -1,53 +1,233 @@
1
- // 通用翻译加载器
2
- const loadTranslations = (locale: string) => {
3
- // @ts-ignore
4
- // 一次性导入所有语言目录下的所有 JSON 文件(静态 glob 模式)
5
- const allModules = import.meta.glob('./*/**/*.json', { eager: true, import: 'default' });
6
-
7
- const handlePrefix = (translations: Record<string, any>, prefix: string) => {
8
- return Object.keys(translations).reduce((acc, key) => {
9
- acc[`${prefix}.${key}`] = translations[key];
10
- return acc;
11
- }, {} as Record<string, any>);
12
- };
13
-
14
- // 处理动态导入的模块
15
- const processModules = (modules: Record<string, any>) => {
16
- return Object.keys(modules).reduce((acc, modulePath) => {
17
- // 只处理指定语言目录下的文件
18
- if (!modulePath.startsWith(`./${locale}/`)) {
19
- return acc;
20
- }
21
-
22
- // 从路径中提取文件名作为 prefix
23
- const fileNameMatch = modulePath.match(/\/([^/]+)\.json$/);
24
- const fileName = fileNameMatch?.[1] || '';
25
- if (fileName) {
26
- console.log();
27
- // 判断是否为子目录文件
28
- const isPrefixFile = modulePath.split('/').length > 3;
29
- if (isPrefixFile) {
30
- return {
31
- ...acc,
32
- ...handlePrefix(modules[modulePath] as Record<string, any>, fileName)
33
- };
34
- } else {
35
- // 根目录文件,不添加前缀
36
- return {
37
- ...acc,
38
- ...modules[modulePath] as Record<string, any>
39
- };
40
- }
41
- }
42
- return acc;
43
- }, {} as Record<string, any>);
44
- };
1
+ /**
2
+ * 为翻译对象添加前缀
3
+ * @param translations - 原始翻译对象
4
+ * @param prefix - 前缀字符串
5
+ * @returns 添加前缀后的翻译对象
6
+ */
7
+ const addPrefix = (translations: Record<string, any>, prefix: string): Record<string, any> => {
8
+ return Object.keys(translations).reduce((acc, key) => {
9
+ acc[`${prefix}.${key}`] = translations[key];
10
+ return acc;
11
+ }, {} as Record<string, any>);
12
+ };
13
+
14
+ /**
15
+ * 判断文件是否在子目录中
16
+ * @param modulePath - 模块路径
17
+ * @param baseDepth - 基础路径深度(默认为 3,即 ./locale/*.json)
18
+ * @returns 是否为子目录文件
19
+ */
20
+ const isNestedFile = (modulePath: string, baseDepth = 3): boolean => {
21
+ return modulePath.split('/').length > baseDepth;
22
+ };
23
+
24
+ /**
25
+ * 从路径中提取文件名(不含扩展名)
26
+ * @param modulePath - 模块路径
27
+ * @returns 文件名
28
+ */
29
+ const extractFileName = (modulePath: string): string => {
30
+ const match = modulePath.match(/\/([^/]+)\.json$/);
31
+ return match?.[1] || '';
32
+ };
33
+
34
+ /**
35
+ * 处理单个语言目录下的所有翻译文件
36
+ * @param modules - 导入的模块对象
37
+ * @param locale - 语言代码
38
+ * @param basePath - 基础路径前缀(用于自定义目录)
39
+ * @returns 合并后的翻译对象
40
+ */
41
+ const processLocaleModules = (
42
+ modules: Record<string, any>,
43
+ locale: string,
44
+ basePath = '.'
45
+ ): Record<string, any> => {
46
+ const localePrefix = `${basePath}/${locale}/`;
47
+
48
+ return Object.keys(modules).reduce((acc, modulePath) => {
49
+ // 只处理指定语言目录下的文件
50
+ if (!modulePath.startsWith(localePrefix)) {
51
+ return acc;
52
+ }
53
+
54
+ const fileName = extractFileName(modulePath);
55
+ if (!fileName) {
56
+ return acc;
57
+ }
58
+
59
+ const translation = modules[modulePath] as Record<string, any>;
60
+
61
+ // 判断是否为子目录文件,子目录文件添加文件名作为前缀
62
+ if (isNestedFile(modulePath)) {
63
+ return {
64
+ ...acc,
65
+ ...addPrefix(translation, fileName)
66
+ };
67
+ }
68
+
69
+ // 根目录文件,直接合并(不添加前缀)
70
+ return {
71
+ ...acc,
72
+ ...translation
73
+ };
74
+ }, {} as Record<string, any>);
75
+ };
76
+
77
+ /**
78
+ * 自动发现翻译目录下的所有语言
79
+ * @param modules - 导入的模块对象
80
+ * @param basePath - 基础路径前缀
81
+ * @returns 语言代码数组
82
+ */
83
+ const discoverLocales = (modules: Record<string, any>, basePath = '.'): string[] => {
84
+ const locales = new Set<string>();
85
+ const pattern = new RegExp(`^${basePath.replace('.', '\\.')}/([^/]+)/`);
45
86
 
46
- // 处理所有模块
47
- return processModules(allModules);
87
+ Object.keys(modules).forEach(modulePath => {
88
+ const match = modulePath.match(pattern);
89
+ if (match?.[1]) {
90
+ locales.add(match[1]);
91
+ }
92
+ });
93
+
94
+ return Array.from(locales);
95
+ };
96
+
97
+ /**
98
+ * 深度合并翻译对象(后面的值会覆盖前面的值)
99
+ * @param target - 目标对象(基础对象)
100
+ * @param source - 源对象(覆盖对象,优先级更高)
101
+ * @returns 合并后的新对象
102
+ * @example
103
+ * ```typescript
104
+ * const base = { a: { b: 1, c: 2 }, d: 3 };
105
+ * const override = { a: { b: 10 }, e: 4 };
106
+ * const result = deepMerge(base, override);
107
+ * // 结果:{ a: { b: 10, c: 2 }, d: 3, e: 4 }
108
+ * // 说明:override.a.b 覆盖了 base.a.b,但 base.a.c 保留
109
+ * ```
110
+ */
111
+ const deepMerge = (
112
+ target: Record<string, any>,
113
+ source: Record<string, any>
114
+ ): Record<string, any> => {
115
+ // 创建新对象,避免修改原始对象
116
+ const result = { ...target };
117
+
118
+ // 遍历源对象的所有键
119
+ for (const key in source) {
120
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
121
+ const sourceValue = source[key];
122
+ const targetValue = result[key];
123
+
124
+ // 判断是否需要深度合并(两者都是对象且不是数组)
125
+ const shouldDeepMerge =
126
+ typeof sourceValue === 'object' &&
127
+ sourceValue !== null &&
128
+ !Array.isArray(sourceValue) &&
129
+ typeof targetValue === 'object' &&
130
+ targetValue !== null &&
131
+ !Array.isArray(targetValue);
132
+
133
+ if (shouldDeepMerge) {
134
+ // 递归深度合并对象
135
+ result[key] = deepMerge(targetValue, sourceValue);
136
+ } else {
137
+ // 直接覆盖(包括基本类型、数组、null、undefined)
138
+ result[key] = sourceValue;
139
+ }
140
+ }
141
+ }
142
+
143
+ return result;
144
+ };
145
+
146
+ /**
147
+ * 翻译加载器配置接口
148
+ */
149
+ interface TranslationsConfig {
150
+ /** 扩展翻译目录配置数组(自定义目录的值会覆盖默认目录的值) */
151
+ extensions?: Array<{
152
+ /** 扩展目录的模块对象(使用 import.meta.glob 导入) */
153
+ modules: Record<string, any>;
154
+ /** 扩展目录的基础路径(用于路径匹配) */
155
+ basePath?: string;
156
+ }>;
157
+ /** 指定要加载的语言列表,如果不指定则自动发现 */
158
+ locales?: string[];
159
+ }
160
+
161
+ /**
162
+ * 创建多语言翻译对象
163
+ * @param config - 翻译加载器配置(可选)
164
+ * @returns 以语言为 key 的翻译对象
165
+ *
166
+ * @description
167
+ * 该方法实现了多目录翻译文件的深度合并机制:
168
+ * 1. 自动加载默认目录 (translations/) 下的 JSON 文件
169
+ * 2. 支持扩展自定义目录,可以添加多个自定义来源
170
+ * 3. 合并顺序:默认目录 → 自定义目录 1 → 自定义目录 2 → ...
171
+ * 4. 覆盖机制:后面的目录会 **深度覆盖**前面目录的值
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * // 基础用法:只加载默认目录
176
+ * const t = translations();
177
+ *
178
+ * // 高级用法:加载默认目录 + 自定义扩展目录(自定义目录会深度覆盖默认目录)
179
+ * const t = translations({
180
+ * extensions: [
181
+ * {
182
+ * modules: import.meta.glob('../custom/ * \/ ** \/ *.json', { eager: true, import: 'default' }),
183
+ * basePath: '../custom'
184
+ * }
185
+ * ]
186
+ * });
187
+ *
188
+ * // 指定语言列表
189
+ * const t = translations({
190
+ * locales: ['en', 'zh-Hans', 'zh-Hant']
191
+ * });
192
+ *
193
+ * // 深度覆盖示例:
194
+ * // 默认目录的 en.json: { common: { hello: "Hello", world: "World" }, home: { title: "Home" } }
195
+ * // 自定义目录的 en.json: { common: { hello: "Hi" }, about: { title: "About" } }
196
+ * // 最终结果: { common: { hello: "Hi", world: "World" }, home: { title: "Home" }, about: { title: "About" } }
197
+ * ```
198
+ */
199
+ export const translations = (config?: TranslationsConfig): Record<string, Record<string, any>> => {
200
+ const { extensions = [], locales: specifiedLocales } = config || {};
201
+
202
+ // @ts-ignore
203
+ // 自动加载默认翻译目录
204
+ const defaultModules = import.meta.glob('./*/**/*.json', { eager: true, import: 'default' });
205
+
206
+ // 收集所有模块(默认目录在前,自定义目录在后,确保自定义目录覆盖默认目录)
207
+ const allModuleSources = [
208
+ { modules: defaultModules, basePath: '.' },
209
+ ...extensions
210
+ ];
211
+
212
+ // 自动发现所有语言或使用指定的语言列表
213
+ const allLocales = specifiedLocales || [
214
+ ...new Set(
215
+ allModuleSources.flatMap(({ modules, basePath = '.' }) =>
216
+ discoverLocales(modules, basePath)
217
+ )
218
+ )
219
+ ];
220
+
221
+ // 为每个语言构建翻译对象
222
+ return allLocales.reduce((result, locale) => {
223
+ // 合并所有来源的翻译(后面的会覆盖前面的)
224
+ result[locale] = allModuleSources.reduce((acc, {modules, basePath = '.'}) => {
225
+ const localeTranslations = processLocaleModules(modules, locale, basePath);
226
+ return deepMerge(acc, localeTranslations);
227
+ }, {} as Record<string, any>);
228
+ return result;
229
+ }, {} as Record<string, Record<string, any>>);
48
230
  };
49
231
 
50
- export default {
51
- en: loadTranslations('en'),
52
- 'zh-Hans': loadTranslations('zh-Hans'),
53
- }
232
+ // 默认导出:加载默认翻译目录
233
+ export default translations();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekron/strapi",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "极客领航网站管理插件",
5
5
  "type": "commonjs",
6
6
  "author": "Geekron",