yh-i18n 2.3.7 → 2.3.9

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/list.vue CHANGED
@@ -105,23 +105,33 @@
105
105
  class="form-drawer"
106
106
  v-model="formShow"
107
107
  @close="cancelForm"
108
+ :close-on-click-modal="false"
108
109
  draggable
109
110
  :title="formData.id ? ct('编辑翻译') : ct('新增翻译')">
110
- <vxe-form
111
- title-align="right"
112
- title-width="100px"
113
- ref="vxeFormRef"
114
- title-colon
115
- :data="formData"
116
- :items="formItems"
117
- :rules="formRules"></vxe-form>
111
+ <el-form
112
+ ref="formRef"
113
+ :model="formData"
114
+ :rules="formRules"
115
+ label-width="100px"
116
+ label-position="right">
117
+ <el-form-item :label="ct('翻译键值')" prop="name">
118
+ <el-input tabindex="1" v-model="formData.name" class="i18n-form-item" id="i18nFormItem1" />
119
+ </el-form-item>
120
+ <el-form-item
121
+ v-for="(item, index) in langFields"
122
+ :key="item.field"
123
+ :label="ct(item.label)"
124
+ :prop="item.field">
125
+ <el-input ref="langFieldsRef" :tabindex="index + 2" v-model="formData[item.field]" class="i18n-form-item" :id="item.id" />
126
+ </el-form-item>
127
+ </el-form>
118
128
  <template #footer>
119
129
  <div class="yh-i18n-form-actions">
120
130
  <el-button
121
131
  @click="prevOne"
122
132
  text
123
133
  :disabled="!isNaN(formDataIndex) && formDataIndex <= 0">
124
- {{ ct('上一个') }}(←)
134
+ {{ ct('上一个') }} (ctrl/alt + ←)
125
135
  </el-button>
126
136
  <el-button
127
137
  type="primary"
@@ -132,27 +142,47 @@
132
142
  <el-button
133
143
  type="primary"
134
144
  @click="saveOne">
135
- {{ ct('保存') }}
145
+ {{ ct('保存') }}(ctrl + S)
136
146
  </el-button>
137
147
  <el-button
138
148
  @click="nextOne"
139
149
  text
140
- :disabled="!isNaN(formDataIndex) && formDataIndex >= dataList.leng - 1">
141
- {{ ct('下一个') }}(→)
150
+ :disabled="!isNaN(formDataIndex) && formDataIndex >= dataList.length - 1">
151
+ {{ ct('下一个') }}(ctrl/alt + →)
142
152
  </el-button>
143
153
  </div>
144
154
  </template>
145
155
  </el-dialog>
146
156
  </template>
147
157
  <script setup lang="ts">
148
- import {reactive, ref, onMounted, watch} from 'vue';
158
+ import {reactive, ref, onMounted, onUnmounted,onActivated,onDeactivated, watch} from 'vue';
149
159
  import {ElLoadingService, ElMessage, ElMessageBox} from 'element-plus';
150
- import {useI18nStore, ct} from 'yh-i18n';
160
+ import {useI18nStore, ct} from './index';
151
161
  import http from '@/libs/api.request';
152
- import {VxeFormInstance, VxeFormPropTypes} from 'vxe-table';
153
- import {exportExcel, importExcel} from './excelTool';
162
+ import {exportExcel, importExcel, parseTranslateContent} from './excelTool';
163
+
164
+ interface TranslateItem {
165
+ id?: string;
166
+ name: string;
167
+ content: string;
168
+ [key: string]: any;
169
+ }
170
+
171
+ interface ListColumn {
172
+ field: string;
173
+ title: string;
174
+ minWidth: string;
175
+ }
176
+
177
+ interface SaveData {
178
+ name: string;
179
+ content: Record<string, string> | string;
180
+ id?: string;
181
+ }
182
+
154
183
  const i18nStore = useI18nStore();
155
- const vxeFormRef = ref<VxeFormInstance>();
184
+ const formRef = ref<FormInstance>();
185
+ const langFieldsRef = ref<InstanceType<typeof import('element-plus')['ElInput']>>();
156
186
 
157
187
  const insertUrl = '/translate/insert';
158
188
  const updateUrl = '/translate/edit';
@@ -165,8 +195,8 @@ const listForm = reactive({
165
195
  pageSize: 10,
166
196
  total: 0,
167
197
  });
