tang-ui-x 1.1.1 → 1.1.2

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/README.md +1003 -0
  2. package/components/TActionSheet/index.uvue +15 -2
  3. package/components/TCollapse/index.uvue +1 -1
  4. package/components/TCollapse/type.uts +3 -1
  5. package/components/TCollapseItem/index.uvue +22 -26
  6. package/components/TDialog/index.uvue +19 -4
  7. package/components/TEmpty/index.uvue +28 -14
  8. package/components/TForm/index.uvue +30 -9
  9. package/components/TForm/type.uts +4 -0
  10. package/components/TInput/index.uvue +24 -5
  11. package/components/TInput/type.uts +10 -0
  12. package/components/TPicker/index.uvue +26 -6
  13. package/components/TSearchBar/index.uvue +19 -4
  14. package/composables/i18n/error.uts +82 -0
  15. package/composables/i18n/index.uts +188 -0
  16. package/composables/i18n/manager-demo.uts +104 -0
  17. package/composables/i18n/manager.test.uts +182 -0
  18. package/composables/i18n/manager.uts +336 -0
  19. package/composables/i18n/register-demo.uts +125 -0
  20. package/composables/i18n/task22-verification.uts +198 -0
  21. package/composables/i18n/task23-verification.uts +343 -0
  22. package/composables/i18n/task8-demo.uts +93 -0
  23. package/composables/i18n/task8-verification.uts +98 -0
  24. package/composables/i18n/test-task23.uts +9 -0
  25. package/composables/i18n/types.uts +46 -0
  26. package/composables/i18n/useI18n-verification.uts +105 -0
  27. package/composables/i18n/validation-demo.uts +45 -0
  28. package/composables/i18n/validation-test.uts +106 -0
  29. package/composables/useI18n.uts +77 -0
  30. package/index.uts +23 -0
  31. package/locales/cross-platform-verification.uts +510 -0
  32. package/locales/en-US/actionSheet.json +3 -0
  33. package/locales/en-US/common.json +10 -0
  34. package/locales/en-US/dialog.json +5 -0
  35. package/locales/en-US/empty.json +5 -0
  36. package/locales/en-US/errorState.json +5 -0
  37. package/locales/en-US/examplePages.json +1236 -0
  38. package/locales/en-US/examples.json +218 -0
  39. package/locales/en-US/form.json +11 -0
  40. package/locales/en-US/input.json +3 -0
  41. package/locales/en-US/list.json +5 -0
  42. package/locales/en-US/loading.json +3 -0
  43. package/locales/en-US/navBar.json +4 -0
  44. package/locales/en-US/noticeBar.json +3 -0
  45. package/locales/en-US/picker.json +5 -0
  46. package/locales/en-US/searchBar.json +4 -0
  47. package/locales/en-US/textarea.json +3 -0
  48. package/locales/en-US/toast.json +6 -0
  49. package/locales/index.uts +79 -0
  50. package/locales/init-verification.uts +101 -0
  51. package/locales/loader.uts +251 -0
  52. package/locales/run-verification.uts +16 -0
  53. package/locales/zh-CN/actionSheet.json +3 -0
  54. package/locales/zh-CN/common.json +10 -0
  55. package/locales/zh-CN/dialog.json +5 -0
  56. package/locales/zh-CN/empty.json +5 -0
  57. package/locales/zh-CN/errorState.json +5 -0
  58. package/locales/zh-CN/examplePages.json +1236 -0
  59. package/locales/zh-CN/examples.json +218 -0
  60. package/locales/zh-CN/form.json +11 -0
  61. package/locales/zh-CN/input.json +3 -0
  62. package/locales/zh-CN/list.json +5 -0
  63. package/locales/zh-CN/loading.json +3 -0
  64. package/locales/zh-CN/navBar.json +4 -0
  65. package/locales/zh-CN/noticeBar.json +3 -0
  66. package/locales/zh-CN/picker.json +5 -0
  67. package/locales/zh-CN/searchBar.json +4 -0
  68. package/locales/zh-CN/textarea.json +3 -0
  69. package/locales/zh-CN/toast.json +6 -0
  70. package/locales/zh-TW/actionSheet.json +3 -0
  71. package/locales/zh-TW/common.json +8 -0
  72. package/locales/zh-TW/dialog.json +5 -0
  73. package/locales/zh-TW/empty.json +5 -0
  74. package/locales/zh-TW/errorState.json +5 -0
  75. package/locales/zh-TW/examplePages.json +705 -0
  76. package/locales/zh-TW/examples.json +218 -0
  77. package/locales/zh-TW/form.json +11 -0
  78. package/locales/zh-TW/input.json +3 -0
  79. package/locales/zh-TW/list.json +5 -0
  80. package/locales/zh-TW/loading.json +3 -0
  81. package/locales/zh-TW/navBar.json +4 -0
  82. package/locales/zh-TW/noticeBar.json +3 -0
  83. package/locales/zh-TW/picker.json +5 -0
  84. package/locales/zh-TW/searchBar.json +4 -0
  85. package/locales/zh-TW/textarea.json +3 -0
  86. package/locales/zh-TW/toast.json +6 -0
  87. package/package.json +2 -1
