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.
- package/README.md +1003 -0
- package/components/TActionSheet/index.uvue +15 -2
- package/components/TCollapse/index.uvue +1 -1
- package/components/TCollapse/type.uts +3 -1
- package/components/TCollapseItem/index.uvue +22 -26
- package/components/TDialog/index.uvue +19 -4
- package/components/TEmpty/index.uvue +28 -14
- package/components/TForm/index.uvue +30 -9
- package/components/TForm/type.uts +4 -0
- package/components/TInput/index.uvue +24 -5
- package/components/TInput/type.uts +10 -0
- package/components/TPicker/index.uvue +26 -6
- package/components/TSearchBar/index.uvue +19 -4
- package/composables/i18n/error.uts +82 -0
- package/composables/i18n/index.uts +188 -0
- package/composables/i18n/manager-demo.uts +104 -0
- package/composables/i18n/manager.test.uts +182 -0
- package/composables/i18n/manager.uts +336 -0
- package/composables/i18n/register-demo.uts +125 -0
- package/composables/i18n/task22-verification.uts +198 -0
- package/composables/i18n/task23-verification.uts +343 -0
- package/composables/i18n/task8-demo.uts +93 -0
- package/composables/i18n/task8-verification.uts +98 -0
- package/composables/i18n/test-task23.uts +9 -0
- package/composables/i18n/types.uts +46 -0
- package/composables/i18n/useI18n-verification.uts +105 -0
- package/composables/i18n/validation-demo.uts +45 -0
- package/composables/i18n/validation-test.uts +106 -0
- package/composables/useI18n.uts +77 -0
- package/index.uts +23 -0
- package/locales/cross-platform-verification.uts +510 -0
- package/locales/en-US/actionSheet.json +3 -0
- package/locales/en-US/common.json +10 -0
- package/locales/en-US/dialog.json +5 -0
- package/locales/en-US/empty.json +5 -0
- package/locales/en-US/errorState.json +5 -0
- package/locales/en-US/examplePages.json +1236 -0
- package/locales/en-US/examples.json +218 -0
- package/locales/en-US/form.json +11 -0
- package/locales/en-US/input.json +3 -0
- package/locales/en-US/list.json +5 -0
- package/locales/en-US/loading.json +3 -0
- package/locales/en-US/navBar.json +4 -0
- package/locales/en-US/noticeBar.json +3 -0
- package/locales/en-US/picker.json +5 -0
- package/locales/en-US/searchBar.json +4 -0
- package/locales/en-US/textarea.json +3 -0
- package/locales/en-US/toast.json +6 -0
- package/locales/index.uts +79 -0
- package/locales/init-verification.uts +101 -0
- package/locales/loader.uts +251 -0
- package/locales/run-verification.uts +16 -0
- package/locales/zh-CN/actionSheet.json +3 -0
- package/locales/zh-CN/common.json +10 -0
- package/locales/zh-CN/dialog.json +5 -0
- package/locales/zh-CN/empty.json +5 -0
- package/locales/zh-CN/errorState.json +5 -0
- package/locales/zh-CN/examplePages.json +1236 -0
- package/locales/zh-CN/examples.json +218 -0
- package/locales/zh-CN/form.json +11 -0
- package/locales/zh-CN/input.json +3 -0
- package/locales/zh-CN/list.json +5 -0
- package/locales/zh-CN/loading.json +3 -0
- package/locales/zh-CN/navBar.json +4 -0
- package/locales/zh-CN/noticeBar.json +3 -0
- package/locales/zh-CN/picker.json +5 -0
- package/locales/zh-CN/searchBar.json +4 -0
- package/locales/zh-CN/textarea.json +3 -0
- package/locales/zh-CN/toast.json +6 -0
- package/locales/zh-TW/actionSheet.json +3 -0
- package/locales/zh-TW/common.json +8 -0
- package/locales/zh-TW/dialog.json +5 -0
- package/locales/zh-TW/empty.json +5 -0
- package/locales/zh-TW/errorState.json +5 -0
- package/locales/zh-TW/examplePages.json +705 -0
- package/locales/zh-TW/examples.json +218 -0
- package/locales/zh-TW/form.json +11 -0
- package/locales/zh-TW/input.json +3 -0
- package/locales/zh-TW/list.json +5 -0
- package/locales/zh-TW/loading.json +3 -0
- package/locales/zh-TW/navBar.json +4 -0
- package/locales/zh-TW/noticeBar.json +3 -0
- package/locales/zh-TW/picker.json +5 -0
- package/locales/zh-TW/searchBar.json +4 -0
- package/locales/zh-TW/textarea.json +3 -0
- package/locales/zh-TW/toast.json +6 -0
- package/package.json +2 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n 错误处理工具类
|
|
3
|
+
* 提供统一的错误和警告输出
|
|
4
|
+
*/
|
|
5
|
+
export class I18nError {
|
|
6
|
+
/**
|
|
7
|
+
* 警告:语言代码不存在
|
|
8
|
+
* @param locale 语言代码
|
|
9
|
+
*/
|
|
10
|
+
static warnLocaleNotFound(locale: string): void {
|
|
11
|
+
console.warn(`[Tang UI I18n] Locale "${locale}" not found, using fallback locale`)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 警告:翻译键不存在
|
|
16
|
+
* @param key 翻译键
|
|
17
|
+
* @param locale 语言代码
|
|
18
|
+
*/
|
|
19
|
+
static warnKeyNotFound(key: string, locale: string): void {
|
|
20
|
+
// 仅在开发环境输出警告
|
|
21
|
+
if (process.env.NODE_ENV === 'development') {
|
|
22
|
+
console.warn(`[Tang UI I18n] Translation key "${key}" not found in locale "${locale}"`)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 错误:语言包格式无效
|
|
28
|
+
* @param locale 语言代码
|
|
29
|
+
*/
|
|
30
|
+
static errorInvalidMessages(locale: string): void {
|
|
31
|
+
console.error(`[Tang UI I18n] Invalid messages format for locale "${locale}"`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 警告:参数缺失
|
|
36
|
+
* @param key 翻译键
|
|
37
|
+
* @param param 参数名
|
|
38
|
+
*/
|
|
39
|
+
static warnMissingParam(key: string, param: string): void {
|
|
40
|
+
// 仅在开发环境输出警告
|
|
41
|
+
if (process.env.NODE_ENV === 'development') {
|
|
42
|
+
console.warn(`[Tang UI I18n] Missing parameter "${param}" for key "${key}"`)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 警告:翻译键格式无效
|
|
48
|
+
* @param key 翻译键
|
|
49
|
+
*/
|
|
50
|
+
static warnInvalidKey(key: string): void {
|
|
51
|
+
if (process.env.NODE_ENV === 'development') {
|
|
52
|
+
console.warn(`[Tang UI I18n] Invalid translation key format: "${key}". Expected format: "moduleName.key"`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 错误:语言包不是有效的对象
|
|
58
|
+
* @param locale 语言代码
|
|
59
|
+
*/
|
|
60
|
+
static errorMessagesNotObject(locale: string): void {
|
|
61
|
+
console.error(`[Tang UI I18n] Messages for locale "${locale}" must be a valid object`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 错误:模块不是有效的对象
|
|
66
|
+
* @param locale 语言代码
|
|
67
|
+
* @param moduleName 模块名
|
|
68
|
+
*/
|
|
69
|
+
static errorModuleNotObject(locale: string, moduleName: string): void {
|
|
70
|
+
console.error(`[Tang UI I18n] Module "${moduleName}" in locale "${locale}" must be a valid object`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 错误:键值不是字符串
|
|
75
|
+
* @param locale 语言代码
|
|
76
|
+
* @param moduleName 模块名
|
|
77
|
+
* @param key 键名
|
|
78
|
+
*/
|
|
79
|
+
static errorValueNotString(locale: string, moduleName: string, key: string): void {
|
|
80
|
+
console.error(`[Tang UI I18n] Value for key "${key}" in module "${moduleName}" of locale "${locale}" must be a string`)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n 全局导出函数
|
|
3
|
+
* 提供全局访问的便捷方法
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { I18nManager } from './manager.uts'
|
|
7
|
+
import type { ModularLocaleMessages } from './types.uts'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 设置语言(全局)
|
|
11
|
+
* 切换整个应用的显示语言
|
|
12
|
+
*
|
|
13
|
+
* @param locale 语言代码(如 'zh-CN', 'en-US', 'zh-TW')
|
|
14
|
+
* @returns 是否切换成功
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { setLanguage } from 'tang-ui-x'
|
|
19
|
+
*
|
|
20
|
+
* // 切换到英语
|
|
21
|
+
* const success = setLanguage('en-US')
|
|
22
|
+
* if (success) {
|
|
23
|
+
* console.log('语言切换成功')
|
|
24
|
+
* } else {
|
|
25
|
+
* console.log('语言切换失败,语言包未注册')
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function setLanguage(locale: string): boolean {
|
|
30
|
+
const manager = I18nManager.getInstance()
|
|
31
|
+
return manager.setLocale(locale)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 注册语言包(默认使用合并模式)
|
|
36
|
+
* 添加新语言或覆盖现有语言的翻译
|
|
37
|
+
* 默认使用合并模式,新内容会与现有内容合并,新键覆盖旧键,未覆盖的键保留
|
|
38
|
+
*
|
|
39
|
+
* @param locale 语言代码
|
|
40
|
+
* @param messages 模块化语言包
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* import { registerLocale } from 'tang-ui-x'
|
|
45
|
+
*
|
|
46
|
+
* // 注册日语语言包
|
|
47
|
+
* registerLocale('ja-JP', {
|
|
48
|
+
* common: {
|
|
49
|
+
* confirm: '確認',
|
|
50
|
+
* cancel: 'キャンセル',
|
|
51
|
+
* ok: 'OK'
|
|
52
|
+
* },
|
|
53
|
+
* dialog: {
|
|
54
|
+
* title: 'ヒント',
|
|
55
|
+
* confirmText: '確認',
|
|
56
|
+
* cancelText: 'キャンセル'
|
|
57
|
+
* }
|
|
58
|
+
* })
|
|
59
|
+
*
|
|
60
|
+
* // 覆盖部分中文翻译(合并模式)
|
|
61
|
+
* registerLocale('zh-CN', {
|
|
62
|
+
* common: {
|
|
63
|
+
* confirm: '好的' // 只覆盖这个键,其他保持不变
|
|
64
|
+
* }
|
|
65
|
+
* })
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export function registerLocale(locale: string, messages: ModularLocaleMessages): void {
|
|
69
|
+
const manager = I18nManager.getInstance()
|
|
70
|
+
manager.registerMessages(locale, messages)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 注册语言包(指定模式)
|
|
75
|
+
* 支持合并模式和替换模式
|
|
76
|
+
* - 合并模式:新内容与现有内容合并,新键覆盖旧键,未覆盖的键保留
|
|
77
|
+
* - 替换模式:完全替换现有语言包,不保留任何原有内容
|
|
78
|
+
*
|
|
79
|
+
* @param locale 语言代码
|
|
80
|
+
* @param messages 模块化语言包
|
|
81
|
+
* @param mode 注册模式:'merge' 合并(默认),'replace' 替换
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* import { registerLocaleWithMode } from 'tang-ui-x'
|
|
86
|
+
*
|
|
87
|
+
* // 使用合并模式(与 registerLocale 相同)
|
|
88
|
+
* registerLocaleWithMode('zh-CN', {
|
|
89
|
+
* common: {
|
|
90
|
+
* confirm: '好的' // 只覆盖这个键,其他保持不变
|
|
91
|
+
* }
|
|
92
|
+
* }, 'merge')
|
|
93
|
+
*
|
|
94
|
+
* // 使用替换模式(完全替换)
|
|
95
|
+
* registerLocaleWithMode('zh-CN', {
|
|
96
|
+
* common: {
|
|
97
|
+
* confirm: '好的',
|
|
98
|
+
* cancel: '取消'
|
|
99
|
+
* }
|
|
100
|
+
* // 必须提供所有模块,否则缺失的模块将为空
|
|
101
|
+
* }, 'replace')
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function registerLocaleWithMode(
|
|
105
|
+
locale: string,
|
|
106
|
+
messages: ModularLocaleMessages,
|
|
107
|
+
mode: 'merge' | 'replace'
|
|
108
|
+
): void {
|
|
109
|
+
const manager = I18nManager.getInstance()
|
|
110
|
+
manager.registerMessagesWithMode(locale, messages, mode)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 替换语言包(完全替换)
|
|
115
|
+
* 完全替换指定语言的所有翻译内容,不保留任何原有内容
|
|
116
|
+
* 这是 registerLocaleWithMode(locale, messages, 'replace') 的便捷方法
|
|
117
|
+
*
|
|
118
|
+
* @param locale 语言代码
|
|
119
|
+
* @param messages 模块化语言包
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* import { replaceLocale } from 'tang-ui-x'
|
|
124
|
+
*
|
|
125
|
+
* // 完全替换中文翻译
|
|
126
|
+
* replaceLocale('zh-CN', {
|
|
127
|
+
* common: {
|
|
128
|
+
* confirm: '好的',
|
|
129
|
+
* cancel: '取消',
|
|
130
|
+
* ok: 'OK'
|
|
131
|
+
* },
|
|
132
|
+
* dialog: {
|
|
133
|
+
* title: '提示',
|
|
134
|
+
* confirmText: '好的',
|
|
135
|
+
* cancelText: '取消'
|
|
136
|
+
* }
|
|
137
|
+
* // 必须提供所有模块,否则缺失的模块将为空
|
|
138
|
+
* })
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function replaceLocale(locale: string, messages: ModularLocaleMessages): void {
|
|
142
|
+
const manager = I18nManager.getInstance()
|
|
143
|
+
manager.replaceMessages(locale, messages)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 获取当前语言
|
|
148
|
+
* 返回当前激活的语言代码
|
|
149
|
+
*
|
|
150
|
+
* @returns 当前语言代码
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* import { getCurrentLocale } from 'tang-ui-x'
|
|
155
|
+
*
|
|
156
|
+
* const current = getCurrentLocale()
|
|
157
|
+
* console.log('当前语言:', current) // 输出: '当前语言: zh-CN'
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
export function getCurrentLocale(): string {
|
|
161
|
+
const manager = I18nManager.getInstance()
|
|
162
|
+
return manager.getCurrentLocale()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 获取可用语言列表
|
|
167
|
+
* 返回所有已注册语言的语言代码数组
|
|
168
|
+
*
|
|
169
|
+
* @returns 可用语言代码数组
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* import { getAvailableLocales } from 'tang-ui-x'
|
|
174
|
+
*
|
|
175
|
+
* const locales = getAvailableLocales()
|
|
176
|
+
* console.log('可用语言:', locales) // 输出: ['zh-CN', 'en-US', 'zh-TW']
|
|
177
|
+
*
|
|
178
|
+
* // 在语言选择器中使用
|
|
179
|
+
* locales.forEach(locale => {
|
|
180
|
+
* console.log(`语言选项: ${locale}`)
|
|
181
|
+
* })
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export function getAvailableLocales(): string[] {
|
|
185
|
+
const manager = I18nManager.getInstance()
|
|
186
|
+
// 注意:这里返回的是计算属性的当前值,而不是响应式引用
|
|
187
|
+
return manager.getAvailableLocales().value
|
|
188
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* I18nManager 功能演示
|
|
3
|
+
* 演示语言切换功能的使用
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { I18nManager } from './manager.uts'
|
|
7
|
+
import type { ModularLocaleMessages } from './types.uts'
|
|
8
|
+
|
|
9
|
+
// 获取管理器实例
|
|
10
|
+
const manager = I18nManager.getInstance()
|
|
11
|
+
|
|
12
|
+
// 注册测试语言包
|
|
13
|
+
const zhCN: ModularLocaleMessages = {
|
|
14
|
+
common: {
|
|
15
|
+
confirm: '确定',
|
|
16
|
+
cancel: '取消',
|
|
17
|
+
hello: '你好,{name}'
|
|
18
|
+
},
|
|
19
|
+
dialog: {
|
|
20
|
+
title: '提示'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const enUS: ModularLocaleMessages = {
|
|
25
|
+
common: {
|
|
26
|
+
confirm: 'Confirm',
|
|
27
|
+
cancel: 'Cancel',
|
|
28
|
+
hello: 'Hello, {name}'
|
|
29
|
+
},
|
|
30
|
+
dialog: {
|
|
31
|
+
title: 'Notice'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const zhTW: ModularLocaleMessages = {
|
|
36
|
+
common: {
|
|
37
|
+
confirm: '確定',
|
|
38
|
+
cancel: '取消',
|
|
39
|
+
hello: '你好,{name}'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 注册语言包
|
|
44
|
+
manager.registerMessages('zh-CN', zhCN)
|
|
45
|
+
manager.registerMessages('en-US', enUS)
|
|
46
|
+
manager.registerMessages('zh-TW', zhTW)
|
|
47
|
+
|
|
48
|
+
console.log('=== 语言切换功能演示 ===\n')
|
|
49
|
+
|
|
50
|
+
// 测试 1: 检查语言包是否已注册
|
|
51
|
+
console.log('1. 检查语言包是否已注册:')
|
|
52
|
+
console.log(' hasLocale("zh-CN"):', manager.hasLocale('zh-CN'))
|
|
53
|
+
console.log(' hasLocale("en-US"):', manager.hasLocale('en-US'))
|
|
54
|
+
console.log(' hasLocale("zh-TW"):', manager.hasLocale('zh-TW'))
|
|
55
|
+
console.log(' hasLocale("ja-JP"):', manager.hasLocale('ja-JP'))
|
|
56
|
+
console.log('')
|
|
57
|
+
|
|
58
|
+
// 测试 2: 切换到有效的语言
|
|
59
|
+
console.log('2. 切换到有效的语言:')
|
|
60
|
+
console.log(' 当前语言:', manager.getCurrentLocale())
|
|
61
|
+
console.log(' 翻译 "common.confirm":', manager.translate('common.confirm'))
|
|
62
|
+
|
|
63
|
+
const success1 = manager.setLocale('en-US')
|
|
64
|
+
console.log(' setLocale("en-US") 返回:', success1)
|
|
65
|
+
console.log(' 当前语言:', manager.getCurrentLocale())
|
|
66
|
+
console.log(' 翻译 "common.confirm":', manager.translate('common.confirm'))
|
|
67
|
+
console.log('')
|
|
68
|
+
|
|
69
|
+
// 测试 3: 切换到另一个有效语言
|
|
70
|
+
console.log('3. 切换到繁体中文:')
|
|
71
|
+
const success2 = manager.setLocale('zh-TW')
|
|
72
|
+
console.log(' setLocale("zh-TW") 返回:', success2)
|
|
73
|
+
console.log(' 当前语言:', manager.getCurrentLocale())
|
|
74
|
+
console.log(' 翻译 "common.confirm":', manager.translate('common.confirm'))
|
|
75
|
+
console.log('')
|
|
76
|
+
|
|
77
|
+
// 测试 4: 尝试切换到无效的语言
|
|
78
|
+
console.log('4. 尝试切换到无效的语言:')
|
|
79
|
+
console.log(' 当前语言:', manager.getCurrentLocale())
|
|
80
|
+
const success3 = manager.setLocale('invalid-locale')
|
|
81
|
+
console.log(' setLocale("invalid-locale") 返回:', success3)
|
|
82
|
+
console.log(' 当前语言(应保持不变):', manager.getCurrentLocale())
|
|
83
|
+
console.log(' 翻译 "common.confirm"(应保持繁体中文):', manager.translate('common.confirm'))
|
|
84
|
+
console.log('')
|
|
85
|
+
|
|
86
|
+
// 测试 5: 验证响应式更新
|
|
87
|
+
console.log('5. 验证响应式状态:')
|
|
88
|
+
console.log(' currentLocale.value:', manager.currentLocale.value)
|
|
89
|
+
manager.setLocale('zh-CN')
|
|
90
|
+
console.log(' 切换后 currentLocale.value:', manager.currentLocale.value)
|
|
91
|
+
console.log('')
|
|
92
|
+
|
|
93
|
+
// 测试 6: 获取可用语言列表
|
|
94
|
+
console.log('6. 获取可用语言列表:')
|
|
95
|
+
const availableLocales = manager.getAvailableLocales()
|
|
96
|
+
console.log(' 可用语言:', availableLocales.value)
|
|
97
|
+
console.log('')
|
|
98
|
+
|
|
99
|
+
console.log('=== 演示完成 ===')
|
|
100
|
+
console.log('✅ setLocale() 方法已实现')
|
|
101
|
+
console.log('✅ hasLocale() 辅助方法已实现')
|
|
102
|
+
console.log('✅ 验证语言代码是否已注册')
|
|
103
|
+
console.log('✅ 更新 currentLocale ref 以触发响应式更新')
|
|
104
|
+
console.log('✅ 返回切换成功/失败状态')
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* I18nManager 单元测试
|
|
3
|
+
* 测试核心管理器的基本功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
7
|
+
import { I18nManager } from './manager.uts'
|
|
8
|
+
import type { ModularLocaleMessages } from './types.uts'
|
|
9
|
+
|
|
10
|
+
describe('I18nManager', () => {
|
|
11
|
+
let manager: I18nManager
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
// 获取单例实例
|
|
15
|
+
manager = I18nManager.getInstance()
|
|
16
|
+
|
|
17
|
+
// 注册测试语言包
|
|
18
|
+
const zhCN: ModularLocaleMessages = {
|
|
19
|
+
common: {
|
|
20
|
+
confirm: '确定',
|
|
21
|
+
cancel: '取消',
|
|
22
|
+
hello: '你好,{name}'
|
|
23
|
+
},
|
|
24
|
+
dialog: {
|
|
25
|
+
title: '提示'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const enUS: ModularLocaleMessages = {
|
|
30
|
+
common: {
|
|
31
|
+
confirm: 'Confirm',
|
|
32
|
+
cancel: 'Cancel',
|
|
33
|
+
hello: 'Hello, {name}'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
manager.registerMessages('zh-CN', zhCN)
|
|
38
|
+
manager.registerMessages('en-US', enUS)
|
|
39
|
+
manager.setLocale('zh-CN')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe('translate()', () => {
|
|
43
|
+
it('should translate simple keys', () => {
|
|
44
|
+
const result = manager.translate('common.confirm')
|
|
45
|
+
expect(result).toBe('确定')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should translate with module name', () => {
|
|
49
|
+
const result = manager.translate('dialog.title')
|
|
50
|
+
expect(result).toBe('提示')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should return key if translation not found', () => {
|
|
54
|
+
const result = manager.translate('common.notexist')
|
|
55
|
+
expect(result).toBe('common.notexist')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should return key if invalid format', () => {
|
|
59
|
+
const result = manager.translate('invalidkey')
|
|
60
|
+
expect(result).toBe('invalidkey')
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('interpolate()', () => {
|
|
65
|
+
it('should interpolate parameters', () => {
|
|
66
|
+
const result = manager.translate('common.hello', { name: '张三' })
|
|
67
|
+
expect(result).toBe('你好,张三')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should handle missing parameters', () => {
|
|
71
|
+
const result = manager.translate('common.hello', {})
|
|
72
|
+
expect(result).toBe('你好,{name}')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should handle multiple parameters', () => {
|
|
76
|
+
// 注册带多个参数的消息
|
|
77
|
+
manager.registerMessages('zh-CN', {
|
|
78
|
+
test: {
|
|
79
|
+
multi: '{greeting}, {name}! 你有 {count} 条消息'
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const result = manager.translate('test.multi', {
|
|
84
|
+
greeting: '你好',
|
|
85
|
+
name: '李四',
|
|
86
|
+
count: 5
|
|
87
|
+
})
|
|
88
|
+
expect(result).toBe('你好, 李四! 你有 5 条消息')
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
describe('setLocale()', () => {
|
|
93
|
+
it('should switch locale successfully', () => {
|
|
94
|
+
const success = manager.setLocale('en-US')
|
|
95
|
+
expect(success).toBe(true)
|
|
96
|
+
expect(manager.getCurrentLocale()).toBe('en-US')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should translate in new locale after switch', () => {
|
|
100
|
+
manager.setLocale('en-US')
|
|
101
|
+
const result = manager.translate('common.confirm')
|
|
102
|
+
expect(result).toBe('Confirm')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('should return false for invalid locale', () => {
|
|
106
|
+
const success = manager.setLocale('invalid-locale')
|
|
107
|
+
expect(success).toBe(false)
|
|
108
|
+
expect(manager.getCurrentLocale()).toBe('zh-CN')
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
describe('fallback mechanism', () => {
|
|
113
|
+
it('should fallback to default locale when key not found', () => {
|
|
114
|
+
manager.setLocale('en-US')
|
|
115
|
+
// dialog.title 只在 zh-CN 中存在
|
|
116
|
+
const result = manager.translate('dialog.title')
|
|
117
|
+
expect(result).toBe('提示')
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
describe('registerMessages()', () => {
|
|
122
|
+
it('should register new locale', () => {
|
|
123
|
+
const zhTW: ModularLocaleMessages = {
|
|
124
|
+
common: {
|
|
125
|
+
confirm: '確定'
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
manager.registerMessages('zh-TW', zhTW)
|
|
130
|
+
manager.setLocale('zh-TW')
|
|
131
|
+
const result = manager.translate('common.confirm')
|
|
132
|
+
expect(result).toBe('確定')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('should merge messages for existing locale', () => {
|
|
136
|
+
const additional: ModularLocaleMessages = {
|
|
137
|
+
common: {
|
|
138
|
+
ok: '好的'
|
|
139
|
+
},
|
|
140
|
+
newModule: {
|
|
141
|
+
test: '测试'
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
manager.registerMessages('zh-CN', additional)
|
|
146
|
+
|
|
147
|
+
// 原有的键应该保留
|
|
148
|
+
expect(manager.translate('common.confirm')).toBe('确定')
|
|
149
|
+
// 新增的键应该可用
|
|
150
|
+
expect(manager.translate('common.ok')).toBe('好的')
|
|
151
|
+
expect(manager.translate('newModule.test')).toBe('测试')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should override existing keys when merging', () => {
|
|
155
|
+
const override: ModularLocaleMessages = {
|
|
156
|
+
common: {
|
|
157
|
+
confirm: '好的'
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
manager.registerMessages('zh-CN', override)
|
|
162
|
+
const result = manager.translate('common.confirm')
|
|
163
|
+
expect(result).toBe('好的')
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
describe('getAvailableLocales()', () => {
|
|
168
|
+
it('should return all registered locales', () => {
|
|
169
|
+
const locales = manager.getAvailableLocales()
|
|
170
|
+
expect(locales.value).toContain('zh-CN')
|
|
171
|
+
expect(locales.value).toContain('en-US')
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
describe('singleton pattern', () => {
|
|
176
|
+
it('should return same instance', () => {
|
|
177
|
+
const instance1 = I18nManager.getInstance()
|
|
178
|
+
const instance2 = I18nManager.getInstance()
|
|
179
|
+
expect(instance1).toBe(instance2)
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
})
|