tang-ui-x 1.1.1 → 1.1.3
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/TCheckboxGroup/index.uvue +30 -11
- package/components/TCheckboxGroup/type.uts +10 -0
- 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 +394 -392
- package/components/TForm/type.uts +90 -80
- package/components/TInput/index.uvue +24 -5
- package/components/TInput/type.uts +10 -0
- package/components/TPicker/index.uvue +26 -6
- package/components/TRadioGroup/index.uvue +32 -12
- package/components/TRadioGroup/type.uts +7 -0
- 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 +531 -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 +17 -0
- package/locales/en-US/dialog.json +5 -0
- package/locales/en-US/empty.json +6 -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 +18 -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 +17 -0
- package/locales/zh-CN/dialog.json +5 -0
- package/locales/zh-CN/empty.json +6 -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 +18 -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 +15 -0
- package/locales/zh-TW/dialog.json +5 -0
- package/locales/zh-TW/empty.json +6 -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 +18 -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 +3 -2
package/README.md
CHANGED
|
@@ -88,6 +88,1009 @@ function showMessage() {
|
|
|
88
88
|
</script>
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
## 🌍 国际化 (i18n)
|
|
92
|
+
|
|
93
|
+
Tang UI X 内置了完整的多语言支持系统,让您的应用轻松支持多种语言。
|
|
94
|
+
|
|
95
|
+
### 内置语言
|
|
96
|
+
|
|
97
|
+
组件库默认支持以下语言:
|
|
98
|
+
|
|
99
|
+
- 🇨🇳 简体中文 (zh-CN) - 默认语言
|
|
100
|
+
- 🇺🇸 英语 (en-US)
|
|
101
|
+
- 🇭🇰 繁体中文 (zh-TW)
|
|
102
|
+
|
|
103
|
+
### 基本使用
|
|
104
|
+
|
|
105
|
+
#### 在组件中使用翻译
|
|
106
|
+
|
|
107
|
+
```vue
|
|
108
|
+
<script setup lang="uts">
|
|
109
|
+
import { useI18n } from 'tang-ui-x'
|
|
110
|
+
|
|
111
|
+
const { $t, locale, setLocale, availableLocales } = useI18n()
|
|
112
|
+
|
|
113
|
+
// 获取翻译文本
|
|
114
|
+
const confirmText = $t('common.confirm') // "确定"
|
|
115
|
+
const cancelText = $t('common.cancel') // "取消"
|
|
116
|
+
|
|
117
|
+
// 带参数的翻译
|
|
118
|
+
const greeting = $t('common.hello', { name: '张三' }) // "你好,张三"
|
|
119
|
+
|
|
120
|
+
// 切换语言
|
|
121
|
+
function switchLanguage() {
|
|
122
|
+
setLocale('en-US')
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<template>
|
|
127
|
+
<view>
|
|
128
|
+
<text>{{ confirmText }}</text>
|
|
129
|
+
<text>当前语言: {{ locale }}</text>
|
|
130
|
+
<button @click="switchLanguage">Switch to English</button>
|
|
131
|
+
</view>
|
|
132
|
+
</template>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### useI18n API
|
|
136
|
+
|
|
137
|
+
`useI18n()` 返回以下属性和方法:
|
|
138
|
+
|
|
139
|
+
- `$t(key, params?)` - 翻译函数,获取指定键的翻译文本
|
|
140
|
+
- `key`: 翻译键,格式为 `moduleName.key`(如 `common.confirm`)
|
|
141
|
+
- `params`: 可选的插值参数对象
|
|
142
|
+
- `locale` - 当前语言代码(响应式)
|
|
143
|
+
- `setLocale(code)` - 切换语言函数
|
|
144
|
+
- `availableLocales` - 可用语言列表(响应式)
|
|
145
|
+
|
|
146
|
+
### 全局语言切换
|
|
147
|
+
|
|
148
|
+
在应用的任何位置使用全局函数切换语言:
|
|
149
|
+
|
|
150
|
+
```vue
|
|
151
|
+
<script setup lang="uts">
|
|
152
|
+
import { setLanguage, getCurrentLocale, getAvailableLocales } from 'tang-ui-x'
|
|
153
|
+
|
|
154
|
+
// 切换到英语
|
|
155
|
+
const success = setLanguage('en-US')
|
|
156
|
+
console.log('切换成功:', success) // true
|
|
157
|
+
|
|
158
|
+
// 获取当前语言
|
|
159
|
+
const currentLang = getCurrentLocale() // 'en-US'
|
|
160
|
+
|
|
161
|
+
// 获取所有可用语言
|
|
162
|
+
const languages = getAvailableLocales() // ['zh-CN', 'en-US', 'zh-TW']
|
|
163
|
+
</script>
|
|
164
|
+
|
|
165
|
+
<template>
|
|
166
|
+
<view>
|
|
167
|
+
<button @click="setLanguage('zh-CN')">中文</button>
|
|
168
|
+
<button @click="setLanguage('en-US')">English</button>
|
|
169
|
+
<button @click="setLanguage('zh-TW')">繁體中文</button>
|
|
170
|
+
</view>
|
|
171
|
+
</template>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 注册自定义语言包
|
|
175
|
+
|
|
176
|
+
#### 方式一:注册新语言
|
|
177
|
+
|
|
178
|
+
添加组件库未内置的语言(如日语、韩语等):
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { registerLocale, setLanguage } from 'tang-ui-x'
|
|
182
|
+
|
|
183
|
+
// 注册日语语言包
|
|
184
|
+
registerLocale('ja-JP', {
|
|
185
|
+
common: {
|
|
186
|
+
confirm: '確認',
|
|
187
|
+
cancel: 'キャンセル',
|
|
188
|
+
ok: 'OK',
|
|
189
|
+
close: '閉じる',
|
|
190
|
+
loading: '読み込み中...',
|
|
191
|
+
noData: 'データなし'
|
|
192
|
+
},
|
|
193
|
+
dialog: {
|
|
194
|
+
title: 'ヒント',
|
|
195
|
+
confirmText: '確認',
|
|
196
|
+
cancelText: 'キャンセル'
|
|
197
|
+
},
|
|
198
|
+
empty: {
|
|
199
|
+
title: 'データなし',
|
|
200
|
+
description: '関連コンテンツがありません',
|
|
201
|
+
actionText: '更新'
|
|
202
|
+
},
|
|
203
|
+
searchBar: {
|
|
204
|
+
placeholder: '検索キーワードを入力',
|
|
205
|
+
cancelText: 'キャンセル'
|
|
206
|
+
}
|
|
207
|
+
// ... 其他组件模块
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
// 切换到日语
|
|
211
|
+
setLanguage('ja-JP')
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### 方式二:覆盖默认翻译
|
|
215
|
+
|
|
216
|
+
只覆盖部分翻译文本,其他保持默认:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import { registerLocale } from 'tang-ui-x'
|
|
220
|
+
|
|
221
|
+
// 自定义简体中文的部分翻译
|
|
222
|
+
registerLocale('zh-CN', {
|
|
223
|
+
common: {
|
|
224
|
+
confirm: '好的', // 覆盖默认的"确定"
|
|
225
|
+
cancel: '算了' // 覆盖默认的"取消"
|
|
226
|
+
// 其他键(ok, close, loading 等)保持默认值
|
|
227
|
+
}
|
|
228
|
+
// 其他模块(dialog, empty 等)保持默认翻译
|
|
229
|
+
})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 语言包注册模式
|
|
233
|
+
|
|
234
|
+
Tang UI X 提供了两种语言包注册模式,以满足不同的使用场景:**合并模式(merge)** 和 **替换模式(replace)**。
|
|
235
|
+
|
|
236
|
+
#### 合并模式(默认)
|
|
237
|
+
|
|
238
|
+
合并模式会将新语言包与现有语言包合并,新内容覆盖旧内容,但未覆盖的内容会被保留。这是 `registerLocale` 函数的默认行为。
|
|
239
|
+
|
|
240
|
+
**使用场景:**
|
|
241
|
+
- 只想覆盖部分翻译文本
|
|
242
|
+
- 添加新的翻译键而不影响现有翻译
|
|
243
|
+
- 逐步自定义组件库的翻译
|
|
244
|
+
|
|
245
|
+
**示例 1:覆盖部分通用文本**
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { registerLocale } from 'tang-ui-x'
|
|
249
|
+
|
|
250
|
+
// 只覆盖 common 模块的部分键
|
|
251
|
+
registerLocale('zh-CN', {
|
|
252
|
+
common: {
|
|
253
|
+
confirm: '好的', // 覆盖默认的"确定"
|
|
254
|
+
cancel: '算了' // 覆盖默认的"取消"
|
|
255
|
+
// ok, close, loading, noData 等其他键保持默认值
|
|
256
|
+
}
|
|
257
|
+
// dialog, empty, searchBar 等其他模块保持默认翻译
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
// 结果:
|
|
261
|
+
// - common.confirm → "好的"(已覆盖)
|
|
262
|
+
// - common.cancel → "算了"(已覆盖)
|
|
263
|
+
// - common.ok → "好的"(保持默认)
|
|
264
|
+
// - common.close → "关闭"(保持默认)
|
|
265
|
+
// - dialog.title → "提示"(保持默认)
|
|
266
|
+
// - empty.title → "暂无数据"(保持默认)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**示例 2:添加新的翻译键**
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import { registerLocale } from 'tang-ui-x'
|
|
273
|
+
|
|
274
|
+
// 为现有语言添加新的翻译键
|
|
275
|
+
registerLocale('zh-CN', {
|
|
276
|
+
common: {
|
|
277
|
+
save: '保存', // 新增键
|
|
278
|
+
delete: '删除', // 新增键
|
|
279
|
+
edit: '编辑' // 新增键
|
|
280
|
+
},
|
|
281
|
+
// 添加新的自定义模块
|
|
282
|
+
myComponent: {
|
|
283
|
+
title: '我的组件',
|
|
284
|
+
description: '这是自定义组件'
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
// 原有的所有翻译都会保留,只是新增了这些键
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**示例 3:使用 registerLocaleWithMode 显式指定合并模式**
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
import { registerLocaleWithMode } from 'tang-ui-x'
|
|
295
|
+
|
|
296
|
+
// 显式指定合并模式(与 registerLocale 效果相同)
|
|
297
|
+
registerLocaleWithMode('zh-CN', {
|
|
298
|
+
common: {
|
|
299
|
+
confirm: '好的'
|
|
300
|
+
}
|
|
301
|
+
}, 'merge')
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### 替换模式
|
|
305
|
+
|
|
306
|
+
替换模式会完全替换现有语言包,不保留任何原有内容。使用此模式时,您需要提供完整的语言包,否则缺失的模块和键将无法使用。
|
|
307
|
+
|
|
308
|
+
**使用场景:**
|
|
309
|
+
- 完全自定义某个语言的所有翻译
|
|
310
|
+
- 从外部 JSON 文件加载完整的语言包
|
|
311
|
+
- 确保语言包的完整性和一致性
|
|
312
|
+
|
|
313
|
+
**方式 1:使用 replaceLocale 函数**
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
import { replaceLocale } from 'tang-ui-x'
|
|
317
|
+
|
|
318
|
+
// 完全替换简体中文语言包
|
|
319
|
+
replaceLocale('zh-CN', {
|
|
320
|
+
common: {
|
|
321
|
+
confirm: '好的',
|
|
322
|
+
cancel: '取消',
|
|
323
|
+
ok: 'OK',
|
|
324
|
+
close: '关闭',
|
|
325
|
+
loading: '加载中...',
|
|
326
|
+
noData: '暂无数据'
|
|
327
|
+
},
|
|
328
|
+
dialog: {
|
|
329
|
+
title: '提示',
|
|
330
|
+
confirmText: '好的',
|
|
331
|
+
cancelText: '取消'
|
|
332
|
+
},
|
|
333
|
+
empty: {
|
|
334
|
+
title: '暂无数据',
|
|
335
|
+
description: '当前没有相关内容',
|
|
336
|
+
actionText: '刷新试试'
|
|
337
|
+
},
|
|
338
|
+
searchBar: {
|
|
339
|
+
placeholder: '请输入搜索关键词',
|
|
340
|
+
cancelText: '取消'
|
|
341
|
+
}
|
|
342
|
+
// 必须提供所有组件模块,否则缺失的模块将无法使用
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
// 注意:原有的所有翻译都被清除,只保留新提供的内容
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**方式 2:使用 registerLocaleWithMode 指定替换模式**
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
import { registerLocaleWithMode } from 'tang-ui-x'
|
|
352
|
+
|
|
353
|
+
// 使用替换模式注册语言包
|
|
354
|
+
registerLocaleWithMode('zh-CN', {
|
|
355
|
+
common: {
|
|
356
|
+
confirm: '好的',
|
|
357
|
+
cancel: '取消'
|
|
358
|
+
// ... 其他键
|
|
359
|
+
},
|
|
360
|
+
dialog: {
|
|
361
|
+
title: '提示'
|
|
362
|
+
// ... 其他键
|
|
363
|
+
}
|
|
364
|
+
// ... 其他模块
|
|
365
|
+
}, 'replace')
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
#### 从 JSON 文件注册语言包
|
|
369
|
+
|
|
370
|
+
您可以将语言包保存为 JSON 文件,然后导入并注册。这种方式特别适合管理大型语言包或从外部系统加载翻译。
|
|
371
|
+
|
|
372
|
+
**JSON 文件格式:**
|
|
373
|
+
|
|
374
|
+
```json
|
|
375
|
+
// custom-zh-CN.json
|
|
376
|
+
{
|
|
377
|
+
"common": {
|
|
378
|
+
"confirm": "好的",
|
|
379
|
+
"cancel": "取消",
|
|
380
|
+
"ok": "OK",
|
|
381
|
+
"close": "关闭",
|
|
382
|
+
"loading": "加载中...",
|
|
383
|
+
"noData": "暂无数据"
|
|
384
|
+
},
|
|
385
|
+
"dialog": {
|
|
386
|
+
"title": "提示",
|
|
387
|
+
"confirmText": "好的",
|
|
388
|
+
"cancelText": "取消"
|
|
389
|
+
},
|
|
390
|
+
"empty": {
|
|
391
|
+
"title": "暂无数据",
|
|
392
|
+
"description": "当前没有相关内容",
|
|
393
|
+
"actionText": "刷新试试"
|
|
394
|
+
},
|
|
395
|
+
"searchBar": {
|
|
396
|
+
"placeholder": "请输入搜索关键词",
|
|
397
|
+
"cancelText": "取消"
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**使用合并模式加载 JSON 文件:**
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import { registerLocale } from 'tang-ui-x'
|
|
406
|
+
import customZhCN from './locales/custom-zh-CN.json'
|
|
407
|
+
|
|
408
|
+
// 合并模式:保留未覆盖的默认翻译
|
|
409
|
+
registerLocale('zh-CN', customZhCN)
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**使用替换模式加载 JSON 文件:**
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
import { replaceLocale } from 'tang-ui-x'
|
|
416
|
+
import completeZhCN from './locales/complete-zh-CN.json'
|
|
417
|
+
|
|
418
|
+
// 替换模式:完全替换,不保留默认翻译
|
|
419
|
+
replaceLocale('zh-CN', completeZhCN)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**从多个 JSON 文件组合语言包:**
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { registerLocale } from 'tang-ui-x'
|
|
426
|
+
import commonTranslations from './locales/common.json'
|
|
427
|
+
import dialogTranslations from './locales/dialog.json'
|
|
428
|
+
import emptyTranslations from './locales/empty.json'
|
|
429
|
+
|
|
430
|
+
// 组合多个 JSON 文件
|
|
431
|
+
const customLocale = {
|
|
432
|
+
common: commonTranslations,
|
|
433
|
+
dialog: dialogTranslations,
|
|
434
|
+
empty: emptyTranslations
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// 注册组合后的语言包
|
|
438
|
+
registerLocale('zh-CN', customLocale)
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
#### 两种模式的对比
|
|
442
|
+
|
|
443
|
+
| 特性 | 合并模式(merge) | 替换模式(replace) |
|
|
444
|
+
|------|------------------|-------------------|
|
|
445
|
+
| **默认行为** | ✓ 是(registerLocale) | ✗ 否(需显式使用) |
|
|
446
|
+
| **保留原有内容** | ✓ 是 | ✗ 否 |
|
|
447
|
+
| **覆盖指定键** | ✓ 是 | ✓ 是 |
|
|
448
|
+
| **需要完整语言包** | ✗ 否 | ✓ 是 |
|
|
449
|
+
| **适合部分自定义** | ✓ 是 | ✗ 否 |
|
|
450
|
+
| **适合完全自定义** | ✗ 否 | ✓ 是 |
|
|
451
|
+
| **使用函数** | registerLocale<br>registerLocaleWithMode(..., 'merge') | replaceLocale<br>registerLocaleWithMode(..., 'replace') |
|
|
452
|
+
|
|
453
|
+
#### 选择合适的模式
|
|
454
|
+
|
|
455
|
+
**使用合并模式的情况:**
|
|
456
|
+
- ✓ 只想修改少数几个翻译文本
|
|
457
|
+
- ✓ 想要添加新的翻译键
|
|
458
|
+
- ✓ 希望保留组件库的默认翻译作为后备
|
|
459
|
+
- ✓ 逐步自定义翻译,不想一次性提供所有内容
|
|
460
|
+
|
|
461
|
+
**使用替换模式的情况:**
|
|
462
|
+
- ✓ 需要完全控制语言包内容
|
|
463
|
+
- ✓ 从外部系统或 CMS 加载完整的翻译
|
|
464
|
+
- ✓ 确保翻译的完整性和一致性
|
|
465
|
+
- ✓ 不希望依赖组件库的默认翻译
|
|
466
|
+
|
|
467
|
+
#### 完整示例:动态语言包管理
|
|
468
|
+
|
|
469
|
+
```vue
|
|
470
|
+
<script setup lang="uts">
|
|
471
|
+
import { registerLocale, replaceLocale, registerLocaleWithMode } from 'tang-ui-x'
|
|
472
|
+
import { ref } from 'vue'
|
|
473
|
+
|
|
474
|
+
// 场景 1:部分自定义(合并模式)
|
|
475
|
+
function customizePartial() {
|
|
476
|
+
registerLocale('zh-CN', {
|
|
477
|
+
common: {
|
|
478
|
+
confirm: '好的',
|
|
479
|
+
cancel: '算了'
|
|
480
|
+
}
|
|
481
|
+
})
|
|
482
|
+
console.log('已应用部分自定义翻译(合并模式)')
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// 场景 2:完全替换(替换模式)
|
|
486
|
+
function replaceComplete() {
|
|
487
|
+
replaceLocale('zh-CN', {
|
|
488
|
+
common: {
|
|
489
|
+
confirm: '确认',
|
|
490
|
+
cancel: '取消',
|
|
491
|
+
ok: 'OK',
|
|
492
|
+
close: '关闭',
|
|
493
|
+
loading: '加载中...',
|
|
494
|
+
noData: '暂无数据'
|
|
495
|
+
},
|
|
496
|
+
dialog: {
|
|
497
|
+
title: '提示',
|
|
498
|
+
confirmText: '确认',
|
|
499
|
+
cancelText: '取消'
|
|
500
|
+
}
|
|
501
|
+
// ... 提供所有必需的模块
|
|
502
|
+
})
|
|
503
|
+
console.log('已完全替换语言包(替换模式)')
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// 场景 3:从 JSON 文件加载
|
|
507
|
+
async function loadFromJSON() {
|
|
508
|
+
try {
|
|
509
|
+
// 假设从服务器获取语言包
|
|
510
|
+
const response = await fetch('/api/locales/zh-CN.json')
|
|
511
|
+
const localeData = await response.json()
|
|
512
|
+
|
|
513
|
+
// 使用合并模式
|
|
514
|
+
registerLocale('zh-CN', localeData)
|
|
515
|
+
|
|
516
|
+
// 或使用替换模式
|
|
517
|
+
// replaceLocale('zh-CN', localeData)
|
|
518
|
+
|
|
519
|
+
console.log('已从 JSON 加载语言包')
|
|
520
|
+
} catch (error) {
|
|
521
|
+
console.error('加载语言包失败:', error)
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// 场景 4:显式指定模式
|
|
526
|
+
function explicitMode() {
|
|
527
|
+
// 合并模式
|
|
528
|
+
registerLocaleWithMode('zh-CN', {
|
|
529
|
+
common: { confirm: '好的' }
|
|
530
|
+
}, 'merge')
|
|
531
|
+
|
|
532
|
+
// 替换模式
|
|
533
|
+
registerLocaleWithMode('en-US', {
|
|
534
|
+
common: {
|
|
535
|
+
confirm: 'OK',
|
|
536
|
+
cancel: 'Cancel'
|
|
537
|
+
// ... 完整内容
|
|
538
|
+
}
|
|
539
|
+
}, 'replace')
|
|
540
|
+
}
|
|
541
|
+
</script>
|
|
542
|
+
|
|
543
|
+
<template>
|
|
544
|
+
<view class="locale-manager">
|
|
545
|
+
<button @click="customizePartial">部分自定义(合并)</button>
|
|
546
|
+
<button @click="replaceComplete">完全替换</button>
|
|
547
|
+
<button @click="loadFromJSON">从 JSON 加载</button>
|
|
548
|
+
<button @click="explicitMode">显式指定模式</button>
|
|
549
|
+
</view>
|
|
550
|
+
</template>
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
#### 注意事项
|
|
554
|
+
|
|
555
|
+
1. **替换模式需要完整语言包**:使用替换模式时,确保提供所有必需的模块和键,否则缺失的翻译将无法使用。
|
|
556
|
+
|
|
557
|
+
2. **合并模式的覆盖规则**:在合并模式下,新键会覆盖旧键,但只在提供的模块内生效。未提供的模块完全保留。
|
|
558
|
+
|
|
559
|
+
3. **JSON 结构验证**:系统会验证注册的语言包结构。如果结构无效(如不是对象、包含非字符串值等),注册会失败并输出错误信息。
|
|
560
|
+
|
|
561
|
+
4. **模式选择建议**:如果不确定使用哪种模式,建议使用默认的合并模式(`registerLocale`),它更安全且易于使用。
|
|
562
|
+
|
|
563
|
+
### 语言包结构
|
|
564
|
+
|
|
565
|
+
语言包采用模块化结构,每个模块对应一组相关的翻译:
|
|
566
|
+
|
|
567
|
+
```typescript
|
|
568
|
+
{
|
|
569
|
+
// 通用文本模块
|
|
570
|
+
common: {
|
|
571
|
+
confirm: '确定',
|
|
572
|
+
cancel: '取消',
|
|
573
|
+
ok: '好的',
|
|
574
|
+
close: '关闭',
|
|
575
|
+
loading: '加载中...',
|
|
576
|
+
noData: '暂无数据'
|
|
577
|
+
},
|
|
578
|
+
|
|
579
|
+
// 对话框模块
|
|
580
|
+
dialog: {
|
|
581
|
+
title: '提示',
|
|
582
|
+
confirmText: '确定',
|
|
583
|
+
cancelText: '取消'
|
|
584
|
+
},
|
|
585
|
+
|
|
586
|
+
// 空状态模块
|
|
587
|
+
empty: {
|
|
588
|
+
title: '暂无数据',
|
|
589
|
+
description: '当前没有相关内容',
|
|
590
|
+
actionText: '刷新试试'
|
|
591
|
+
},
|
|
592
|
+
|
|
593
|
+
// 搜索框模块
|
|
594
|
+
searchBar: {
|
|
595
|
+
placeholder: '请输入搜索关键词',
|
|
596
|
+
cancelText: '取消'
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// ... 其他组件模块
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### 翻译键命名规范
|
|
604
|
+
|
|
605
|
+
翻译键采用 `模块名.键名` 的格式:
|
|
606
|
+
|
|
607
|
+
- `common.confirm` - 通用模块的确定按钮
|
|
608
|
+
- `dialog.title` - 对话框模块的标题
|
|
609
|
+
- `empty.description` - 空状态模块的描述文本
|
|
610
|
+
- `searchBar.placeholder` - 搜索框模块的占位符
|
|
611
|
+
|
|
612
|
+
### 组件中使用自定义文本
|
|
613
|
+
|
|
614
|
+
所有支持 i18n 的组件都允许通过 props 覆盖默认翻译:
|
|
615
|
+
|
|
616
|
+
```vue
|
|
617
|
+
<template>
|
|
618
|
+
<view>
|
|
619
|
+
<!-- 使用默认翻译 -->
|
|
620
|
+
<TEmpty />
|
|
621
|
+
|
|
622
|
+
<!-- 使用自定义文本(优先级高于翻译) -->
|
|
623
|
+
<TEmpty
|
|
624
|
+
title="没有找到结果"
|
|
625
|
+
description="请尝试其他搜索条件"
|
|
626
|
+
actionText="重新搜索"
|
|
627
|
+
/>
|
|
628
|
+
|
|
629
|
+
<!-- 使用默认翻译,但会随语言切换自动更新 -->
|
|
630
|
+
<TSearchBar />
|
|
631
|
+
|
|
632
|
+
<!-- 使用自定义占位符 -->
|
|
633
|
+
<TSearchBar placeholder="搜索商品" />
|
|
634
|
+
</view>
|
|
635
|
+
</template>
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### 参数插值
|
|
639
|
+
|
|
640
|
+
翻译文本支持动态参数替换:
|
|
641
|
+
|
|
642
|
+
```typescript
|
|
643
|
+
// 定义带占位符的翻译
|
|
644
|
+
registerLocale('zh-CN', {
|
|
645
|
+
common: {
|
|
646
|
+
hello: '你好,{name}',
|
|
647
|
+
itemCount: '共 {count} 个项目',
|
|
648
|
+
welcome: '{user},欢迎回来!'
|
|
649
|
+
}
|
|
650
|
+
})
|
|
651
|
+
|
|
652
|
+
// 使用参数
|
|
653
|
+
const { $t } = useI18n()
|
|
654
|
+
|
|
655
|
+
const greeting = $t('common.hello', { name: '张三' })
|
|
656
|
+
// 结果: "你好,张三"
|
|
657
|
+
|
|
658
|
+
const count = $t('common.itemCount', { count: 5 })
|
|
659
|
+
// 结果: "共 5 个项目"
|
|
660
|
+
|
|
661
|
+
const welcome = $t('common.welcome', { user: 'Admin' })
|
|
662
|
+
// 结果: "Admin,欢迎回来!"
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### 响应式语言切换
|
|
666
|
+
|
|
667
|
+
语言切换会自动触发所有使用翻译的组件更新:
|
|
668
|
+
|
|
669
|
+
```vue
|
|
670
|
+
<script setup lang="uts">
|
|
671
|
+
import { useI18n } from 'tang-ui-x'
|
|
672
|
+
|
|
673
|
+
const { $t, locale, setLocale } = useI18n()
|
|
674
|
+
|
|
675
|
+
// 这些文本会随语言切换自动更新
|
|
676
|
+
const title = computed(() => $t('common.confirm'))
|
|
677
|
+
const description = computed(() => $t('empty.description'))
|
|
678
|
+
</script>
|
|
679
|
+
|
|
680
|
+
<template>
|
|
681
|
+
<view>
|
|
682
|
+
<!-- 语言切换后,这些文本会自动更新 -->
|
|
683
|
+
<text>{{ title }}</text>
|
|
684
|
+
<text>{{ description }}</text>
|
|
685
|
+
<text>当前语言: {{ locale }}</text>
|
|
686
|
+
|
|
687
|
+
<!-- 组件内的文本也会自动更新 -->
|
|
688
|
+
<TEmpty />
|
|
689
|
+
<TSearchBar />
|
|
690
|
+
|
|
691
|
+
<button @click="setLocale('en-US')">English</button>
|
|
692
|
+
<button @click="setLocale('zh-CN')">中文</button>
|
|
693
|
+
</view>
|
|
694
|
+
</template>
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### 完整示例:语言切换器
|
|
698
|
+
|
|
699
|
+
创建一个完整的语言切换组件:
|
|
700
|
+
|
|
701
|
+
```vue
|
|
702
|
+
<script setup lang="uts">
|
|
703
|
+
import { useI18n, setLanguage } from 'tang-ui-x'
|
|
704
|
+
import { ref } from 'vue'
|
|
705
|
+
|
|
706
|
+
const { locale, availableLocales } = useI18n()
|
|
707
|
+
|
|
708
|
+
// 语言显示名称映射
|
|
709
|
+
const languageNames = {
|
|
710
|
+
'zh-CN': '简体中文',
|
|
711
|
+
'en-US': 'English',
|
|
712
|
+
'zh-TW': '繁體中文'
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// 切换语言
|
|
716
|
+
function switchLanguage(code: string) {
|
|
717
|
+
const success = setLanguage(code)
|
|
718
|
+
if (success) {
|
|
719
|
+
console.log(`已切换到: ${languageNames[code]}`)
|
|
720
|
+
} else {
|
|
721
|
+
console.error(`切换失败: ${code}`)
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
</script>
|
|
725
|
+
|
|
726
|
+
<template>
|
|
727
|
+
<view class="language-switcher">
|
|
728
|
+
<text class="title">选择语言 / Select Language</text>
|
|
729
|
+
|
|
730
|
+
<view class="language-list">
|
|
731
|
+
<view
|
|
732
|
+
v-for="lang in availableLocales"
|
|
733
|
+
:key="lang"
|
|
734
|
+
class="language-item"
|
|
735
|
+
:class="{ active: locale === lang }"
|
|
736
|
+
@click="switchLanguage(lang)"
|
|
737
|
+
>
|
|
738
|
+
<text>{{ languageNames[lang] || lang }}</text>
|
|
739
|
+
<text v-if="locale === lang" class="check">✓</text>
|
|
740
|
+
</view>
|
|
741
|
+
</view>
|
|
742
|
+
|
|
743
|
+
<text class="current">当前语言: {{ languageNames[locale] }}</text>
|
|
744
|
+
</view>
|
|
745
|
+
</template>
|
|
746
|
+
|
|
747
|
+
<style>
|
|
748
|
+
.language-switcher {
|
|
749
|
+
padding: 20px;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.title {
|
|
753
|
+
font-size: 18px;
|
|
754
|
+
font-weight: bold;
|
|
755
|
+
margin-bottom: 15px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.language-list {
|
|
759
|
+
border: 1px solid #e0e0e0;
|
|
760
|
+
border-radius: 8px;
|
|
761
|
+
overflow: hidden;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.language-item {
|
|
765
|
+
padding: 15px;
|
|
766
|
+
border-bottom: 1px solid #e0e0e0;
|
|
767
|
+
flex-direction: row;
|
|
768
|
+
justify-content: space-between;
|
|
769
|
+
align-items: center;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.language-item:last-child {
|
|
773
|
+
border-bottom: none;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.language-item.active {
|
|
777
|
+
background-color: #f0f9ff;
|
|
778
|
+
color: #0066cc;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
.check {
|
|
782
|
+
color: #0066cc;
|
|
783
|
+
font-weight: bold;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.current {
|
|
787
|
+
margin-top: 15px;
|
|
788
|
+
color: #666;
|
|
789
|
+
font-size: 14px;
|
|
790
|
+
}
|
|
791
|
+
</style>
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
### 组件迁移指南
|
|
795
|
+
|
|
796
|
+
如果您正在开发自定义组件并希望支持 i18n,请按以下步骤操作:
|
|
797
|
+
|
|
798
|
+
#### 步骤 1: 导入 useI18n
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
import { useI18n } from 'tang-ui-x'
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
#### 步骤 2: 在 setup 中获取翻译函数
|
|
805
|
+
|
|
806
|
+
```typescript
|
|
807
|
+
const { $t } = useI18n()
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
#### 步骤 3: 替换硬编码文本
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
// 之前
|
|
814
|
+
const confirmText = '确定'
|
|
815
|
+
|
|
816
|
+
// 之后
|
|
817
|
+
const confirmText = $t('common.confirm')
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
#### 步骤 4: 支持用户覆盖(推荐)
|
|
821
|
+
|
|
822
|
+
```typescript
|
|
823
|
+
interface Props {
|
|
824
|
+
title?: string
|
|
825
|
+
description?: string
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
const props = defineProps<Props>()
|
|
829
|
+
const { $t } = useI18n()
|
|
830
|
+
|
|
831
|
+
// 优先使用用户传入的值,否则使用翻译
|
|
832
|
+
const displayTitle = computed(() => props.title || $t('empty.title'))
|
|
833
|
+
const displayDescription = computed(() => props.description || $t('empty.description'))
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
#### 步骤 5: 更新模板
|
|
837
|
+
|
|
838
|
+
```vue
|
|
839
|
+
<template>
|
|
840
|
+
<view>
|
|
841
|
+
<!-- 使用计算属性 -->
|
|
842
|
+
<text>{{ displayTitle }}</text>
|
|
843
|
+
<text>{{ displayDescription }}</text>
|
|
844
|
+
</view>
|
|
845
|
+
</template>
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
#### 完整示例
|
|
849
|
+
|
|
850
|
+
```vue
|
|
851
|
+
<script setup lang="uts">
|
|
852
|
+
import { useI18n } from 'tang-ui-x'
|
|
853
|
+
import { computed } from 'vue'
|
|
854
|
+
|
|
855
|
+
interface Props {
|
|
856
|
+
title?: string
|
|
857
|
+
description?: string
|
|
858
|
+
actionText?: string
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const props = defineProps<Props>()
|
|
862
|
+
const { $t } = useI18n()
|
|
863
|
+
|
|
864
|
+
// 优先使用用户传入的值
|
|
865
|
+
const displayTitle = computed(() => props.title || $t('empty.title'))
|
|
866
|
+
const displayDescription = computed(() => props.description || $t('empty.description'))
|
|
867
|
+
const displayActionText = computed(() => props.actionText || $t('empty.actionText'))
|
|
868
|
+
|
|
869
|
+
function handleAction() {
|
|
870
|
+
console.log('Action clicked')
|
|
871
|
+
}
|
|
872
|
+
</script>
|
|
873
|
+
|
|
874
|
+
<template>
|
|
875
|
+
<view class="custom-component">
|
|
876
|
+
<text class="title">{{ displayTitle }}</text>
|
|
877
|
+
<text class="description">{{ displayDescription }}</text>
|
|
878
|
+
<button @click="handleAction">{{ displayActionText }}</button>
|
|
879
|
+
</view>
|
|
880
|
+
</template>
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
### API 参考
|
|
884
|
+
|
|
885
|
+
#### useI18n()
|
|
886
|
+
|
|
887
|
+
组合式 API,用于在组件中使用 i18n 功能。
|
|
888
|
+
|
|
889
|
+
**返回值:**
|
|
890
|
+
|
|
891
|
+
```typescript
|
|
892
|
+
{
|
|
893
|
+
$t: (key: string, params?: Record<string, any>) => string
|
|
894
|
+
locale: ComputedRef<string>
|
|
895
|
+
availableLocales: ComputedRef<string[]>
|
|
896
|
+
setLocale: (locale: string) => boolean
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
#### 全局函数
|
|
901
|
+
|
|
902
|
+
##### setLanguage(locale: string): boolean
|
|
903
|
+
|
|
904
|
+
切换应用语言。
|
|
905
|
+
|
|
906
|
+
- **参数:**
|
|
907
|
+
- `locale`: 语言代码(如 'zh-CN', 'en-US')
|
|
908
|
+
- **返回值:** 切换是否成功
|
|
909
|
+
|
|
910
|
+
##### registerLocale(locale: string, messages: object): void
|
|
911
|
+
|
|
912
|
+
注册或更新语言包。
|
|
913
|
+
|
|
914
|
+
- **参数:**
|
|
915
|
+
- `locale`: 语言代码
|
|
916
|
+
- `messages`: 模块化语言包对象
|
|
917
|
+
|
|
918
|
+
##### getCurrentLocale(): string
|
|
919
|
+
|
|
920
|
+
获取当前语言代码。
|
|
921
|
+
|
|
922
|
+
- **返回值:** 当前语言代码
|
|
923
|
+
|
|
924
|
+
##### getAvailableLocales(): string[]
|
|
925
|
+
|
|
926
|
+
获取所有可用语言列表。
|
|
927
|
+
|
|
928
|
+
- **返回值:** 语言代码数组
|
|
929
|
+
|
|
930
|
+
### 常见问题
|
|
931
|
+
|
|
932
|
+
#### Q: 如何添加新语言?
|
|
933
|
+
|
|
934
|
+
A: 使用 `registerLocale` 函数注册新语言包,然后使用 `setLanguage` 切换。
|
|
935
|
+
|
|
936
|
+
```typescript
|
|
937
|
+
registerLocale('ja-JP', { /* 日语翻译 */ })
|
|
938
|
+
setLanguage('ja-JP')
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
#### Q: 如何覆盖默认翻译?
|
|
942
|
+
|
|
943
|
+
A: 使用 `registerLocale` 注册同语言代码的语言包,只需包含要覆盖的键。
|
|
944
|
+
|
|
945
|
+
```typescript
|
|
946
|
+
registerLocale('zh-CN', {
|
|
947
|
+
common: {
|
|
948
|
+
confirm: '好的' // 只覆盖这一个键
|
|
949
|
+
}
|
|
950
|
+
})
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
#### Q: 组件的文本不随语言切换更新?
|
|
954
|
+
|
|
955
|
+
A: 确保使用 `computed` 包装翻译文本:
|
|
956
|
+
|
|
957
|
+
```typescript
|
|
958
|
+
// ❌ 错误:不会更新
|
|
959
|
+
const title = $t('common.title')
|
|
960
|
+
|
|
961
|
+
// ✓ 正确:会自动更新
|
|
962
|
+
const title = computed(() => $t('common.title'))
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
#### Q: 如何在组件外使用翻译?
|
|
966
|
+
|
|
967
|
+
A: 使用全局函数或直接访问 I18nManager:
|
|
968
|
+
|
|
969
|
+
```typescript
|
|
970
|
+
import { getCurrentLocale } from 'tang-ui-x'
|
|
971
|
+
|
|
972
|
+
const locale = getCurrentLocale()
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
#### Q: 支持哪些语言?
|
|
976
|
+
|
|
977
|
+
A: 内置支持简体中文、英语、繁体中文。您可以通过 `registerLocale` 添加任何语言。
|
|
978
|
+
|
|
979
|
+
### 跨平台支持
|
|
980
|
+
|
|
981
|
+
Tang UI X 的国际化系统经过精心设计,确保在所有 uni-app x 支持的平台上都能正常工作。
|
|
982
|
+
|
|
983
|
+
#### 支持的平台
|
|
984
|
+
|
|
985
|
+
i18n 系统已在以下平台测试并验证:
|
|
986
|
+
|
|
987
|
+
- ✅ **Web H5** - 浏览器环境
|
|
988
|
+
- ✅ **微信小程序** - WeChat Mini Program
|
|
989
|
+
- ✅ **支付宝小程序** - Alipay Mini Program
|
|
990
|
+
- ✅ **App (Android/iOS)** - 原生应用
|
|
991
|
+
|
|
992
|
+
#### 跨平台兼容性设计
|
|
993
|
+
|
|
994
|
+
为了确保在所有平台上的一致性和可靠性,i18n 系统采用了以下技术方案:
|
|
995
|
+
|
|
996
|
+
**1. 静态导入机制**
|
|
997
|
+
|
|
998
|
+
所有语言包文件使用静态 `import` 语句导入,避免使用动态导入或平台特定 API(如 `import.meta.glob`),确保在小程序等受限环境中也能正常工作。
|
|
999
|
+
|
|
1000
|
+
```typescript
|
|
1001
|
+
// ✓ 使用静态导入(跨平台兼容)
|
|
1002
|
+
import zhCNCommon from '../locales/zh-CN/common.json'
|
|
1003
|
+
import enUSCommon from '../locales/en-US/common.json'
|
|
1004
|
+
|
|
1005
|
+
// ✗ 避免动态导入(小程序不支持)
|
|
1006
|
+
// const module = await import(`../locales/${locale}/common.json`)
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
**2. 编译时确定性**
|
|
1010
|
+
|
|
1011
|
+
所有文件路径在编译时可解析,确保打包工具能够正确处理语言包文件,无论目标平台是什么。
|
|
1012
|
+
|
|
1013
|
+
**3. 同步初始化**
|
|
1014
|
+
|
|
1015
|
+
i18n 系统使用同步初始化方式,避免异步操作可能带来的平台兼容性问题:
|
|
1016
|
+
|
|
1017
|
+
```typescript
|
|
1018
|
+
// 同步初始化,所有平台都支持
|
|
1019
|
+
import { useI18n } from 'tang-ui-x'
|
|
1020
|
+
const { $t } = useI18n()
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
**4. JSON 文件处理**
|
|
1024
|
+
|
|
1025
|
+
语言包使用标准 JSON 格式,确保在所有平台的编译和打包过程中都能被正确处理。
|
|
1026
|
+
|
|
1027
|
+
#### 平台特定注意事项
|
|
1028
|
+
|
|
1029
|
+
**小程序平台**
|
|
1030
|
+
|
|
1031
|
+
- ✓ 语言包会在编译时被打包到小程序包中
|
|
1032
|
+
- ✓ 所有 i18n API 都可以正常使用
|
|
1033
|
+
- ✓ 语言切换会立即生效,无需重启小程序
|
|
1034
|
+
|
|
1035
|
+
**App 平台**
|
|
1036
|
+
|
|
1037
|
+
- ✓ 语言包会被编译到原生应用中
|
|
1038
|
+
- ✓ 支持热更新后的语言切换
|
|
1039
|
+
- ✓ 性能与 Web 平台一致
|
|
1040
|
+
|
|
1041
|
+
**Web H5 平台**
|
|
1042
|
+
|
|
1043
|
+
- ✓ 语言包会被打包到 JavaScript bundle 中
|
|
1044
|
+
- ✓ 支持浏览器缓存优化
|
|
1045
|
+
- ✓ 可以与浏览器语言检测结合使用
|
|
1046
|
+
|
|
1047
|
+
#### 使用建议
|
|
1048
|
+
|
|
1049
|
+
1. **统一的代码**: 在所有平台使用相同的 i18n 代码,无需平台判断
|
|
1050
|
+
2. **提前测试**: 在目标平台上测试语言切换功能
|
|
1051
|
+
3. **包体积优化**: 如果只需要部分语言,可以考虑按需注册语言包
|
|
1052
|
+
|
|
1053
|
+
#### 示例:跨平台语言切换
|
|
1054
|
+
|
|
1055
|
+
以下代码在所有平台上都能正常工作:
|
|
1056
|
+
|
|
1057
|
+
```vue
|
|
1058
|
+
<script setup lang="uts">
|
|
1059
|
+
import { useI18n, setLanguage } from 'tang-ui-x'
|
|
1060
|
+
|
|
1061
|
+
const { locale, availableLocales } = useI18n()
|
|
1062
|
+
|
|
1063
|
+
// 这段代码在所有平台都能正常运行
|
|
1064
|
+
function switchLanguage(lang: string) {
|
|
1065
|
+
const success = setLanguage(lang)
|
|
1066
|
+
if (success) {
|
|
1067
|
+
// 在所有平台上,UI 都会立即更新
|
|
1068
|
+
console.log(`语言已切换到: ${lang}`)
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
</script>
|
|
1072
|
+
|
|
1073
|
+
<template>
|
|
1074
|
+
<view>
|
|
1075
|
+
<!-- 在所有平台上显示效果一致 -->
|
|
1076
|
+
<button @click="switchLanguage('zh-CN')">中文</button>
|
|
1077
|
+
<button @click="switchLanguage('en-US')">English</button>
|
|
1078
|
+
<button @click="switchLanguage('zh-TW')">繁體中文</button>
|
|
1079
|
+
|
|
1080
|
+
<text>当前语言: {{ locale }}</text>
|
|
1081
|
+
</view>
|
|
1082
|
+
</template>
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
#### 技术细节
|
|
1086
|
+
|
|
1087
|
+
如果您对 i18n 系统的跨平台实现感兴趣,以下是关键技术点:
|
|
1088
|
+
|
|
1089
|
+
- **语言包加载器**: 使用静态导入映射表,在编译时确定所有语言包路径
|
|
1090
|
+
- **模块注册表**: 显式维护模块列表,避免运行时文件系统访问
|
|
1091
|
+
- **响应式系统**: 基于 Vue 3 的响应式系统,在所有平台上表现一致
|
|
1092
|
+
- **无外部依赖**: 不依赖任何平台特定的 API 或第三方库
|
|
1093
|
+
|
|
91
1094
|
## 📚 组件列表
|
|
92
1095
|
|
|
93
1096
|
### 基础组件 (5个)
|