yh-i18n 2.3.15 → 3.0.4

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/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,6 +31,10 @@ 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
 
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";
6
-
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";
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';
7
+
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
  }
@@ -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,103 +211,119 @@ 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 = [], VXETable} = 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,
313
267
  messages,
314
268
  });
315
269
  app.use(i18n);
316
- app.config.globalProperties.$T = ct;
317
270
 
318
271
  if (!window.translateReady) {
319
- cLog("没有开启翻译管理,可以在开发环境或者在控制台运行后面的代码再刷新页面: `localStorage.translateReady = '1'`");
320
- }
321
- if (router) {
322
- addI18nPage(router);
323
- } else {
324
- if (!router) {
325
- cLog("没有传递 router 对象,所以无法将翻译管理页面添加到应用中", true);
326
- }
272
+ cLog(
273
+ "没有开启翻译管理,可以在开发环境或者在控制台运行后面的代码再刷新页面: `localStorage.translateReady = '1'`"
274
+ );
327
275
  }
276
+ getRemoteMessage(list);
277
+
278
+ const isNew = app.config.globalProperties.$isNew;
279
+ if (isNew) {
280
+ const {
281
+ $addInitTask: addInitTask,
282
+ $pinia: pinia,
283
+ $router: router,
284
+ $slotsStore: slotsStore,
285
+ $setCt: setCt
286
+ } = app.config.globalProperties;
287
+ addInitTask(async () => {
288
+ if (!router || !router.hasRoute('Index')) return;
289
+ addI18nPage(router);
290
+ });
328
291
 
329
- if (pinia) {
292
+ setCt(ct)
330
293
  const i18nStore = useI18nStore(pinia);
331
- i18nStore.setLocalList(list);
294
+ i18nStore.rebuildLangList();
295
+ i18nStore.rebuildLocalList();
296
+
297
+ slotsStore.registerSlot({
298
+ location: 'HEADER_RIGHT',
299
+ component: newLanguageVue,
300
+ });
332
301
  } else {
333
- if (!pinia) {
334
- cLog("没有传递 router 对象,所以无法为国际化插件设置语言列表", true);
302
+ const {router, pinia} = config;
303
+ app.config.globalProperties.$T = ct;
304
+ app.config.globalProperties.ct = ct;
305
+ if (router) {
306
+ addI18nPage(router);
307
+ } else {
308
+ cLog('没有传递 router 对象,所以无法将翻译管理页面添加到应用中', true);
309
+ }
310
+ if (pinia) {
311
+ const i18nStore = useI18nStore(pinia);
312
+ i18nStore.rebuildLangList();
313
+ i18nStore.rebuildLocalList();
314
+ } else {
315
+ cLog('没有传递 router 对象,所以无法为国际化插件设置语言列表', true);
335
316
  }
336
317
  }
318
+
337
319
  if (VXETable) {
338
320
  VXETable.setup({
339
321
  i18n: (key, args) => ct(key, args),
340
322
  translate: (key, args) => ct(key, args),
341
323
  });
342
324
  } else {
343
- if (!pinia) {
344
- cLog("没有传递 VXETable 对象,所以无法为 SLW 和 VXETable 设置国际化", true);
345
- }
325
+ cLog('没有传递 VXETable 对象,所以无法为 SLW 和 VXETable 设置国际化', true);
346
326
  }
347
-
348
- getRemoteMessage(list);
349
327
  },
350
328
  };
351
329
 
package/list.vue CHANGED
@@ -155,7 +155,7 @@
155
155
  </el-dialog>
156
156
  </template>
157
157
  <script setup lang="ts">
158
- import {reactive, ref, onMounted, onUnmounted, watch} from 'vue';
158
+ import {reactive, ref, onMounted, onUnmounted,onActivated,onDeactivated, watch} from 'vue';
159
159
  import {ElLoadingService, ElMessage, ElMessageBox} from 'element-plus';
160
160
  import {useI18nStore, ct} from './index';
161
161
  import http from '@/libs/api.request';
@@ -0,0 +1,75 @@
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: isAdmin?'/admin/translate':'/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 {ref, watch} from 'vue';
44
+ import {useRouter} from 'vue-router';
45
+ import {useClientStore} from 'yh-client';
46
+ import {storeToRefs} from 'pinia';
47
+
48
+ const router = useRouter();
49
+ const clientStore = useClientStore();
50
+ const {isAdmin} = storeToRefs(clientStore);
51
+
52
+ const isDev = ref(window.translateReady);
53
+
54
+ const i18nStore = useI18nStore();
55
+ const isCollect = ref(!!localStorage.translateCollect);
56
+
57
+ watch(
58
+ () => isCollect.value,
59
+ (val) => {
60
+ if (val) {
61
+ localStorage.translateCollect = '1';
62
+ } else {
63
+ localStorage.removeItem('translateCollect');
64
+ }
65
+ window.translateCollect = val;
66
+ },
67
+ {
68
+ immediate: true,
69
+ }
70
+ );
71
+
72
+ const {localList, title} = storeToRefs(i18nStore);
73
+
74
+ const {setLang} = i18nStore;
75
+ </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yh-i18n",
3
- "version": "2.3.15",
3
+ "version": "3.0.4",
4
4
  "description": "对于国际化的封装",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -8,14 +8,12 @@
8
8
  "pub:npm": "npm publish --registry https://registry.npmjs.org/ --no-git-checks",
9
9
  "pub:aliyun": "npm publish --registry https://packages.aliyun.com/60765e0161a945067837bb5f/npm/npm-registry/ --no-git-checks"
10
10
  },
11
- "dependencies": {
12
- "exceljs": "4.4.0"
13
- },
14
11
  "peerDependencies": {
12
+ "exceljs": "4.4.0",
15
13
  "vue-i18n": "^9.0.0",
16
14
  "vue": "^3.0.0",
17
- "vxe-table": "^4.3.10",
15
+ "vue-router": "^4.5.0",
18
16
  "element-plus": "^2.9.0"
19
17
  },
20
18
  "author": "Liubin"
21
- }
19
+ }
package/readme.md CHANGED
@@ -5,7 +5,6 @@
5
5
  **此包依赖最新,前端包**
6
6
  - vue 3.2.47
7
7
  - pinia 2.0.35
8
- - vxe-table 4.3.10
9
8
  - element-plus 2.4.4
10
9
 
11
10
  ## 基础配置