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.
Files changed (91) hide show
  1. package/README.md +1003 -0
  2. package/components/TActionSheet/index.uvue +15 -2
  3. package/components/TCheckboxGroup/index.uvue +30 -11
  4. package/components/TCheckboxGroup/type.uts +10 -0
  5. package/components/TCollapse/index.uvue +1 -1
  6. package/components/TCollapse/type.uts +3 -1
  7. package/components/TCollapseItem/index.uvue +22 -26
  8. package/components/TDialog/index.uvue +19 -4
  9. package/components/TEmpty/index.uvue +28 -14
  10. package/components/TForm/index.uvue +394 -392
  11. package/components/TForm/type.uts +90 -80
  12. package/components/TInput/index.uvue +24 -5
  13. package/components/TInput/type.uts +10 -0
  14. package/components/TPicker/index.uvue +26 -6
  15. package/components/TRadioGroup/index.uvue +32 -12
  16. package/components/TRadioGroup/type.uts +7 -0
  17. package/components/TSearchBar/index.uvue +19 -4
  18. package/composables/i18n/error.uts +82 -0
  19. package/composables/i18n/index.uts +188 -0
  20. package/composables/i18n/manager-demo.uts +104 -0
  21. package/composables/i18n/manager.test.uts +182 -0
  22. package/composables/i18n/manager.uts +531 -0
  23. package/composables/i18n/register-demo.uts +125 -0
  24. package/composables/i18n/task22-verification.uts +198 -0
  25. package/composables/i18n/task23-verification.uts +343 -0
  26. package/composables/i18n/task8-demo.uts +93 -0
  27. package/composables/i18n/task8-verification.uts +98 -0
  28. package/composables/i18n/test-task23.uts +9 -0
  29. package/composables/i18n/types.uts +46 -0
  30. package/composables/i18n/useI18n-verification.uts +105 -0
  31. package/composables/i18n/validation-demo.uts +45 -0
  32. package/composables/i18n/validation-test.uts +106 -0
  33. package/composables/useI18n.uts +77 -0
  34. package/index.uts +23 -0
  35. package/locales/cross-platform-verification.uts +510 -0
  36. package/locales/en-US/actionSheet.json +3 -0
  37. package/locales/en-US/common.json +17 -0
  38. package/locales/en-US/dialog.json +5 -0
  39. package/locales/en-US/empty.json +6 -0
  40. package/locales/en-US/errorState.json +5 -0
  41. package/locales/en-US/examplePages.json +1236 -0
  42. package/locales/en-US/examples.json +218 -0
  43. package/locales/en-US/form.json +18 -0
  44. package/locales/en-US/input.json +3 -0
  45. package/locales/en-US/list.json +5 -0
  46. package/locales/en-US/loading.json +3 -0
  47. package/locales/en-US/navBar.json +4 -0
  48. package/locales/en-US/noticeBar.json +3 -0
  49. package/locales/en-US/picker.json +5 -0
  50. package/locales/en-US/searchBar.json +4 -0
  51. package/locales/en-US/textarea.json +3 -0
  52. package/locales/en-US/toast.json +6 -0
  53. package/locales/index.uts +79 -0
  54. package/locales/init-verification.uts +101 -0
  55. package/locales/loader.uts +251 -0
  56. package/locales/run-verification.uts +16 -0
  57. package/locales/zh-CN/actionSheet.json +3 -0
  58. package/locales/zh-CN/common.json +17 -0
  59. package/locales/zh-CN/dialog.json +5 -0
  60. package/locales/zh-CN/empty.json +6 -0
  61. package/locales/zh-CN/errorState.json +5 -0
  62. package/locales/zh-CN/examplePages.json +1236 -0
  63. package/locales/zh-CN/examples.json +218 -0
  64. package/locales/zh-CN/form.json +18 -0
  65. package/locales/zh-CN/input.json +3 -0
  66. package/locales/zh-CN/list.json +5 -0
  67. package/locales/zh-CN/loading.json +3 -0
  68. package/locales/zh-CN/navBar.json +4 -0
  69. package/locales/zh-CN/noticeBar.json +3 -0
  70. package/locales/zh-CN/picker.json +5 -0
  71. package/locales/zh-CN/searchBar.json +4 -0
  72. package/locales/zh-CN/textarea.json +3 -0
  73. package/locales/zh-CN/toast.json +6 -0
  74. package/locales/zh-TW/actionSheet.json +3 -0
  75. package/locales/zh-TW/common.json +15 -0
  76. package/locales/zh-TW/dialog.json +5 -0
  77. package/locales/zh-TW/empty.json +6 -0
  78. package/locales/zh-TW/errorState.json +5 -0
  79. package/locales/zh-TW/examplePages.json +705 -0
  80. package/locales/zh-TW/examples.json +218 -0
  81. package/locales/zh-TW/form.json +18 -0
  82. package/locales/zh-TW/input.json +3 -0
  83. package/locales/zh-TW/list.json +5 -0
  84. package/locales/zh-TW/loading.json +3 -0
  85. package/locales/zh-TW/navBar.json +4 -0
  86. package/locales/zh-TW/noticeBar.json +3 -0
  87. package/locales/zh-TW/picker.json +5 -0
  88. package/locales/zh-TW/searchBar.json +4 -0
  89. package/locales/zh-TW/textarea.json +3 -0
  90. package/locales/zh-TW/toast.json +6 -0
  91. package/package.json +3 -2