168
- const listColumns = reactive<any>([]);
169
- const dataList = ref<any>([]);
198
+ const listColumns = reactive<ListColumn[]>([]);
199
+ const dataList = ref<TranslateItem[]>([]);
170
200
  function getDataList(isReset = false) {
171
201
  let {name, pageNum, pageSize} = listForm;
172
202
  if (isReset) {
@@ -188,26 +218,14 @@ function getDataList(isReset = false) {
188
218
  .then((res) => {
189
219
  let localKeys = i18nStore.localList.map((item) => item.value);
190
220
  let {records, total} = res.data.data;
191
- records = records.map((item) => {
192
- try {
193
- let content = JSON.parse(item.content);
194
- let keys = Object.keys(content);
195
-
196
- keys.forEach((key) => {
197
- let val = content[key];
198
- item[key] = val;
199
- });
200
- localKeys.forEach((k) => {
201
- if (!keys.includes(k)) {
202
- item[k] = '';
203
- }
204
- });
205
- } catch (error) {}
206
- return item;
207
- });
221
+ records = records.map((item) => parseTranslateContent(item, localKeys));
208
222
  dataList.value = records;
209
223
  listForm.total = total;
210
224
  })
225
+ .catch((error) => {
226
+ ElMessage.error('获取数据失败');
227
+ console.error('获取列表数据失败:', error);
228
+ })
211
229
  .finally(() => {
212
230
  loading.close();
213
231
  });
@@ -238,15 +256,17 @@ function resetList() {
238
256
  }
239
257
 
240
258
  const langList = Object.keys(i18nStore.langList);
241
- const formDataIndex = ref();
242
- const formData = reactive<any>({});
259
+ const formDataIndex = ref<number>();
260
+ const formData = reactive<TranslateItem>({
261
+ name: '',
262
+ content: '',
263
+ });
243
264
  const formShow = ref(false);
244
- let inputs: HTMLInputElement[] = [];
245
265
  function cancelForm() {
246
- vxeFormRef?.value?.reset();
247
- vxeFormRef?.value?.clearValidate();
266
+ formRef.value?.resetFields();
267
+ formRef.value?.clearValidate();
248
268
  formDataIndex.value = void 0;
249
- formData.id = null;
269
+ formData.id = undefined;
250
270
  formShow.value = false;
251
271
  }
252
272
 
@@ -255,7 +275,7 @@ function addOne() {
255
275
  }
256
276
 
257
277
  function prevOne() {
258
- if (formDataIndex.value > 0) {
278
+ if (formDataIndex.value !== void 0 && formDataIndex.value > 0) {
259
279
  let index = formDataIndex.value - 1;
260
280
  let item = dataList.value[index];
261
281
  editOne(item, index);
@@ -264,6 +284,13 @@ function prevOne() {
264
284
 
265
285
  function editOne(item, index) {
266
286
  formDataIndex.value = index;
287
+ // 先清空表单数据,除了 id
288
+ for (const key in formData) {
289
+ if (key !== 'id') {
290
+ delete formData[key];
291
+ }
292
+ }
293
+ // 然后将新项目的数据复制到表单
267
294
  for (const key in item) {
268
295
  if (Object.prototype.hasOwnProperty.call(item, key)) {
269
296
  const val = item[key];
@@ -272,13 +299,12 @@ function editOne(item, index) {
272
299
  }
273
300
  formShow.value = true;
274
301
  setTimeout(() => {
275
- (document.querySelector('#i18nFormItem1 input') as HTMLInputElement)?.focus();
276
- inputs = Array.from(document.querySelectorAll('.i18n-form-item input'));
302
+ langFieldsRef.value[0]?.focus();
277
303
  }, 500);
278
304
  }
279
305
 
280
306
  function nextOne() {
281
- if (formDataIndex.value < dataList.value.length - 1) {
307
+ if (formDataIndex.value !== void 0 && formDataIndex.value < dataList.value.length - 1) {
282
308
  let index = formDataIndex.value + 1;
283
309
  let item = dataList.value[index];
284
310
  editOne(item, index);
@@ -286,10 +312,10 @@ function nextOne() {
286
312
  }
287
313
 
288
314
  function saveOne() {
289
- let isAdd = !!formData.id;
315
+ let isAdd = !!!formData.id;
290
316
  let url = updateUrl;
291
- vxeFormRef?.value?.validate().then((errMap) => {
292
- if (!errMap) {
317
+ formRef.value?.validate((valid) => {
318
+ if (valid) {
293
319
  let data: any = {
294
320
  name: formData.name,
295
321
  content: {},
@@ -316,13 +342,13 @@ function saveOne() {
316
342
  if (res?.data?.status === 200) {
317
343
  ElMessage.success(res.data.msg);
318
344
  if (isAdd) {
345
+ cancelForm();
346
+ getDataList(true);
347
+ } else {
319
348
  dataList.value[formDataIndex.value] = {
320
349
  ...formData,
321
350
  };
322
351
  nextOne();
323
- } else {
324
- cancelForm();
325
- getDataList();
326
352
  }
327
353
  } else {
328
354
  ElMessage.error(res.data.msg);
@@ -355,7 +381,8 @@ function delOne(id) {
355
381
 
356
382
  function delMore() {
357
383
  ElMessageBox.confirm('确认删除选中的翻译记录吗?').then(async () => {
358
- let ids = i18nList.value?.getSelectionRows().map((row) => row.id);
384
+ const selectedRows = i18nList.value?.getSelectionRows();
385
+ const ids = selectedRows?.map((row) => row.id) || [];
359
386
  if (ids && ids.length) {
360
387
  let len = ids.length;
361
388
  let loading = ElLoadingService({
@@ -391,20 +418,10 @@ function delMore() {
391
418
  });
392
419
  }
393
420
 
394
- const formItems = reactive<VxeFormPropTypes.Items>([
395
- {
396
- field: 'name',
397
- span: 24,
398
- title: '翻译键值',
399
- itemRender: {
400
- name: '$input',
401
- props: {class: 'i18n-form-item', id: `i18nFormItem${1}`},
402
- },
403
- },
404
- ]);
421
+ const langFields = reactive<{field: string; label: string; id: string}[]>([]);
405
422
 
406
- const formRules = reactive<VxeFormPropTypes.Rules>({
407
- name: [{required: true, type: 'string', message: '请输入翻译键值'}],
423
+ const formRules = reactive({
424
+ name: [{required: true, message: '请输入翻译键值', trigger: 'blur'}],
408
425
  });
409
426
 
410
427
  let needInit = true;
@@ -419,14 +436,10 @@ watch(
419
436
  title: item.label,
420
437
  minWidth: '200',
421
438
  });
422
- formItems.push({
439
+ langFields.push({
423
440
  field: item.value,
424
- span: 24,
425
- title: item.label,
426
- itemRender: {
427
- name: '$input',
428
- props: {class: 'i18n-form-item', id: `i18nFormItem${index + 2}`},
429
- },
441
+ label: item.label,
442
+ id: `i18nFormItem${index + 2}`,
430
443
  });
431
444
  });
432
445
  }
@@ -437,51 +450,41 @@ watch(
437
450
  }
438
451
  );
439
452
 
453
+ function keydownHandler(e: KeyboardEvent) {
454
+ if (!formShow.value) return;
455
+ const {key, ctrlKey, altKey} = e;
456
+ if (key === 's' && ctrlKey) {
457
+ e.preventDefault();
458
+ e.stopPropagation();
459
+ saveOne();
460
+ }
461
+ if (key === 'ArrowRight' && (ctrlKey || altKey)) {
462
+ e.preventDefault();
463
+ e.stopPropagation();
464
+ nextOne();
465
+ }
466
+ if (key === 'ArrowLeft' && (ctrlKey || altKey)) {
467
+ e.preventDefault();
468
+ e.stopPropagation();
469
+ prevOne();
470
+ }
471
+ }
472
+
440
473
  onMounted(() => {
441
474
  getDataList();
442
- window.addEventListener('keydown', (e) => {
443
- let {key, ctrlKey, altKey} = e;
444
- if (key === 's' && ctrlKey) {
445
- e.preventDefault();
446
- e.stopPropagation();
447
- saveOne();
448
- }
449
- if (key === 'ArrowRight' && (ctrlKey || altKey)) {
450
- e.preventDefault();
451
- e.stopPropagation();
452
- nextOne();
453
- }
454
- if (key === 'ArrowLeft' && (ctrlKey || altKey)) {
455
- e.preventDefault();
456
- e.stopPropagation();
457
- prevOne();
458
- }
459
- if (key === 'Tab') {
460
- e.preventDefault();
461
- e.stopPropagation();
462
- if (
463
- document.activeElement ||
464
- // @ts-ignore
465
- inputs.includes(document.activeElement)
466
- ) {
467
- // @ts-ignore
468
- let index = inputs.indexOf(document.activeElement);
475
+ window.addEventListener('keydown', keydownHandler);
476
+ });
469
477
 
470
- if (index === inputs.length) {
471
- index = 0;
472
- } else {
473
- index++;
474
- }
475
- inputs[index].focus();
476
- } else {
477
- setTimeout(() => {
478
- if (!document.activeElement || !inputs.includes(document.activeElement as HTMLInputElement)) {
479
- (document.querySelector('#i18nFormItem1 input') as HTMLInputElement)?.focus();
480
- }
481
- }, 100);
482
- }
483
- }
484
- });
478
+ onUnmounted(() => {
479
+ window.removeEventListener('keydown', keydownHandler);
480
+ });
481
+
482
+ onActivated(() => {
483
+ window.addEventListener('keydown', keydownHandler);
484
+ });
485
+
486
+ onDeactivated(() => {
487
+ window.removeEventListener('keydown', keydownHandler);
485
488
  });
486
489
  </script>
487
490
  <style lang="scss">
@@ -0,0 +1,71 @@
1
+ <template>
2
+ <el-popover
3
+ placement="bottom"
4
+ popper-class="yh-user-popover"
5
+ :width="150"
6
+ trigger="hover">
7
+ <template #reference>
8
+ <div class="header-bar-button">
9
+ {{ title }}
10
+ <YhIcon
11
+ class="user-name-icon"
12
+ fontFamily="yhicon"
13
+ prefix="yh-"
14
+ name="down"></YhIcon>
15
+ </div>
16
+ </template>
17
+ <div class="user-actions">
18
+ <div
19
+ class="action-item"
20
+ v-for="lo in localList"
21
+ @click="setLang(lo.value)">
22
+ {{ lo.label }}
23
+ </div>
24
+ <el-divider content-position="left">翻译工具</el-divider>
25
+ <div
26
+ class="action-item"
27
+ @click="router.push({path: '/translate'})">
28
+ {{ ct('翻译') }}
29
+ </div>
30
+ <div class="action-item">
31
+ <el-switch
32
+ v-model="isCollect"
33
+ :active-text="ct('自动收集翻译')"
34
+ :inactive-text="ct('停止收集翻译')"
35
+ inline-prompt></el-switch>
36
+ </div>
37
+ </div>
38
+ </el-popover>
39
+ </template>
40
+
41
+ <script setup>
42
+ import {useI18nStore, ct} from 'yh-i18n';
43
+ import {storeToRefs} from 'pinia';
44
+ import {ref, watch} from 'vue';
45
+ import {useRouter} from 'vue-router';
46
+
47
+ const router = useRouter();
48
+
49
+ const isDev = ref(window.translateReady);
50
+
51
+ const i18nStore = useI18nStore();
52
+ const isCollect = ref(!!localStorage.translateCollect);
53
+ watch(
54
+ () => isCollect.value,
55
+ (val) => {
56
+ if (val) {
57
+ localStorage.translateCollect = '1';
58
+ } else {
59
+ localStorage.removeItem('translateCollect');
60
+ }
61
+ window.translateCollect = val;
62
+ },
63
+ {
64
+ immediate: true,
65
+ }
66
+ );
67
+
68
+ const {localList, title} = storeToRefs(i18nStore);
69
+
70
+ const {setLang} = i18nStore;
71
+ </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yh-i18n",
3
- "version": "2.3.7",
3
+ "version": "2.3.9",
4
4
  "description": "对于国际化的封装",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -15,7 +15,7 @@
15
15
  "vue-i18n": "^9.0.0",
16
16
  "vue": "^3.0.0",
17
17
  "vxe-table": "^4.3.10",
18
- "element-plus": "^2.3.8"
18
+ "element-plus": "^2.9.0"
19
19
  },
20
20
  "author": "Liubin"
21
21
  }
package/lang/baseFa.js DELETED
@@ -1,27 +0,0 @@
1
- export default {
2
- 翻译键名: "کلید ترجمه",
3
- 翻译管理: "مدیریت ترجمه",
4
- 键入以筛选键名: "برای فیلتر کردن کلید تایپ کنید",
5
- 搜索: "جستجو",
6
- 新增: "جدید",
7
- 批量删除: "حذف گروهی",
8
- 重置: "بازنشانی",
9
- 编辑: "ویرایش",
10
- 删除: "حذف",
11
- 操作: "عملیات",
12
- 导出: "صادرات",
13
- 导入: "واردات",
14
- 翻译键值: "مقدار ترجمه",
15
- 新增翻译: "افزودن ترجمه",
16
- 编辑翻译: "ویرایش ترجمه",
17
- 请输入翻译键值: "لطفاً مقدار ترجمه را وارد کنید",
18
- 上一个: "قبلی",
19
- 下一个: "بعدی",
20
- 取消: "لغو",
21
- 中文简体: "چینی ساده شده",
22
- English: "انگلیسی",
23
- ไทย: "تایلندی",
24
- "Việt nam": "ویتنامی",
25
- Türkçe: "ترکی",
26
- "فارسی": "فارسی",
27
- };
package/lang/baseTh.js DELETED
@@ -1,27 +0,0 @@
1
- export default {
2
- 翻译键名: "ชื่อคีย์การแปล",
3
- 翻译管理: "การจัดการการแปล",
4
- 键入以筛选键名: "พิมพ์เพื่อกรองชื่อคีย์",
5
- 搜索: "ค้นหา",
6
- 新增: "เพิ่มใหม่",
7
- 批量删除: "ลบแบทช์",
8
- 重置: "รีเซ็ต",
9
- 编辑: "บรรณาธิการ",
10
- 删除: "ลบ",
11
- 操作: "การดำเนินงาน",
12
- 导出: "ส่งออก",
13
- 导入: "นำเข้า",
14
- 翻译键值: "แปลค่ากุญแจ",
15
- 新增翻译: "เพิ่มการแปล",
16
- 编辑翻译: "แก้ไขการแปล",
17
- 请输入翻译键值: "โปรดป้อนค่ากุญแจการแปล",
18
- 上一个: "ก่อนหน้า",
19
- 下一个: "ถัดไป",
20
- 取消: "การยกเลิก",
21
- 中文简体: "ภาษาจีนตัวย่อ",
22
- English: "ภาษาอังกฤษ",
23
- ไทย: "ไทย",
24
- "Việt nam": "เวียดนาม",
25
- Türkçe: "ตุรกี",
26
- "فارسی": "ภาษาเปอร์เซีย"
27
- };
package/lang/baseTr.js DELETED
@@ -1,27 +0,0 @@
1
- export default {
2
- 翻译键名: "Anahtar isimlerini çevir",
3
- 翻译管理: "Çeviri Yönetimi",
4
- 键入以筛选键名: "Anahtar isimlerini silmek için yazın",
5
- 搜索: "arama",
6
- 新增: "Yeni ekleme",
7
- 批量删除: "Toplu silme",
8
- 重置: "Sıfırla",
9
- 编辑: "edit",
10
- 删除: "Sil",
11
- 操作: "operasyon",
12
- 导出: "dışarı aktar",
13
- 导入: "İçeri",
14
- 翻译键值: "Çeviri Anahtarı Değerleri",
15
- 新增翻译: "Çeviri ekle",
16
- 编辑翻译: "Çeviri düzenle",
17
- 请输入翻译键值: "Lütfen çevirim anahtarı değerini girin",
18
- 上一个: "Önceki",
19
- 下一个: "Sonraki",
20
- 取消: "iptal et",
21
- 中文简体: "Basitleştirilmiş Çince",
22
- English: "İngilizce",
23
- ไทย: "Tayland.",
24
- "Việt nam": "Vietnamca",
25
- Türkçe: "Türkçe",
26
- "فارسی": "Farsça"
27
- };
package/lang/baseVi.js DELETED
@@ -1,27 +0,0 @@
1
- export default {
2
- 翻译键名: "Tên khóa dịch",
3
- 翻译管理: "Quản lý phiên dịch",
4
- 键入以筛选键名: "Nhập để lọc các tên khóa",
5
- 搜索: "Tìm kiếm",
6
- 新增: "Mới",
7
- 批量删除: "Xóa hàng loạt",
8
- 重置: "Đặt lại",
9
- 编辑: "Chỉnh sửa",
10
- 删除: "Xoá",
11
- 操作: "Hoạt động",
12
- 导出: "Xuất",
13
- 导入: "Nhập khẩu",
14
- 翻译键值: "Dịch giá trị khóa",
15
- 新增翻译: "Thêm bản dịch",
16
- 编辑翻译: "Biên dịch",
17
- 请输入翻译键值: "Vui lòng nhập giá trị khóa dịch",
18
- 上一个: "Trước",
19
- 下一个: "Tiếp theo",
20
- 取消: "Hủy bỏ",
21
- 中文简体: "Trung Quốc",
22
- English: "Tiếng Việt",
23
- ไทย: "Thái Lan.",
24
- "Việt nam": "Việt nam",
25
- Türkçe: "Thổ Nhĩ Kỳ",
26
- "فارسی": "Tiếng Ba Tư"
27
- };