@liujitcn/kratos-taro-app-core 0.0.61 → 0.0.64

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/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  - `@liujitcn/kratos-taro-app-core`:启动、模块、导航、状态和常用工具,包含动态路径使用的 `resolveBundledAsset()`。
22
22
  - `@liujitcn/kratos-taro-app-core/static/*`:页面图片等可由 Webpack 静态分析的打包资源。
23
- - `@liujitcn/kratos-taro-app-core/build`:构建期模块描述。
23
+ - `@liujitcn/kratos-taro-app-core/build`:构建期模块描述和双语构建错误文案格式化器。
24
24
  - `@liujitcn/kratos-taro-app-core/runner`:Taro 构建装配入口。
25
25
  - `api/*`、`components/*`、`rpc/*`、`styles/*`、`utils/*`、`views/*`:白名单子路径。
26
26
 
package/dist/build.mjs CHANGED
@@ -22,6 +22,42 @@ var corePages = {
22
22
  }
23
23
  };
24
24
 
25
+ // src/runner-messages.ts
26
+ var messages = {
27
+ "zh-CN": {
28
+ https_certificate_missing: "VITE_APP_HTTPS \u5DF2\u5F00\u542F\uFF0C\u4F46\u672A\u627E\u5230\u8BC1\u4E66\u6587\u4EF6\uFF0C\u8BF7\u5148\u5728\u4ED3\u5E93\u6839\u76EE\u5F55\u8FD0\u884C scripts/generate-dev-cert.sh\uFF1B\u671F\u671B\u8DEF\u5F84\uFF1A{keyPath} \u548C {certPath}",
29
+ project_name: "\u901A\u7528\u5E94\u7528",
30
+ unsupported_type: "\u4E0D\u652F\u6301\u7684 Taro \u7C7B\u578B\uFF1A{value}",
31
+ unknown_argument: "\u672A\u77E5\u53C2\u6570\uFF1A{argument}",
32
+ type_required: "\u7F3A\u5C11 --type h5|weapp",
33
+ manifest_missing: "\u6A21\u5757\u6E05\u5355\u672A\u5BFC\u51FA moduleManifest\uFF1A{file}",
34
+ static_import_missing: "\u6A21\u5757 {name} \u7F3A\u5C11\u9759\u6001 import",
35
+ build_export_missing: "{packageName}/build \u672A\u5BFC\u51FA buildModule",
36
+ transaction_mismatch: "Taro \u6784\u5EFA\u4E8B\u52A1\u76EE\u5F55\u4E0D\u5339\u914D\uFF1A{file}",
37
+ assembly_timeout: "\u7B49\u5F85 Taro \u9875\u9762\u88C5\u914D\u9501\u8D85\u65F6\uFF1A{file}"
38
+ },
39
+ "en-US": {
40
+ https_certificate_missing: "VITE_APP_HTTPS is enabled, but certificate files were not found. Run scripts/generate-dev-cert.sh from the repository root; expected paths: {keyPath} and {certPath}",
41
+ project_name: "Generic app",
42
+ unsupported_type: "Unsupported Taro type: {value}",
43
+ unknown_argument: "Unknown argument: {argument}",
44
+ type_required: "Missing --type h5|weapp",
45
+ manifest_missing: "The module manifest does not export moduleManifest: {file}",
46
+ static_import_missing: "Module {name} is missing a static import",
47
+ build_export_missing: "{packageName}/build does not export buildModule",
48
+ transaction_mismatch: "Taro build transaction directory does not match: {file}",
49
+ assembly_timeout: "Timed out waiting for the Taro page assembly lock: {file}"
50
+ }
51
+ };
52
+ function resolveRunnerLocale() {
53
+ const value = process.env.KRATOS_ADMIN_LOCALE ?? process.env.LC_ALL ?? process.env.LANG ?? "";
54
+ return value.toLowerCase().startsWith("zh") ? "zh-CN" : "en-US";
55
+ }
56
+ function runnerMessage(key, params = {}) {
57
+ const template = messages[resolveRunnerLocale()][key] ?? messages["en-US"][key] ?? key;
58
+ return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_, name) => params[name] ?? `{${name}}`);
59
+ }
60
+
25
61
  // src/build.ts