@@ -1,80 +1,90 @@
1
- /**
2
- * 表单选项类型
3
- */
4
- export type FormOption = {
5
- label: string
6
- value: string | number
7
- }
8
-
9
- /**
10
- * 组件通用属性
11
- */
12
- export type ComponentProps = {
13
- /** 占位符 */
14
- placeholder?: string
15
- /** 是否禁用 */
16
- disabled?: boolean
17
- /** 选项列表(用于 select、radio、checkbox) */
18
- options?: FormOption[]
19
- /** 输入类型(用于 input) */
20
- type?: string
21
- /** 最大长度(用于 input、textarea) */
22
- maxlength?: number
23
- /** 最小值(用于 number、slider) */
24
- min?: number
25
- /** 最大值(用于 number、slider、rate) */
26
- max?: number
27
- /** 步长(用于 slider) */
28
- step?: number
29
- /** 是否自动聚焦(用于 input、textarea) */
30
- focus?: boolean
31
- /** 确认按钮文字(用于 input) */
32
- confirmType?: string
33
- /** 是否自动高度(用于 textarea) */
34
- autoHeight?: boolean
35
- /** 是否显示确认栏(用于 textarea) */
36
- showConfirmBar?: boolean
37
- /** 开始日期(用于 date) */
38
- start?: string
39
- /** 结束日期(用于 date) */
40
- end?: string
41
- /** 激活颜色(用于 switch) */
42
- color?: string
43
- /** 是否允许半星(用于 rate) */
44
- allowHalf?: boolean
45
- /** 是否显示值(用于 slider) */
46
- showValue?: boolean
47
- /** 其他扩展属性 */
48
- [key: string]: any
49
- }
50
-
51
- /**
52
- * 表单字段配置
53
- */
54
- export type FormSchema = {
55
- /** 字段名 */
56
- field: string
57
- /** 标签文本 */
58
- label: string
59
- /** 组件类型 */
60
- component: 'Input' | 'Textarea' | 'Select' | 'Date' | 'Time' | 'Radio' | 'Checkbox' | 'Switch' | 'Rate' | 'Slider' | 'InputNumber'
61
- /** 是否必填 */
62
- required?: boolean
63
- /** 组件属性 */
64
- componentProps?: ComponentProps
65
- }
66
-
67
- /**
68
- * 表单组件属性
69
- */
70
- export type TFormProps = {
71
- /** 表单配置 */
72
- schemas: FormSchema[]
73
- /** 标签宽度 */
74
- labelWidth?: string
75
- /** 是否隐藏默认按钮 */
76
- hideButtons?: boolean
77
- }
78
-
79
- // 导出所有类型
80
- export { FormOption, ComponentProps, FormSchema, TFormProps }
1
+ /**
2
+ * 表单选项类型
3
+ */
4
+ export type FormOption = {
5
+ label: string
6
+ value: string | number
7
+ }
8
+
9
+ /**
10
+ * 组件通用属性
11
+ */
12
+ export type ComponentProps = {
13
+ /** 占位符 */
14
+ placeholder?: string
15
+ /** 是否禁用 */
16
+ disabled?: boolean
17
+ /** 选项列表(用于 select、radio、checkbox) */
18
+ options?: FormOption[]
19
+ /** 输入类型(用于 input) */
20
+ type?: string
21
+ /** 最大长度(用于 input、textarea) */
22
+ maxlength?: number
23
+ /** 最小值(用于 number、slider) */
24
+ min?: number
25
+ /** 最大值(用于 number、slider、rate) */
26
+ max?: number
27
+ /** 步长(用于 slider) */
28
+ step?: number
29
+ /** 是否自动聚焦(用于 input、textarea) */
30
+ focus?: boolean
31
+ /** 确认按钮文字(用于 input) */
32
+ confirmType?: string
33
+ /** 是否自动高度(用于 textarea) */
34
+ autoHeight?: boolean
35
+ /** 是否显示确认栏(用于 textarea) */
36
+ showConfirmBar?: boolean
37
+ /** 开始日期(用于 date) */
38
+ start?: string
39
+ /** 结束日期(用于 date) */
40
+ end?: string
41
+ /** 激活颜色(用于 switch) */
42
+ color?: string
43
+ /** 是否允许半星(用于 rate) */
44
+ allowHalf?: boolean
45
+ /** 是否显示值(用于 slider) */
46
+ showValue?: boolean
47
+ /** 其他扩展属性 */
48
+ [key: string]: any
49
+ }
50
+
51
+ /**
52
+ * 表单字段配置
53
+ */
54
+ export type FormSchema = {
55
+ /** 字段名 */
56
+ field: string
57
+ /** 标签文本 */
58
+ label: string
59
+ /** 组件类型 */
60
+ component: 'Input' | 'Textarea' | 'Select' | 'Date' | 'Time' | 'Radio' | 'Checkbox' | 'Switch' | 'Rate' | 'Slider' | 'InputNumber'
61
+ /** 是否必填 */
62
+ required?: boolean
63
+ /** 组件属性 */
64
+ componentProps?: ComponentProps
65
+ /** 单个配置项的布局方向(优先级高于整体 layout) */
66
+ layout?: 'horizontal' | 'vertical'
67
+ /** 单个配置项的标签宽度(优先级高于整体 labelWidth) */
68
+ labelWidth?: string
69
+ }
70
+
71
+ /**
72
+ * 表单组件属性
73
+ */
74
+ export type TFormProps = {
75
+ /** 表单配置 */
76
+ schemas: FormSchema[]
77
+ /** 标签宽度 */
78
+ labelWidth?: string
79
+ /** 表单项布局方向 */
80
+ layout?: 'horizontal' | 'vertical'
81
+ /** 是否隐藏默认按钮 */
82
+ hideButtons?: boolean
83
+ /** 提交按钮文本 */
84
+ submitText?: string
85
+ /** 重置按钮文本 */
86
+ resetText?: string
87
+ }
88
+
89
+ // 导出所有类型
90
+ export { FormOption, ComponentProps, FormSchema, TFormProps }
@@ -16,6 +16,8 @@ const props = withDefaults(defineProps<TInputProps>(), {
16
16
  clearable: false,
17
17
  showCount: false,
18
18
  maxlength: -1,
19
+ prefix: '',
20
+ suffix: '',
19
21
  prefixIcon: '',
20
22
  suffixIcon: '',
21
23
  rows: 3,
@@ -70,13 +72,13 @@ const inputWrapperClasses = computed((): string => {
70
72
  classes.push('t-input--focused')
71
73
  }
72
74
 
73
- // 前缀图标
74
- if (props.prefixIcon) {
75
+ // 前缀文本或图标
76
+ if (props.prefix || props.prefixIcon) {
75
77
  classes.push('t-input--prefix')
76
78
  }
77
79
 
78
- // 后缀图标或清除按钮
79
- if (props.suffixIcon || props.clearable) {
80
+ // 后缀文本、图标或清除按钮
81
+ if (props.suffix || props.suffixIcon || props.clearable) {
80
82
  classes.push('t-input--suffix')
81
83
  }
82
84
 
@@ -142,8 +144,13 @@ const handleConfirm = () => {
142
144
 
143
145
  <template>
144
146
  <view class="t-input" :class="inputWrapperClasses" :style="customStyle">
147
+ <!-- 前缀文本 -->
148
+ <view v-if="prefix" class="t-input__prefix">
149
+ <text class="t-input__prefix-text">{{ prefix }}</text>
150
+ </view>
151
+
145
152
  <!-- 前缀图标 -->
146
- <view v-if="prefixIcon" class="t-input__prefix">
153
+ <view v-else-if="prefixIcon" class="t-input__prefix">
147
154
  <text class="t-input__icon">{{ prefixIcon }}</text>
148
155
  </view>
149
156
 
@@ -189,6 +196,11 @@ const handleConfirm = () => {
189
196
  <text class="t-input__icon">✕</text>
190
197
  </view>
191
198
 
199
+ <!-- 后缀文本 -->
200
+ <view v-else-if="suffix" class="t-input__suffix">
201
+ <text class="t-input__suffix-text">{{ suffix }}</text>
202
+ </view>
203
+
192
204
  <!-- 后缀图标 -->
193
205
  <view v-else-if="suffixIcon" class="t-input__suffix">
194
206
  <text class="t-input__icon">{{ suffixIcon }}</text>
@@ -242,6 +254,13 @@ const handleConfirm = () => {
242
254
  font-size: 16px;
243
255
  }
244
256
 
257
+ &__prefix-text,
258
+ &__suffix-text {
259
+ font-size: 14px;
260
+ color: #606266;
261
+ white-space: nowrap;
262
+ }
263
+
245
264
  &__inner,
246
265
  &__textarea {
247
266
  flex: 1;
@@ -63,6 +63,16 @@ export interface TInputProps {
63
63
  */
64
64
  maxlength?: number
65
65
 
66
+ /**
67
+ * 前缀文本
68
+ */
69
+ prefix?: string
70
+
71
+ /**
72
+ * 后缀文本
73
+ */
74
+ suffix?: string
75
+
66
76
  /**
67
77
  * 前缀图标
68
78
  */
@@ -1,6 +1,7 @@
1
1
  <script setup lang="uts">
2
2
  import { computed, ref, watch } from 'vue'
3
3
  import type { TPickerProps, TPickerOption } from './type.uts'
4
+ import { useI18n } from '../../composables/useI18n.uts'
4
5
 
5
6
  /**
6
7
  * TPicker 通用选择器组件
@@ -11,11 +12,8 @@ import type { TPickerProps, TPickerOption } from './type.uts'
11
12
  type Props = Omit<TPickerProps, 'visible'>
12
13
 
13
14
  const props = withDefaults(defineProps<Props>(), {
14
- title: '请选择',
15
15
  options: () => [] as TPickerOption[],
16
16
  columns: () => [] as TPickerOption[][],
17
- confirmText: '确定',
18
- cancelText: '取消',
19
17
  itemHeight: '44px',
20
18
  visibleItemCount: 5,
21
19
  showToolbar: true
@@ -34,6 +32,28 @@ const emit = defineEmits<{
34
32
  change: [value: any, index: number | number[], columnIndex: number]
35
33
  }>()
36
34
 
35
+ // 使用 i18n
36
+ const { $t } = useI18n()
37
+
38
+ // 优先使用用户传入的值,否则使用翻译
39
+ const displayTitle = computed(() => {
40
+ return props.title !== undefined && props.title !== ''
41
+ ? props.title
42
+ : $t('picker.title')
43
+ })
44
+
45
+ const displayConfirmText = computed(() => {
46
+ return props.confirmText !== undefined && props.confirmText !== ''
47
+ ? props.confirmText
48
+ : $t('picker.confirmText')
49
+ })
50
+
51
+ const displayCancelText = computed(() => {
52
+ return props.cancelText !== undefined && props.cancelText !== ''
53
+ ? props.cancelText
54
+ : $t('picker.cancelText')
55
+ })
56
+
37
57
  // 当前选中的索引(单列为 number,多列为 number[])
38
58
  const selectedIndex = ref<number[]>([0])
39
59
 
@@ -154,13 +174,13 @@ const handleChange = (e: any): void => {
154
174
  <!-- 工具栏 -->
155
175
  <view v-if="showToolbar" class="t-picker__toolbar">
156
176
  <view class="t-picker__btn t-picker__btn--cancel" @click="handleCancel">
157
- <text class="t-picker__btn-text">{{ cancelText }}</text>
177
+ <text class="t-picker__btn-text">{{ displayCancelText }}</text>
158
178
  </view>
159
179
  <view class="t-picker__title">
160
- <text class="t-picker__title-text">{{ title }}</text>
180
+ <text class="t-picker__title-text">{{ displayTitle }}</text>
161
181
  </view>
162
182
  <view class="t-picker__btn t-picker__btn--confirm" @click="handleConfirm">
163
- <text class="t-picker__btn-text t-picker__btn-text--primary">{{ confirmText }}</text>
183
+ <text class="t-picker__btn-text t-picker__btn-text--primary">{{ displayConfirmText }}</text>
164
184
  </view>
165
185
  </view>
166
186
 
@@ -12,6 +12,9 @@ type Props = Omit<TRadioGroupProps, 'modelValue'>
12
12
  const props = withDefaults(defineProps<Props>(), {
13
13
  options: () => [] as RadioOption[],
14
14
  direction: 'vertical',
15
+ size: 'medium',
16
+ activeColor: '#00bba7',
17
+ inactiveColor: '#c8c9cc',
15
18
  disabled: false,
16
19
  customClass: '',
17
20
  customStyle: ''
@@ -34,20 +37,37 @@ const handleChange = (option: RadioOption): void => {
34
37
  const isChecked = (option: RadioOption): boolean => {
35
38
  return modelValue.value === option.value
36
39
  }
40
+
41
+ // 尺寸映射
42
+ const sizeMap = {
43
+ small: { icon: 28, dot: 14, fontSize: 24 },
44
+ medium: { icon: 36, dot: 20, fontSize: 28 },
45
+ large: { icon: 44, dot: 26, fontSize: 32 }
46
+ }
47
+
48
+ const currentSize = computed(() => sizeMap[props.size])
49
+
50
+ const cssVars = computed(() => ({
51
+ '--icon-size': `${currentSize.value.icon}rpx`,
52
+ '--dot-size': `${currentSize.value.dot}rpx`,
53
+ '--font-size': `${currentSize.value.fontSize}rpx`,
54
+ '--active-color': props.activeColor,
55
+ '--inactive-color': props.inactiveColor
56
+ }))
37
57
  </script>
38
58
 
39
59
  <template>
40
60
  <view
41
61
  class="t-radio-group"
42
62
  :class="[`t-radio-group--${direction}`, customClass]"
43
- :style="customStyle"
63
+ :style="[customStyle, cssVars]"
44
64
  >
45
65
  <view
46
66
  v-for="(option, index) in options"
47
67
  :key="index"
48
68
  class="t-radio-group__item"
49
69
  :class="{ 't-radio-group__item--disabled': disabled || option.disabled }"
50
- @click="() => handleChange(option)"
70
+ @click="handleChange(option)"
51
71
  >
52
72
  <view class="t-radio-group__icon" :class="{ 't-radio-group__icon--checked': isChecked(option) }">
53
73
  <view v-if="isChecked(option)" class="t-radio-group__dot"></view>
@@ -73,7 +93,7 @@ const isChecked = (option: RadioOption): boolean => {
73
93
 
74
94
  .t-radio-group__item {
75
95
  display: flex;
76
- align-items: center;
96
+ flex-direction: row;
77
97
  padding: 12px 0;
78
98
  cursor: pointer;
79
99
 
@@ -88,30 +108,30 @@ const isChecked = (option: RadioOption): boolean => {
88
108
  }
89
109
 
90
110
  .t-radio-group__icon {
91
- width: 20px;
92
- height: 20px;
93
- border: 2px solid #c8c9cc;
111
+ width: var(--icon-size);
112
+ height: var(--icon-size);
113
+ border: 2rpx solid var(--inactive-color);
94
114
  border-radius: 50%;
95
- margin-right: 8px;
115
+ margin-right: 16rpx;
96
116
  display: flex;
97
117
  align-items: center;
98
118
  justify-content: center;
99
119
  transition: all 0.3s;
100
120
 
101
121
  &--checked {
102
- border-color: #1890ff;
122
+ border-color: var(--active-color);
103
123
  }
104
124
  }
105
125
 
106
126
  .t-radio-group__dot {
107
- width: 10px;
108
- height: 10px;
109
- background-color: #1890ff;
127
+ width: var(--dot-size);
128
+ height: var(--dot-size);
129
+ background-color: var(--active-color);
110
130
  border-radius: 50%;
111
131
  }
112
132
 
113
133
  .t-radio-group__label {
114
- font-size: 14px;
134
+ font-size: var(--font-size);
115
135
  color: #323233;
116
136
  }
117
137
  </style>
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  export type RadioDirection = 'horizontal' | 'vertical'
6
+ export type RadioSize = 'small' | 'medium' | 'large'
6
7
 
7
8
  export interface RadioOption {
8
9
  label: string
@@ -14,6 +15,12 @@ export interface TRadioGroupProps {
14
15
  modelValue?: string | number
15
16
  options?: RadioOption[]
16
17
  direction?: RadioDirection
18
+ /** 按钮尺寸 */
19
+ size?: RadioSize
20
+ /** 活动状态颜色 */
21
+ activeColor?: string
22
+ /** 非活动状态颜色 */
23
+ inactiveColor?: string
17
24
  disabled?: boolean
18
25
  customClass?: string
19
26
  customStyle?: string
@@ -1,6 +1,7 @@
1
1
  <script setup lang="uts">
2
2
  import { ref, computed } from 'vue'
3
3
  import type { TSearchBarProps } from './type.uts'
4
+ import { useI18n } from '../../composables/useI18n.uts'
4
5
 
5
6
  /**
6
7
  * TSearchBar 搜索框组件
@@ -11,13 +12,11 @@ import type { TSearchBarProps } from './type.uts'
11
12
  type Props = Omit<TSearchBarProps, 'modelValue'>
12
13
 
13
14
  const props = withDefaults(defineProps<Props>(), {
14
- placeholder: '请输入搜索关键词',
15
15
  shape: 'square',
16
16
  background: '#f5f5f5',
17
17
  maxlength: -1,
18
18
  clearable: true,
19
19
  showCancel: false,
20
- cancelText: '取消',
21
20
  disabled: false,
22
21
  readonly: false,
23
22
  autoFocus: false,
@@ -40,6 +39,22 @@ const emit = defineEmits<{
40
39
  blur: [event: Event]
41
40
  }>()
42
41
 
42
+ // 使用 i18n
43
+ const { $t } = useI18n()
44
+
45
+ // 优先使用用户传入的值,否则使用翻译
46
+ const displayPlaceholder = computed(() => {
47
+ return props.placeholder !== undefined && props.placeholder !== ''
48
+ ? props.placeholder
49
+ : $t('searchBar.placeholder')
50
+ })
51
+
52
+ const displayCancelText = computed(() => {
53
+ return props.cancelText !== undefined && props.cancelText !== ''
54
+ ? props.cancelText
55
+ : $t('searchBar.cancelText')
56
+ })
57
+
43
58
  // 状态管理
44
59
  const isFocused = ref<boolean>(false)
45
60
  let debounceTimer: number | null = null
@@ -149,7 +164,7 @@ const handleCancel = (): void => {
149
164
  class="t-search-bar__input"
150
165
  type="text"
151
166
  :value="modelValue"
152
- :placeholder="placeholder"
167
+ :placeholder="displayPlaceholder"
153
168
  :maxlength="maxlength"
154
169
  :disabled="disabled"
155
170
  :focus="autoFocus"
@@ -175,7 +190,7 @@ const handleCancel = (): void => {
175
190
  class="t-search-bar__cancel"
176
191
  @click="handleCancel"
177
192
  >
178
- {{ cancelText }}
193
+ {{ displayCancelText }}
179
194
  </text>
180
195
  </view>
181
196
  </template>
@@ -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
+ }