@_tc/template-core 0.2.0 → 0.2.1-bate.1

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.
Files changed (87) hide show
  1. package/AGENT_README.md +5 -2
  2. package/README.md +76 -31
  3. package/cjs/app/controller/project.js +1 -1
  4. package/cjs/app/controller/view.js +1 -1
  5. package/cjs/app/extends/db.js +4 -4
  6. package/cjs/app/middleware.js +1 -1
  7. package/cjs/app/middlewares/error-handle.js +1 -1
  8. package/cjs/app/middlewares/project-handler.js +1 -1
  9. package/cjs/app/utils/i18n.js +1 -0
  10. package/cjs/app/view/entry.tpl +1 -0
  11. package/cjs/config/config.default.js +1 -1
  12. package/cjs/packages/common/i18n/default.js +1 -1
  13. package/cjs/packages/common/i18n/en-US.js +1 -1
  14. package/cjs/packages/common/index.js +1 -1
  15. package/esm/app/controller/project.js +12 -11
  16. package/esm/app/controller/view.js +2 -1
  17. package/esm/app/extends/db.js +64 -60
  18. package/esm/app/middleware.js +1 -1
  19. package/esm/app/middlewares/error-handle.js +16 -15
  20. package/esm/app/middlewares/project-handler.js +8 -7
  21. package/esm/app/utils/i18n.js +36 -0
  22. package/esm/app/view/entry.tpl +1 -0
  23. package/esm/config/config.default.js +2 -1
  24. package/esm/packages/common/i18n/default.js +13 -0
  25. package/esm/packages/common/i18n/en-US.js +13 -0
  26. package/esm/packages/common/index.js +9 -9
  27. package/fe/frontend/apps/dash/Dashboard.js +6 -4
  28. package/fe/frontend/apps/dash/dash.entry.js +2 -0
  29. package/fe/frontend/src/common/generateMenuData.d.ts +4 -1
  30. package/fe/frontend/src/common/generateMenuData.js +3 -3
  31. package/fe/frontend/src/common/language.d.ts +1 -2
  32. package/fe/frontend/src/common/language.js +10 -10
  33. package/fe/frontend/src/common/request.js +3 -1
  34. package/fe/frontend/src/components/AsyncSelect/AsyncSelect.js +10 -2
  35. package/fe/frontend/src/components/BasePage/HeaderView.js +2 -2
  36. package/fe/frontend/src/components/LanguageSwitch/LanguageSwitch.js +13 -9
  37. package/fe/frontend/src/components/ThemeSwitch/ThemeSwitch.js +4 -3
  38. package/fe/frontend/src/defaultPages/NotFoundPage/index.js +4 -3
  39. package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/DetailPanel.js +14 -9
  40. package/fe/frontend/src/defaultPages/SchemaPage/components/CallCom/PopFrom.js +8 -7
  41. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaSearch/index.js +6 -12
  42. package/fe/frontend/src/defaultPages/SchemaPage/components/SchemaTable/index.js +25 -18
  43. package/fe/frontend/src/defaultPages/SchemaPage/index.js +5 -3
  44. package/fe/frontend/src/defaultPages/SidebarSlotPageTmp.js +4 -2
  45. package/fe/frontend/src/hooks/useText.d.ts +3 -0
  46. package/fe/frontend/src/hooks/useText.js +14 -0
  47. package/fe/frontend/src/index.d.ts +1 -0
  48. package/fe/frontend/src/index.js +3 -2
  49. package/fe/frontend/src/language/index.d.ts +0 -2
  50. package/fe/frontend/src/language/index.js +1 -7
  51. package/fe/frontend/src/language/resources.d.ts +2 -0
  52. package/fe/frontend/src/language/resources.js +9 -0
  53. package/fe/packages/common/i18n/default.d.ts +15 -0
  54. package/fe/packages/common/i18n/default.js +16 -0
  55. package/fe/packages/common/i18n/en-US.d.ts +15 -0
  56. package/fe/packages/common/i18n/en-US.js +18 -2
  57. package/fe/packages/common/i18n/index.js +13 -0
  58. package/fe/packages/common/i18n/locales.js +7 -0
  59. package/fe/packages/react/ui/components/Date/Calendar.js +9 -5
  60. package/fe/packages/react/ui/components/Date/LocaleContext.d.ts +22 -1
  61. package/fe/packages/react/ui/components/Date/LocaleContext.js +28 -3
  62. package/fe/packages/react/ui/components/Date/LocaleProvider.d.ts +1 -1
  63. package/fe/packages/react/ui/components/Date/LocaleProvider.js +7 -16
  64. package/fe/packages/react/ui/components/Date/index.js +2 -2
  65. package/fe/packages/react/ui/components/Date/locales.d.ts +2 -0
  66. package/fe/packages/react/ui/components/Date/locales.js +29 -13
  67. package/fe/packages/react/ui/components/TableSearch/TableSearch.js +21 -1
  68. package/fe/packages/react/ui/components/TableSearch/lang.d.ts +2 -0
  69. package/fe/packages/react/ui/components/TableSearch/lang.js +18 -7
  70. package/model/frontend/src/common/language.d.ts +1 -2
  71. package/model/frontend/src/hooks/useText.d.ts +3 -0
  72. package/model/frontend/src/language/index.d.ts +0 -2
  73. package/model/frontend/src/language/resources.d.ts +2 -0
  74. package/model/packages/common/i18n/default.d.ts +15 -0
  75. package/model/packages/common/i18n/en-US.d.ts +15 -0
  76. package/model/packages/react/ui/components/Date/LocaleContext.d.ts +22 -1
  77. package/model/packages/react/ui/components/Date/LocaleProvider.d.ts +1 -1
  78. package/model/packages/react/ui/components/Date/locales.d.ts +2 -0
  79. package/model/packages/react/ui/components/TableSearch/lang.d.ts +2 -0
  80. package/package.json +1 -1
  81. package/types/app/utils/i18n.d.ts +12 -0
  82. package/types/config/config.default.d.ts +6 -0
  83. package/types/packages/common/i18n/default.d.ts +19 -0
  84. package/types/packages/common/i18n/en-US.d.ts +21 -2
  85. package/types/packages/common/i18n/index.d.ts +21 -0
  86. package/types/packages/common/i18n/locales.d.ts +10 -0
  87. package/types/packages/common/i18n/types.d.ts +40 -0