26
62
  function defineKratosTaroBuildModule(module) {
27
63
  return module;
@@ -34,5 +70,6 @@ var buildModule = defineKratosTaroBuildModule({
34
70
  });
35
71
  export {
36
72
  buildModule,
37
- defineKratosTaroBuildModule
73
+ defineKratosTaroBuildModule,
74
+ runnerMessage
38
75
  };
package/dist/runner.mjs CHANGED
@@ -15,6 +15,44 @@ import { dirname, relative, resolve } from "node:path";
15
15
  import { pathToFileURL } from "node:url";
16
16
  import { spawn } from "node:child_process";
17
17
  import ts from "typescript";
18
+
19
+ // src/runner-messages.ts
20
+ var messages = {
21
+ "zh-CN": {
22
+ https_certificate_missing: "VITE_APP_HTTPS \u5DF2\u5F00\u542F\uFF0C\u4F46\u672A\u627E\u5230\u8BC1\u4E66\u6587\u4EF6\uFF0C\u8BF7\u5148\u5728\u4ED3\u5E93\u6839\u76EE\u5F55\u8FD0\u884C scripts/generate-dev-cert.sh\uFF1B\u671F\u671B\u8DEF\u5F84\uFF1A{keyPath} \u548C {certPath}",
23
+ project_name: "\u901A\u7528\u5E94\u7528",
24
+ unsupported_type: "\u4E0D\u652F\u6301\u7684 Taro \u7C7B\u578B\uFF1A{value}",
25
+ unknown_argument: "\u672A\u77E5\u53C2\u6570\uFF1A{argument}",
26
+ type_required: "\u7F3A\u5C11 --type h5|weapp",
27
+ manifest_missing: "\u6A21\u5757\u6E05\u5355\u672A\u5BFC\u51FA moduleManifest\uFF1A{file}",
28
+ static_import_missing: "\u6A21\u5757 {name} \u7F3A\u5C11\u9759\u6001 import",
29
+ build_export_missing: "{packageName}/build \u672A\u5BFC\u51FA buildModule",
30
+ transaction_mismatch: "Taro \u6784\u5EFA\u4E8B\u52A1\u76EE\u5F55\u4E0D\u5339\u914D\uFF1A{file}",
31
+ assembly_timeout: "\u7B49\u5F85 Taro \u9875\u9762\u88C5\u914D\u9501\u8D85\u65F6\uFF1A{file}"
32
+ },
33
+ "en-US": {
34
+ https_certificate_missing: "VITE_APP_HTTPS is enabled, but certificate files were not found. Run scripts/generate-dev-cert.sh from the repository root; expected paths: {keyPath} and {certPath}",
35
+ project_name: "Generic app",
36
+ unsupported_type: "Unsupported Taro type: {value}",
37
+ unknown_argument: "Unknown argument: {argument}",
38
+ type_required: "Missing --type h5|weapp",
39
+ manifest_missing: "The module manifest does not export moduleManifest: {file}",
40
+ static_import_missing: "Module {name} is missing a static import",
41
+ build_export_missing: "{packageName}/build does not export buildModule",
42
+ transaction_mismatch: "Taro build transaction directory does not match: {file}",
43
+ assembly_timeout: "Timed out waiting for the Taro page assembly lock: {file}"
44
+ }
45
+ };
46
+ function resolveRunnerLocale() {
47
+ const value = process.env.KRATOS_ADMIN_LOCALE ?? process.env.LC_ALL ?? process.env.LANG ?? "";
48
+ return value.toLowerCase().startsWith("zh") ? "zh-CN" : "en-US";
49
+ }
50
+ function runnerMessage(key, params = {}) {
51
+ const template = messages[resolveRunnerLocale()][key] ?? messages["en-US"][key] ?? key;
52
+ return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_, name) => params[name] ?? `{${name}}`);
53
+ }
54
+
55
+ // src/runner.ts
18
56
  var sourceVersionCounter = 0;
19
57
  var PAGE_ASSEMBLY_WAIT_TIMEOUT_MS = 3e4;
20
58
  var PAGE_ASSEMBLY_POLL_INTERVAL_MS = 25;
