gc_i18n 1.0.0
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/.vscode/extensions.json +3 -0
- package/README.md +5 -0
- package/index.html +12 -0
- package/lib/gc_i18n.css +1 -0
- package/lib/gc_i18n.js +24 -0
- package/lib/gc_i18n.umd.cjs +23 -0
- package/package.json +32 -0
- package/packages/components/LangChange.vue +39 -0
- package/packages/components/config.vue +236 -0
- package/packages/index.js +100 -0
- package/packages/libs/http.js +69 -0
- package/packages/libs/service.js +99 -0
- package/packages/libs/utils.js +20 -0
- package/src/App.vue +3 -0
- package/src/assets/vue.svg +1 -0
- package/src/main.js +21 -0
- package/src/router/index.js +17 -0
- package/src/view/Home.vue +51 -0
- package/vite.config.js +42 -0
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gc_i18n",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"gc_i18n": {
|
|
5
|
+
"appCode": "TEST"
|
|
6
|
+
},
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./lib/gc_i18n.umd.cjs",
|
|
9
|
+
"module": "./lib/gc_i18n.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "vite",
|
|
12
|
+
"build": "vite build",
|
|
13
|
+
"preview": "vite preview"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"keyboardjs": "^2.7.0",
|
|
17
|
+
"lodash-es": "^4.17.21",
|
|
18
|
+
"store2": "^2.14.4",
|
|
19
|
+
"view-ui-plus": "^1.3.19",
|
|
20
|
+
"vue": "^3.5.13",
|
|
21
|
+
"vue-i18n": "^11.1.1",
|
|
22
|
+
"vue-router": "^4.5.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
26
|
+
"@vitejs/plugin-vue": "^5.2.1",
|
|
27
|
+
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
|
28
|
+
"less": "^4.2.2",
|
|
29
|
+
"vite": "^6.1.0",
|
|
30
|
+
"vite-plugin-libcss": "^1.1.1"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getLanguages } from "../libs/service";
|
|
3
|
+
export default {
|
|
4
|
+
name: "LangChange",
|
|
5
|
+
data() {
|
|
6
|
+
return {
|
|
7
|
+
languages: [],
|
|
8
|
+
language: ""
|
|
9
|
+
};
|
|
10
|
+
},
|
|
11
|
+
props: {
|
|
12
|
+
more: {
|
|
13
|
+
type: Boolean,
|
|
14
|
+
default: false
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
async mounted() {
|
|
18
|
+
this.language = navigator.language || "zh-CN";
|
|
19
|
+
console.log("language", this.language);
|
|
20
|
+
const res = await getLanguages();
|
|
21
|
+
if (res && res.result === 0) {
|
|
22
|
+
this.languages = res.retVal;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
</script>
|
|
27
|
+
<template>
|
|
28
|
+
<div>
|
|
29
|
+
<div v-if="more">
|
|
30
|
+
<span>切换语种</span>
|
|
31
|
+
</div>
|
|
32
|
+
<Select
|
|
33
|
+
v-model="language"
|
|
34
|
+
v-else
|
|
35
|
+
>
|
|
36
|
+
<Option value="zh-CN">中文</Option>
|
|
37
|
+
</Select>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<script lang="jsx">
|
|
2
|
+
import _ from "lodash-es";
|
|
3
|
+
import { getAllTranslate, getLanguages, saveTranslate } from "../libs/service";
|
|
4
|
+
import { Message, Modal } from "view-ui-plus";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
data() {
|
|
8
|
+
return {
|
|
9
|
+
isModalVisible: false,
|
|
10
|
+
searchText: "",
|
|
11
|
+
languages: [],
|
|
12
|
+
data: []
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
computed: {
|
|
16
|
+
firstResult() {
|
|
17
|
+
return this.data.firstResult / this.data.pageSize + 1;
|
|
18
|
+
},
|
|
19
|
+
columns() {
|
|
20
|
+
let arr = [
|
|
21
|
+
{
|
|
22
|
+
title: "关键字",
|
|
23
|
+
fixed: "left",
|
|
24
|
+
width: 200,
|
|
25
|
+
key: "dictKey"
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
_.map(this.languages, (lang) => {
|
|
29
|
+
const key = lang.code;
|
|
30
|
+
return arr.push({
|
|
31
|
+
title: lang.name,
|
|
32
|
+
key,
|
|
33
|
+
width: 200,
|
|
34
|
+
render: (h, { row, index }) => {
|
|
35
|
+
const data = row[key];
|
|
36
|
+
return (
|
|
37
|
+
<Input
|
|
38
|
+
modelValue={data}
|
|
39
|
+
onOnChange={(e) => {
|
|
40
|
+
this.data.datas[index][key] = e.target.value;
|
|
41
|
+
}}
|
|
42
|
+
></Input>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
return arr;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
props: { appCode: String, name: String, setLanguage: Function },
|
|
51
|
+
methods: {
|
|
52
|
+
closeModal() {
|
|
53
|
+
this.searchText = "";
|
|
54
|
+
this.isModalVisible = false;
|
|
55
|
+
},
|
|
56
|
+
openModal() {
|
|
57
|
+
if (!this.isModalVisible) {
|
|
58
|
+
this.isModalVisible = true; // 打开弹窗
|
|
59
|
+
this.init();
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
findShallowStringDiff(obj1, obj2) {
|
|
63
|
+
const { appCode, dictKey, page, unitCode } = obj1;
|
|
64
|
+
const diff = [];
|
|
65
|
+
_.forIn(obj1, (value, key) => {
|
|
66
|
+
if (!_.isEqual(value, obj2[key])) {
|
|
67
|
+
diff.push({
|
|
68
|
+
appCode,
|
|
69
|
+
key: dictKey,
|
|
70
|
+
page,
|
|
71
|
+
unitCode,
|
|
72
|
+
lang: key,
|
|
73
|
+
value
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return diff;
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
async saveData({ msg = "" }) {
|
|
81
|
+
const data = _.differenceWith(
|
|
82
|
+
this.data.datas,
|
|
83
|
+
this.initialData.datas,
|
|
84
|
+
_.isEqual
|
|
85
|
+
);
|
|
86
|
+
let arr = [];
|
|
87
|
+
for (let index = 0; index < data.length; index++) {
|
|
88
|
+
const value = data[index];
|
|
89
|
+
const original = _.find(this.initialData.datas, {
|
|
90
|
+
dictKey: value.dictKey
|
|
91
|
+
});
|
|
92
|
+
const diff = this.findShallowStringDiff(value, original);
|
|
93
|
+
arr = _.concat(arr, diff);
|
|
94
|
+
}
|
|
95
|
+
const res = await saveTranslate({
|
|
96
|
+
appCode: this.appCode,
|
|
97
|
+
language: this.language,
|
|
98
|
+
data: arr
|
|
99
|
+
});
|
|
100
|
+
if (res && res.result === 0) {
|
|
101
|
+
Message.success(msg ? msg : res.msg);
|
|
102
|
+
// 更新到本地缓存
|
|
103
|
+
this.setLanguage();
|
|
104
|
+
this.initialData.datas = _.cloneDeep(this.data.datas);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
async saveNoEqual() {
|
|
108
|
+
if (!_.isEqual(this.initialData, this.data)) {
|
|
109
|
+
this.saveData({ msg: "已为您自动保存" });
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
changePage(value) {
|
|
113
|
+
this.saveNoEqual();
|
|
114
|
+
this.search({ firstResult: (value - 1) * this.data.pageSize });
|
|
115
|
+
},
|
|
116
|
+
async search(data) {
|
|
117
|
+
const options = {
|
|
118
|
+
appCode: this.appCode,
|
|
119
|
+
searchBlur: this.searchText,
|
|
120
|
+
page: this.name ? _.toUpper(this.name) : "HOME",
|
|
121
|
+
commaSeparatedLangs: _.map(this.languages, "code").toString(),
|
|
122
|
+
firstResult: 0,
|
|
123
|
+
pageSize: 10,
|
|
124
|
+
...data
|
|
125
|
+
};
|
|
126
|
+
const res = await getAllTranslate(options);
|
|
127
|
+
if (res) {
|
|
128
|
+
this.initialData = _.cloneDeep(res.retVal);
|
|
129
|
+
this.data = res.retVal;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
async init() {
|
|
133
|
+
const res = await getLanguages();
|
|
134
|
+
if (res && res.result == 0) {
|
|
135
|
+
this.languages = res.retVal;
|
|
136
|
+
this.search();
|
|
137
|
+
} else {
|
|
138
|
+
Message.error("获取语言失败,出错了");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
</script>
|
|
144
|
+
|
|
145
|
+
<template>
|
|
146
|
+
<Modal
|
|
147
|
+
v-model="isModalVisible"
|
|
148
|
+
:mask-closable="false"
|
|
149
|
+
:width="70"
|
|
150
|
+
title="多语言管理中心"
|
|
151
|
+
footer-hide
|
|
152
|
+
>
|
|
153
|
+
<Tabs
|
|
154
|
+
type="card"
|
|
155
|
+
class="gc_i18n_tabs"
|
|
156
|
+
>
|
|
157
|
+
<TabPane label="当前页面">
|
|
158
|
+
<Table
|
|
159
|
+
border
|
|
160
|
+
:height="550"
|
|
161
|
+
:columns="columns"
|
|
162
|
+
:data="data.datas"
|
|
163
|
+
></Table
|
|
164
|
+
></TabPane>
|
|
165
|
+
<!-- <TabPane label="当前应用">
|
|
166
|
+
<Table
|
|
167
|
+
border
|
|
168
|
+
:height="550"
|
|
169
|
+
:columns="columns"
|
|
170
|
+
:data="data.currentPageItems"
|
|
171
|
+
></Table
|
|
172
|
+
></TabPane> -->
|
|
173
|
+
<template #extra>
|
|
174
|
+
<div class="extra">
|
|
175
|
+
<Input
|
|
176
|
+
prefix="ios-search"
|
|
177
|
+
placeholder="请输入搜索内容"
|
|
178
|
+
v-model="searchText"
|
|
179
|
+
clearable
|
|
180
|
+
@on-enter="search"
|
|
181
|
+
@on-clear="search"
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
</template>
|
|
185
|
+
</Tabs>
|
|
186
|
+
|
|
187
|
+
<div class="gc_i18n_page">
|
|
188
|
+
<div style="display: flex">
|
|
189
|
+
<Page
|
|
190
|
+
v-model="firstResult"
|
|
191
|
+
:total="data.totalRows"
|
|
192
|
+
:page-size="10"
|
|
193
|
+
simple
|
|
194
|
+
show-total
|
|
195
|
+
@on-change="changePage"
|
|
196
|
+
/>
|
|
197
|
+
<div>共 {{ data.totalRows }} 项数据</div>
|
|
198
|
+
</div>
|
|
199
|
+
<div>
|
|
200
|
+
<Button
|
|
201
|
+
style="margin-right: 10px"
|
|
202
|
+
@click="closeModal"
|
|
203
|
+
>关闭</Button
|
|
204
|
+
>
|
|
205
|
+
<Button
|
|
206
|
+
type="primary"
|
|
207
|
+
@click="saveData"
|
|
208
|
+
>保存</Button
|
|
209
|
+
>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</Modal>
|
|
213
|
+
</template>
|
|
214
|
+
<style lang="less">
|
|
215
|
+
.gc_i18n_tabs {
|
|
216
|
+
padding-top: 5px;
|
|
217
|
+
.ivu-tabs-bar {
|
|
218
|
+
margin-bottom: 1px !important;
|
|
219
|
+
}
|
|
220
|
+
.ivu-tabs-content {
|
|
221
|
+
position: relative;
|
|
222
|
+
top: -1px;
|
|
223
|
+
}
|
|
224
|
+
.extra {
|
|
225
|
+
position: relative;
|
|
226
|
+
top: -3px;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.gc_i18n_page {
|
|
231
|
+
display: flex;
|
|
232
|
+
justify-content: space-between;
|
|
233
|
+
align-items: center;
|
|
234
|
+
margin-top: 10px;
|
|
235
|
+
}
|
|
236
|
+
</style>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import keyboardJS from "keyboardjs";
|
|
2
|
+
import iview from "view-ui-plus";
|
|
3
|
+
import { createApp, nextTick } from "vue";
|
|
4
|
+
import { createI18n } from "vue-i18n";
|
|
5
|
+
import configVue from "./components/config.vue";
|
|
6
|
+
import LangChange from "./components/LangChange.vue";
|
|
7
|
+
//
|
|
8
|
+
import { getTranslate } from "./libs/service";
|
|
9
|
+
import { convertArrayToObject } from "./libs/utils";
|
|
10
|
+
import "./libs/http";
|
|
11
|
+
import _ from "lodash-es";
|
|
12
|
+
export default class I18n {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
const { router } = options;
|
|
15
|
+
this.appCode = options.appCode;
|
|
16
|
+
this.router = router;
|
|
17
|
+
this.locale = navigator.language || "zh-CN";
|
|
18
|
+
this.modalLoad = false;
|
|
19
|
+
this.messages = options.messages || {};
|
|
20
|
+
this.i18n = createI18n({
|
|
21
|
+
locale: "zh-CN",
|
|
22
|
+
allowComposition: true,
|
|
23
|
+
globalInjection: true,
|
|
24
|
+
legacy: false,
|
|
25
|
+
silentTranslationWarn: true, // 屏蔽翻译未找到的警告
|
|
26
|
+
silentFallbackWarn: true, // 屏蔽回退语言的警告
|
|
27
|
+
missingWarn: false, // 屏蔽缺失翻译的警告
|
|
28
|
+
fallbackWarn: false, // 屏蔽回退过程中的警告
|
|
29
|
+
...options
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 保存原始的 t 方法
|
|
33
|
+
const originalT = this.i18n.global.t;
|
|
34
|
+
// 自定义 t 方法
|
|
35
|
+
this.i18n.global.t = (key) => {
|
|
36
|
+
const routeName = router?.currentRoute?.value?.name;
|
|
37
|
+
// 使用原始的 t 方法进行翻译
|
|
38
|
+
const originalTranslation = originalT(key);
|
|
39
|
+
// 如果没有找到翻译值,尝试使用路由名.key
|
|
40
|
+
if (originalTranslation === key && routeName) {
|
|
41
|
+
const prefixedKey = `${routeName}.${key}`;
|
|
42
|
+
// 同样使用原始的 t 方法进行翻译
|
|
43
|
+
return originalT(prefixedKey);
|
|
44
|
+
}
|
|
45
|
+
return originalTranslation;
|
|
46
|
+
};
|
|
47
|
+
this.i18n.global.changeLocal = (newLocale) => {
|
|
48
|
+
this.setLanguage(newLocale || this.locale);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
router.afterEach((to, from) => {
|
|
52
|
+
const { language } = to.query;
|
|
53
|
+
this.setLanguage(language);
|
|
54
|
+
|
|
55
|
+
nextTick(() => {
|
|
56
|
+
if (!this.configInstance) {
|
|
57
|
+
this.createModal(to.name);
|
|
58
|
+
} else {
|
|
59
|
+
this.configInstance.closeModal();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async setLanguage(language = "zh-CN") {
|
|
65
|
+
this.locale = language;
|
|
66
|
+
const res = await getTranslate({
|
|
67
|
+
appCode: this.appCode,
|
|
68
|
+
language
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (res) {
|
|
72
|
+
const messages = convertArrayToObject(res);
|
|
73
|
+
this.i18n.global.setLocaleMessage(
|
|
74
|
+
language,
|
|
75
|
+
_.assign({}, _.get(this.messages, language), messages)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
this.i18n.global.locale.value = language;
|
|
79
|
+
}
|
|
80
|
+
createModal(name) {
|
|
81
|
+
this.modalLoad = true;
|
|
82
|
+
// 创建 config 组件的实例
|
|
83
|
+
this.configInstance = createApp(configVue, {
|
|
84
|
+
appCode: this.appCode,
|
|
85
|
+
setLanguage: this.setLanguage.bind(this),
|
|
86
|
+
name
|
|
87
|
+
})
|
|
88
|
+
.use(iview)
|
|
89
|
+
.mount(document.createElement("div")); // 挂载到一个临时的 div
|
|
90
|
+
keyboardJS.bind("shift > t", (e) => {
|
|
91
|
+
// 打开弹窗
|
|
92
|
+
this.configInstance.openModal(); // 调用 openModal 方法
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
install(app, { router }) {
|
|
96
|
+
app.use(this.i18n);
|
|
97
|
+
app.use(iview);
|
|
98
|
+
app.component("LangChange", LangChange);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as Vue from "vue";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import { Message } from "view-ui-plus";
|
|
4
|
+
import * as _ from "lodash-es";
|
|
5
|
+
// Vue.prototype.$http = axios;
|
|
6
|
+
|
|
7
|
+
Message.config({
|
|
8
|
+
duration: 3
|
|
9
|
+
});
|
|
10
|
+
axios.defaults.timeout = 60000;
|
|
11
|
+
|
|
12
|
+
axios.interceptors.request.use(
|
|
13
|
+
(config) => {
|
|
14
|
+
//这边可根据自己的需求设置headers,我司采用basic基本认证
|
|
15
|
+
const authToken = localStorage.getItem("token");
|
|
16
|
+
if (!_.isEmpty(authToken)) {
|
|
17
|
+
config.headers["Authorization"] = authToken;
|
|
18
|
+
}
|
|
19
|
+
config.headers["Content-Type"] = "application/json";
|
|
20
|
+
return config;
|
|
21
|
+
},
|
|
22
|
+
(err) => {
|
|
23
|
+
Message.error({
|
|
24
|
+
content: "请求超时!"
|
|
25
|
+
});
|
|
26
|
+
return Promise.resolve(err);
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
axios.interceptors.response.use(
|
|
30
|
+
(res) => {
|
|
31
|
+
const { nomsg } = res.config.headers;
|
|
32
|
+
if (res.status && res.status != 200) {
|
|
33
|
+
if (!nomsg) {
|
|
34
|
+
Message.error({
|
|
35
|
+
content: res.data.message || "未知错误"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
res.data.success = true;
|
|
40
|
+
}
|
|
41
|
+
return res.data;
|
|
42
|
+
},
|
|
43
|
+
(err) => {
|
|
44
|
+
if (err.response) {
|
|
45
|
+
if (err.response.status == 504 || err.response.status == 404) {
|
|
46
|
+
Message.error({ content: "服务器被吃了⊙﹏⊙∥" });
|
|
47
|
+
} else if (err.response.status == 403) {
|
|
48
|
+
Message.error({ content: "权限不足,请联系管理员!" });
|
|
49
|
+
} else
|
|
50
|
+
Message.error({
|
|
51
|
+
content: `${err.response.status}:${
|
|
52
|
+
err.response.statusText || err.response.error
|
|
53
|
+
}`
|
|
54
|
+
});
|
|
55
|
+
} else if (
|
|
56
|
+
err.code === "ECONNABORTED" &&
|
|
57
|
+
err.message.indexOf("timeout") !== -1
|
|
58
|
+
) {
|
|
59
|
+
Message.error({
|
|
60
|
+
content: "请求超时!"
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
Message.error({ content: err.message || "未知错误!" });
|
|
64
|
+
}
|
|
65
|
+
return Promise.resolve(err);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export default { axios };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import store2 from "store2";
|
|
3
|
+
import _ from "lodash-es";
|
|
4
|
+
import { mergeArraysByKey } from "./utils";
|
|
5
|
+
export const service = "https://test.ihotel.cn";
|
|
6
|
+
const i18nStore = store2.namespace("i18n");
|
|
7
|
+
const Authorization =
|
|
8
|
+
"eyJhbGciOiJIUzUxMiJ9.eyJkZXZpY2VUeXBlIjoiQ09NUFVURVIiLCJtYWluQXBwQ29kZSI6IlNTTyIsIm9yZ0NvZGUiOiJHQ0JaRyIsInVjU2VydmVyVXJsIjoiaHR0cHM6Ly90ZXN0Lmlob3RlbC5jbi91Yy13ZWIvIiwiYXBwQ29kZSI6IlNTTyIsInVzZXJUeXBlIjoiTk9STUFMIiwibG9naW5BdCI6MTczODczNTczOTAwMCwicHJpbmNpcGFsVXNlckNvZGUiOiJHQ0JaR19BRE1JTiIsImV4cCI6MzI1MDM2NTEyMDAsInVzZXJDb2RlIjoiR0NCWkdfQURNSU4iLCJzc28iOiJTU09fU0VSVkVSIn0.KQt1YbUdJ7DfqrfXEVYT0Ux-7Zlo2GQBiIoq0rxK0cv1LHqOOMtBkv8kmChM6VavtdnlyXM2GkW6YMvIIHvu0Q";
|
|
9
|
+
export const getLanguages = async () => {
|
|
10
|
+
return axios.get(service + "/i18n-web/sysoption/getsupportedlangs", {
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
export const fetchTranslate = async ({
|
|
17
|
+
appCode,
|
|
18
|
+
language = "zh-CN",
|
|
19
|
+
page,
|
|
20
|
+
lastPullDate
|
|
21
|
+
}) => {
|
|
22
|
+
return new Promise(async (resolve, reject) => {
|
|
23
|
+
const serverURI = service + "/i18n-web/kv_translate/kv_translates";
|
|
24
|
+
const url = lastPullDate
|
|
25
|
+
? serverURI + "?lastPullDate=" + lastPullDate
|
|
26
|
+
: serverURI;
|
|
27
|
+
const res = await axios({
|
|
28
|
+
url,
|
|
29
|
+
method: "GET",
|
|
30
|
+
headers: {
|
|
31
|
+
appCode,
|
|
32
|
+
page,
|
|
33
|
+
language
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
if (res && res.result == 0) {
|
|
37
|
+
resolve(res.retVal);
|
|
38
|
+
} else {
|
|
39
|
+
reject(res);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const getAllTranslate = async (data) => {
|
|
45
|
+
console.log("data", data);
|
|
46
|
+
|
|
47
|
+
return axios({
|
|
48
|
+
url: service + "/i18n-web/kv_translate/kv_translates",
|
|
49
|
+
method: "POST",
|
|
50
|
+
data,
|
|
51
|
+
headers: { token: Authorization }
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
export const saveTranslate = async (data) => {
|
|
55
|
+
return axios({
|
|
56
|
+
url: service + "/i18n-web/kv_translate/batch",
|
|
57
|
+
method: "POST",
|
|
58
|
+
data,
|
|
59
|
+
headers: { token: Authorization }
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
export const getTranslate = async ({ appCode, language = "zh-CN" }) => {
|
|
63
|
+
return new Promise(async (resolve, reject) => {
|
|
64
|
+
// const appCodeStore = i18nStore.get(appCode);
|
|
65
|
+
const languageStore = i18nStore.namespace(appCode);
|
|
66
|
+
const options = {
|
|
67
|
+
appCode,
|
|
68
|
+
language
|
|
69
|
+
};
|
|
70
|
+
const lastData = languageStore.get(language);
|
|
71
|
+
|
|
72
|
+
if (!lastData || !lastData.lastPullDate) {
|
|
73
|
+
// 如果是第一次获取
|
|
74
|
+
const res = await fetchTranslate(options);
|
|
75
|
+
if (res) {
|
|
76
|
+
languageStore.set(language, res);
|
|
77
|
+
resolve(res.translatesDTOs);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
const { lastPullDate } = lastData;
|
|
81
|
+
const res = await fetchTranslate({
|
|
82
|
+
...options,
|
|
83
|
+
lastPullDate
|
|
84
|
+
});
|
|
85
|
+
if (res) {
|
|
86
|
+
// 合并增量数据
|
|
87
|
+
const langData = _.get(lastData, "translatesDTOs");
|
|
88
|
+
if (!_.isEmpty(res.translatesDTOs)) {
|
|
89
|
+
const data = mergeArraysByKey(langData, res.translatesDTOs);
|
|
90
|
+
const saveData = { lastPullDate, translatesDTOs: data };
|
|
91
|
+
i18nStore[appCode].set(language, saveData, ":"); // Only update the specific key
|
|
92
|
+
resolve(data);
|
|
93
|
+
} else {
|
|
94
|
+
resolve(langData);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import _ from "lodash-es";
|
|
2
|
+
export const convertArrayToObject = (arr) => {
|
|
3
|
+
const result = {};
|
|
4
|
+
for (const item of arr) {
|
|
5
|
+
result[item.key] = item.value;
|
|
6
|
+
}
|
|
7
|
+
return result;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const mergeArraysByKey = (arr1, arr2) => {
|
|
11
|
+
arr2.forEach((obj2) => {
|
|
12
|
+
const foundObj = _.find(arr1, { key: obj2.key });
|
|
13
|
+
if (foundObj) {
|
|
14
|
+
_.merge(foundObj, obj2);
|
|
15
|
+
} else {
|
|
16
|
+
arr1.push(obj2);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return arr1;
|
|
20
|
+
};
|
package/src/App.vue
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
package/src/main.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createApp } from "vue";
|
|
2
|
+
import App from "./App.vue";
|
|
3
|
+
import gc_i18n from "../packages/index.js";
|
|
4
|
+
import router from "./router/index";
|
|
5
|
+
import "view-ui-plus/dist/styles/viewuiplus.css";
|
|
6
|
+
|
|
7
|
+
import zh from "view-ui-plus/dist/locale/zh-CN";
|
|
8
|
+
import en from "view-ui-plus/dist/locale/en-US";
|
|
9
|
+
|
|
10
|
+
const i18n = new gc_i18n({
|
|
11
|
+
appCode: "TEST",
|
|
12
|
+
router,
|
|
13
|
+
messages: {
|
|
14
|
+
"zh-CN": zh,
|
|
15
|
+
"en-US": en
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const app = createApp(App).use(router).use(i18n, { router });
|
|
20
|
+
|
|
21
|
+
app.mount("#app");
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createRouter, createWebHashHistory } from "vue-router";
|
|
2
|
+
|
|
3
|
+
const routes = [
|
|
4
|
+
{
|
|
5
|
+
path: "/BOOK",
|
|
6
|
+
name: "BOOK",
|
|
7
|
+
component: () => import("../view/Home.vue")
|
|
8
|
+
}
|
|
9
|
+
];
|
|
10
|
+
const router = createRouter({
|
|
11
|
+
history: createWebHashHistory(),
|
|
12
|
+
routes
|
|
13
|
+
});
|
|
14
|
+
router.beforeEach((to, from, next) => {
|
|
15
|
+
next();
|
|
16
|
+
});
|
|
17
|
+
export default router;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useI18n } from "vue-i18n";
|
|
3
|
+
const { locale, changeLocal } = useI18n();
|
|
4
|
+
|
|
5
|
+
defineProps({
|
|
6
|
+
msg: String
|
|
7
|
+
});
|
|
8
|
+
const langs = [
|
|
9
|
+
{
|
|
10
|
+
label: "中文",
|
|
11
|
+
code: "zh-CN"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
label: "English",
|
|
15
|
+
code: "en-US"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: "繁体",
|
|
19
|
+
code: "zh-TW"
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
const change = (lang) => {
|
|
23
|
+
changeLocal(lang);
|
|
24
|
+
};
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<div>
|
|
29
|
+
<Button
|
|
30
|
+
v-for="item in langs"
|
|
31
|
+
:type="item.code === locale ? 'primary' : 'default'"
|
|
32
|
+
@click="change(item.code)"
|
|
33
|
+
>{{ item.label }}</Button
|
|
34
|
+
>
|
|
35
|
+
<div>
|
|
36
|
+
<div>带路由前缀:</div>
|
|
37
|
+
<div>{{ $t("BOOK.ZHENGJIANLEIXING", { comment: "姓名" }) }}</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div>
|
|
40
|
+
<div>不带前缀:</div>
|
|
41
|
+
<div>{{ $t("ZHENGJIANLEIXING") }}</div>
|
|
42
|
+
</div>
|
|
43
|
+
<Page
|
|
44
|
+
:total="40"
|
|
45
|
+
size="small"
|
|
46
|
+
show-total
|
|
47
|
+
/>
|
|
48
|
+
|
|
49
|
+
<!-- <LangChange></LangChange> -->
|
|
50
|
+
</div>
|
|
51
|
+
</template>
|