@@ -0,0 +1,336 @@
1
+ /**
2
+ * I18n 核心管理器
3
+ * 管理语言包、当前语言状态、执行翻译逻辑
4
+ */
5
+
6
+ import { ref, computed } from 'vue'
7
+ import type { Ref, ComputedRef } from 'vue'
8
+ import type { ModularLocaleMessages, TranslateParams } from './types.uts'
9
+ import { I18nError } from './error.uts'
10
+
11
+ /**
12
+ * I18nManager 单例类
13
+ * 提供多语言系统的核心功能
14
+ */
15
+ export class I18nManager {
16
+ /** 单例实例 */
17
+ private static instance: I18nManager | null = null
18
+
19
+ /** 当前语言代码(响应式) */
20
+ public currentLocale: Ref<string>
21
+
22
+ /** 回退语言代码 */
23
+ public fallbackLocale: string
24
+
25
+ /** 语言包存储 */
26
+ private messages: Map<string, ModularLocaleMessages>
27
+
28
+ /**
29
+ * 私有构造函数,确保单例模式
30
+ */
31
+ private constructor() {
32
+ this.currentLocale = ref<string>('zh-CN')
33
+ this.fallbackLocale = 'zh-CN'
34
+ this.messages = new Map<string, ModularLocaleMessages>()
35
+ }
36
+
37
+ /**
38
+ * 获取单例实例
39
+ * @returns I18nManager 实例
40
+ */
41
+ static getInstance(): I18nManager {
42
+ if (I18nManager.instance === null) {
43
+ I18nManager.instance = new I18nManager()
44
+ }
45
+ return I18nManager.instance
46
+ }
47
+
48
+ /**
49
+ * 翻译函数
50
+ * 支持模块化键查询(moduleName.key)和参数插值
51
+ * @param key 翻译键(格式:moduleName.key)
52
+ * @param params 插值参数(可选)
53
+ * @returns 翻译后的文本
54
+ */
55
+ translate(key: string, params?: TranslateParams): string {
56
+ // 1. 解析键:moduleName.key
57
+ const parts = key.split('.')
58
+
59
+ if (parts.length < 2) {
60
+ I18nError.warnInvalidKey(key)
61
+ return key
62
+ }
63
+
64
+ const moduleName = parts[0]
65
+ const messageKey = parts.slice(1).join('.')
66
+
67
+ if (!moduleName || !messageKey) {
68
+ I18nError.warnInvalidKey(key)
69
+ return key
70
+ }
71
+
72
+ // 2. 在当前语言中查找
73
+ let message = this.getModuleMessage(this.currentLocale.value, moduleName, messageKey)
74
+
75
+ // 3. 如果未找到,尝试回退语言
76
+ if (message === undefined) {
77
+ message = this.getModuleMessage(this.fallbackLocale, moduleName, messageKey)
78
+
79
+ // 4. 如果仍未找到,返回键本身
80
+ if (message === undefined) {
81
+ I18nError.warnKeyNotFound(key, this.currentLocale.value)
82
+ return key
83
+ }
84
+ }
85
+
86
+ // 5. 如果有参数,执行插值
87
+ if (params && typeof message === 'string') {
88
+ return this.interpolate(message, params)
89
+ }
90
+
91
+ return message as string
92
+ }
93
+
94
+ /**
95
+ * 获取模块中的消息(支持深层嵌套)
96
+ * @param locale 语言代码
97
+ * @param moduleName 模块名
98
+ * @param key 消息键(支持点号分隔的嵌套路径)
99
+ * @returns 消息文本或 undefined
100
+ */
101
+ private getModuleMessage(locale: string, moduleName: string, key: string): string | undefined {
102
+ const localeMessages = this.messages.get(locale)
103
+ if (!localeMessages) {
104
+ return undefined
105
+ }
106
+
107
+ const module = localeMessages[moduleName]
108
+ if (!module) {
109
+ return undefined
110
+ }
111
+
112
+ // 支持嵌套路径查询(例如:components.TButton.name)
113
+ const keys = key.split('.')
114
+ let current: any = module
115
+
116
+ for (const k of keys) {
117
+ if (current && typeof current === 'object' && k in current) {
118
+ current = current[k]
119
+ } else {
120
+ return undefined
121
+ }
122
+ }
123
+
124
+ // 确保最终值是字符串
125
+ return typeof current === 'string' ? current : undefined
126
+ }
127
+
128
+ /**
129
+ * 字符串插值
130
+ * 支持 {key} 占位符格式
131
+ * @param template 模板字符串(使用 {key} 作为占位符)
132
+ * @param params 参数对象
133
+ * @returns 插值后的字符串
134
+ */
135
+ private interpolate(template: string, params: TranslateParams): string {
136
+ return template.replace(/\{(\w+)\}/g, (match: string, key: string): string => {
137
+ if (key in params) {
138
+ return String(params[key])
139
+ }
140
+ I18nError.warnMissingParam(template, key)
141
+ return match // 保留未匹配的占位符
142
+ })
143
+ }
144
+
145
+ /**
146
+ * 设置当前语言
147
+ * @param locale 语言代码
148
+ * @returns 是否切换成功
149
+ */
150
+ setLocale(locale: string): boolean {
151
+ if (!this.hasLocale(locale)) {
152
+ I18nError.warnLocaleNotFound(locale)
153
+ return false
154
+ }
155
+
156
+ // 更新 ref 会自动触发所有依赖的重新计算
157
+ this.currentLocale.value = locale
158
+ return true
159
+ }
160
+
161
+ /**
162
+ * 检查语言包是否已注册
163
+ * @param locale 语言代码
164
+ * @returns 是否存在
165
+ */
166
+ hasLocale(locale: string): boolean {
167
+ return this.messages.has(locale)
168
+ }
169
+
170
+ /**
171
+ * 验证语言包结构(支持嵌套对象)
172
+ * @param locale 语言代码
173
+ * @param messages 模块化语言包
174
+ * @returns 是否验证通过
175
+ */
176
+ private validateMessages(locale: string, messages: ModularLocaleMessages): boolean {
177
+ // 1. 验证语言包是否为有效的对象
178
+ if (!messages || typeof messages !== 'object' || Array.isArray(messages)) {
179
+ I18nError.errorMessagesNotObject(locale)
180
+ return false
181
+ }
182
+
183
+ // 2. 验证每个模块是否为对象
184
+ for (const moduleName in messages) {
185
+ const module = messages[moduleName]
186
+
187
+ if (!module || typeof module !== 'object' || Array.isArray(module)) {
188
+ I18nError.errorModuleNotObject(locale, moduleName)
189
+ return false
190
+ }
191
+
192
+ // 3. 递归验证模块内容(支持嵌套对象)
193
+ if (!this.validateModuleContent(locale, moduleName, module)) {
194
+ return false
195
+ }
196
+ }
197
+
198
+ return true
199
+ }
200
+
201
+ /**
202
+ * 递归验证模块内容(支持嵌套对象)
203
+ * @param locale 语言代码
204
+ * @param moduleName 模块名
205
+ * @param obj 要验证的对象
206
+ * @returns 是否验证通过
207
+ */
208
+ private validateModuleContent(locale: string, moduleName: string, obj: any): boolean {
209
+ for (const key in obj) {
210
+ const value = obj[key]
211
+
212
+ if (typeof value === 'string') {
213
+ // 字符串值,验证通过
214
+ continue
215
+ } else if (value && typeof value === 'object' && !Array.isArray(value)) {
216
+ // 嵌套对象,递归验证
217
+ if (!this.validateModuleContent(locale, moduleName, value)) {
218
+ return false
219
+ }
220
+ } else {
221
+ // 其他类型(数组、null等),验证失败
222
+ I18nError.errorValueNotString(locale, moduleName, key)
223
+ return false
224
+ }
225
+ }
226
+
227
+ return true
228
+ }
229
+
230
+ /**
231
+ * 注册或更新语言包(默认使用合并模式)
232
+ * @param locale 语言代码
233
+ * @param messages 模块化语言包
234
+ */
235
+ registerMessages(locale: string, messages: ModularLocaleMessages): void {
236
+ this.registerMessagesWithMode(locale, messages, 'merge')
237
+ }
238
+
239
+ /**
240
+ * 注册语言包(指定模式)
241
+ * @param locale 语言代码
242
+ * @param messages 模块化语言包
243
+ * @param mode 注册模式:'merge' 合并,'replace' 替换
244
+ */
245
+ registerMessagesWithMode(
246
+ locale: string,
247
+ messages: ModularLocaleMessages,
248
+ mode: 'merge' | 'replace'
249
+ ): void {
250
+ // 验证语言包结构
251
+ if (!this.validateMessages(locale, messages)) {
252
+ // 验证失败,拒绝注册
253
+ return
254
+ }
255
+
256
+ if (mode === 'replace') {
257
+ // 替换模式:完全替换现有语言包(直接设置,不再次验证)
258
+ this.messages.set(locale, messages)
259
+ } else {
260
+ // 合并模式:合并现有语言包
261
+ const existingMessages = this.messages.get(locale)
262
+
263
+ if (existingMessages) {
264
+ // 合并现有语言包
265
+ const merged = this.mergeModularMessages(existingMessages, messages)
266
+ this.messages.set(locale, merged)
267
+ } else {
268
+ // 新增语言包
269
+ this.messages.set(locale, messages)
270
+ }
271
+ }
272
+ }
273
+
274
+ /**
275
+ * 替换语言包(完全替换)
276
+ * @param locale 语言代码
277
+ * @param messages 模块化语言包
278
+ */
279
+ replaceMessages(locale: string, messages: ModularLocaleMessages): void {
280
+ // 验证语言包结构
281
+ if (!this.validateMessages(locale, messages)) {
282
+ // 验证失败,拒绝替换
283
+ return
284
+ }
285
+
286
+ this.messages.set(locale, messages)
287
+ }
288
+
289
+ /**
290
+ * 合并模块化语言包
291
+ * @param target 目标语言包
292
+ * @param source 源语言包
293
+ * @returns 合并后的语言包
294
+ */
295
+ private mergeModularMessages(
296
+ target: ModularLocaleMessages,
297
+ source: ModularLocaleMessages
298
+ ): ModularLocaleMessages {
299
+ const result: ModularLocaleMessages = { ...target }
300
+
301
+ // 遍历源语言包的所有模块
302
+ for (const moduleName in source) {
303
+ const sourceModule = source[moduleName]
304
+ const targetModule = result[moduleName]
305
+
306
+ if (targetModule) {
307
+ // 如果目标中已有该模块,合并键值对
308
+ result[moduleName] = {
309
+ ...targetModule,
310
+ ...sourceModule // 源模块的键覆盖目标模块
311
+ }
312
+ } else {
313
+ // 如果目标中没有该模块,直接添加
314
+ result[moduleName] = sourceModule
315
+ }
316
+ }
317
+
318
+ return result
319
+ }
320
+
321
+ /**
322
+ * 获取可用语言列表(响应式)
323
+ * @returns 可用语言代码数组
324
+ */
325
+ getAvailableLocales(): ComputedRef<string[]> {
326
+ return computed(() => Array.from(this.messages.keys()))
327
+ }
328
+
329
+ /**
330
+ * 获取当前语言代码
331
+ * @returns 当前语言代码
332
+ */
333
+ getCurrentLocale(): string {
334
+ return this.currentLocale.value
335
+ }
336
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * 演示语言包注册和合并功能
3
+ * 用于验证 Task 7 的实现
4
+ */
5
+
6
+ import { I18nManager } from './manager.uts'
7
+ import type { ModularLocaleMessages } from './types.uts'
8
+
9
+ // 获取管理器实例
10
+ const manager = I18nManager.getInstance()
11
+
12
+ console.log('=== Task 7: 语言包注册和合并功能演示 ===\n')
13
+
14
+ // 1. 注册新语言包(日语)
15
+ console.log('1. 注册新语言包(日语)')
16
+ const jaJP: ModularLocaleMessages = {
17
+ common: {
18
+ confirm: '確認',
19
+ cancel: 'キャンセル',
20
+ ok: 'OK'
21
+ },
22
+ dialog: {
23
+ title: 'ヒント'
24
+ }
25
+ }
26
+
27
+ manager.registerMessages('ja-JP', jaJP)
28
+ console.log('✓ 日语语言包已注册')
29
+
30
+ // 验证新语言包可用
31
+ const hasJapanese = manager.hasLocale('ja-JP')
32
+ console.log(`✓ 日语语言包可用: ${hasJapanese}`)
33
+
34
+ // 切换到日语并测试翻译
35
+ manager.setLocale('ja-JP')
36
+ const japaneseConfirm = manager.translate('common.confirm')
37
+ console.log(`✓ 日语翻译测试: common.confirm = "${japaneseConfirm}"\n`)
38
+
39
+ // 2. 注册已存在语言的部分翻译(覆盖)
40
+ console.log('2. 测试语言包合并(覆盖现有键)')
41
+ manager.setLocale('zh-CN')
42
+
43
+ // 先注册初始中文语言包
44
+ const zhCNInitial: ModularLocaleMessages = {
45
+ common: {
46
+ confirm: '确定',
47
+ cancel: '取消',
48
+ close: '关闭'
49
+ },
50
+ dialog: {
51
+ title: '提示',
52
+ confirmText: '确定'
53
+ }
54
+ }
55
+ manager.registerMessages('zh-CN', zhCNInitial)
56
+
57
+ console.log('初始中文翻译:')
58
+ console.log(` common.confirm = "${manager.translate('common.confirm')}"`)
59
+ console.log(` common.cancel = "${manager.translate('common.cancel')}"`)
60
+ console.log(` common.close = "${manager.translate('common.close')}"`)
61
+ console.log(` dialog.title = "${manager.translate('dialog.title')}"`)
62
+
63
+ // 注册覆盖部分键的语言包
64
+ const zhCNOverride: ModularLocaleMessages = {
65
+ common: {
66
+ confirm: '好的', // 覆盖
67
+ ok: '行' // 新增
68
+ },
69
+ empty: { // 新模块
70
+ title: '暂无数据'
71
+ }
72
+ }
73
+ manager.registerMessages('zh-CN', zhCNOverride)
74
+
75
+ console.log('\n合并后的中文翻译:')
76
+ console.log(` common.confirm = "${manager.translate('common.confirm')}" (已覆盖)`)
77
+ console.log(` common.cancel = "${manager.translate('common.cancel')}" (保留)`)
78
+ console.log(` common.close = "${manager.translate('common.close')}" (保留)`)
79
+ console.log(` common.ok = "${manager.translate('common.ok')}" (新增)`)
80
+ console.log(` dialog.title = "${manager.translate('dialog.title')}" (保留)`)
81
+ console.log(` empty.title = "${manager.translate('empty.title')}" (新模块)\n`)
82
+
83
+ // 3. 验证可用语言列表更新
84
+ console.log('3. 验证可用语言列表')
85
+ const availableLocales = manager.getAvailableLocales()
86
+ console.log(`可用语言: ${availableLocales.value.join(', ')}`)
87
+ console.log(`✓ 语言列表已自动更新\n`)
88
+
89
+ // 4. 测试复杂合并场景
90
+ console.log('4. 测试复杂合并场景')
91
+ const frFR: ModularLocaleMessages = {
92
+ common: {
93
+ confirm: 'Confirmer',
94
+ cancel: 'Annuler'
95
+ }
96
+ }
97
+ manager.registerMessages('fr-FR', frFR)
98
+
99
+ // 添加更多模块到法语
100
+ const frFRAdditional: ModularLocaleMessages = {
101
+ common: {
102
+ ok: 'OK',
103
+ close: 'Fermer'
104
+ },
105
+ dialog: {
106
+ title: 'Conseil'
107
+ }
108
+ }
109
+ manager.registerMessages('fr-FR', frFRAdditional)
110
+
111
+ manager.setLocale('fr-FR')
112
+ console.log('法语翻译(多次合并后):')
113
+ console.log(` common.confirm = "${manager.translate('common.confirm')}" (第一次注册)`)
114
+ console.log(` common.cancel = "${manager.translate('common.cancel')}" (第一次注册)`)
115
+ console.log(` common.ok = "${manager.translate('common.ok')}" (第二次注册)`)
116
+ console.log(` common.close = "${manager.translate('common.close')}" (第二次注册)`)
117
+ console.log(` dialog.title = "${manager.translate('dialog.title')}" (第二次注册)\n`)
118
+
119
+ console.log('=== 所有测试通过!✓ ===')
120
+ console.log('\n需求验证:')
121
+ console.log('✓ 3.1: 新语言包可以注册并立即可用')
122
+ console.log('✓ 3.2: 已存在语言的语言包可以合并')
123
+ console.log('✓ 3.3: 合并时新内容覆盖旧内容,未覆盖的保留')
124
+ console.log('✓ 3.4: 注册完成后立即可用')
125
+ console.log('✓ 3.5: 接受任意语言代码')
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Task 22 验证脚本
3
+ * 验证语言包注册模式功能
4
+ */
5
+
6
+ import { I18nManager } from './manager.uts'
7
+ import type { ModularLocaleMessages } from './types.uts'
8
+
9
+ /**
10
+ * 测试语言包注册模式功能
11
+ */
12
+ export function testRegistrationModes(): void {
13
+ console.log('=== Task 22: 语言包注册模式功能验证 ===\n')
14
+
15
+ const manager = I18nManager.getInstance()
16
+
17
+ // 测试 1: 合并模式(默认)
18
+ console.log('测试 1: 合并模式(默认 registerMessages)')
19
+ const initialMessages: ModularLocaleMessages = {
20
+ common: {
21
+ confirm: '确定',
22
+ cancel: '取消',
23
+ ok: '好的'
24
+ },
25
+ dialog: {
26
+ title: '提示',
27
+ confirmText: '确定'
28
+ }
29
+ }
30
+
31
+ manager.registerMessages('test-locale', initialMessages)
32
+ console.log('✓ 初始语言包已注册')
33
+
34
+ // 部分覆盖
35
+ const partialMessages: ModularLocaleMessages = {
36
+ common: {
37
+ confirm: '好的', // 覆盖
38
+ close: '关闭' // 新增
39
+ },
40
+ empty: { // 新模块
41
+ title: '暂无数据'
42
+ }
43
+ }
44
+
45
+ manager.registerMessages('test-locale', partialMessages)
46
+ console.log('✓ 部分语言包已合并')
47
+
48
+ // 验证合并结果
49
+ manager.setLocale('test-locale')
50
+ const confirmText = manager.translate('common.confirm')
51
+ const cancelText = manager.translate('common.cancel')
52
+ const okText = manager.translate('common.ok')
53
+ const closeText = manager.translate('common.close')
54
+ const dialogTitle = manager.translate('dialog.title')
55
+ const emptyTitle = manager.translate('empty.title')
56
+
57
+ console.log(` common.confirm: ${confirmText} (应为 "好的")`)
58
+ console.log(` common.cancel: ${cancelText} (应为 "取消" - 保留)`)
59
+ console.log(` common.ok: ${okText} (应为 "好的" - 保留)`)
60
+ console.log(` common.close: ${closeText} (应为 "关闭" - 新增)`)
61
+ console.log(` dialog.title: ${dialogTitle} (应为 "提示" - 保留)`)
62
+ console.log(` empty.title: ${emptyTitle} (应为 "暂无数据" - 新模块)`)
63
+
64
+ const mergeSuccess =
65
+ confirmText === '好的' &&
66
+ cancelText === '取消' &&
67
+ okText === '好的' &&
68
+ closeText === '关闭' &&
69
+ dialogTitle === '提示' &&
70
+ emptyTitle === '暂无数据'
71
+
72
+ if (mergeSuccess) {
73
+ console.log('✅ 合并模式测试通过\n')
74
+ } else {
75
+ console.log('❌ 合并模式测试失败\n')
76
+ }
77
+
78
+ // 测试 2: 替换模式(registerMessagesWithMode)
79
+ console.log('测试 2: 替换模式(registerMessagesWithMode)')
80
+ const replaceMessages: ModularLocaleMessages = {
81
+ button: {
82
+ submit: '提交',
83
+ reset: '重置'
84
+ }
85
+ }
86
+
87
+ manager.registerMessagesWithMode('test-locale', replaceMessages, 'replace')
88
+ console.log('✓ 语言包已完全替换')
89
+
90
+ // 验证替换结果 - 旧内容应该不存在
91
+ const submitText = manager.translate('button.submit')
92
+ const oldConfirmText = manager.translate('common.confirm')
93
+ const oldDialogTitle = manager.translate('dialog.title')
94
+
95
+ console.log(` button.submit: ${submitText} (应为 "提交")`)
96
+ console.log(` common.confirm: ${oldConfirmText} (应为 "common.confirm" - 已被清除)`)
97
+ console.log(` dialog.title: ${oldDialogTitle} (应为 "dialog.title" - 已被清除)`)
98
+
99
+ const replaceSuccess =
100
+ submitText === '提交' &&
101
+ oldConfirmText === 'common.confirm' &&
102
+ oldDialogTitle === 'dialog.title'
103
+
104
+ if (replaceSuccess) {
105
+ console.log('✅ 替换模式测试通过\n')
106
+ } else {
107
+ console.log('❌ 替换模式测试失败\n')
108
+ }
109
+
110
+ // 测试 3: replaceMessages 方法
111
+ console.log('测试 3: replaceMessages 方法')
112
+ const newMessages: ModularLocaleMessages = {
113
+ search: {
114
+ placeholder: '搜索',
115
+ cancel: '取消'
116
+ }
117
+ }
118
+
119
+ manager.replaceMessages('test-locale', newMessages)
120
+ console.log('✓ 使用 replaceMessages 方法替换')
121
+
122
+ const searchPlaceholder = manager.translate('search.placeholder')
123
+ const oldSubmitText = manager.translate('button.submit')
124
+
125
+ console.log(` search.placeholder: ${searchPlaceholder} (应为 "搜索")`)
126
+ console.log(` button.submit: ${oldSubmitText} (应为 "button.submit" - 已被清除)`)
127
+
128
+ const replaceMethodSuccess =
129
+ searchPlaceholder === '搜索' &&
130
+ oldSubmitText === 'button.submit'
131
+
132
+ if (replaceMethodSuccess) {
133
+ console.log('✅ replaceMessages 方法测试通过\n')
134
+ } else {
135
+ console.log('❌ replaceMessages 方法测试失败\n')
136
+ }
137
+
138
+ // 测试 4: 合并模式使用 registerMessagesWithMode
139
+ console.log('测试 4: 合并模式使用 registerMessagesWithMode')
140
+ const baseMessages: ModularLocaleMessages = {
141
+ common: {
142
+ yes: '是',
143
+ no: '否'
144
+ }
145
+ }
146
+
147
+ manager.registerMessagesWithMode('test-locale-2', baseMessages, 'merge')
148
+ console.log('✓ 基础语言包已注册')
149
+
150
+ const additionalMessages: ModularLocaleMessages = {
151
+ common: {
152
+ yes: 'Yes', // 覆盖
153
+ maybe: 'Maybe' // 新增
154
+ }
155
+ }
156
+
157
+ manager.registerMessagesWithMode('test-locale-2', additionalMessages, 'merge')
158
+ console.log('✓ 额外语言包已合并')
159
+
160
+ manager.setLocale('test-locale-2')
161
+ const yesText = manager.translate('common.yes')
162
+ const noText = manager.translate('common.no')
163
+ const maybeText = manager.translate('common.maybe')
164
+
165
+ console.log(` common.yes: ${yesText} (应为 "Yes")`)
166
+ console.log(` common.no: ${noText} (应为 "否" - 保留)`)
167
+ console.log(` common.maybe: ${maybeText} (应为 "Maybe" - 新增)`)
168
+
169
+ const mergeWithModeSuccess =
170
+ yesText === 'Yes' &&
171
+ noText === '否' &&
172
+ maybeText === 'Maybe'
173
+
174
+ if (mergeWithModeSuccess) {
175
+ console.log('✅ registerMessagesWithMode 合并模式测试通过\n')
176
+ } else {
177
+ console.log('❌ registerMessagesWithMode 合并模式测试失败\n')
178
+ }
179
+
180
+ // 总结
181
+ console.log('=== 测试总结 ===')
182
+ const allSuccess = mergeSuccess && replaceSuccess && replaceMethodSuccess && mergeWithModeSuccess
183
+
184
+ if (allSuccess) {
185
+ console.log('✅ 所有测试通过!')
186
+ console.log('\n实现的功能:')
187
+ console.log('1. registerMessages() - 默认使用合并模式')
188
+ console.log('2. registerMessagesWithMode() - 支持 merge 和 replace 模式')
189
+ console.log('3. replaceMessages() - 完全替换语言包')
190
+ console.log('4. 合并模式正确保留未覆盖的内容')
191
+ console.log('5. 替换模式完全清除旧内容')
192
+ } else {
193
+ console.log('❌ 部分测试失败,请检查实现')
194
+ }
195
+ }
196
+
197
+ // 执行测试
198
+ testRegistrationModes()