@@ -1,141 +1,145 @@
1
1
  import { __require as e } from "../../_virtual/_rolldown/runtime.js";
2
- import { mkdirSync as t } from "node:fs";
3
- import { dirname as n, isAbsolute as r, resolve as i } from "node:path";
2
+ import { createI18nError as t } from "../utils/i18n.js";
3
+ import { mkdirSync as n } from "node:fs";
4
+ import { dirname as r, isAbsolute as i, resolve as a } from "node:path";
4
5
  //#region app/extends/db.ts
5
- var a = "framework", o = ".template-core/template-core.sqlite";
6
- function s(e) {
7
- let r = u(e), i, a = !1, o = 0, s = () => (x(a), i || (t(n(r), { recursive: !0 }), i = c(r), l(i)), i), d = {
8
- dbPath: r,
6
+ var o = "framework", s = ".template-core/template-core.sqlite";
7
+ function c(e) {
8
+ let t = d(e), i, a = !1, o = 0, s = () => (S(a), i || (n(r(t), { recursive: !0 }), i = l(t), u(i)), i), c = {
9
+ dbPath: t,
9
10
  getDBConnection: s,
10
11
  execDB: (e) => {
11
12
  s().exec(e);
12
13
  },
13
14
  runDB: (e, t) => {
14
- let n = s().prepare(e).run(...p(t));
15
+ let n = s().prepare(e).run(...m(t));
15
16
  return {
16
17
  changes: Number(n.changes ?? 0),
17
18
  lastInsertRowid: n.lastInsertRowid ?? 0
18
19
  };
19
20
  },
20
- queryDB: (e, t) => s().prepare(e).all(...p(t)),
21
- getDBFirst: (e, t) => s().prepare(e).get(...p(t)),
21
+ queryDB: (e, t) => s().prepare(e).all(...m(t)),
22
+ getDBFirst: (e, t) => s().prepare(e).get(...m(t)),
22
23
  transactionDB: (e) => {
23
24
  let t = s(), n = `tc_savepoint_${o}`, r = o === 0;
24
25
  t.exec(r ? "BEGIN IMMEDIATE" : `SAVEPOINT ${n}`), o += 1;
25
26
  try {
26
- let i = e(d);
27
+ let i = e(c);
27
28
  return --o, t.exec(r ? "COMMIT" : `RELEASE SAVEPOINT ${n}`), i;
28
29
  } catch (e) {
29
30
  throw --o, t.exec(r ? "ROLLBACK" : `ROLLBACK TO SAVEPOINT ${n}`), r || t.exec(`RELEASE SAVEPOINT ${n}`), e;
30
31
  }
31
32
  },
32
- getDBData: (e, t) => d.getDBDataRecord(e, t)?.value,
33
+ getDBData: (e, t) => c.getDBDataRecord(e, t)?.value,
33
34
  getDBDataRecord: (e, t) => {
34
- let n = d.getDBFirst("SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [m(t?.namespace), h(e)]);
35
- return n ? b(n) : void 0;
35
+ let n = c.getDBFirst("SELECT namespace, data_key, data_value, created_at, updated_at FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [h(t?.namespace), g(e)]);
36
+ return n ? x(n) : void 0;
36
37
  },
37
38
  setDBData: (e, t, n) => {
38
39
  let r = (/* @__PURE__ */ new Date()).toISOString();
39
- return d.runDB("INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(namespace, data_key) DO UPDATE SET\n data_value = excluded.data_value,\n updated_at = excluded.updated_at", [
40
- m(n?.namespace),
41
- h(e),
42
- v(t),
40
+ return c.runDB("INSERT INTO tc_framework_data (namespace, data_key, data_value, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(namespace, data_key) DO UPDATE SET\n data_value = excluded.data_value,\n updated_at = excluded.updated_at", [
41
+ h(n?.namespace),
42
+ g(e),
43
+ y(t),
43
44
  r,
44
45
  r
45
46
  ]);
46
47
  },
47
- hasDBData: (e, t) => !!d.getDBFirst("SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [m(t?.namespace), h(e)]),
48
- deleteDBData: (e, t) => d.runDB("DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?", [m(t?.namespace), h(e)]).changes > 0,
48
+ hasDBData: (e, t) => !!c.getDBFirst("SELECT 1 AS exists_value FROM tc_framework_data WHERE namespace = ? AND data_key = ? LIMIT 1", [h(t?.namespace), g(e)]),
49
+ deleteDBData: (e, t) => c.runDB("DELETE FROM tc_framework_data WHERE namespace = ? AND data_key = ?", [h(t?.namespace), g(e)]).changes > 0,
49
50
  listDBData: (e) => {
50
- let t = g(e?.limit), n = _(e?.offset);
51
- return d.queryDB("SELECT namespace, data_key, data_value, created_at, updated_at\n FROM tc_framework_data\n WHERE namespace = ?\n ORDER BY updated_at DESC, data_key ASC\n LIMIT ? OFFSET ?", [
52
- m(e?.namespace),
51
+ let t = _(e?.limit), n = v(e?.offset);
52
+ return c.queryDB("SELECT namespace, data_key, data_value, created_at, updated_at\n FROM tc_framework_data\n WHERE namespace = ?\n ORDER BY updated_at DESC, data_key ASC\n LIMIT ? OFFSET ?", [
53
+ h(e?.namespace),
53
54
  t,
54
55
  n
55
- ]).map((e) => b(e));
56
+ ]).map((e) => x(e));
56
57
  },
57
58
  countDBData: (e) => {
58
- let t = d.getDBFirst("SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?", [m(e?.namespace)]);
59
+ let t = c.getDBFirst("SELECT COUNT(1) AS count_value FROM tc_framework_data WHERE namespace = ?", [h(e?.namespace)]);
59
60
  return Number(t?.count_value ?? 0);
60
61
  },
61
- clearDBData: (e) => d.runDB("DELETE FROM tc_framework_data WHERE namespace = ?", [m(e?.namespace)]).changes,
62
+ clearDBData: (e) => c.runDB("DELETE FROM tc_framework_data WHERE namespace = ?", [h(e?.namespace)]).changes,
62
63
  closeDB: () => {
63
64
  a ||= (i?.close(), !0);
64
65
  }
65
66
  };
66
- return d;
67
+ return c;
67
68
  }
68
- function c(t) {
69
- let n = "node:sqlite", r;
69
+ function l(n) {
70
+ let r = "node:sqlite", i;
70
71
  try {
71
- r = e(n);
72
+ i = e(r);
72
73
  } catch (e) {
73
- throw Error(`[db] 默认数据库依赖 Node.js 内置 ${n},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。${S(e)}`);
74
+ throw t("server.errors.dbNodeSqliteUnavailable", {
75
+ sqliteSpecifier: r,
76
+ cause: C(e)
77
+ });
74
78
  }
75
- if (!r.DatabaseSync) throw Error(`[db] ${n} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。`);
76
- return new r.DatabaseSync(t);
77
- }
78
- function l(e) {
79
- e.exec("\n CREATE TABLE IF NOT EXISTS tc_framework_data (\n namespace TEXT NOT NULL,\n data_key TEXT NOT NULL,\n data_value TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (namespace, data_key)\n );\n CREATE INDEX IF NOT EXISTS idx_tc_framework_data_namespace_updated_at\n ON tc_framework_data (namespace, updated_at);\n ");
79
+ if (!i.DatabaseSync) throw t("server.errors.dbDatabaseSyncUnavailable", { sqliteSpecifier: r });
80
+ return new i.DatabaseSync(n);
80
81
  }
81
82
  function u(e) {
82
- let t = d(e), n = typeof t == "string" ? t : t?.path ?? t?.filename ?? t?.sqlitePath ?? f(t?.sqlite);
83
- return n ? r(n) ? n : i(e.baseDir, n) : i(e.baseDir, o);
83
+ e.exec("\n CREATE TABLE IF NOT EXISTS tc_framework_data (\n namespace TEXT NOT NULL,\n data_key TEXT NOT NULL,\n data_value TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (namespace, data_key)\n );\n CREATE INDEX IF NOT EXISTS idx_tc_framework_data_namespace_updated_at\n ON tc_framework_data (namespace, updated_at);\n ");
84
84
  }
85
85
  function d(e) {
86
+ let t = f(e), n = typeof t == "string" ? t : t?.path ?? t?.filename ?? t?.sqlitePath ?? p(t?.sqlite);
87
+ return n ? i(n) ? n : a(e.baseDir, n) : a(e.baseDir, s);
88
+ }
89
+ function f(e) {
86
90
  let t = e.config;
87
91
  return t.db ?? (t.sqlite ? { sqlite: t.sqlite } : void 0);
88
92
  }
89
- function f(e) {
93
+ function p(e) {
90
94
  if (e) return typeof e == "string" ? e : e.path ?? e.filename;
91
95
  }
92
- function p(e) {
96
+ function m(e) {
93
97
  return e ? Array.isArray(e) ? e : [e] : [];
94
98
  }
95
- function m(e = a) {
96
- let t = e.trim();
97
- if (!t) throw Error("[db] namespace 不能为空");
98
- return t;
99
+ function h(e = o) {
100
+ let n = e.trim();
101
+ if (!n) throw t("server.errors.dbNamespaceRequired");
102
+ return n;
99
103
  }
100
- function h(e) {
101
- let t = e.trim();
102
- if (!t) throw Error("[db] key 不能为空");
103
- return t;
104
+ function g(e) {
105
+ let n = e.trim();
106
+ if (!n) throw t("server.errors.dbKeyRequired");
107
+ return n;
104
108
  }
105
- function g(e = 100) {
106
- if (!Number.isSafeInteger(e) || e <= 0) throw Error("[db] limit 必须是大于 0 的整数");
109
+ function _(e = 100) {
110
+ if (!Number.isSafeInteger(e) || e <= 0) throw t("server.errors.dbLimitInvalid");
107
111
  return e;
108
112
  }
109
- function _(e = 0) {
110
- if (!Number.isSafeInteger(e) || e < 0) throw Error("[db] offset 必须是大于等于 0 的整数");
113
+ function v(e = 0) {
114
+ if (!Number.isSafeInteger(e) || e < 0) throw t("server.errors.dbOffsetInvalid");
111
115
  return e;
112
116
  }
113
- function v(e) {
117
+ function y(e) {
114
118
  try {
115
119
  let t = JSON.stringify(e);
116
120
  if (t === void 0) throw Error("value is not JSON serializable");
117
121
  return t;
118
122
  } catch (e) {
119
- throw Error(`[db] value 必须可以被 JSON.stringify 序列化。${S(e)}`);
123
+ throw t("server.errors.dbValueNotSerializable", { cause: C(e) });
120
124
  }
121
125
  }
122
- function y(e) {
126
+ function b(e) {
123
127
  return JSON.parse(e);
124
128
  }
125
- function b(e) {
129
+ function x(e) {
126
130
  return {
127
131
  key: e.data_key,
128
- value: y(e.data_value),
132
+ value: b(e.data_value),
129
133
  namespace: e.namespace,
130
134
  createdAt: e.created_at,
131
135
  updatedAt: e.updated_at
132
136
  };
133
137
  }
134
- function x(e) {
135
- if (e) throw Error("[db] SQLite 数据库连接已关闭");
136
- }
137
138
  function S(e) {
139
+ if (e) throw t("server.errors.dbClosed");
140
+ }
141
+ function C(e) {
138
142
  return e instanceof Error && e.message ? ` Cause: ${e.message}` : "";
139
143
  }
140
144
  //#endregion
141
- export { s as default };
145
+ export { c as default };
@@ -15,7 +15,7 @@ var r = t({
15
15
  setHeaders(e) {
16
16
  e.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate"), e.setHeader("Pragma", "no-cache"), e.setHeader("Expires", "0");
17
17
  }
18
- } : { maxage: 365 * 24 * 60 * 60 * 1e3 };
18
+ } : { maxage: t.config.resourceCacheTimeMs ?? 300 * 1e3 };
19
19
  t.use(t.middlewares.errorHandle), t.use(e({ threshold: 2048 })), t.publicsPath.forEach((e) => t.use(n(e, i))), t.use(r), t.use(t.middlewares.requestParameterParsing), t.use(t.middlewares.projectHandler), !t.envs.isLocal() && t.use(t.middlewares.apiSignVerify), t.use(t.middlewares.apiParamsVerify);
20
20
  };
21
21
  //#endregion
@@ -1,24 +1,25 @@
1
+ import { getRequestErrorMessage as e, requestT as t } from "../utils/i18n.js";
1
2
  //#region app/middlewares/error-handle.ts
2
- var e = {}, t = (t) => async (n, r) => {
3
+ var n = {}, r = (r) => async (i, a) => {
3
4
  try {
4
- await r();
5
- } catch (r) {
6
- let { status: i = 200, message: a, detail: o, code: s = 5e4, returnError: c } = r;
7
- if (t.extends.logger?.info(`error info -> ${JSON.stringify(r)}`), t.extends.logger?.error("-- [excption] --", r), t.extends.logger?.error("-- [excption] info --", i, a, o), a?.includes("template not found")) {
8
- let r = n.path ?? n.req.url ?? n.url;
9
- if (e[r] === void 0 ? e[r] = 0 : e[r] += 1, e[r] < t.config.notFoundRedirectCount) {
10
- n.status = 302, n.redirect(t.options?.homePage ?? "/");
5
+ await a();
6
+ } catch (a) {
7
+ let o = a, { status: s = 200, message: c, detail: l, code: u = 5e4, returnError: d } = o, f = e(i, o, c);
8
+ if (r.extends.logger?.info(`error info -> ${JSON.stringify(a)}`), r.extends.logger?.error("-- [excption] --", a), r.extends.logger?.error("-- [excption] info --", s, c, l), c?.includes("template not found")) {
9
+ let e = i.path ?? i.req.url ?? i.url;
10
+ if (n[e] === void 0 ? n[e] = 0 : n[e] += 1, n[e] < r.config.notFoundRedirectCount) {
11
+ i.status = 302, i.redirect(r.options?.homePage ?? "/");
11
12
  return;
12
- } else e[r] = 0;
13
+ } else n[e] = 0;
13
14
  }
14
- c ? (n.status = i, n.body = {
15
- code: s,
16
- message: a
17
- }) : (n.status = 200, n.body = {
15
+ d ? (i.status = s, i.body = {
16
+ code: u,
17
+ message: f
18
+ }) : (i.status = 200, i.body = {
18
19
  code: 5e4,
19
- message: "网络错误"
20
+ message: t(i, "server.errors.network")
20
21
  });
21
22
  }
22
23
  };
23
24
  //#endregion
24
- export { t as default };
25
+ export { r as default };
@@ -1,15 +1,16 @@
1
+ import { requestT as e } from "../utils/i18n.js";
1
2
  //#region app/middlewares/project-handler.ts
2
- var e = (e) => async (t, n) => {
3
- let r = t.headers.projk, { path: i } = t;
4
- if (i.indexOf(`${e.options.apiPrefix}/proj/`) !== -1 && (!r || ["undefined", "null"].includes(r))) {
5
- t.status = 200, t.body = {
3
+ var t = (t) => async (n, r) => {
4
+ let i = n.headers.projk, { path: a } = n;
5
+ if (a.indexOf(`${t.options.apiPrefix}/proj/`) !== -1 && (!i || ["undefined", "null"].includes(i))) {
6
+ n.status = 200, n.body = {
6
7
  code: 110,
7
8
  data: null,
8
- message: "请求不合法"
9
+ message: e(n, "server.errors.invalidRequest")
9
10
  };
10
11
  return;
11
12
  }
12
- t.extInfo = { key: r }, await n();
13
+ n.extInfo = { key: i }, await r();
13
14
  };
14
15
  //#endregion
15
- export { e as default };
16
+ export { t as default };
@@ -0,0 +1,36 @@
1
+ import { i18n as e, i18nStore as t } from "../../packages/common/i18n/index.js";
2
+ //#region app/utils/i18n.ts
3
+ var n = "x-tc-language", r = "en-US", i = [
4
+ n,
5
+ "tc_language",
6
+ "tc-language",
7
+ "language",
8
+ "lang",
9
+ "locale"
10
+ ], a = (e) => Array.isArray(e) ? e[0] : e, o = (e, t) => a(e[t.toLowerCase()]), s = (e) => e ? e.split(",").map((e) => e.trim().split(";")[0]?.trim()).filter((e) => !!e) : [], c = (e) => {
11
+ if (!e) return r;
12
+ let n = Object.keys(t.getState().resources), i = e.trim().toLowerCase(), a = n.find((e) => e.toLowerCase() === i);
13
+ if (a) return a;
14
+ let o = i.split("-")[0];
15
+ return n.find((e) => e.toLowerCase().split("-")[0] === o) ?? r;
16
+ }, l = (e) => {
17
+ for (let t of i) {
18
+ let n = o(e.headers, t);
19
+ if (n) return c(n);
20
+ }
21
+ let t = s(o(e.headers, "accept-language"));
22
+ for (let e of t) {
23
+ let t = c(e);
24
+ if (t) return t;
25
+ }
26
+ return r;
27
+ }, u = (t, n, i, a) => e(n, i, {
28
+ ...a,
29
+ language: a?.language ?? l(t),
30
+ fallbackLanguage: a?.fallbackLanguage ?? r
31
+ }), d = (e, t, n) => {
32
+ let r = Error(n ?? e);
33
+ return r.i18nKey = e, r.i18nData = t, r;
34
+ }, f = (e, t, n) => t.i18nKey ? u(e, t.i18nKey, t.i18nData, { fallback: n ?? t.message }) : n ?? t.message;
35
+ //#endregion
36
+ export { n as LANGUAGE_HEADER_KEY, d as createI18nError, f as getRequestErrorMessage, l as getRequestLanguage, c as normalizeI18nLanguage, u as requestT };
@@ -10,6 +10,7 @@
10
10
 
11
11
  <script id="input">
12
12
  window['_basePath'] = {{basePath | safe}}
13
+ window['_FEBasePage'] = {{FEBasePage | safe}}
13
14
  window['_projKey'] = {{projKeyJson | safe}}
14
15
  window['_signKey'] = {{signKey | safe}}
15
16
  const s = document.getElementById('input')
@@ -7,7 +7,8 @@ var e = {
7
7
  ATKey: "Authorization",
8
8
  RTKey: "RT"
9
9
  },
10
- notFoundRedirectCount: 5
10
+ notFoundRedirectCount: 5,
11
+ resourceCacheTimeMs: 300 * 1e3
11
12
  };
12
13
  //#endregion
13
14
  export { e as default };
@@ -8,6 +8,19 @@ var e = {
8
8
  submit: "提交",
9
9
  reset: "重置"
10
10
  },
11
+ server: { errors: {
12
+ network: "网络错误",
13
+ invalidRequest: "请求不合法",
14
+ getProjectFailed: "获取项目异常",
15
+ dbNodeSqliteUnavailable: "[db] 默认数据库依赖 Node.js 内置 {sqliteSpecifier},当前运行环境不可用。请升级 Node.js,或在业务项目覆盖 app/extends/db.ts。{cause}",
16
+ dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} 未提供 DatabaseSync,无法初始化默认 SQLite 数据库。",
17
+ dbNamespaceRequired: "[db] namespace 不能为空",
18
+ dbKeyRequired: "[db] key 不能为空",
19
+ dbLimitInvalid: "[db] limit 必须是大于 0 的整数",
20
+ dbOffsetInvalid: "[db] offset 必须是大于等于 0 的整数",
21
+ dbValueNotSerializable: "[db] value 必须可以被 JSON.stringify 序列化。{cause}",
22
+ dbClosed: "[db] SQLite 数据库连接已关闭"
23
+ } },
11
24
  components: {
12
25
  breadcrumb: { close: "关闭" },
13
26
  confirmDialog: {
@@ -8,6 +8,19 @@ var e = {
8
8
  submit: "Submit",
9
9
  reset: "Reset"
10
10
  },
11
+ server: { errors: {
12
+ network: "Network error",
13
+ invalidRequest: "Invalid request",
14
+ getProjectFailed: "Failed to get project",
15
+ dbNodeSqliteUnavailable: "[db] The default database depends on Node.js built-in {sqliteSpecifier}, which is unavailable in the current runtime. Upgrade Node.js or override app/extends/db.ts in the business project.{cause}",
16
+ dbDatabaseSyncUnavailable: "[db] {sqliteSpecifier} does not provide DatabaseSync, so the default SQLite database cannot be initialized.",
17
+ dbNamespaceRequired: "[db] namespace cannot be empty",
18
+ dbKeyRequired: "[db] key cannot be empty",
19
+ dbLimitInvalid: "[db] limit must be an integer greater than 0",
20
+ dbOffsetInvalid: "[db] offset must be an integer greater than or equal to 0",
21
+ dbValueNotSerializable: "[db] value must be serializable by JSON.stringify.{cause}",
22
+ dbClosed: "[db] SQLite database connection is closed"
23
+ } },
11
24
  components: {
12
25
  breadcrumb: { close: "Close" },
13
26
  confirmDialog: {
@@ -1,15 +1,15 @@
1
- import { isBoolean as e, isFunction as t, isNil as n, isNonNullable as r, isNumber as i, isPlainObject as a, isString as o } from "./guards/index.js";
2
- import { chunk as s, compact as c, groupBy as l, toArray as u, uniqueBy as d } from "./array/index.js";
3
- import { LRUCache as f } from "./cache/LRUCache.js";
4
- import { FetchAxios as p, axios as m, createInstance as h } from "./http/index.js";
5
- import { defaultLanguageResources as g } from "./i18n/default.js";
6
- import { defaultEnglishResources as _ } from "./i18n/en-US.js";
7
- import { defaultLanguage as v, languageLocalKey as y, translations as b } from "./i18n/locales.js";
8
- import { getI18nPathValue as x, getLanguage as S, i18n as C, i18nStore as w, interpolateI18nMessage as T, isPlainI18nDictionary as E, mergeI18nDictionary as D, mergeI18nResources as O, t as k, translate as A } from "./i18n/index.js";
1
+ import { defaultLanguageResources as e } from "./i18n/default.js";
2
+ import { defaultEnglishResources as t } from "./i18n/en-US.js";
3
+ import { defaultLanguage as n, languageLocalKey as r, translations as i } from "./i18n/locales.js";
4
+ import { getI18nPathValue as a, getLanguage as o, i18n as s, i18nStore as c, interpolateI18nMessage as l, isPlainI18nDictionary as u, mergeI18nDictionary as d, mergeI18nResources as f, t as p, translate as m } from "./i18n/index.js";
5
+ import { isBoolean as h, isFunction as g, isNil as _, isNonNullable as v, isNumber as y, isPlainObject as b, isString as x } from "./guards/index.js";
6
+ import { chunk as S, compact as C, groupBy as w, toArray as T, uniqueBy as E } from "./array/index.js";
7
+ import { LRUCache as D } from "./cache/LRUCache.js";
8
+ import { FetchAxios as O, axios as k, createInstance as A } from "./http/index.js";
9
9
  import { ANSI_RESET as j, ansiColors as M, colorLog as N, colorize as P, joinColorized as F, logColor as I, logColorized as L, logGreen as R, logJoinColorized as z, logPink as B, logRed as V, logWhite as H, logYellow as U } from "./log/index.js";
10
10
  import { clamp as W, toFiniteNumber as G } from "./number/index.js";
11
11
  import { filterEmpty as K, filtereEmpty as q } from "./object/filterEmpty.js";
12
12
  import { mapValues as J, omit as Y, pick as X } from "./object/index.js";
13
13
  import { clearRafTimer as Z, rafClearInterval as Q, rafClearTimeout as $, rafSetInterval as ee, rafSetTimeout as te } from "./rafTimer.js";
14
14
  import { capitalize as ne, isBlank as re, joinStr as ie, kebabCase as ae } from "./string/index.js";
15
- export { j as ANSI_RESET, p as FetchAxios, f as LRUCache, M as ansiColors, m as axios, ne as capitalize, s as chunk, W as clamp, Z as clearRafTimer, N as colorLog, P as colorize, c as compact, h as createInstance, _ as defaultEnglishResources, v as defaultLanguage, g as defaultLanguageResources, K as filterEmpty, q as filtereEmpty, x as getI18nPathValue, S as getLanguage, l as groupBy, C as i18n, w as i18nStore, T as interpolateI18nMessage, re as isBlank, e as isBoolean, t as isFunction, n as isNil, r as isNonNullable, i as isNumber, E as isPlainI18nDictionary, a as isPlainObject, o as isString, F as joinColorized, ie as joinStr, ae as kebabCase, y as languageLocalKey, I as logColor, L as logColorized, R as logGreen, z as logJoinColorized, B as logPink, V as logRed, H as logWhite, U as logYellow, J as mapValues, D as mergeI18nDictionary, O as mergeI18nResources, Y as omit, X as pick, Q as rafClearInterval, $ as rafClearTimeout, ee as rafSetInterval, te as rafSetTimeout, k as t, u as toArray, G as toFiniteNumber, A as translate, b as translations, d as uniqueBy };
15
+ export { j as ANSI_RESET, O as FetchAxios, D as LRUCache, M as ansiColors, k as axios, ne as capitalize, S as chunk, W as clamp, Z as clearRafTimer, N as colorLog, P as colorize, C as compact, A as createInstance, t as defaultEnglishResources, n as defaultLanguage, e as defaultLanguageResources, K as filterEmpty, q as filtereEmpty, a as getI18nPathValue, o as getLanguage, w as groupBy, s as i18n, c as i18nStore, l as interpolateI18nMessage, re as isBlank, h as isBoolean, g as isFunction, _ as isNil, v as isNonNullable, y as isNumber, u as isPlainI18nDictionary, b as isPlainObject, x as isString, F as joinColorized, ie as joinStr, ae as kebabCase, r as languageLocalKey, I as logColor, L as logColorized, R as logGreen, z as logJoinColorized, B as logPink, V as logRed, H as logWhite, U as logYellow, J as mapValues, d as mergeI18nDictionary, f as mergeI18nResources, Y as omit, X as pick, Q as rafClearInterval, $ as rafClearTimeout, ee as rafSetInterval, te as rafSetTimeout, p as t, T as toArray, G as toFiniteNumber, m as translate, i as translations, E as uniqueBy };
@@ -1,10 +1,10 @@
1
1
  import { getAuthToken } from "../../src/common/auth/index.js";
2
- import { getText } from "../../src/common/language.js";
3
2
  import { generateMenuItemData } from "../../src/common/generateMenuData.js";
4
3
  import { Menu } from "../../../packages/react/ui/components/Menu/Menu.js";
5
4
  import "../../../packages/react/ui/components/index.js";
6
5
  import { useModeStore } from "../../src/stores/mode.js";
7
6
  import { findMenuItem, leftSidebarBasePath } from "../../src/common/menu.js";
7
+ import { useText } from "../../src/hooks/useText.js";
8
8
  import HeaderView from "../../src/components/BasePage/HeaderView.js";
9
9
  import useRouterParams from "../../src/hooks/useRouterParams.js";
10
10
  import useInit from "../../../packages/react/hooks/useInit.js";
@@ -83,6 +83,7 @@ var getRenderableHomePage = (projectInfo) => {
83
83
  var Dashboard = () => {
84
84
  const { initModeData, initData, projectInfo } = useModeStore();
85
85
  const HeaderUserArea = dashComponents["HeaderView.userArea"];
86
+ const text = useText();
86
87
  useInit(() => {
87
88
  !initData && initModeData();
88
89
  });
@@ -94,7 +95,7 @@ var Dashboard = () => {
94
95
  if (initData && projectInfo?.menuLayout === "top") return /* @__PURE__ */ jsx(Menu, {
95
96
  className: " w-full",
96
97
  mode: "top",
97
- items: generateMenuItemData(projectInfo.menu),
98
+ items: generateMenuItemData(projectInfo.menu, text),
98
99
  selectedKey: SK,
99
100
  onSelect: (e) => {
100
101
  uSK(e);
@@ -107,7 +108,8 @@ var Dashboard = () => {
107
108
  initData,
108
109
  projectInfo,
109
110
  SK,
110
- nav
111
+ nav,
112
+ text
111
113
  ]);
112
114
  useEffect(() => {
113
115
  if (initData && projectInfo) {
@@ -165,7 +167,7 @@ var Dashboard = () => {
165
167
  const getTitle = () => {
166
168
  const title = projectInfo?.desc ?? projectInfo?.name;
167
169
  if (!isInit.current && title) document.title = projectInfo?.name ?? title;
168
- return title ? getText(title) : void 0;
170
+ return title ? text(title) : void 0;
169
171
  };
170
172
  return /* @__PURE__ */ jsxs("div", {
171
173
  className: "dash-main h-screen flex flex-col overflow-hidden bg-theme-bg text-foreground",
@@ -1,3 +1,4 @@
1
+ import { registerFrontendI18nResources } from "../../src/common/language.js";
1
2
  import { QK, leftSidebarBasePath } from "../../src/common/menu.js";
2
3
  import Dashboard from "./Dashboard.js";
3
4
  import { renderImportComponent } from "../../src/common/importComponent.js";
@@ -55,6 +56,7 @@ initApp(({ children }) => /* @__PURE__ */ jsx("div", {
55
56
  }), {
56
57
  routes: getDefaultPageRoutes(),
57
58
  beforeRender: async (context) => {
59
+ await registerFrontendI18nResources();
58
60
  initThemeMode();
59
61
  if (typeof initDash === "function") await initDash(context);
60
62
  }
@@ -1,3 +1,6 @@
1
1
  import type { ProjectInfo } from "../api/baseInfo";
2
2
  import type { MenuItemData } from "../../../packages/react/ui/components/index";
3
- export declare const generateMenuItemData: (data: ProjectInfo["menu"]) => MenuItemData[];
3
+ import { getText } from "./language";
4
+ type TextResolver = typeof getText;
5
+ export declare const generateMenuItemData: (data: ProjectInfo["menu"], text?: TextResolver) => MenuItemData[];
6
+ export {};
@@ -1,11 +1,11 @@
1
1
  import { getText } from "./language.js";
2
2
  //#region frontend/src/common/generateMenuData.ts
3
- var generateMenuItemData = (data) => {
3
+ var generateMenuItemData = (data, text = getText) => {
4
4
  return data.map((m) => {
5
- const children = m.menuType === "group" && m.subMenu.length ? generateMenuItemData(m.subMenu) : void 0;
5
+ const children = m.menuType === "group" && m.subMenu.length ? generateMenuItemData(m.subMenu, text) : void 0;
6
6
  return {
7
7
  key: m.key,
8
- label: getText(m.name),
8
+ label: text(m.name),
9
9
  icon: m.icon,
10
10
  children,
11
11
  minWidth: 100
@@ -1,7 +1,5 @@
1
1
  import type { I18nAddResourcesOptions, I18nDictionary, I18nInterpolationValues, I18nLanguage, I18nResources, I18nSetResourcesOptions, I18nTranslateOptions } from "../../../packages/react/ui/i18n/index";
2
2
  export declare const addLanguageResources: (language: I18nLanguage, messages: I18nDictionary, options?: I18nAddResourcesOptions) => void;
3
- export declare const addResources: (language: I18nLanguage, messages: I18nDictionary, options?: I18nAddResourcesOptions) => void;
4
- export declare const addLanguage: (language: I18nLanguage, messages?: I18nDictionary, options?: I18nAddResourcesOptions) => void;
5
3
  export declare const setLanguage: (language: I18nLanguage) => void;
6
4
  export declare const setFallbackLanguage: (language: I18nLanguage) => void;
7
5
  export declare const setResources: (resources: I18nResources, options?: I18nSetResourcesOptions) => void;
@@ -9,6 +7,7 @@ export declare const getCurrentLanguage: () => string;
9
7
  export declare const getFallbackLanguage: () => string;
10
8
  export declare const getI18nResources: () => Partial<Record<string, I18nDictionary>>;
11
9
  export declare const getSupportedLanguages: () => string[];
10
+ export declare const registerFrontendI18nResources: (resources?: I18nResources) => Promise<void>;
12
11
  export declare const getText: (key: string, fillingData?: I18nInterpolationValues, options?: I18nTranslateOptions) => string;
13
12
  export declare const t: <T = string>(key: string, fillingData?: I18nInterpolationValues, options?: I18nTranslateOptions) => string | T;
14
13
  export type { I18nAddResourcesOptions, I18nDictionary, I18nInterpolationValues, I18nLanguage, I18nResources, I18nSetResourcesOptions, I18nTranslateOptions, };
@@ -1,14 +1,10 @@
1
- import { frontendI18nResources, i18nKeyPrefix } from "../language/index.js";
1
+ import { i18nKeyPrefix } from "../language/index.js";
2
2
  import { i18n, i18nStore } from "../../../packages/common/i18n/index.js";
3
3
  import "../../../packages/react/ui/i18n/index.js";
4
4
  //#region frontend/src/common/language.ts
5
5
  var addLanguageResources = (language, messages, options) => {
6
6
  i18nStore.getState().addResources(language, messages, options);
7
7
  };
8
- var addResources = addLanguageResources;
9
- var addLanguage = (language, messages = {}, options) => {
10
- addLanguageResources(language, messages, options);
11
- };
12
8
  var setLanguage = (language) => {
13
9
  i18nStore.getState().setLanguage(language);
14
10
  };
@@ -22,12 +18,16 @@ var getCurrentLanguage = () => i18nStore.getState().language;
22
18
  var getFallbackLanguage = () => i18nStore.getState().fallbackLanguage;
23
19
  var getI18nResources = () => i18nStore.getState().resources;
24
20
  var getSupportedLanguages = () => Object.keys(getI18nResources());
25
- addLanguageResources("zh-CN", frontendI18nResources["zh-CN"] ?? {});
26
- addLanguageResources("en-US", frontendI18nResources["en-US"] ?? {});
21
+ var registerFrontendI18nResources = async (resources) => {
22
+ const nextResources = resources ?? (await import("../language/resources.js")).frontendI18nResources;
23
+ Object.entries(nextResources).forEach(([language, messages]) => {
24
+ addLanguageResources(language, messages ?? {});
25
+ });
26
+ };
27
27
  var getText = (key, fillingData, options) => {
28
- if (key.includes("$i18n::")) return i18n(key.replace(i18nKeyPrefix, ""), fillingData, options);
29
- return key;
28
+ if (key.startsWith("$i18n::")) return i18n(key.slice(i18nKeyPrefix.length), fillingData, options);
29
+ return i18n(key, fillingData, options);
30
30
  };
31
31
  var t = i18n;
32
32
  //#endregion
33
- export { addLanguage, addLanguageResources, addResources, getCurrentLanguage, getFallbackLanguage, getI18nResources, getSupportedLanguages, getText, setFallbackLanguage, setLanguage, setResources, t };
33
+ export { addLanguageResources, getCurrentLanguage, getFallbackLanguage, getI18nResources, getSupportedLanguages, getText, registerFrontendI18nResources, setFallbackLanguage, setLanguage, setResources, t };
@@ -1,10 +1,11 @@
1
1
  import { API_AUTH_HEADER_KEY, AUTH_HEADER_KEY, clearAuthToken, getApiAuth, getAuthToken } from "./auth/index.js";
2
2
  import { frontendLangKeys } from "../language/index.js";
3
- import { getText } from "./language.js";
3
+ import { getCurrentLanguage, getText } from "./language.js";
4
4
  import { FreezeState, apiFreezerStore } from "../stores/apiFreezer.js";
5
5
  import FetchAxios from "../../../packages/common/http/index.js";
6
6
  import md5 from "md5";
7
7
  //#region frontend/src/common/request.ts
8
+ var LANGUAGE_HEADER_KEY = "x-tc-language";
8
9
  var BASE_URL = "/api";
9
10
  var NumberConcurrentCalls = 4;
10
11
  var isRequestWhitelisted = (api, params) => {
@@ -102,6 +103,7 @@ api.interceptors.request.use(async (config) => {
102
103
  config.headers = {
103
104
  "Content-Type": "application/json",
104
105
  ...config.headers,
106
+ [LANGUAGE_HEADER_KEY]: getCurrentLanguage(),
105
107
  s_t: time + "",
106
108
  s_sign: md5(`${window["_signKey"]}_${time}`),
107
109
  [API_AUTH_HEADER_KEY]: aauto
@@ -1,13 +1,15 @@
1
1
  import { Select } from "../../../../packages/react/ui/components/Select/Select.js";
2
2
  import "../../../../packages/react/ui/index.js";
3
3
  import { request } from "../../common/request.js";
4
+ import { useText } from "../../hooks/useText.js";
4
5
  import { handlingRequestErrors } from "../../common/fetchErrorShow.js";
5
6
  import useExecuteOnce from "../../../../packages/react/hooks/useExecuteOnce.js";
6
- import { useState, useTransition } from "react";
7
+ import { useMemo, useState, useTransition } from "react";
7
8
  import { jsx } from "react/jsx-runtime";
8
9
  //#region frontend/src/components/AsyncSelect/AsyncSelect.tsx
9
10
  var AsyncSelect = (props) => {
10
11
  const { fetchConfig, ...params } = props;
12
+ const text = useText();
11
13
  const [options, setOptions] = useState([]);
12
14
  const [loading, setLoading] = useState(false);
13
15
  const [lzayLoading, startTranstion] = useTransition();
@@ -26,9 +28,15 @@ var AsyncSelect = (props) => {
26
28
  }
27
29
  });
28
30
  }, { executionPhase: "mount" });
31
+ const options_ = useMemo(() => {
32
+ return options.map((i) => {
33
+ i.label = i.searchText = text(i.searchText);
34
+ return i;
35
+ });
36
+ }, [options, text]);
29
37
  return /* @__PURE__ */ jsx(Select, {
30
38
  loading: lzayLoading || loading,
31
- options,
39
+ options: options_,
32
40
  ...params
33
41
  });
34
42
  };
@@ -1,7 +1,7 @@
1
1
  import { frontendLangKeys } from "../../language/index.js";
2
- import { getText } from "../../common/language.js";
3
2
  import { cn } from "../../../../packages/react/ui/lib/utils.js";
4
3
  import "../../../../packages/react/ui/index.js";
4
+ import { useText } from "../../hooks/useText.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Boxes } from "lucide-react";
7
7
  //#region frontend/src/components/BasePage/HeaderView.tsx
@@ -14,7 +14,7 @@ var headerThemeStyle = {
14
14
  var imageLogoPattern = /^(https?:\/\/|data:image\/|\/|\.\/|\.\.\/|.*\.(svg|png|jpe?g|webp|gif)$)/i;
15
15
  var HeaderView = (props) => {
16
16
  const { icon, title, menu, userArea, children } = props ?? defaultProps;
17
- const defaultTitle = getText(frontendLangKeys.appTitle);
17
+ const defaultTitle = useText()(frontendLangKeys.appTitle);
18
18
  const brandLogo = icon ? typeof icon === "string" ? imageLogoPattern.test(icon) ? /* @__PURE__ */ jsx("img", {
19
19
  className: "h-full max-w-[112px] object-contain",
20
20
  src: icon,