@@ -113,7 +151,7 @@ function parseArguments(args) {
113
151
  const argument = args[index];
114
152
  if (argument === "--type") {
115
153
  const value = args[++index];
116
- if (value !== "h5" && value !== "weapp") throw new Error(`\u4E0D\u652F\u6301\u7684 Taro \u7C7B\u578B\uFF1A${value}`);
154
+ if (value !== "h5" && value !== "weapp") throw new Error(runnerMessage("unsupported_type", { value }));
117
155
  type = value;
118
156
  } else if (argument === "--mode") {
119
157
  mode = args[++index] || mode;
@@ -124,10 +162,10 @@ function parseArguments(args) {
124
162
  } else if (argument === "--cleanup-only") {
125
163
  cleanupOnly = true;
126
164
  } else {
127
- throw new Error(`\u672A\u77E5\u53C2\u6570\uFF1A${argument}`);
165
+ throw new Error(runnerMessage("unknown_argument", { argument }));
128
166
  }
129
167
  }
130
- if (!type) throw new Error("\u7F3A\u5C11 --type h5|weapp");
168
+ if (!type) throw new Error(runnerMessage("type_required"));
131
169
  return { type, mode, watch, prepareOnly, cleanupOnly };
132
170
  }
133
171
  async function loadBuildModules(hostRoot, manifestFile) {
@@ -161,15 +199,15 @@ async function loadBuildModules(hostRoot, manifestFile) {
161
199
  }
162
200
  });
163
201
  });
164
- if (!moduleNames.length) throw new Error(`\u6A21\u5757\u6E05\u5355\u672A\u5BFC\u51FA moduleManifest\uFF1A${manifestFile}`);
202
+ if (!moduleNames.length) throw new Error(runnerMessage("manifest_missing", { file: manifestFile }));
165
203
  const hostRequire = createRequire(resolve(hostRoot, "package.json"));
166
204
  return Promise.all(
167
205
  moduleNames.map(async (name) => {
168
206
  const packageName = imports.get(name);
169
- if (!packageName) throw new Error(`\u6A21\u5757 ${name} \u7F3A\u5C11\u9759\u6001 import`);
207
+ if (!packageName) throw new Error(runnerMessage("static_import_missing", { name }));
170
208
  const buildEntry = hostRequire.resolve(`${packageName}/build`);
171
209
  const loaded = await import(pathToFileURL(buildEntry).href);
172
- if (!loaded.buildModule) throw new Error(`${packageName}/build \u672A\u5BFC\u51FA buildModule`);
210
+ if (!loaded.buildModule) throw new Error(runnerMessage("build_export_missing", { packageName }));
173
211
  return loaded.buildModule;
174
212
  })
175
213
  );
@@ -263,7 +301,7 @@ function readBuildTransaction(transactionFile, inputDir, appConfigFile) {
263
301
  if (!existsSync(transactionFile)) return;
264
302
  const transaction = JSON.parse(readFileSync(transactionFile, "utf8"));
265
303
  if (transaction.inputDir !== inputDir || transaction.appConfigFile !== appConfigFile) {
266
- throw new Error(`Taro \u6784\u5EFA\u4E8B\u52A1\u76EE\u5F55\u4E0D\u5339\u914D\uFF1A${transactionFile}`);
304
+ throw new Error(runnerMessage("transaction_mismatch", { file: transactionFile }));
267
305
  }
268
306
  return transaction;
269
307
  }
@@ -362,7 +400,7 @@ function acquirePageAssemblyLock(lockFile) {
362
400
  unlinkSync(lockFile);
363
401
  continue;
364
402
  }
365
- if (Date.now() >= deadline) throw new Error(`\u7B49\u5F85 Taro \u9875\u9762\u88C5\u914D\u9501\u8D85\u65F6\uFF1A${lockFile}`);
403
+ if (Date.now() >= deadline) throw new Error(runnerMessage("assembly_timeout", { file: lockFile }));
366
404
  waitForPageAssembly(PAGE_ASSEMBLY_POLL_INTERVAL_MS);
367
405
  }
368
406
  }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "type": "git",
8
8
  "url": "git@github.com:liujitcn/kratos-admin.git"
9
9
  },
10
- "version": "0.0.61",
10
+ "version": "0.0.64",
11
11
  "type": "module",
