@liujitcn/kratos-taro-app-core 0.0.48 → 0.0.50

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
@@ -41,3 +41,5 @@ pnpm check:exports
41
41
  ```
42
42
 
43
43
  构建产物按模式与平台隔离:开发使用 `dist/dev/h5`、`dist/dev/mp-weixin`,生产默认使用 `dist/build/h5`、`dist/build/mp-weixin`。`KRATOS_TARO_OUTPUT_ROOT` 可覆盖默认目录;仓库宿主及 Kratos 配套项目的 H5 生产构建输出到 `backend/data/taro-app`。微信开发者工具默认指向开发目录,发布时导入生产目录。
44
+
45
+ 应用配置加载成功后,core 会将 `i18n_customs` 按 `locale + key` 覆盖已注册的本地文案,并刷新页面翻译。仅覆盖已有 key 的非空文案;未配置或已删除的覆盖项恢复本地默认值,未知语言和未知 key 忽略。切换语言时沿用配置重载流程。
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.48",
10
+ "version": "0.0.50",
11
11
  "type": "module",
12
12
  "files": [
13
13
  "dist",
@@ -5,6 +5,7 @@
5
5
  import Taro from '@tarojs/taro'
6
6
  import { create } from 'zustand'
7
7
  import type { KratosTaroModule } from '../module'
8
+ import type { I18nCustomItem } from '../rpc/base/v1/config'
8
9
  import type { OptionLanguageResponse } from '../rpc/base/v1/language'
9
10
  import {
10
11
  DEFAULT_LOCALE as GENERATED_DEFAULT_LOCALE,
@@ -38,7 +39,9 @@ export interface LocaleStoreState {
38
39
 
39
40
  const DEFAULT_LOCALE: SupportedLocale = GENERATED_DEFAULT_LOCALE
40
41
  const LOCALE_STORAGE_KEY = 'kratos-app:locale'
42
+ const defaultLocaleMessages = new Map<SupportedLocale, LocaleMessages>()
41
43
  const localeMessages = new Map<SupportedLocale, LocaleMessages>()
44
+ const useLocaleMessagesRevision = create<number>(() => 0)
42
45
  const localeChangeHandlers = new Set<() => void | Promise<void>>()
43
46
 
44
47
  /** 响应式语言 Zustand Store。 */
@@ -106,8 +109,8 @@ export function getSupportedLocales(): SupportedLocale[] {
106
109
 
107
110
  /** 注册所有模块贡献的语言包并校验语言键集合。 */
108
111
  export function registerLocaleMessages(modules: KratosTaroModule[]): void {
109
- localeMessages.clear()
110
- SUPPORTED_LOCALES.forEach((locale) => localeMessages.set(locale, {}))
112
+ defaultLocaleMessages.clear()
113
+ SUPPORTED_LOCALES.forEach((locale) => defaultLocaleMessages.set(locale, {}))
111
114
  modules.forEach((module) => {
112
115
  const expectedKeys = requiredLocaleKeys(module.messages?.[DEFAULT_LOCALE] || {})
113
116
  SUPPORTED_LOCALES.forEach((locale) => {
@@ -117,7 +120,7 @@ export function registerLocaleMessages(modules: KratosTaroModule[]): void {
117
120
  if (keys.join('\u0000') !== expectedKeys.join('\u0000')) {
118
121
  throw new Error(`${module.name} 的 ${locale} 语言包键集合不一致`)
119
122
  }
120
- const target = localeMessages.get(locale) as LocaleMessages
123
+ const target = defaultLocaleMessages.get(locale) as LocaleMessages
121
124
  Object.keys(messages).forEach((key) => {
122
125
  if (!isAllowedLocaleKey(module.name, key)) {
123
126
  throw new Error(`${module.name} 的语言键命名空间无效: ${key}`)
@@ -130,6 +133,21 @@ export function registerLocaleMessages(modules: KratosTaroModule[]): void {
130
133
  })
131
134
  })
132
135
  })
136
+ applyCustomLocaleMessages([])
137
+ }
138
+
139
+ /** 按语言和已有 key 覆盖本地文案,每次重新应用以清除已删除的自定义配置。 */
140
+ export function applyCustomLocaleMessages(customs: I18nCustomItem[]): void {
141
+ SUPPORTED_LOCALES.forEach((locale) => {
142
+ const messages = { ...(defaultLocaleMessages.get(locale) ?? {}) }
143
+ customs.forEach((item) => {
144
+ if (parseSupportedLocale(item.locale) !== locale || !item.key || !item.value) return
145
+ if (!Object.prototype.hasOwnProperty.call(messages, item.key)) return
146
+ messages[item.key] = item.value
147
+ })
148
+ localeMessages.set(locale, messages)
149
+ })
150
+ useLocaleMessagesRevision.setState((revision) => revision + 1)
133
151
  }
134
152
 
135
153
  /** 校验公共键和当前业务模块专属的语言键命名空间。 */
@@ -176,6 +194,7 @@ export function t(key: string, params: LocaleParams = {}, locale = getCurrentLoc
176
194
 
177
195
  /** 在 React 页面中使用响应式国际化能力。 */
178
196
  export function useI18n() {
197
+ useLocaleMessagesRevision()
179
198
  const locale = useLocaleStore((state) => state.locale)
180
199
  return {
181
200
  locale,
@@ -40,6 +40,18 @@ export interface GetConfigResponse {
40
40
  configs: ConfigItem[];
41
41
  /** AI 助手是否可用 */
42
42
  ai_enabled: boolean;
43
+ /** 全部语言的自定义国际化覆盖项 */
44
+ i18n_customs: I18nCustomItem[];
45
+ }
46
+
47
+ /** 全部语言的自定义国际化覆盖项。 */
48
+ export interface I18nCustomItem {
49
+ /** 语言区域 */
50
+ locale: string;
51
+ /** 国际化语言键 */
52
+ key: string;
53
+ /** 自定义翻译内容 */
54
+ value: string;
43
55
  }
44
56
 
45
57
  /** Base系统配置公共服务 */
@@ -1,6 +1,6 @@
1
1
  import { create } from 'zustand'
2
2
  import { defConfigService } from '../api/base/v1/config'
3
- import { t } from '../locales'
3
+ import { applyCustomLocaleMessages, t } from '../locales'
4
4
  import { BaseConfigSite } from '../rpc/base/v1/config'
5
5
 
6
6
  const REQUIRED_APP_CONFIGS = [
@@ -36,6 +36,7 @@ export const useSettingStore = create<SettingStoreState>((set, get) => ({
36
36
  set({ aiEnabled: false })
37
37
  return
38
38
  }
39
+ applyCustomLocaleMessages(response.i18n_customs ?? [])
39
40
  const nextData = new Map(response.configs.map((item) => [item.key, item.value]))
40
41
  const missing = REQUIRED_APP_CONFIGS.filter(({ key }) => !nextData.get(key))
41
42
  if (missing.length) {