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/excelTool.ts CHANGED
@@ -5,6 +5,33 @@ import http from '@/libs/api.request';
5
5
  import {useI18nStore} from './index';
6
6
 
7
7
  const verificationCode = 'lkyhtranslateexcel';
8
+
9
+ /**
10
+ * 解析翻译内容,将 JSON 字符串解析并合并到 item 对象中
11
+ * @param item 翻译项对象
12
+ * @param localKeys 本地语言键列表
13
+ * @returns 处理后的翻译项对象
14
+ */
15
+ export function parseTranslateContent(item: any, localKeys: string[]): any {
16
+ try {
17
+ let content = JSON.parse(item.content);
18
+ let keys = Object.keys(content);
19
+
20
+ keys.forEach((key) => {
21
+ let val = content[key];
22
+ item[key] = val;
23
+ });
24
+
25
+ localKeys.forEach((k) => {
26
+ if (!keys.includes(k)) {
27
+ item[k] = '';
28
+ }
29
+ });
30
+ } catch (error) {
31
+ console.error('解析翻译内容失败:', error);
32
+ }
33
+ return item;
34
+ }
8
35
  export async function exportExcel(total) {
9
36
  const loading = ElLoading.service({
10
37
  lock: true,
@@ -24,23 +51,7 @@ export async function exportExcel(total) {
24
51
  .then((res) => {
25
52
  let localKeys = i18nStore.localList.map((item) => item.value);
26
53
  let {records} = res.data.data;
27
- records = records.map((item) => {
28
- try {
29
- let content = JSON.parse(item.content);
30
- let keys = Object.keys(content);
31
-
32
- keys.forEach((key) => {
33
- let val = content[key];
34
- item[key] = val;
35
- });
36
- localKeys.forEach((k) => {
37
- if (!keys.includes(k)) {
38
- item[k] = '';
39
- }
40
- });
41
- } catch (error) {}
42
- return item;
43
- });
54
+ records = records.map((item) => parseTranslateContent(item, localKeys));
44
55
  return records;
45
56
  });
46
57
  loading.setText('正在序列化表格数据……');
@@ -202,6 +213,7 @@ export async function importExcel(e, getDataList) {
202
213
  message: '您选择的文件不是系统导出的文件',
203
214
  type: 'warning',
204
215
  });
216
+ e.target.value = '';
205
217
  return false;
206
218
  }
207
219
  const loading = ElLoading.service({
@@ -251,6 +263,8 @@ export async function importExcel(e, getDataList) {
251
263
  getDataList();
252
264
  } catch (error) {
253
265
  ElMessage.error('导入保存翻译数据遇到错误:', error.message);
266
+ } finally {
267
+ e.target.value = '';
254
268
  }
255
269
  }
256
270
  }
package/index.d.ts CHANGED
@@ -3,13 +3,27 @@ import {Plugin, Component} from 'vue';
3
3
  import {StoreDefinition} from 'pinia';
4
4
 
5
5
  /**
6
- * zh_CN 简体中文
7
- * en_US 英语(美国)
8
- * th 泰语(泰国)
9
- * vi 越南语(越南)
10
- * tr 土耳其语(土耳其)
6
+ * 语言定义
11
7
  */
12
- type I18nList = 'zh_CN' | 'en_US' | 'th' | 'vi' | 'tr' | 'fa_IR';
8
+ interface LangDefinition {
9
+ /** 语言键名,如 "zh_CN"、"th" */
10
+ key: string;
11
+ /** 显示名称(原始语言),如 "中文"、"ไทย" */
12
+ nativeName: string;
13
+ /** 列表显示名称,如 "中文简体"、"English" */
14
+ label: string;
15
+ /** 基础翻译数据 */
16
+ base: Record<string, string>;
17
+ /** VXETable 翻译数据(可选) */
18
+ vxe?: Record<string, any>;
19
+ /** element-plus 语言包(可选) */
20
+ elementLocale?: any;
21
+ }
22
+
23
+ /**
24
+ * 内置语言键,其他语言通过 string 扩展
25
+ */
26
+ type I18nList = 'zh_CN' | 'en_US' | string;
13
27
 
14
28
  declare global {
15
29
  interface Window {
@@ -17,11 +31,15 @@ declare global {
17
31
  translateReady: boolean;
18
32
  }
19
33
  }
34
+
35
+ /** 注册语言包 */
36
+ export function registerLang(def: LangDefinition): void;
37
+
20
38
  /** 国际化组件实例 */
21
39
  export const i18n: I18n;
22
40
 
23
41
  /** 自定义的翻译函数,这个函数包装了 t 函数,在翻译的前提下,可以帮忙手机键 */
24
- export const ct: (key: string, args: any[]) => void;
42
+ export const ct: (key: string, args?: any[]) => void;
25
43
 
26
44
  /** 国际化相关 Pinia Store 实例 */
27
45
  export const useI18nStore: StoreDefinition;
package/index.js CHANGED
@@ -1,45 +1,33 @@
1
- import { reactive, ref, computed } from "vue";
2
- import { defineStore } from "pinia";
3
- import { createI18n } from "vue-i18n";
4
- import languageVue from "./language.vue";
5
- import axios from "@/libs/api.request";
1
+ import {reactive, ref, computed} from 'vue';
2
+ import {defineStore} from 'pinia';
3
+ import {createI18n} from 'vue-i18n';
4
+ import languageVue from './language.vue';
5
+ import newLanguageVue from './newLanguage.vue';
6
+ import axios from '@/libs/api.request';
6
7
 
7
- // base
8
- import zhCNBase from "./lang/baseZhCn.js";
9
- import enUSBase from "./lang/baseEnUS.js";
10
- import thBase from "./lang/baseTh.js";
11
- import viBase from "./lang/baseVi.js";
12
- import trBase from "./lang/baseTr.js";
13
- import faBase from "./lang/baseFa.js"
14
- // vxe table
15
- import zhCNVXETable from "./lang/zh.js";
16
- import enUSVXETable from "./lang/en.js";
17
- import thVXETable from "./lang/th.js";
18
- import viVXETable from "./lang/vi.js";
19
- import trVXETable from "./lang/tr.js";
20
- import faVXETable from "./lang/fa.js"
21
-
22
- // element-plus
23
- import el_zh_CN from "element-plus/dist/locale/zh-cn.mjs";
24
- import el_en_US from "element-plus/dist/locale/en.mjs";
25
- import el_th from "element-plus/dist/locale/th.mjs";
26
- import el_vi from "element-plus/dist/locale/vi.mjs";
27
- import el_tr from "element-plus/dist/locale/tr.mjs";
28
- import el_fa from "element-plus/dist/locale/fa.mjs";
8
+ // 内置语言包
9
+ import zhCNBase from './lang/baseZhCn.js';
10
+ import enUSBase from './lang/baseEnUS.js';
11
+ import zhCNVXETable from './lang/zh.js';
12
+ import enUSVXETable from './lang/en.js';
13
+ import el_zh_CN from 'element-plus/dist/locale/zh-cn.mjs';
14
+ import el_en_US from 'element-plus/dist/locale/en.mjs';
29
15
 
30
16
  // 自动根据浏览器系统语言设置语言
31
- let navLang = navigator.language.replace("-", "_");
32
- if (navLang.indexOf("en") > -1 && navLang !== "en_US") {
33
- navLang = "en_US";
17
+ let navLang = navigator.language.replace('-', '_');
18
+ if (navLang.indexOf('en') > -1 && navLang !== 'en_US') {
19
+ navLang = 'en_US';
34
20
  }
35
21
 
36
- if (navLang.indexOf("zh") > -1 && navLang !== "zh_CN") {
37
- navLang = "zh_CN";
22
+ if (navLang.indexOf('zh') > -1 && navLang !== 'zh_CN') {
23
+ navLang = 'zh_CN';
38
24
  }
39
- const initlang = localStorage.translateLanguage || navLang || "zh_CN";
25
+ const initlang = localStorage.translateLanguage || navLang || 'zh_CN';
40
26
 
41
27
  export let i18n = null;
42
- window.translateReady = localStorage.translateReady ? localStorage.translateReady === "1" : import.meta.env.DEV;
28
+ window.translateReady = localStorage.translateReady
29
+ ? localStorage.translateReady === '1'
30
+ : import.meta.env.DEV;
43
31
  let contentReady = false;
44
32
 
45
33
  const keySet = new Set();
@@ -50,25 +38,50 @@ Object.keys(zhCNBase).forEach((key) => {
50
38
 
51
39
  const unHandle = [];
52
40
 
53
- function addTranslate (name) {
54
- if (name && name.indexOf("vxe") === -1) {
41
+ // 语言注册表
42
+ const langRegistry = new Map();
43
+
44
+ function registerLang(def) {
45
+ langRegistry.set(def.key, def);
46
+ }
47
+
48
+ // 注册内置语言
49
+ registerLang({
50
+ key: 'zh_CN',
51
+ nativeName: '中文',
52
+ label: '中文简体',
53
+ base: zhCNBase,
54
+ vxe: zhCNVXETable,
55
+ elementLocale: el_zh_CN,
56
+ });
57
+ registerLang({
58
+ key: 'en_US',
59
+ nativeName: 'English',
60
+ label: 'English',
61
+ base: enUSBase,
62
+ vxe: enUSVXETable,
63
+ elementLocale: el_en_US,
64
+ });
65
+
66
+ function addTranslate(name) {
67
+ if (name && name.indexOf('vxe') === -1) {
55
68
  try {
56
69
  axios.request({
57
- url: "/translate/insert",
58
- method: "POST",
70
+ url: '/translate/insert',
71
+ method: 'POST',
59
72
  data: {
60
73
  name,
61
74
  content: `{"zh_CN":"${name}"}`,
62
75
  },
63
76
  });
64
77
  } catch (error) {
65
- console.error("insert error:");
78
+ console.error('insert error:');
66
79
  }
67
80
  }
68
81
  }
69
82
 
70
83
  let recursionAddTimer = null;
71
- function recursionAddTranslate () {
84
+ function recursionAddTranslate() {
72
85
  if (recursionAddTimer !== null) {
73
86
  return false;
74
87
  }
@@ -87,7 +100,7 @@ function recursionAddTranslate () {
87
100
  }
88
101
  }
89
102
 
90
- export const ct = (key, args) => {
103
+ export const ct = (key, args = []) => {
91
104
  if (key && window.translateReady && window.translateCollect) {
92
105
  // 将 键的处理全部放入队列中,避免挤兑正常逻辑的运算资源
93
106
  if (!keySet.has(key) && !unHandle.includes(key)) {
@@ -103,12 +116,12 @@ export const ct = (key, args) => {
103
116
  };
104
117
 
105
118
  /** i18n 相关的 store */
106
- export const useI18nStore = defineStore("i18nStore", () => {
119
+ export const useI18nStore = defineStore('i18nStore', () => {
107
120
  const lang = ref(initlang);
108
121
  /**
109
122
  * @param {I18nList} l 要设置的新语言
110
123
  */
111
- function setLang (l) {
124
+ function setLang(l) {
112
125
  lang.value = l;
113
126
  localStorage.translateLanguage = l;
114
127
  if (i18n) {
@@ -116,56 +129,20 @@ export const useI18nStore = defineStore("i18nStore", () => {
116
129
  }
117
130
  }
118
131
 
119
- const langList = reactive({
120
- zh_CN: "中文",
121
- en_US: "English",
122
- th: "ไทย",
123
- vi: "Việt nam",
124
- tr: "Türkçe",
125
- fa_IR: "فارسی",
126
- });
132
+ const langList = reactive({});
133
+
134
+ function rebuildLangList() {
135
+ Object.keys(langList).forEach((k) => delete langList[k]);
136
+ langRegistry.forEach((def, key) => {
137
+ langList[key] = def.nativeName;
138
+ });
139
+ }
127
140
 
128
141
  const localList = reactive([]);
129
- function setLocalList (list) {
130
- list.forEach((item) => {
131
- switch (item) {
132
- case "zh_CN":
133
- localList.push({
134
- label: "中文简体",
135
- value: "zh_CN",
136
- });
137
- break;
138
- case "en_US":
139
- localList.push({
140
- label: "English",
141
- value: "en_US",
142
- });
143
- break;
144
- case "th":
145
- localList.push({
146
- label: "ไทย",
147
- value: "th",
148
- });
149
- break;
150
- case "vi":
151
- localList.push({
152
- label: "Việt nam",
153
- value: "vi",
154
- });
155
- break;
156
- case "tr":
157
- localList.push({
158
- label: "Türkçe",
159
- value: "tr",
160
- });
161
- break;
162
- case "fa_IR":
163
- localList.push({
164
- label: "فارسی",
165
- value: "fa_IR",
166
- });
167
- break;
168
- }
142
+ function rebuildLocalList() {
143
+ localList.length = 0;
144
+ langRegistry.forEach((def) => {
145
+ localList.push({label: def.label, value: def.key});
169
146
  });
170
147
  }
171
148
 
@@ -174,48 +151,33 @@ export const useI18nStore = defineStore("i18nStore", () => {
174
151
  });
175
152
 
176
153
  const eleLang = computed(() => {
177
- switch (lang.value) {
178
- case "zh_CN":
179
- return el_zh_CN;
180
- case "en_US":
181
- return el_en_US;
182
- case "th":
183
- return el_th;
184
- case "vi":
185
- return el_vi;
186
- case "tr":
187
- return el_tr;
188
- case "fa_IR":
189
- return el_fa;
190
- }
154
+ const def = langRegistry.get(lang.value);
155
+ return def?.elementLocale || el_en_US;
191
156
  });
192
157
 
193
158
  return {
194
159
  lang,
195
160
  setLang,
196
161
  langList,
162
+ rebuildLangList,
197
163
  localList,
198
- setLocalList,
164
+ rebuildLocalList,
199
165
  title,
200
166
  eleLang,
201
167
  };
202
168
  });
203
169
 
204
- async function getRemoteMessage (list) {
170
+ async function getRemoteMessage(list) {
205
171
  try {
206
- let messages = {
207
- zh_CN: {},
208
- en_US: {},
209
- th: {},
210
- vi: {},
211
- tr: {},
212
- fa_IR: {},
213
- };
172
+ let messages = {};
173
+ list.forEach((key) => {
174
+ messages[key] = {};
175
+ });
214
176
  let {
215
- data: { data },
177
+ data: {data},
216
178
  } = await axios.request({
217
- url: "/translate/getContent",
218
- method: "POST",
179
+ url: '/translate/getContent',
180
+ method: 'POST',
219
181
  data: {
220
182
  pageNum: 1,
221
183
  pageSize: 10,
@@ -249,64 +211,56 @@ async function getRemoteMessage (list) {
249
211
  } catch (error) {}
250
212
  }
251
213
 
252
- function createLocalMessage (list) {
214
+ function createLocalMessage(list) {
253
215
  let messages = {};
254
- list.forEach((item) => {
255
- switch (item) {
256
- case "zh_CN":
257
- messages["zh_CN"] = Object.assign(zhCNBase, zhCNVXETable);
258
- break;
259
- case "en_US":
260
- messages["en_US"] = Object.assign(enUSBase, enUSVXETable);
261
- break;
262
- case "th":
263
- messages["th"] = Object.assign(thBase, thVXETable);
264
- break;
265
-
266
- case "vi":
267
- messages["vi"] = Object.assign(viBase, viVXETable);
268
- break;
269
-
270
- case "tr":
271
- messages["tr"] = Object.assign(trBase, trVXETable);
272
- break;
273
- case "fa_IR":
274
- messages["fa_IR"] = Object.assign(faBase, faVXETable);
275
- break;
276
- default:
277
- break;
216
+ list.forEach((key) => {
217
+ const def = langRegistry.get(key);
218
+ if (def) {
219
+ messages[key] = Object.assign({}, def.base, def.vxe || {});
278
220
  }
279
221
  });
280
222
  return messages;
281
223
  }
282
224
 
283
- export function addI18nPage (router) {
284
- router.addRoute("Index", {
285
- path: "translate",
286
- name: "翻译管理",
225
+ export function addI18nPage(router) {
226
+ router.addRoute('Index', {
227
+ path: 'translate',
228
+ name: '翻译管理',
287
229
  meta: {
288
- icon: "md-notifications",
289
- title: "翻译管理",
230
+ icon: 'md-notifications',
231
+ title: '翻译管理',
290
232
  },
291
- component: () => import("yh-i18n/list.vue"),
233
+ component: () => import('yh-i18n/list.vue'),
292
234
  });
293
235
  }
294
236
 
295
- export function cLog (string, isError = false) {
237
+ export function cLog(string, isError = false) {
296
238
  if (isError) {
297
- console.error("%cyhI18n:%c", "font-size: 16px;font-weight: bold;color: #00ffff", "font-size: 16px;font-weight: bold;color: #ccccc", string);
239
+ console.error(
240
+ '%cyhI18n:%c',
241
+ 'font-size: 16px;font-weight: bold;color: #00ffff',
242
+ 'font-size: 16px;font-weight: bold;color: #ccccc',
243
+ string
244
+ );
298
245
  } else {
299
- console.log("%cYh-i18n%c " + string, "font-size: 18px;font-weight: bold;color: #61AFEF", "font-size: 12px;color: #999");
246
+ console.log(
247
+ '%cYh-i18n%c ' + string,
248
+ 'font-size: 18px;font-weight: bold;color: #61AFEF',
249
+ 'font-size: 12px;color: #999'
250
+ );
300
251
  }
301
252
  }
302
253
 
303
254
  export const yhI18n = {
304
- install (app, config) {
305
- let { list, router, pinia, VXETable } = config;
306
- if (!list) {
307
- cLog("请设置 Config.i18nList ,并将其设置到 yhI18n 的 congfig.list 上,否则 国际化插件将失效");
308
- return false;
255
+ install(app, config) {
256
+ let {locales, router, pinia, VXETable, isNew} = config;
257
+
258
+ // 注册外部传入的语言包
259
+ if (locales?.length) {
260
+ locales.forEach((def) => registerLang(def));
309
261
  }
262
+
263
+ const list = [...langRegistry.keys()];
310
264
  let messages = createLocalMessage(list);
311
265
  i18n = createI18n({
312
266
  locale: initlang,
@@ -316,22 +270,32 @@ export const yhI18n = {
316
270
  app.config.globalProperties.$T = ct;
317
271
 
318
272
  if (!window.translateReady) {
319
- cLog("没有开启翻译管理,可以在开发环境或者在控制台运行后面的代码再刷新页面: `localStorage.translateReady = '1'`");
273
+ cLog(
274
+ "没有开启翻译管理,可以在开发环境或者在控制台运行后面的代码再刷新页面: `localStorage.translateReady = '1'`"
275
+ );
320
276
  }
321
277
  if (router) {
322
- addI18nPage(router);
278
+ if (isNew) {
279
+ const {addInitTask} = config;
280
+ addInitTask(async () => {
281
+ addI18nPage(router);
282
+ });
283
+ } else {
284
+ addI18nPage(router);
285
+ }
323
286
  } else {
324
287
  if (!router) {
325
- cLog("没有传递 router 对象,所以无法将翻译管理页面添加到应用中", true);
288
+ cLog('没有传递 router 对象,所以无法将翻译管理页面添加到应用中', true);
326
289
  }
327
290
  }
328
291
 
329
292
  if (pinia) {
330
293
  const i18nStore = useI18nStore(pinia);
331
- i18nStore.setLocalList(list);
294
+ i18nStore.rebuildLangList();
295
+ i18nStore.rebuildLocalList();
332
296
  } else {
333
297
  if (!pinia) {
334
- cLog("没有传递 router 对象,所以无法为国际化插件设置语言列表", true);
298
+ cLog('没有传递 router 对象,所以无法为国际化插件设置语言列表', true);
335
299
  }
336
300
  }
337
301
  if (VXETable) {
@@ -341,11 +305,18 @@ export const yhI18n = {
341
305
  });
342
306
  } else {
343
307
  if (!pinia) {
344
- cLog("没有传递 VXETable 对象,所以无法为 SLW 和 VXETable 设置国际化", true);
308
+ cLog('没有传递 VXETable 对象,所以无法为 SLW 和 VXETable 设置国际化', true);
345
309
  }
346
310
  }
347
311
 
348
312
  getRemoteMessage(list);
313
+ if (isNew) {
314
+ const {slotsStore} = config;
315
+ slotsStore.registerSlot({
316
+ location: 'HEADER_RIGHT',
317
+ component: newLanguageVue,
318
+ });
319
+ }
349
320
  },
350
321
  };
351
322