12
12
  "files": [
13
13
  "dist",
package/src/bootstrap.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  } from './stores'
12
12
  import {
13
13
  applyLanguageConfig,
14
+ getCurrentLocale,
14
15
  initializeLocale,
15
16
  registerLocaleChangeHandler,
16
17
  registerLocaleMessages,
@@ -33,6 +34,7 @@ function syncH5DocumentTitle(): void {
33
34
  const titleElement = document.querySelector('title')
34
35
  const appTitle = titleElement?.dataset.appTitle || t('core.home.main_title')
35
36
  const applyTitle = () => {
37
+ document.documentElement.lang = getCurrentLocale()
36
38
  if (document.title !== appTitle) document.title = appTitle
37
39
  }
38
40
  applyTitle()
@@ -50,6 +52,7 @@ export function bootstrapKratosTaroApp(options: KratosTaroBootstrapOptions): voi
50
52
  .OptionLanguage({})
51
53
  .then((response) => {
52
54
  applyLanguageConfig(response)
55
+ syncH5DocumentTitle()
53
56
  })
54
57
  .catch(() => {
55
58
  // 语言公共接口失败时继续使用静态语言包和系统语言。
package/src/build.ts CHANGED
@@ -22,3 +22,5 @@ export const buildModule = defineKratosTaroBuildModule({
22
22
  root: packageRoot,
23
23
  pages: corePages,
24
24
  })
25
+
26
+ export { runnerMessage } from './runner-messages.js'
@@ -8,6 +8,7 @@
8
8
  "common.action.new": "New",
9
9
  "common.action.open_in_new_window": "Open in new window",
10
10
  "common.action.save": "Save",
11
+ "common.action.view": "View",
11
12
  "common.field.language": "Language",
12
13
  "common.language.en-US": "English",
13
14
  "common.language.zh-CN": "简体中文",
@@ -115,18 +115,18 @@ export function registerLocaleMessages(modules: KratosTaroModule[]): void {
115
115
  const expectedKeys = requiredLocaleKeys(module.messages?.[DEFAULT_LOCALE] || {})
116
116
  SUPPORTED_LOCALES.forEach((locale) => {
117
117
  const messages = module.messages?.[locale]
118
- if (!messages) throw new Error(`${module.name} 缺少 ${locale} 语言包`)
118
+ if (!messages) throw new Error(localeRuntimeMessage('missing_bundle', { module: module.name, locale }))
119
119
  const keys = requiredLocaleKeys(messages)
120
120
  if (keys.join('\u0000') !== expectedKeys.join('\u0000')) {
121
- throw new Error(`${module.name} 的 ${locale} 语言包键集合不一致`)
121
+ throw new Error(localeRuntimeMessage('key_set_mismatch', { module: module.name, locale }))
122
122
  }
123
123
  const target = defaultLocaleMessages.get(locale) as LocaleMessages
124
124
  Object.keys(messages).forEach((key) => {
125
125
  if (!isAllowedLocaleKey(module.name, key)) {
126
- throw new Error(`${module.name} 的语言键命名空间无效: ${key}`)
126
+ throw new Error(localeRuntimeMessage('namespace_invalid', { module: module.name, key }))
127
127
  }
128
128
  if (Object.prototype.hasOwnProperty.call(target, key)) {
129
- throw new Error(`${locale} 语言键重复: ${key}`)
129
+ throw new Error(localeRuntimeMessage('duplicate_key', { locale, key }))
130
130
  }
131
131
  assertLocalePlaceholders(module.name, key, messages[key], module.messages?.[DEFAULT_LOCALE]?.[key] || '')
132
132
  target[key] = messages[key]
@@ -212,10 +212,19 @@ function assertLocalePlaceholders(
212
212
  const placeholders = (value: string) =>
213
213
  [...value.matchAll(/\{([A-Za-z0-9_]+)\}/g)].map((match) => match[1]).sort()
214
214
  if (placeholders(message).join('\u0000') !== placeholders(sourceMessage).join('\u0000')) {
215
- throw new Error(`${moduleName} 的 ${key} 占位符集合不一致`)
215
+ throw new Error(localeRuntimeMessage('placeholder_mismatch', { module: moduleName, key }))
216
216
  }
217
217
  }
218
218
 
219
+ function localeRuntimeMessage(key: string, params: Record<string, string>): string {
220
+ const locale = getCurrentLocale().toLowerCase().startsWith('zh') ? 'zh-CN' : 'en-US'
221
+ const templates: Record<string, Record<string, string>> = {
222
+ 'zh-CN': { missing_bundle: '{module} 缺少 {locale} 语言包', key_set_mismatch: '{module} 的 {locale} 语言包键集合不一致', namespace_invalid: '{module} 的语言键命名空间无效: {key}', duplicate_key: '{locale} 语言键重复: {key}', placeholder_mismatch: '{module} 的 {key} 占位符集合不一致' },
223
+ 'en-US': { missing_bundle: '{module} is missing the {locale} locale bundle', key_set_mismatch: '{module} has inconsistent keys in the {locale} locale bundle', namespace_invalid: 'Invalid locale key namespace for {module}: {key}', duplicate_key: 'Duplicate locale key in {locale}: {key}', placeholder_mismatch: 'Placeholder set mismatch for {module}: {key}' },
224
+ }
225
+ return (templates[locale][key] ?? key).replace(/\{([A-Za-z0-9_]+)\}/g, (_, name: string) => params[name] ?? `{${name}}`)
226
+ }
227
+
219
228
  function requiredLocaleKeys(messages: LocaleMessages): string[] {
220
229
  return Object.keys(messages)
221
230
  .filter((key) => !key.startsWith('common.language.'))
@@ -8,6 +8,7 @@
8
8
  "common.action.new": "新規",
9
9
  "common.action.open_in_new_window": "新しいウィンドウが開きます",
10
10
  "common.action.save": "保存",
11
+ "common.action.view": "表示",
11
12
  "common.field.language": "言語",
12
13
  "common.language.en-US": "英語",
13
14
  "common.language.zh-CN": "簡体字中国語",
@@ -8,6 +8,7 @@
8
8
  "common.action.new": "新建",
9
9
  "common.action.open_in_new_window": "新窗口打开",
10
10
  "common.action.save": "保存",
11
+ "common.action.view": "查看",
11
12
  "common.field.language": "语言",
12
13
  "common.language.en-US": "English",
13
14
  "common.language.zh-CN": "简体中文",
@@ -8,6 +8,7 @@
8
8
  "common.action.new": "新建",
9
9
  "common.action.open_in_new_window": "新視窗開啟",
10
10
  "common.action.save": "儲存",
11
+ "common.action.view": "檢視",
11
12
  "common.field.language": "語言",
12
13
  "common.language.en-US": "English",
13
14
  "common.language.zh-CN": "簡體中文",
@@ -191,14 +191,30 @@ export interface UnbindOauthAccountRequest {
191
191
  export interface OauthProvider {
192
192
  /** 登录方式标识 */
193
193
  provider: string;
194
+ /** 登录方式名称 */
195
+ name: string;
196
+ /** 登录方式提示语 */
197
+ description: string;
198
+ /** 图标键或图片地址 */
199
+ icon: string;
200
+ /** Provider个性化配置JSON对象 */
201
+ config: { [key: string]: any } | undefined;
194
202
  }
195
203
 
196
204
  /** 个人中心三方账号绑定信息 */
197
205
  export interface OauthBinding {
198
206
  /** 登录方式标识 */
199
207
  provider: string;
208
+ /** 登录方式名称 */
209
+ name: string;
210
+ /** 登录方式提示语 */
211
+ description: string;
200
212
  /** 是否已绑定 */
201
213
  bound: boolean;
214
+ /** 图标键或图片地址 */
215
+ icon: string;
216
+ /** Provider个性化配置JSON对象 */
217
+ config: { [key: string]: any } | undefined;
202
218
  }
203
219
 
204
220
  /** Base三方登录公共服务 */
@@ -0,0 +1,80 @@
1
+ // Code generated by protoc-gen-ts_proto. DO NOT EDIT.
2
+ // versions:
3
+ // protoc-gen-ts_proto v2.11.8
4
+ // protoc unknown
5
+ // source: google/protobuf/struct.proto
6
+
7
+ /* eslint-disable */
8
+
9
+ /**
10
+ * `NullValue` is a singleton enumeration to represent the null value for the
11
+ * `Value` type union.
12
+ *
13
+ * The JSON representation for `NullValue` is JSON `null`.
14
+ */
15
+ export enum NullValue {
16
+ /** NULL_VALUE - Null value. */
17
+ NULL_VALUE = 0,
18
+ }
19
+
20
+ /**
21
+ * `Struct` represents a structured data value, consisting of fields
22
+ * which map to dynamically typed values. In some languages, `Struct`
23
+ * might be supported by a native representation. For example, in
24
+ * scripting languages like JS a struct is represented as an
25
+ * object. The details of that representation are described together
26
+ * with the proto support for the language.
27
+ *
28
+ * The JSON representation for `Struct` is JSON object.
29
+ */
30
+ export interface Struct {
31
+ /** Unordered map of dynamically typed values. */
32
+ fields: Map<string, any | undefined>;
33
+ }
34
+
35
+ export interface Struct_FieldsEntry {
36
+ key: string;
37
+ value: any | undefined;
38
+ }
39
+
40
+ /**
41
+ * `Value` represents a dynamically typed value which can be either
42
+ * null, a number, a string, a boolean, a recursive struct value, or a
43
+ * list of values. A producer of value is expected to set one of these
44
+ * variants. Absence of any variant indicates an error.
45
+ *
46
+ * The JSON representation for `Value` is JSON value.
47
+ */
48
+ export interface Value {
49
+ /** The kind of value. */
50
+ kind:
51
+ | //
52
+ /** Represents a null value. */
53
+ { $case: "null_value"; null_value: NullValue }
54
+ | //
55
+ /** Represents a double value. */
56
+ { $case: "number_value"; number_value: number }
57
+ | //
58
+ /** Represents a string value. */
59
+ { $case: "string_value"; string_value: string }
60
+ | //
61
+ /** Represents a boolean value. */
62
+ { $case: "bool_value"; bool_value: boolean }
63
+ | //
64
+ /** Represents a structured value. */
65
+ { $case: "struct_value"; struct_value: { [key: string]: any } | undefined }
66
+ | //
67
+ /** Represents a repeated `Value`. */
68
+ { $case: "list_value"; list_value: Array<any> | undefined }
69
+ | undefined;
70
+ }
71
+
72
+ /**
73
+ * `ListValue` is a wrapper around a repeated field of values.
74
+ *
75
+ * The JSON representation for `ListValue` is JSON array.
76
+ */
77
+ export interface ListValue {
78
+ /** Repeated field of dynamically typed values. */
79
+ values: any[];
80
+ }
@@ -0,0 +1,40 @@
1
+ type RunnerLocale = 'zh-CN' | 'en-US'
2
+
3
+ const messages: Record<RunnerLocale, Record<string, string>> = {
4
+ 'zh-CN': {
5
+ https_certificate_missing: 'VITE_APP_HTTPS 已开启,但未找到证书文件,请先在仓库根目录运行 scripts/generate-dev-cert.sh;期望路径:{keyPath} 和 {certPath}',
6
+ project_name: '通用应用',
7
+ unsupported_type: '不支持的 Taro 类型:{value}',
8
+ unknown_argument: '未知参数:{argument}',
9
+ type_required: '缺少 --type h5|weapp',
10
+ manifest_missing: '模块清单未导出 moduleManifest:{file}',
11
+ static_import_missing: '模块 {name} 缺少静态 import',
12
+ build_export_missing: '{packageName}/build 未导出 buildModule',
13
+ transaction_mismatch: 'Taro 构建事务目录不匹配:{file}',
14
+ assembly_timeout: '等待 Taro 页面装配锁超时:{file}',
15
+ },
16
+ 'en-US': {
17
+ https_certificate_missing: 'VITE_APP_HTTPS is enabled, but certificate files were not found. Run scripts/generate-dev-cert.sh from the repository root; expected paths: {keyPath} and {certPath}',
18
+ project_name: 'Generic app',
19
+ unsupported_type: 'Unsupported Taro type: {value}',
20
+ unknown_argument: 'Unknown argument: {argument}',
21
+ type_required: 'Missing --type h5|weapp',
22
+ manifest_missing: 'The module manifest does not export moduleManifest: {file}',
23
+ static_import_missing: 'Module {name} is missing a static import',
24
+ build_export_missing: '{packageName}/build does not export buildModule',
25
+ transaction_mismatch: 'Taro build transaction directory does not match: {file}',
26
+ assembly_timeout: 'Timed out waiting for the Taro page assembly lock: {file}',
27
+ },
28
+ }
29
+
30
+ /** 根据环境变量选择 Taro 构建器错误语言。 */
31
+ function resolveRunnerLocale(): RunnerLocale {
32
+ const value = process.env.KRATOS_ADMIN_LOCALE ?? process.env.LC_ALL ?? process.env.LANG ?? ''
33
+ return value.toLowerCase().startsWith('zh') ? 'zh-CN' : 'en-US'
34
+ }
35
+
36
+ /** 渲染 Taro 构建器稳定错误文案。 */
37
+ export function runnerMessage(key: string, params: Record<string, string> = {}): string {
38
+ const template = messages[resolveRunnerLocale()][key] ?? messages['en-US'][key] ?? key
39
+ return template.replace(/\{([A-Za-z0-9_]+)\}/g, (_, name: string) => params[name] ?? `{${name}}`)
40
+ }
package/src/runner.ts CHANGED
@@ -15,6 +15,7 @@ import { pathToFileURL } from 'node:url'
15
15
  import { spawn } from 'node:child_process'
16
16
  import ts from 'typescript'
17
17
  import type { KratosTaroBuildModule } from './build'
18
+ import { runnerMessage } from './runner-messages.js'
18
19
 
19
20
  type PageEntry = {
20
21
  route: string
@@ -158,7 +159,7 @@ function parseArguments(args: string[]): CliOptions {
158
159
  const argument = args[index]
159
160
  if (argument === '--type') {
160
161
  const value = args[++index]
161
- if (value !== 'h5' && value !== 'weapp') throw new Error(`不支持的 Taro 类型:${value}`)
162
+ if (value !== 'h5' && value !== 'weapp') throw new Error(runnerMessage('unsupported_type', { value }))
162
163
  type = value
163
164
  } else if (argument === '--mode') {
164
165
  mode = args[++index] || mode
@@ -169,10 +170,10 @@ function parseArguments(args: string[]): CliOptions {
169
170
  } else if (argument === '--cleanup-only') {
170
171
  cleanupOnly = true
171
172
  } else {
172
- throw new Error(`未知参数:${argument}`)
173
+ throw new Error(runnerMessage('unknown_argument', { argument }))
173
174
  }
174
175
  }
175
- if (!type) throw new Error('缺少 --type h5|weapp')
176
+ if (!type) throw new Error(runnerMessage('type_required'))
176
177
  return { type, mode, watch, prepareOnly, cleanupOnly }
177
178
  }
178
179
 
@@ -217,18 +218,18 @@ async function loadBuildModules(
217
218
  }
218
219
  })
219
220
  })
220
- if (!moduleNames.length) throw new Error(`模块清单未导出 moduleManifest:${manifestFile}`)
221
+ if (!moduleNames.length) throw new Error(runnerMessage('manifest_missing', { file: manifestFile }))
221
222
 
222
223
  const hostRequire = createRequire(resolve(hostRoot, 'package.json'))
223
224
  return Promise.all(
224
225
  moduleNames.map(async (name) => {
225
226
  const packageName = imports.get(name)
226
- if (!packageName) throw new Error(`模块 ${name} 缺少静态 import`)
227
+ if (!packageName) throw new Error(runnerMessage('static_import_missing', { name }))
227
228
  const buildEntry = hostRequire.resolve(`${packageName}/build`)
228
229
  const loaded = (await import(pathToFileURL(buildEntry).href)) as {
229
230
  buildModule?: KratosTaroBuildModule
230
231
  }
231
- if (!loaded.buildModule) throw new Error(`${packageName}/build 未导出 buildModule`)
232
+ if (!loaded.buildModule) throw new Error(runnerMessage('build_export_missing', { packageName }))
232
233
  return loaded.buildModule
233
234
  }),
234
235
  )
@@ -342,7 +343,7 @@ function readBuildTransaction(
342
343
  if (!existsSync(transactionFile)) return
343
344
  const transaction = JSON.parse(readFileSync(transactionFile, 'utf8')) as BuildTransaction
344
345
  if (transaction.inputDir !== inputDir || transaction.appConfigFile !== appConfigFile) {
345
- throw new Error(`Taro 构建事务目录不匹配:${transactionFile}`)
346
+ throw new Error(runnerMessage('transaction_mismatch', { file: transactionFile }))
346
347
  }
347
348
  return transaction
348
349
  }
@@ -455,7 +456,7 @@ function acquirePageAssemblyLock(lockFile: string): void {
455
456
  unlinkSync(lockFile)
456
457
  continue
457
458
  }
458
- if (Date.now() >= deadline) throw new Error(`等待 Taro 页面装配锁超时:${lockFile}`)
459
+ if (Date.now() >= deadline) throw new Error(runnerMessage('assembly_timeout', { file: lockFile }))
459
460
  waitForPageAssembly(PAGE_ASSEMBLY_POLL_INTERVAL_MS)
460
461
  }
461
462
  }