i18n-jsautotranslate 3.15.6 → 3.16.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/README.md +4 -3
- package/index.js +974 -152
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -14,32 +14,40 @@ var translate = {
|
|
|
14
14
|
* 格式:major.minor.patch.date
|
|
15
15
|
*/
|
|
16
16
|
// AUTO_VERSION_START
|
|
17
|
-
version: '3.
|
|
17
|
+
version: '3.16.0.20250618',
|
|
18
18
|
// AUTO_VERSION_END
|
|
19
19
|
/*
|
|
20
20
|
当前使用的版本,默认使用v2. 可使用 setUseVersion2();
|
|
21
21
|
来设置使用v2 ,已废弃,主要是区分是否是v1版本来着,v2跟v3版本是同样的使用方式
|
|
22
22
|
*/
|
|
23
|
-
useVersion:'v2',
|
|
23
|
+
useVersion:'v2',
|
|
24
|
+
/*js translate.setUseVersion2 start*/
|
|
24
25
|
setUseVersion2:function(){
|
|
25
26
|
translate.useVersion = 'v2';
|
|
26
27
|
console.log('提示:自 v2.10 之后的版本默认就是使用V2版本(当前版本为:'+translate.version+'), translate.setUseVersion2() 可以不用再加这一行了。当然加了也无所谓,只是加了跟不加是完全一样的。');
|
|
27
28
|
},
|
|
29
|
+
/*js translate.setUseVersion2 end*/
|
|
28
30
|
/*
|
|
29
31
|
* 翻译的对象,也就是 new google.translate.TranslateElement(...)
|
|
30
32
|
* 已废弃,v1使用的
|
|
31
33
|
*/
|
|
32
34
|
translate:null,
|
|
35
|
+
|
|
36
|
+
/*js translate.includedLanguages end*/
|
|
33
37
|
/*
|
|
34
38
|
* 支持哪些语言切换,包括:de,hi,lt,hr,lv,ht,hu,zh-CN,hy,uk,mg,id,ur,mk,ml,mn,af,mr,uz,ms,el,mt,is,it,my,es,et,eu,ar,pt-PT,ja,ne,az,fa,ro,nl,en-GB,no,be,fi,ru,bg,fr,bs,sd,se,si,sk,sl,ga,sn,so,gd,ca,sq,sr,kk,st,km,kn,sv,ko,sw,gl,zh-TW,pt-BR,co,ta,gu,ky,cs,pa,te,tg,th,la,cy,pl,da,tr
|
|
35
39
|
* 已废弃,请使用 translate.selectLanguageTag.languages
|
|
36
40
|
*/
|
|
37
41
|
includedLanguages:'zh-CN,zh-TW,en',
|
|
42
|
+
/*js translate.includedLanguages end*/
|
|
43
|
+
|
|
44
|
+
/*js translate.resourcesUrl start*/
|
|
38
45
|
/*
|
|
39
46
|
* 资源文件url的路径
|
|
40
47
|
* 已废弃,v1使用的
|
|
41
48
|
*/
|
|
42
49
|
resourcesUrl:'//res.zvo.cn/translate',
|
|
50
|
+
/*js translate.resourcesUrl end*/
|
|
43
51
|
|
|
44
52
|
/**
|
|
45
53
|
* 默认出现的选择语言的 select 选择框,可以通过这个选择切换语言。
|
|
@@ -193,8 +201,11 @@ var translate = {
|
|
|
193
201
|
* 已废弃,v1使用的
|
|
194
202
|
*/
|
|
195
203
|
//localLanguage:'zh-CN',
|
|
204
|
+
/*js translate.localLanguage start*/
|
|
196
205
|
localLanguage:'zh-CN',
|
|
206
|
+
/*js translate.localLanguage end*/
|
|
197
207
|
|
|
208
|
+
/*js translate.googleTranslateElementInit start*/
|
|
198
209
|
/**
|
|
199
210
|
* google翻译执行的
|
|
200
211
|
* 已废弃,v1使用的
|
|
@@ -223,6 +234,7 @@ var translate = {
|
|
|
223
234
|
selectId //触发按钮的id
|
|
224
235
|
);
|
|
225
236
|
},
|
|
237
|
+
/*js translate.googleTranslateElementInit end*/
|
|
226
238
|
|
|
227
239
|
/**
|
|
228
240
|
* 初始化,如加载js、css资源
|
|
@@ -244,6 +256,9 @@ var translate = {
|
|
|
244
256
|
|
|
245
257
|
},
|
|
246
258
|
*/
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
/*js translate.execute_v1 start*/
|
|
247
262
|
/**
|
|
248
263
|
* 执行翻译操作
|
|
249
264
|
* 已废弃,v1使用的
|
|
@@ -252,7 +267,9 @@ var translate = {
|
|
|
252
267
|
console.log('=====ERROR======');
|
|
253
268
|
console.log('The v1 version has been discontinued since 2022. Please use the latest V3 version and refer to: http://translate.zvo.cn/41162.html');
|
|
254
269
|
},
|
|
255
|
-
|
|
270
|
+
/*js translate.execute_v1 end*/
|
|
271
|
+
|
|
272
|
+
/*js translate.setCookie start*/
|
|
256
273
|
/**
|
|
257
274
|
* 设置Cookie,失效时间一年。
|
|
258
275
|
* @param name
|
|
@@ -263,7 +280,9 @@ var translate = {
|
|
|
263
280
|
var cookieString=name+"="+escape(value);
|
|
264
281
|
document.cookie=cookieString;
|
|
265
282
|
},
|
|
283
|
+
/*js translate.setCookie end*/
|
|
266
284
|
|
|
285
|
+
/*js translate.getCookie start*/
|
|
267
286
|
//获取Cookie。若是不存再,返回空字符串
|
|
268
287
|
//* 已废弃,v1使用的
|
|
269
288
|
getCookie:function (name){
|
|
@@ -277,11 +296,14 @@ var translate = {
|
|
|
277
296
|
}
|
|
278
297
|
return "";
|
|
279
298
|
},
|
|
299
|
+
/*js translate.getCookie end*/
|
|
280
300
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
301
|
+
|
|
302
|
+
/*js translate.currentLanguage start*/
|
|
303
|
+
/*
|
|
304
|
+
获取当前页面采用的是什么语言
|
|
305
|
+
返回值如 en、zh-CN、zh-TW (如果是第一次用,没有设置过,那么返回的是 translate.localLanguage 设置的值)
|
|
306
|
+
已废弃,v1使用的
|
|
285
307
|
*/
|
|
286
308
|
currentLanguage:function(){
|
|
287
309
|
//translate.check();
|
|
@@ -292,6 +314,7 @@ var translate = {
|
|
|
292
314
|
return translate.localLanguage;
|
|
293
315
|
}
|
|
294
316
|
},
|
|
317
|
+
/*js translate.currentLanguage end*/
|
|
295
318
|
|
|
296
319
|
/**
|
|
297
320
|
* 切换语言,比如切换为英语、法语
|
|
@@ -364,17 +387,27 @@ var translate = {
|
|
|
364
387
|
for (let i = 0; i < iframes.length; i++) {
|
|
365
388
|
const iframe = iframes[i];
|
|
366
389
|
// 获取 iframe 的 window 对象
|
|
367
|
-
const iframeWindow = iframe.contentWindow;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
iframeWindow.translate.to
|
|
372
|
-
|
|
373
|
-
|
|
390
|
+
const iframeWindow = iframe.contentWindow;
|
|
391
|
+
try{
|
|
392
|
+
if(typeof(iframeWindow.translate) == 'object' && typeof(iframeWindow.translate.version) == 'string'){
|
|
393
|
+
//iframe页面中存在 translate,那么也控制iframe中的进行翻译
|
|
394
|
+
if(iframeWindow.translate.to != languageName){
|
|
395
|
+
iframeWindow.translate.to = languageName;
|
|
396
|
+
iframeWindow.translate.storage.set('to',languageName); //设置目标翻译语言
|
|
397
|
+
iframeWindow.translate.execute();
|
|
398
|
+
}
|
|
374
399
|
}
|
|
400
|
+
}catch(e){
|
|
401
|
+
//增加try,避免异常,比如跨域,中断导致无法用
|
|
402
|
+
console.log(e);
|
|
375
403
|
}
|
|
376
404
|
}
|
|
377
405
|
}
|
|
406
|
+
|
|
407
|
+
//当用户代码设置里启用了 translate.listener.start() 然后用户加载页面后并没有翻译(这时listener是不启动的只是把listener.use标记为true),然后手动点击翻译按钮翻译为其他语种(这是不会刷新页面),翻译后也要跟着启动监听
|
|
408
|
+
if(translate.listener.use == true && translate.listener.isStart == false){
|
|
409
|
+
translate.listener.start();
|
|
410
|
+
}
|
|
378
411
|
},
|
|
379
412
|
|
|
380
413
|
/**
|
|
@@ -382,11 +415,13 @@ var translate = {
|
|
|
382
415
|
* english
|
|
383
416
|
* 已废弃,v1使用的
|
|
384
417
|
*/
|
|
418
|
+
/*js translate.check start*/
|
|
385
419
|
check:function(){
|
|
386
420
|
if(window.location.protocol == 'file:'){
|
|
387
421
|
console.log('\r\n---WARNING----\r\ntranslate.js 主动翻译组件自检异常,当前协议是file协议,翻译组件要在正常的线上http、https协议下才能正常使用翻译功能\r\n------------');
|
|
388
422
|
}
|
|
389
423
|
},
|
|
424
|
+
/*js translate.check end*/
|
|
390
425
|
|
|
391
426
|
|
|
392
427
|
/**************************** v2.0 */
|
|
@@ -823,6 +858,74 @@ var translate = {
|
|
|
823
858
|
translate.storage.set('hash_'+to+'_'+translate.util.hash(key), value);
|
|
824
859
|
}
|
|
825
860
|
},
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
//全部提取能力(整站的离线翻译数据提取)
|
|
864
|
+
fullExtract:{
|
|
865
|
+
/*js translate.office.fullExtract.set start*/
|
|
866
|
+
/*
|
|
867
|
+
将翻译的结果加入
|
|
868
|
+
hash: 翻译前的文本的hash
|
|
869
|
+
originalText: 翻以前的文本,原始文本
|
|
870
|
+
toLanguage: 翻译为什么语言
|
|
871
|
+
translateText: 翻译结果的文本
|
|
872
|
+
*/
|
|
873
|
+
set: async function(hash, originalText, toLanguage, translateText){
|
|
874
|
+
if(typeof(translate.storage.IndexedDB) == 'undefined'){
|
|
875
|
+
console.log('ERROR: translate.storage.IndexedDB not find');
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
var obj = await translate.storage.IndexedDB.get('hash_'+hash);
|
|
879
|
+
if(typeof(obj) == 'undefined' && obj == null){
|
|
880
|
+
obj = {
|
|
881
|
+
originalText:originalText
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
obj[toLanguage] = translateText;
|
|
885
|
+
await translate.storage.IndexedDB.set('hash_'+hash, obj);
|
|
886
|
+
},
|
|
887
|
+
/*js translate.office.fullExtract.set end*/
|
|
888
|
+
|
|
889
|
+
/*js translate.office.fullExtract.export start*/
|
|
890
|
+
/*
|
|
891
|
+
将存储的数据导出为 txt 文件下载下来
|
|
892
|
+
*/
|
|
893
|
+
export: async function(to){
|
|
894
|
+
if(typeof(translate.storage.IndexedDB) == 'undefined'){
|
|
895
|
+
console.log('ERROR: translate.storage.IndexedDB not find');
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
if(typeof(to) != 'string'){
|
|
899
|
+
console.log('error : to param not find, example: "english"');
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
var text = 'translate.office.append(\'';
|
|
903
|
+
|
|
904
|
+
var data = await translate.storage.IndexedDB.list('hash_*');
|
|
905
|
+
for(var i in data){
|
|
906
|
+
var originalText = data[i].value.originalText.replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
907
|
+
text = text + '\n' + originalText + '='+data[i].value.english.replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
908
|
+
}
|
|
909
|
+
text = text + '\n`);'
|
|
910
|
+
|
|
911
|
+
const blob = new Blob([text], { type: "text/plain" });
|
|
912
|
+
const url = URL.createObjectURL(blob);
|
|
913
|
+
const link = document.createElement("a");
|
|
914
|
+
link.href = url;
|
|
915
|
+
link.download = to+".txt";
|
|
916
|
+
link.click();
|
|
917
|
+
URL.revokeObjectURL(url);
|
|
918
|
+
},
|
|
919
|
+
/*js translate.office.fullExtract.export end*/
|
|
920
|
+
|
|
921
|
+
/*
|
|
922
|
+
是否启用全部提取的能力
|
|
923
|
+
true: 启用, 默认是false不启用。
|
|
924
|
+
如果设置为true,则每次通过调用翻译接口进行翻译后,都会将翻译的原文、译文、翻译为什么语种,都会单独记录一次,存入浏览器的 IndexedDB 的 translate.js 数据库
|
|
925
|
+
然后可以浏览所有页面后,把所有翻译一对一的对应翻译结果直接全部导出,用于做离线翻译配置使用。
|
|
926
|
+
*/
|
|
927
|
+
isUse:false,
|
|
928
|
+
}
|
|
826
929
|
},
|
|
827
930
|
setAutoDiscriminateLocalLanguage:function(){
|
|
828
931
|
translate.autoDiscriminateLocalLanguage = true;
|
|
@@ -893,9 +996,12 @@ var translate = {
|
|
|
893
996
|
//isExecuteFinish:false,
|
|
894
997
|
//是否已经使用了 translate.listener.start() 了,如果使用了,那这里为true,多次调用 translate.listener.start() 只有第一次有效
|
|
895
998
|
isStart:false,
|
|
999
|
+
//用户的代码里是否启用了 translate.listener.start() ,true:启用
|
|
1000
|
+
//当用户加载页面后,但是未启用翻译时,为了降低性能,监听是不会启动的,但是用户手动点击翻译后,也要把监听启动起来,所以就加了这个参数,来表示当前是否在代码里启用了监听,以便当触发翻译时,监听也跟着触发
|
|
1001
|
+
use:false,
|
|
896
1002
|
//translate.listener.start(); //开启html页面变化的监控,对变化部分会进行自动翻译。注意,这里变化区域,是指使用 translate.setDocuments(...) 设置的区域。如果未设置,那么为监控整个网页的变化
|
|
897
1003
|
start:function(){
|
|
898
|
-
|
|
1004
|
+
translate.listener.use = true;
|
|
899
1005
|
translate.temp_linstenerStartInterval = setInterval(function(){
|
|
900
1006
|
if(document.readyState == 'complete'){
|
|
901
1007
|
//dom加载完成,进行启动
|
|
@@ -945,8 +1051,9 @@ var translate = {
|
|
|
945
1051
|
node 是哪个节点被listener扫描到改动后忽略。
|
|
946
1052
|
可传入 node、也可以传入node的uuid字符串
|
|
947
1053
|
expireTime 过期时间,也就是执行当前方法将 node 加入后,过多长时间失效,这里是毫秒,比如传入 500 则这个node在当前时间往后的500毫秒内,如果被listener监听到改动,是直接被忽略的,不会触发任何翻译操作
|
|
1054
|
+
showResultText 实际显示出来的文本,翻译之后显示出来的文本。如果翻译过程中其他js改动了这个文本内容,导致未能翻译,则 analyse.set 的 resultText 会返回 空字符串设置到这里
|
|
948
1055
|
*/
|
|
949
|
-
addIgnore:function(node, expireTime){
|
|
1056
|
+
addIgnore:function(node, expireTime, showResultText){
|
|
950
1057
|
let nodeid = '';
|
|
951
1058
|
if(typeof(node) == 'string'){
|
|
952
1059
|
nodeid = node;
|
|
@@ -954,7 +1061,10 @@ var translate = {
|
|
|
954
1061
|
nodeid = nodeuuid.uuid(node);
|
|
955
1062
|
}
|
|
956
1063
|
|
|
957
|
-
translate.listener.ignoreNode[nodeid] =
|
|
1064
|
+
translate.listener.ignoreNode[nodeid] = {
|
|
1065
|
+
addtime:Date.now()+expireTime,
|
|
1066
|
+
text:showResultText
|
|
1067
|
+
};
|
|
958
1068
|
|
|
959
1069
|
//translate.listener.renderTaskFinish();
|
|
960
1070
|
},
|
|
@@ -965,7 +1075,7 @@ var translate = {
|
|
|
965
1075
|
//console.log('refresh ignore ,current: '+Object.keys(translate.listener.ignoreNode).length);
|
|
966
1076
|
var currentTime = Date.now();
|
|
967
1077
|
for (const node in translate.listener.ignoreNode) {
|
|
968
|
-
if(translate.listener.ignoreNode[node] < currentTime){
|
|
1078
|
+
if(translate.listener.ignoreNode[node].addtime < currentTime){
|
|
969
1079
|
//console.log('delete : ');
|
|
970
1080
|
//console.log(node);
|
|
971
1081
|
delete translate.listener.ignoreNode[node];
|
|
@@ -977,6 +1087,10 @@ var translate = {
|
|
|
977
1087
|
|
|
978
1088
|
//增加监听,开始监听。这个不要直接调用,需要使用上面的 start() 开启
|
|
979
1089
|
addListener:function(){
|
|
1090
|
+
if(translate.listener.isStart == true){
|
|
1091
|
+
console.log('translate.listener.start() 已经启动了,无需再重复启动监听,增加浏览器负担');
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
980
1094
|
translate.listener.isStart = true; //记录已执行过启动方法了
|
|
981
1095
|
|
|
982
1096
|
// 观察器的配置(需要观察什么变动)
|
|
@@ -1052,8 +1166,8 @@ var translate = {
|
|
|
1052
1166
|
|
|
1053
1167
|
//console.log(node);
|
|
1054
1168
|
let nodeid = nodeuuid.uuid(node);
|
|
1055
|
-
if(typeof(translate.listener.ignoreNode[nodeid])
|
|
1056
|
-
if(translate.listener.ignoreNode[nodeid] > Date.now()){
|
|
1169
|
+
if(typeof(translate.listener.ignoreNode[nodeid]) != 'undefined'){
|
|
1170
|
+
if(translate.listener.ignoreNode[nodeid].addtime > Date.now() && typeof(node.nodeValue) == 'string' && node.nodeValue == translate.listener.ignoreNode[nodeid].text){
|
|
1057
1171
|
//console.log('node 未过忽略期,listener扫描后忽略:'+nodeid);
|
|
1058
1172
|
continue;
|
|
1059
1173
|
}
|
|
@@ -1279,12 +1393,10 @@ var translate = {
|
|
|
1279
1393
|
|
|
1280
1394
|
}, 50, ipnode);
|
|
1281
1395
|
|
|
1396
|
+
//渲染页面进行翻译显示
|
|
1397
|
+
var analyseSet = translate.element.nodeAnalyse.set(this.nodes[hash][task_index], task.originalText, task.resultText, task['attribute']);
|
|
1282
1398
|
//加入 translate.listener.ignoreNode
|
|
1283
|
-
translate.listener.addIgnore(this.nodes[hash][task_index], translate.listener.translateExecuteNodeIgnoreExpireTime);
|
|
1284
|
-
translate.element.nodeAnalyse.set(this.nodes[hash][task_index], task.originalText, task.resultText, task['attribute']);
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1399
|
+
translate.listener.addIgnore(this.nodes[hash][task_index], translate.listener.translateExecuteNodeIgnoreExpireTime, analyseSet.resultText);
|
|
1288
1400
|
|
|
1289
1401
|
|
|
1290
1402
|
/*
|
|
@@ -1331,7 +1443,7 @@ var translate = {
|
|
|
1331
1443
|
//console.log(translate.nodeQueue[uuid].list[lang][hash].original);
|
|
1332
1444
|
//var nodename = translate.element.getNodeName(translate.nodeQueue[uuid].list[lang][hash].nodes[0].node);
|
|
1333
1445
|
//console.log("nodename:"+nodename);
|
|
1334
|
-
var analyse = translate.element.nodeAnalyse.get(renderTask.nodes[hash][
|
|
1446
|
+
var analyse = translate.element.nodeAnalyse.get(renderTask.nodes[hash][nodeindex]);
|
|
1335
1447
|
//analyse.text analyse.node
|
|
1336
1448
|
var nodeid = nodeuuid.uuid(analyse.node);
|
|
1337
1449
|
|
|
@@ -1357,7 +1469,15 @@ var translate = {
|
|
|
1357
1469
|
//console.log(analyse.node);
|
|
1358
1470
|
translate.nodeHistory[nodeid] = {};
|
|
1359
1471
|
translate.nodeHistory[nodeid].node = analyse.node;
|
|
1360
|
-
translate.
|
|
1472
|
+
if(translate.whole.isWhole(analyse.node)){
|
|
1473
|
+
//这个元素使用的是整体翻译的方式,那就直接将API接口返回的翻译内容作为node最终显示的结果。
|
|
1474
|
+
//这样即使在翻译过程中其他js对这个元素的内容有改动了,那下次再触发翻译,还能对改动后的文本正常翻译,不至于使这个元素已被标记翻译过了,造成漏翻译。
|
|
1475
|
+
translate.nodeHistory[nodeid].translateText = renderTask.taskQueue[hash][nodeindex].resultText;
|
|
1476
|
+
}else{
|
|
1477
|
+
//时间差会造成漏翻译情况,见if中的注释
|
|
1478
|
+
translate.nodeHistory[nodeid].translateText = analyse.text;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1361
1481
|
}
|
|
1362
1482
|
|
|
1363
1483
|
}
|
|
@@ -1392,6 +1512,7 @@ var translate = {
|
|
|
1392
1512
|
|
|
1393
1513
|
*/
|
|
1394
1514
|
waitingExecute:{
|
|
1515
|
+
use:true, //默认是使用,自有部署场景不担心并发的场景,可以禁用,以提高用户使用体验。
|
|
1395
1516
|
|
|
1396
1517
|
/*
|
|
1397
1518
|
一维数组形态,存放执行的翻译任务
|
|
@@ -1479,11 +1600,14 @@ var translate = {
|
|
|
1479
1600
|
如果不传入或者传入null,则是翻译整个网页所有能翻译的元素
|
|
1480
1601
|
*/
|
|
1481
1602
|
execute:function(docs){
|
|
1482
|
-
if(translate.
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1603
|
+
if(translate.waitingExecute.use){
|
|
1604
|
+
if(translate.state != 0){
|
|
1605
|
+
console.log('当前翻译还未完结,新的翻译任务已加入等待翻译队列中,待翻译结束后便会执行当前翻译任务。');
|
|
1606
|
+
translate.waitingExecute.add(docs);
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1486
1609
|
}
|
|
1610
|
+
|
|
1487
1611
|
translate.state = 1;
|
|
1488
1612
|
//console.log('translate.state = 1');
|
|
1489
1613
|
if(typeof(docs) != 'undefined'){
|
|
@@ -2174,6 +2298,10 @@ var translate = {
|
|
|
2174
2298
|
|
|
2175
2299
|
//将翻译结果以 key:hash value翻译结果的形式缓存
|
|
2176
2300
|
translate.storage.set('hash_'+data.to+'_'+cacheHash,text);
|
|
2301
|
+
//如果离线翻译启用了全部提取,那么还要存入离线翻译指定存储
|
|
2302
|
+
if(translate.office.fullExtract.isUse){
|
|
2303
|
+
translate.office.fullExtract.set(hash, originalWord, data.to, text);
|
|
2304
|
+
}
|
|
2177
2305
|
}
|
|
2178
2306
|
task.execute(); //执行渲染任务
|
|
2179
2307
|
//translate.temp_executeFinishNumber++; //记录执行完的次数
|
|
@@ -2268,9 +2396,12 @@ var translate = {
|
|
|
2268
2396
|
originalText 翻译之前的内容文本
|
|
2269
2397
|
resultText 翻译之后的内容文本
|
|
2270
2398
|
attribute 存放要替换的属性,比如 a标签的title属性。 如果是直接替换node.nodeValue ,那这个没有
|
|
2399
|
+
返回结果是一个数组,其中:
|
|
2400
|
+
resultText: 翻译完成之后的text内容文本,注意,如果返回的是空字符串,那么则是翻译结果进行替换时,并没有成功替换,应该是翻译的过程中,这个node的值被其他js又赋予其他内容了。
|
|
2401
|
+
node: 进行翻译的目标node
|
|
2271
2402
|
*/
|
|
2272
2403
|
set:function(node, originalText, resultText, attribute){
|
|
2273
|
-
translate.element.nodeAnalyse.analyse(node,originalText,resultText, attribute);
|
|
2404
|
+
return translate.element.nodeAnalyse.analyse(node,originalText,resultText, attribute);
|
|
2274
2405
|
},
|
|
2275
2406
|
/*
|
|
2276
2407
|
|
|
@@ -2285,6 +2416,11 @@ var translate = {
|
|
|
2285
2416
|
则是进行翻译之后的渲染显示
|
|
2286
2417
|
|
|
2287
2418
|
attribute : 进行替换渲染时使用,存放要替换的属性,比如 a标签的title属性。 如果是直接替换node.nodeValue ,那这个没有
|
|
2419
|
+
|
|
2420
|
+
返回结果是一个数组,其中:
|
|
2421
|
+
resultText: 翻译完成之后的text内容文本。 当使用 translate.element.nodeAnalyse.set 时才会有这个参数返回。 注意,如果返回的是空字符串,那么则是翻译结果进行替换时,并没有成功替换,应该是翻译的过程中,这个node的值被其他js又赋予其他内容了。
|
|
2422
|
+
text : 要进行翻译的text内容文本,当使用 translate.element.nodeAnalyse.get 时才会有这个参数的返回
|
|
2423
|
+
node: 进行翻译的目标node
|
|
2288
2424
|
*/
|
|
2289
2425
|
analyse:function(node, originalText, resultText, attribute){
|
|
2290
2426
|
var result = new Array(); //返回的结果
|
|
@@ -2301,16 +2437,26 @@ var translate = {
|
|
|
2301
2437
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2302
2438
|
if(typeof(node[attribute]) != 'undefined'){
|
|
2303
2439
|
//这种是主流框架,像是vue、element、react 都是用这种 DOM Property 的方式,更快
|
|
2304
|
-
|
|
2305
|
-
|
|
2440
|
+
var resultShowText = translate.util.textReplace(node[attribute], originalText, resultText, translate.to);
|
|
2441
|
+
node[attribute] = resultShowText; //2025.4.26 变更为此方式
|
|
2442
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2443
|
+
result['resultText'] = resultShowText;
|
|
2444
|
+
}else{
|
|
2445
|
+
result['resultText'] = '';
|
|
2446
|
+
}
|
|
2306
2447
|
}
|
|
2307
2448
|
|
|
2308
2449
|
//这种 Html Attribute 方式 是 v3.12 版本之前一直使用的方式,速度上要慢于 上面的,为了向前兼容不至于升级出问题,后面可能会优化掉
|
|
2309
2450
|
var htmlAttributeValue = node.getAttribute(attribute);
|
|
2310
2451
|
if(htmlAttributeValue != null && typeof(htmlAttributeValue) != 'undefined'){
|
|
2452
|
+
var resultShowText = translate.util.textReplace(htmlAttributeValue, originalText, resultText, translate.to);
|
|
2311
2453
|
//这个才是在v3.9.2 后要用的,上面的留着只是为了适配以前的
|
|
2312
|
-
node.setAttribute(attribute,
|
|
2313
|
-
|
|
2454
|
+
node.setAttribute(attribute, resultShowText);
|
|
2455
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2456
|
+
result['resultText'] = resultShowText;
|
|
2457
|
+
}else{
|
|
2458
|
+
result['resultText'] = '';
|
|
2459
|
+
}
|
|
2314
2460
|
}
|
|
2315
2461
|
}
|
|
2316
2462
|
return result;
|
|
@@ -2357,9 +2503,13 @@ var translate = {
|
|
|
2357
2503
|
if(input_value_node != null && typeof(input_value_node) != 'undefined' && typeof(input_value_node.nodeValue) != 'undefined' && input_value_node.nodeValue.length > 0){
|
|
2358
2504
|
//替换渲染
|
|
2359
2505
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2360
|
-
|
|
2361
|
-
input_value_node.nodeValue =
|
|
2362
|
-
|
|
2506
|
+
var resultShowText = translate.util.textReplace(input_value_node.nodeValue, originalText, resultText, translate.to);
|
|
2507
|
+
input_value_node.nodeValue = resultShowText; //2025.4.26 变更为此方式
|
|
2508
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2509
|
+
result['resultText'] = resultShowText;
|
|
2510
|
+
}else{
|
|
2511
|
+
result['resultText'] = '';
|
|
2512
|
+
}
|
|
2363
2513
|
}
|
|
2364
2514
|
|
|
2365
2515
|
result['text'] = input_value_node.nodeValue;
|
|
@@ -2375,9 +2525,13 @@ var translate = {
|
|
|
2375
2525
|
//console.log(node);
|
|
2376
2526
|
//替换渲染
|
|
2377
2527
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2378
|
-
|
|
2379
|
-
node.attributes['placeholder'].nodeValue =
|
|
2380
|
-
|
|
2528
|
+
var resultShowText = translate.util.textReplace(node.attributes['placeholder'].nodeValue, originalText, resultText, translate.to);
|
|
2529
|
+
node.attributes['placeholder'].nodeValue = resultShowText; //2025.4.26 变更为此方式
|
|
2530
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2531
|
+
result['resultText'] = resultShowText;
|
|
2532
|
+
}else{
|
|
2533
|
+
result['resultText'] = '';
|
|
2534
|
+
}
|
|
2381
2535
|
}
|
|
2382
2536
|
|
|
2383
2537
|
result['text'] = node.attributes['placeholder'].nodeValue;
|
|
@@ -2401,9 +2555,13 @@ var translate = {
|
|
|
2401
2555
|
if(nodeAttributeName == 'keywords' || nodeAttributeName == 'description' || nodeAttributeName == 'sharetitle' || nodeAttributeProperty == 'og:title' || nodeAttributeProperty == 'og:description' || nodeAttributeProperty == 'og:site_name' || nodeAttributeProperty == 'og:novel:latest_chapter_name'){
|
|
2402
2556
|
//替换渲染
|
|
2403
2557
|
if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
|
|
2404
|
-
|
|
2405
|
-
node.content =
|
|
2406
|
-
|
|
2558
|
+
var resultShowText = translate.util.textReplace(node.content, originalText, resultText, translate.to);
|
|
2559
|
+
node.content = resultShowText; //2025.4.26 变更为此方式
|
|
2560
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2561
|
+
result['resultText'] = resultShowText;
|
|
2562
|
+
}else{
|
|
2563
|
+
result['resultText'] = '';
|
|
2564
|
+
}
|
|
2407
2565
|
}
|
|
2408
2566
|
|
|
2409
2567
|
result['text'] = node.content;
|
|
@@ -2422,9 +2580,13 @@ var translate = {
|
|
|
2422
2580
|
|
|
2423
2581
|
//替换渲染
|
|
2424
2582
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2425
|
-
|
|
2426
|
-
node.alt =
|
|
2427
|
-
|
|
2583
|
+
var resultShowText = translate.util.textReplace(node.alt, originalText, resultText, translate.to);
|
|
2584
|
+
node.alt = resultShowText; //2025.4.26 变更为此方式
|
|
2585
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2586
|
+
result['resultText'] = resultShowText;
|
|
2587
|
+
}else{
|
|
2588
|
+
result['resultText'] = '';
|
|
2589
|
+
}
|
|
2428
2590
|
}
|
|
2429
2591
|
result['text'] = node.alt;
|
|
2430
2592
|
return result;
|
|
@@ -2440,9 +2602,13 @@ var translate = {
|
|
|
2440
2602
|
}else{
|
|
2441
2603
|
//替换渲染
|
|
2442
2604
|
if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
|
|
2443
|
-
|
|
2444
|
-
node.nodeValue =
|
|
2445
|
-
|
|
2605
|
+
var resultShowText = translate.util.textReplace(node.nodeValue, originalText, resultText, translate.to);
|
|
2606
|
+
node.nodeValue = resultShowText; //2025.4.26 变更为此方式
|
|
2607
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2608
|
+
result['resultText'] = resultShowText;
|
|
2609
|
+
}else{
|
|
2610
|
+
result['resultText'] = '';
|
|
2611
|
+
}
|
|
2446
2612
|
}
|
|
2447
2613
|
result['text'] = node.nodeValue;
|
|
2448
2614
|
}
|
|
@@ -2460,8 +2626,17 @@ var translate = {
|
|
|
2460
2626
|
}
|
|
2461
2627
|
|
|
2462
2628
|
var nodename = node.nodeName;
|
|
2463
|
-
|
|
2464
|
-
|
|
2629
|
+
if(typeof(node.nodeName) == 'string'){
|
|
2630
|
+
return node.nodeName;
|
|
2631
|
+
}else{
|
|
2632
|
+
if(typeof(node.tagName) == 'string' && node.tagName.length > 0){
|
|
2633
|
+
return node.tagName;
|
|
2634
|
+
}else{
|
|
2635
|
+
console.log('warn : get nodeName is null, this node ignore translate. node : ');
|
|
2636
|
+
console.log(node);
|
|
2637
|
+
return '';
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2465
2640
|
},
|
|
2466
2641
|
//向下遍历node
|
|
2467
2642
|
whileNodes:function(uuid, node){
|
|
@@ -2526,9 +2701,12 @@ var translate = {
|
|
|
2526
2701
|
// //这个tag标签没有这个 attribute,忽略
|
|
2527
2702
|
// continue
|
|
2528
2703
|
//}
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
translate.
|
|
2704
|
+
|
|
2705
|
+
//判断当前元素是否在ignore忽略的tag、id、class name中 v3.15.7 增加
|
|
2706
|
+
if(!translate.ignore.isIgnore(node)){
|
|
2707
|
+
//加入翻译
|
|
2708
|
+
translate.addNodeToQueue(uuid, node, attributeValue, attributeName);
|
|
2709
|
+
}
|
|
2532
2710
|
}
|
|
2533
2711
|
|
|
2534
2712
|
}
|
|
@@ -3165,6 +3343,10 @@ var translate = {
|
|
|
3165
3343
|
*/
|
|
3166
3344
|
isWhole:function(ele){
|
|
3167
3345
|
|
|
3346
|
+
if(translate.whole.isEnableAll){
|
|
3347
|
+
return true;
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3168
3350
|
//如果设置了 class|tag|id 其中某个,或者 all=true ,那么就是启用,反之未启用
|
|
3169
3351
|
if((translate.whole.class.length == 0 && translate.whole.tag.length == 0 && translate.whole.id.length == 0) && translate.whole.isEnableAll == false){
|
|
3170
3352
|
//未设置,那么直接返回false
|
|
@@ -3173,9 +3355,7 @@ var translate = {
|
|
|
3173
3355
|
if(ele == null || typeof(ele) == 'undefined'){
|
|
3174
3356
|
return false;
|
|
3175
3357
|
}
|
|
3176
|
-
|
|
3177
|
-
return true;
|
|
3178
|
-
}
|
|
3358
|
+
|
|
3179
3359
|
|
|
3180
3360
|
var parentNode = ele;
|
|
3181
3361
|
var maxnumber = 100; //最大循环次数,避免死循环
|
|
@@ -3231,7 +3411,7 @@ var translate = {
|
|
|
3231
3411
|
}
|
|
3232
3412
|
|
|
3233
3413
|
//赋予判断的元素向上一级
|
|
3234
|
-
parentNode = parentNode.
|
|
3414
|
+
parentNode = parentNode.parentElement;
|
|
3235
3415
|
}
|
|
3236
3416
|
|
|
3237
3417
|
return false;
|
|
@@ -4059,7 +4239,7 @@ var translate = {
|
|
|
4059
4239
|
},
|
|
4060
4240
|
//希伯来语
|
|
4061
4241
|
hebrew:function(str){
|
|
4062
|
-
return
|
|
4242
|
+
return /^[\u0590-\u05FF]$/.test(str);
|
|
4063
4243
|
},
|
|
4064
4244
|
//0-9 阿拉伯数字
|
|
4065
4245
|
number:function(str){
|
|
@@ -4301,7 +4481,7 @@ var translate = {
|
|
|
4301
4481
|
var text = '你世好word世界';
|
|
4302
4482
|
var translateOriginal = '世';
|
|
4303
4483
|
var translateResult = '世杰'; //翻译结果
|
|
4304
|
-
translate.
|
|
4484
|
+
translate.util.textReplace(text, translateOriginal, translateResult, 'english');
|
|
4305
4485
|
|
|
4306
4486
|
*/
|
|
4307
4487
|
textReplace:function(text, translateOriginal, translateResult, language){
|
|
@@ -4329,7 +4509,7 @@ var translate = {
|
|
|
4329
4509
|
let replaceOriginalText = '' + translateOriginal;
|
|
4330
4510
|
|
|
4331
4511
|
//根据不同的语种,如果有的语种需要加空格来进行区分单词,那么也要进行空格的判定
|
|
4332
|
-
if(translate.language.wordBlankConnector(
|
|
4512
|
+
if(translate.language.wordBlankConnector(language)){
|
|
4333
4513
|
let originalIndex = text.indexOf(translateOriginal, currentReplaceEndIndex); //翻译之前,翻译的单词在字符串中的起始坐标(0开始)
|
|
4334
4514
|
//console.log("originalIndex: "+originalIndex);
|
|
4335
4515
|
|
|
@@ -4345,21 +4525,38 @@ var translate = {
|
|
|
4345
4525
|
}else if(/,/.test(char)){
|
|
4346
4526
|
replaceResultText = replaceResultText + ', ';
|
|
4347
4527
|
replaceOriginalText = translateOriginal + ',';
|
|
4348
|
-
}else if(
|
|
4349
|
-
|
|
4350
|
-
|
|
4528
|
+
}else if(/:/.test(char)){
|
|
4529
|
+
replaceResultText = replaceResultText + ': ';
|
|
4530
|
+
replaceOriginalText = translateOriginal + ':';
|
|
4531
|
+
}else if([' ', '\n','\t',']','|', '_','-','/'].indexOf(char) !== -1){
|
|
4532
|
+
// 如果后面的字符是 这些字符,那么不用添加空格隔开
|
|
4533
|
+
}else{
|
|
4534
|
+
//补充上一个空格,用于将两个单词隔开
|
|
4351
4535
|
replaceResultText = replaceResultText + ' ';
|
|
4352
4536
|
}
|
|
4537
|
+
|
|
4353
4538
|
}
|
|
4354
4539
|
|
|
4355
4540
|
//判断它前面是否还有文本
|
|
4356
4541
|
if(originalIndex > 0){
|
|
4357
4542
|
let char = text.charAt(originalIndex-1);
|
|
4358
4543
|
//console.log(char);
|
|
4359
|
-
|
|
4360
|
-
|
|
4544
|
+
|
|
4545
|
+
if(/。/.test(char)){
|
|
4546
|
+
replaceResultText = '. '+replaceResultText;
|
|
4547
|
+
replaceOriginalText = '。'+replaceOriginalText;
|
|
4548
|
+
}else if(/,/.test(char)){
|
|
4549
|
+
replaceResultText = ', '+replaceResultText;
|
|
4550
|
+
replaceOriginalText = ','+replaceOriginalText;
|
|
4551
|
+
}else if(/:/.test(char)){
|
|
4552
|
+
replaceResultText = ': '+replaceResultText;
|
|
4553
|
+
replaceOriginalText = ':'+replaceOriginalText;
|
|
4554
|
+
}else if([' ', '\n','\t','[', '|', '_','-','/'].indexOf(char) !== -1){
|
|
4555
|
+
// 如果前面的字符是 这些字符,那么不用添加空格隔开
|
|
4556
|
+
}else{
|
|
4557
|
+
//补充上一个空格,用于将两个单词隔开
|
|
4361
4558
|
//text = text.replace(translateOriginal, ' '+translateResult);
|
|
4362
|
-
|
|
4559
|
+
replaceResultText = ' '+replaceResultText;
|
|
4363
4560
|
}
|
|
4364
4561
|
}
|
|
4365
4562
|
}else{
|
|
@@ -4577,6 +4774,8 @@ var translate = {
|
|
|
4577
4774
|
return false;
|
|
4578
4775
|
}
|
|
4579
4776
|
},
|
|
4777
|
+
|
|
4778
|
+
/*js translate.util.loadMsgJs start*/
|
|
4580
4779
|
//加载 msg.js
|
|
4581
4780
|
loadMsgJs:function(){
|
|
4582
4781
|
if(typeof(msg) != 'undefined'){
|
|
@@ -4584,6 +4783,7 @@ var translate = {
|
|
|
4584
4783
|
}
|
|
4585
4784
|
translate.util.synchronizesLoadJs('https://res.zvo.cn/msg/msg.js');
|
|
4586
4785
|
},
|
|
4786
|
+
/*js translate.util.loadMsgJs end*/
|
|
4587
4787
|
/*
|
|
4588
4788
|
对一个对象,按照对象的key的长度进行排序,越长越在前面
|
|
4589
4789
|
*/
|
|
@@ -5007,6 +5207,7 @@ var translate = {
|
|
|
5007
5207
|
*/
|
|
5008
5208
|
name:'translate.service',
|
|
5009
5209
|
|
|
5210
|
+
/*js translate.service.use start*/
|
|
5010
5211
|
/*
|
|
5011
5212
|
其实就是设置 translate.service.name
|
|
5012
5213
|
可以设置为:
|
|
@@ -5014,19 +5215,27 @@ var translate = {
|
|
|
5014
5215
|
translate.service 自行部署的translate.service 翻译API服务,部署参考: https://translate.zvo.cn/391129.html
|
|
5015
5216
|
client.edge 使用无服务器的翻译,有edge浏览器接口提供翻译服务
|
|
5016
5217
|
siliconflow 使用指点云提供的服务器、硅基流动提供的AI算力进行大模型翻译
|
|
5218
|
+
giteeAI 使用 giteeAI , 亚洲、美洲、欧洲 网络节点覆盖
|
|
5017
5219
|
|
|
5018
5220
|
*/
|
|
5019
5221
|
use: function(serviceName){
|
|
5020
|
-
if(translate.enterprise.isUse == true){
|
|
5222
|
+
if(typeof(translate.enterprise) != 'undefined' && translate.enterprise.isUse == true){
|
|
5021
5223
|
console.log('您已启用了企业级翻译通道 translate.enterprise.use(); (文档:https://translate.zvo.cn/4087.html) , 所以您设置的 translate.service.use(\''+serviceName+'\'); (文档:https://translate.zvo.cn/4081.html) 将失效不起作用,有企业级翻译通道全部接管。');
|
|
5022
5224
|
return;
|
|
5023
5225
|
}
|
|
5226
|
+
//console.log('--'+serviceName);
|
|
5024
5227
|
if(typeof(serviceName) == 'string'){
|
|
5025
5228
|
translate.service.name = serviceName;
|
|
5026
5229
|
if(serviceName != 'translate.service'){
|
|
5027
|
-
if(serviceName == '
|
|
5230
|
+
if(serviceName.toLowerCase() == 'giteeai'){
|
|
5231
|
+
//设定翻译接口为GiteeAI的
|
|
5232
|
+
translate.request.api.host=['https://giteeai.zvo.cn/','https://deutsch.enterprise.api.translate.zvo.cn:1000/','https://api.translate.zvo.cn:1000/'];
|
|
5233
|
+
return;
|
|
5234
|
+
}
|
|
5235
|
+
if(serviceName.toLowerCase() == 'siliconflow'){
|
|
5028
5236
|
//设定翻译接口为硅基流动的
|
|
5029
5237
|
translate.request.api.host=['https://siliconflow.zvo.cn/','https://america.api.translate.zvo.cn:1414/','https://deutsch.enterprise.api.translate.zvo.cn:1414/'];
|
|
5238
|
+
return;
|
|
5030
5239
|
}
|
|
5031
5240
|
|
|
5032
5241
|
//增加元素整体翻译能力
|
|
@@ -5034,6 +5243,9 @@ var translate = {
|
|
|
5034
5243
|
}
|
|
5035
5244
|
}
|
|
5036
5245
|
},
|
|
5246
|
+
/*js translate.service.use end*/
|
|
5247
|
+
|
|
5248
|
+
/*js translate.service.edge start*/
|
|
5037
5249
|
//客户端方式的edge提供机器翻译服务
|
|
5038
5250
|
edge:{
|
|
5039
5251
|
api:{ //edge浏览器的翻译功能
|
|
@@ -5161,6 +5373,7 @@ var translate = {
|
|
|
5161
5373
|
|
|
5162
5374
|
}
|
|
5163
5375
|
}
|
|
5376
|
+
/*js translate.service.edge end*/
|
|
5164
5377
|
},
|
|
5165
5378
|
//request请求来源于 https://github.com/xnx3/request
|
|
5166
5379
|
request:{
|
|
@@ -5182,6 +5395,34 @@ var translate = {
|
|
|
5182
5395
|
connectTest:'connectTest.json', //用于 translate.js 多节点翻译自动检测网络连通情况
|
|
5183
5396
|
init:'init.json', //获取最新版本号,跟当前版本进行比对,用于提醒版本升级等使用
|
|
5184
5397
|
|
|
5398
|
+
},
|
|
5399
|
+
/*
|
|
5400
|
+
追加参数, v3.15.9.20250527 增加
|
|
5401
|
+
所有通过 translate.request.send 进行网络请求的,都会追加上这个参数
|
|
5402
|
+
默认是空,没有任何追加参数。
|
|
5403
|
+
|
|
5404
|
+
设置方式: https://translate.zvo.cn/471711.html
|
|
5405
|
+
translate.request.appendParams = {
|
|
5406
|
+
key1:'key1',
|
|
5407
|
+
key2:'key2'
|
|
5408
|
+
}
|
|
5409
|
+
*/
|
|
5410
|
+
appendParams:{
|
|
5411
|
+
|
|
5412
|
+
},
|
|
5413
|
+
/*
|
|
5414
|
+
追加header头的参数, v3.15.13 增加
|
|
5415
|
+
所有通过 translate.request.send 进行网络请求的,都会追加上这个参数
|
|
5416
|
+
默认是空,没有任何追加参数。
|
|
5417
|
+
|
|
5418
|
+
设置方式: https://translate.zvo.cn/471711.html
|
|
5419
|
+
translate.request.appendHeaders = {
|
|
5420
|
+
key1:'key1',
|
|
5421
|
+
Aauthorization:'Bearer xxxxxxxxxx'
|
|
5422
|
+
}
|
|
5423
|
+
*/
|
|
5424
|
+
appendHeaders:{
|
|
5425
|
+
|
|
5185
5426
|
},
|
|
5186
5427
|
/*
|
|
5187
5428
|
请求后端接口的响应。无论是否成功,都会触发此处。
|
|
@@ -5195,6 +5436,7 @@ var translate = {
|
|
|
5195
5436
|
//console.log(xhr);
|
|
5196
5437
|
},
|
|
5197
5438
|
|
|
5439
|
+
|
|
5198
5440
|
/*
|
|
5199
5441
|
速度检测控制中心, 检测主备翻译接口的响应速度进行排列,真正请求时,按照排列的顺序进行请求
|
|
5200
5442
|
v2.8.2增加
|
|
@@ -5460,8 +5702,10 @@ var translate = {
|
|
|
5460
5702
|
}
|
|
5461
5703
|
|
|
5462
5704
|
//企业级翻译自动检测
|
|
5463
|
-
translate.enterprise
|
|
5464
|
-
|
|
5705
|
+
if(typeof(translate.enterprise) != 'undefined'){
|
|
5706
|
+
translate.enterprise.automaticAdaptationService();
|
|
5707
|
+
}
|
|
5708
|
+
|
|
5465
5709
|
// ------- edge start --------
|
|
5466
5710
|
var url = translate.request.getUrl(path);
|
|
5467
5711
|
//if(url.indexOf('edge') > -1 && path == translate.request.api.translate){
|
|
@@ -5512,9 +5756,16 @@ var translate = {
|
|
|
5512
5756
|
//加入浏览器默认语种 v3.6.1 增加,以便更好的进行自动切换语种
|
|
5513
5757
|
data.browserDefaultLanguage = translate.util.browserDefaultLanguage();
|
|
5514
5758
|
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
data
|
|
5759
|
+
//追加附加参数
|
|
5760
|
+
for(var apindex in translate.request.appendParams){
|
|
5761
|
+
data[apindex] = translate.request.appendParams[apindex];
|
|
5762
|
+
}
|
|
5763
|
+
|
|
5764
|
+
if(typeof(translate.enterprise) != 'undefined'){
|
|
5765
|
+
//加入key
|
|
5766
|
+
if(typeof(translate.enterprise.key) != 'undefined' && typeof(translate.enterprise.key) == 'string' && translate.enterprise.key.length > 0){
|
|
5767
|
+
data.key = translate.enterprise.key;
|
|
5768
|
+
}
|
|
5518
5769
|
}
|
|
5519
5770
|
|
|
5520
5771
|
//组合参数
|
|
@@ -5547,6 +5798,12 @@ var translate = {
|
|
|
5547
5798
|
xhr.setRequestHeader(index,headers[index]);
|
|
5548
5799
|
}
|
|
5549
5800
|
}
|
|
5801
|
+
|
|
5802
|
+
//追加附加参数
|
|
5803
|
+
for(var ahindex in translate.request.appendHeaders){
|
|
5804
|
+
xhr.setRequestHeader(ahindex,translate.request.appendHeaders[ahindex]);
|
|
5805
|
+
}
|
|
5806
|
+
|
|
5550
5807
|
if(translate.service.name == 'translate.service'){
|
|
5551
5808
|
xhr.setRequestHeader('currentpage', window.location.href+'');
|
|
5552
5809
|
}
|
|
@@ -5586,8 +5843,8 @@ var translate = {
|
|
|
5586
5843
|
|
|
5587
5844
|
//判断是否是v2版本的翻译,如果是 translate.service 模式并且没有使用企业级翻译,参会提示
|
|
5588
5845
|
//2024.3月底开始,翻译使用量增加的太快,开源的翻译服务器有点扛不住经常出故障,所以直接把这个提示加到这里
|
|
5589
|
-
if(translate.service.name == 'translate.service'
|
|
5590
|
-
console.log('----- translate.js 提示 -----\n
|
|
5846
|
+
if(translate.service.name == 'translate.service'){
|
|
5847
|
+
console.log('----- translate.js 提示 -----\n翻译服务响应异常,解决这种情况可以有两种方案:\n【方案一】:使用采用最新版本 3.16.0及更高版本,js引用文件为 https://cdn.staticfile.net/translate.js/3.16.0/translate.js 并且使用 client.edge 模式 (增加一行设置代码就好,可参考 https://translate.zvo.cn/4081.html ),这样就不会再出现这种情况了,而且这个方案也是完全免费的。 \n【方案二】:采用企业级稳定翻译通道 ,但是这个相比于 方案一 来说,是有一定的收费的,大概一年600,这个就是专门为了高速及高稳定准备的,而相比于这个方案二,方案一则是全免费的。 因为方案二我们是部署了两个集群,而每个集群又下分了数个网络节点,包含中国大陆、香港、美国、欧洲、 等多个州,充分保障稳定、高效,同样也产生了不少成本,所以才需要付费。更多信息说明可以参考: http://translate.zvo.cn/4087.html \n【方案三】:私有部署你自己的翻译通道,并且启用内存级翻译缓存,毫秒级响应,但是需要依赖一台1核2G服务器,是最推荐的方式。具体参考:https://translate.zvo.cn/391129.html\n-------------');
|
|
5591
5848
|
}
|
|
5592
5849
|
|
|
5593
5850
|
//console.log(xhr);
|
|
@@ -5681,6 +5938,19 @@ var translate = {
|
|
|
5681
5938
|
}
|
|
5682
5939
|
}
|
|
5683
5940
|
|
|
5941
|
+
/*
|
|
5942
|
+
for(var i = texts.length - 1; i >= 0; i--){
|
|
5943
|
+
console.log(texts[i]);
|
|
5944
|
+
|
|
5945
|
+
//判断是否在浏览器缓存中出现了
|
|
5946
|
+
var cacheHash = translate.util.hash(texts[i]);
|
|
5947
|
+
var cache = translate.storage.get('hash_'+translate.to+'_'+cacheHash);
|
|
5948
|
+
if(cache != null && cache.length > 0){
|
|
5949
|
+
//缓存中发现了这个得结果,那这个就不需要再进行翻译了
|
|
5950
|
+
}
|
|
5951
|
+
}
|
|
5952
|
+
*/
|
|
5953
|
+
|
|
5684
5954
|
|
|
5685
5955
|
var url = translate.request.api.translate;
|
|
5686
5956
|
var data = {
|
|
@@ -5787,6 +6057,10 @@ var translate = {
|
|
|
5787
6057
|
}
|
|
5788
6058
|
}
|
|
5789
6059
|
}, 100);
|
|
6060
|
+
if(typeof(PerformanceObserver) == 'undefined'){
|
|
6061
|
+
console.log('因浏览器版本较低, translate.request.listener.start() 中 PerformanceObserver 对象不存在,浏览器不支持,所以 translate.request.listener.start() 未生效。');
|
|
6062
|
+
return;
|
|
6063
|
+
}
|
|
5790
6064
|
|
|
5791
6065
|
const observer = new PerformanceObserver((list) => {
|
|
5792
6066
|
var translateExecute = false; //是否需要执行翻译 true 要执行
|
|
@@ -5810,8 +6084,8 @@ var translate = {
|
|
|
5810
6084
|
break;
|
|
5811
6085
|
}
|
|
5812
6086
|
}
|
|
5813
|
-
//client.edge 判断
|
|
5814
|
-
if(url.indexOf(translate.service.edge.api.auth) > -1){
|
|
6087
|
+
//client.edge 判断 translate.service.edge可能会被精简translate.js定制时给直接干掉,所以提前加个判断
|
|
6088
|
+
if(typeof(translate.service.edge) != 'undefined' && url.indexOf(translate.service.edge.api.auth) > -1){
|
|
5815
6089
|
ignoreUrl = true;
|
|
5816
6090
|
}
|
|
5817
6091
|
if(url.indexOf('.microsofttranslator.com/translate') > -1){
|
|
@@ -5838,19 +6112,157 @@ var translate = {
|
|
|
5838
6112
|
translate.request.listener.addExecute();
|
|
5839
6113
|
}
|
|
5840
6114
|
});
|
|
5841
|
-
|
|
5842
|
-
|
|
6115
|
+
|
|
6116
|
+
//v3.15.14.20250617 增加
|
|
6117
|
+
// 优先使用 entryTypes 兼容 ES5 的写法
|
|
6118
|
+
|
|
6119
|
+
var supportedTypes = PerformanceObserver.supportedEntryTypes;
|
|
6120
|
+
if (supportedTypes) {
|
|
6121
|
+
var hasResource = false;
|
|
6122
|
+
for (var i = 0; i < supportedTypes.length; i++) {
|
|
6123
|
+
if (supportedTypes[i] === "resource") {
|
|
6124
|
+
hasResource = true;
|
|
6125
|
+
break;
|
|
6126
|
+
}
|
|
6127
|
+
}
|
|
6128
|
+
if (hasResource) {
|
|
6129
|
+
try {
|
|
6130
|
+
observer.observe({ entryTypes: ["resource"] });
|
|
6131
|
+
return;
|
|
6132
|
+
} catch (e) {
|
|
6133
|
+
console.log("PerformanceObserver entryTypes 失败,尝试 type 参数");
|
|
6134
|
+
}
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
6137
|
+
|
|
6138
|
+
|
|
6139
|
+
// 回退到 type 参数
|
|
6140
|
+
try {
|
|
6141
|
+
observer.observe({ type: "resource", buffered: true });
|
|
6142
|
+
console.log("使用 PerformanceObserver type");
|
|
6143
|
+
} catch (e) {
|
|
6144
|
+
console.log("当前浏览器不支持 PerformanceObserver 的任何参数, translate.request.listener.start() 未启动");
|
|
6145
|
+
}
|
|
6146
|
+
|
|
5843
6147
|
}
|
|
5844
6148
|
}
|
|
5845
6149
|
},
|
|
5846
6150
|
//存储,本地缓存
|
|
5847
6151
|
storage:{
|
|
6152
|
+
/*js translate.storage.IndexedDB start*/
|
|
6153
|
+
//对浏览器的 IndexedDB 操作
|
|
6154
|
+
IndexedDB:{
|
|
6155
|
+
db: null,
|
|
6156
|
+
// 初始化数据库
|
|
6157
|
+
initDB: function () {
|
|
6158
|
+
const self = this;
|
|
6159
|
+
return new Promise((resolve, reject) => {
|
|
6160
|
+
const DB_NAME = 'translate.js';
|
|
6161
|
+
const STORE_NAME = 'kvStore';
|
|
6162
|
+
const DB_VERSION = 1;
|
|
6163
|
+
|
|
6164
|
+
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
6165
|
+
|
|
6166
|
+
request.onupgradeneeded = function(event) {
|
|
6167
|
+
const upgradedDb = event.target.result;
|
|
6168
|
+
if (!upgradedDb.objectStoreNames.contains(STORE_NAME)) {
|
|
6169
|
+
upgradedDb.createObjectStore(STORE_NAME, { keyPath: 'key' });
|
|
6170
|
+
}
|
|
6171
|
+
};
|
|
6172
|
+
|
|
6173
|
+
request.onsuccess = function(event) {
|
|
6174
|
+
self.db = event.target.result;
|
|
6175
|
+
resolve();
|
|
6176
|
+
};
|
|
6177
|
+
|
|
6178
|
+
request.onerror = function(event) {
|
|
6179
|
+
reject('IndexedDB 打开失败');
|
|
6180
|
+
};
|
|
6181
|
+
});
|
|
6182
|
+
},
|
|
6183
|
+
/*
|
|
6184
|
+
存储键值对
|
|
6185
|
+
使用方式:
|
|
6186
|
+
await translate.storage.indexedDB.set("user_001", { name: "Alice" });
|
|
6187
|
+
*/
|
|
6188
|
+
set: async function (key, value) {
|
|
6189
|
+
if (!this.db) await this.initDB();
|
|
6190
|
+
|
|
6191
|
+
return new Promise((resolve, reject) => {
|
|
6192
|
+
const tx = this.db.transaction('kvStore', 'readwrite');
|
|
6193
|
+
const store = tx.objectStore('kvStore');
|
|
6194
|
+
const item = { key, value };
|
|
6195
|
+
const request = store.put(item);
|
|
6196
|
+
|
|
6197
|
+
request.onsuccess = () => resolve();
|
|
6198
|
+
request.onerror = () => reject('写入失败');
|
|
6199
|
+
});
|
|
6200
|
+
},
|
|
6201
|
+
/*
|
|
6202
|
+
获取键对应的值
|
|
6203
|
+
使用方式:
|
|
6204
|
+
var user = await translate.storage.indexedDB.get("user_001");
|
|
6205
|
+
*/
|
|
6206
|
+
get: async function (key) {
|
|
6207
|
+
if (!this.db) await this.initDB();
|
|
6208
|
+
|
|
6209
|
+
return new Promise((resolve, reject) => {
|
|
6210
|
+
const tx = this.db.transaction('kvStore', 'readonly');
|
|
6211
|
+
const store = tx.objectStore('kvStore');
|
|
6212
|
+
const request = store.get(key);
|
|
6213
|
+
|
|
6214
|
+
request.onsuccess = () => {
|
|
6215
|
+
const result = request.result;
|
|
6216
|
+
resolve(result ? result.value : undefined);
|
|
6217
|
+
};
|
|
6218
|
+
|
|
6219
|
+
request.onerror = () => reject('读取失败');
|
|
6220
|
+
});
|
|
6221
|
+
},
|
|
6222
|
+
/*
|
|
6223
|
+
列出针对key进行模糊匹配的所有键值对
|
|
6224
|
+
使用方式:
|
|
6225
|
+
const users = await translate.storage.indexedDB.list("*us*r*");
|
|
6226
|
+
其中传入的key可以模糊搜索,其中的 * 标识另个或多个
|
|
6227
|
+
*/
|
|
6228
|
+
list: async function (key = '') {
|
|
6229
|
+
if (!this.db) await this.initDB();
|
|
6230
|
+
|
|
6231
|
+
return new Promise((resolve, reject) => {
|
|
6232
|
+
const tx = this.db.transaction('kvStore', 'readonly');
|
|
6233
|
+
const store = tx.objectStore('kvStore');
|
|
6234
|
+
const request = store.openCursor();
|
|
6235
|
+
const results = [];
|
|
6236
|
+
|
|
6237
|
+
// 将通配符 pattern 转换为正则表达式
|
|
6238
|
+
const regexStr = '^' + key.replace(/\*/g, '.*') + '$';
|
|
6239
|
+
const regex = new RegExp(regexStr);
|
|
6240
|
+
|
|
6241
|
+
request.onsuccess = (event) => {
|
|
6242
|
+
const cursor = event.target.result;
|
|
6243
|
+
if (cursor) {
|
|
6244
|
+
if (regex.test(cursor.key)) {
|
|
6245
|
+
results.push({ key: cursor.key, value: cursor.value.value });
|
|
6246
|
+
}
|
|
6247
|
+
cursor.continue();
|
|
6248
|
+
} else {
|
|
6249
|
+
resolve(results);
|
|
6250
|
+
}
|
|
6251
|
+
};
|
|
6252
|
+
|
|
6253
|
+
request.onerror = () => reject('游标读取失败');
|
|
6254
|
+
});
|
|
6255
|
+
}
|
|
6256
|
+
},
|
|
6257
|
+
/*js translate.storage.IndexedDB end*/
|
|
6258
|
+
|
|
5848
6259
|
set:function(key,value){
|
|
5849
6260
|
localStorage.setItem(key,value);
|
|
5850
6261
|
},
|
|
5851
6262
|
get:function(key){
|
|
5852
6263
|
return localStorage.getItem(key);
|
|
5853
6264
|
}
|
|
6265
|
+
|
|
5854
6266
|
},
|
|
5855
6267
|
//针对图片进行相关的语种图片替换
|
|
5856
6268
|
images:{
|
|
@@ -5971,6 +6383,7 @@ var translate = {
|
|
|
5971
6383
|
return str;
|
|
5972
6384
|
}
|
|
5973
6385
|
},
|
|
6386
|
+
/*js translate.reset start*/
|
|
5974
6387
|
//对翻译结果进行复原。比如当前网页是简体中文的,被翻译为了英文,执行此方法即可复原为网页本身简体中文的状态,而无需在通过刷新页面来实现
|
|
5975
6388
|
reset:function(){
|
|
5976
6389
|
var currentLanguage = translate.language.getCurrent(); //获取当前翻译至的语种
|
|
@@ -6024,7 +6437,9 @@ var translate = {
|
|
|
6024
6437
|
//重新渲染select
|
|
6025
6438
|
translate.selectLanguageTag.render();
|
|
6026
6439
|
},
|
|
6440
|
+
/*js translate.reset end*/
|
|
6027
6441
|
|
|
6442
|
+
/*js translate.selectionTranslate start*/
|
|
6028
6443
|
/*
|
|
6029
6444
|
划词翻译,鼠标在网页中选中一段文字,会自动出现对应翻译后的文本
|
|
6030
6445
|
有网友 https://gitee.com/huangguishen 提供。
|
|
@@ -6071,7 +6486,9 @@ var translate = {
|
|
|
6071
6486
|
document.addEventListener('click', (event)=>{ document.querySelector('#translateTooltip').style.display = "none"}, false);
|
|
6072
6487
|
}
|
|
6073
6488
|
},
|
|
6489
|
+
/*js translate.selectionTranslate end*/
|
|
6074
6490
|
|
|
6491
|
+
/*js translate.enterprise start*/
|
|
6075
6492
|
/*
|
|
6076
6493
|
企业级翻译服务
|
|
6077
6494
|
注意,这个企业级翻译中的不在开源免费之中,企业级翻译服务追求的是高稳定,这个是收费的!详情可参考:http://translate.zvo.cn/43262.html
|
|
@@ -6113,6 +6530,7 @@ var translate = {
|
|
|
6113
6530
|
/* 企业级翻译通道的key, v3.12.3.20250107 增加,针对打包成APP的场景 */
|
|
6114
6531
|
key:'',
|
|
6115
6532
|
},
|
|
6533
|
+
/*js translate.enterprise end*/
|
|
6116
6534
|
|
|
6117
6535
|
/*
|
|
6118
6536
|
如果使用的是 translate.service 翻译通道,那么翻译后的语种会自动以小写的方式进行显示。
|
|
@@ -6126,6 +6544,7 @@ var translate = {
|
|
|
6126
6544
|
},
|
|
6127
6545
|
*/
|
|
6128
6546
|
|
|
6547
|
+
/*js translate.init start*/
|
|
6129
6548
|
/*
|
|
6130
6549
|
初始化,如版本检测、初始数据加载等。 v2.11.11.20240124 增加
|
|
6131
6550
|
会自动在 translate.js 加载后的 200毫秒后 执行,进行初始化。同时也是节点测速
|
|
@@ -6167,12 +6586,66 @@ var translate = {
|
|
|
6167
6586
|
}catch(e){
|
|
6168
6587
|
}
|
|
6169
6588
|
},
|
|
6589
|
+
/*js translate.init end*/
|
|
6170
6590
|
|
|
6591
|
+
/*js translate.progress start*/
|
|
6171
6592
|
/*
|
|
6172
6593
|
翻译执行的进展相关
|
|
6173
6594
|
比如,浏览器本地缓存没有,需要走API接口的文本所在的元素区域,出现 记载中的动画蒙版,给用户以友好的使用提示
|
|
6174
6595
|
*/
|
|
6175
6596
|
progress:{
|
|
6597
|
+
style: `
|
|
6598
|
+
/* CSS部分 */
|
|
6599
|
+
/* 灰色水平加载动画 */
|
|
6600
|
+
.translate_api_in_progress {
|
|
6601
|
+
position: relative;
|
|
6602
|
+
overflow: hidden; /* 隐藏超出部分的动画 */
|
|
6603
|
+
}
|
|
6604
|
+
|
|
6605
|
+
/* 蒙版层 */
|
|
6606
|
+
.translate_api_in_progress::after {
|
|
6607
|
+
content: '';
|
|
6608
|
+
position: absolute;
|
|
6609
|
+
top: 0;
|
|
6610
|
+
left: 0;
|
|
6611
|
+
width: 100%;
|
|
6612
|
+
height: 100%;
|
|
6613
|
+
background: rgba(255, 255, 255, 1); /* 半透明白色遮罩 */
|
|
6614
|
+
z-index: 2;
|
|
6615
|
+
}
|
|
6616
|
+
|
|
6617
|
+
/* 水平加载条动画 */
|
|
6618
|
+
.translate_api_in_progress::before {
|
|
6619
|
+
content: '';
|
|
6620
|
+
position: absolute;
|
|
6621
|
+
top: 50%;
|
|
6622
|
+
left: 0;
|
|
6623
|
+
width: 100%;
|
|
6624
|
+
height:100%; /* 细线高度 */
|
|
6625
|
+
background: linear-gradient(
|
|
6626
|
+
90deg,
|
|
6627
|
+
transparent 0%,
|
|
6628
|
+
#e8e8e8 25%, /* 浅灰色 */
|
|
6629
|
+
#d0d0d0 50%, /* 中灰色 */
|
|
6630
|
+
#e8e8e8 75%, /* 浅灰色 */
|
|
6631
|
+
transparent 100%
|
|
6632
|
+
);
|
|
6633
|
+
background-size: 200% 100%;
|
|
6634
|
+
animation: translate_api_in_progress_horizontal-loader 3.5s linear infinite;
|
|
6635
|
+
z-index: 3;
|
|
6636
|
+
transform: translateY(-50%);
|
|
6637
|
+
}
|
|
6638
|
+
|
|
6639
|
+
@keyframes translate_api_in_progress_horizontal-loader {
|
|
6640
|
+
0% {
|
|
6641
|
+
background-position: 200% 0;
|
|
6642
|
+
}
|
|
6643
|
+
100% {
|
|
6644
|
+
background-position: -200% 0;
|
|
6645
|
+
}
|
|
6646
|
+
}
|
|
6647
|
+
`,
|
|
6648
|
+
|
|
6176
6649
|
/*
|
|
6177
6650
|
通过文本翻译API进行的
|
|
6178
6651
|
*/
|
|
@@ -6185,57 +6658,7 @@ var translate = {
|
|
|
6185
6658
|
// 创建一个 style 元素
|
|
6186
6659
|
const style = document.createElement('style');
|
|
6187
6660
|
// 设置 style 元素的文本内容为要添加的 CSS 规则
|
|
6188
|
-
style.textContent =
|
|
6189
|
-
/* CSS部分 */
|
|
6190
|
-
/* 灰色水平加载动画 */
|
|
6191
|
-
.translate_api_in_progress {
|
|
6192
|
-
position: relative;
|
|
6193
|
-
overflow: hidden; /* 隐藏超出部分的动画 */
|
|
6194
|
-
}
|
|
6195
|
-
|
|
6196
|
-
/* 蒙版层 */
|
|
6197
|
-
.translate_api_in_progress::after {
|
|
6198
|
-
content: '';
|
|
6199
|
-
position: absolute;
|
|
6200
|
-
top: 0;
|
|
6201
|
-
left: 0;
|
|
6202
|
-
width: 100%;
|
|
6203
|
-
height: 100%;
|
|
6204
|
-
background: rgba(255, 255, 255, 1); /* 半透明白色遮罩 */
|
|
6205
|
-
z-index: 2;
|
|
6206
|
-
}
|
|
6207
|
-
|
|
6208
|
-
/* 水平加载条动画 */
|
|
6209
|
-
.translate_api_in_progress::before {
|
|
6210
|
-
content: '';
|
|
6211
|
-
position: absolute;
|
|
6212
|
-
top: 50%;
|
|
6213
|
-
left: 0;
|
|
6214
|
-
width: 100%;
|
|
6215
|
-
height:100%; /* 细线高度 */
|
|
6216
|
-
background: linear-gradient(
|
|
6217
|
-
90deg,
|
|
6218
|
-
transparent 0%,
|
|
6219
|
-
#e8e8e8 25%, /* 浅灰色 */
|
|
6220
|
-
#d0d0d0 50%, /* 中灰色 */
|
|
6221
|
-
#e8e8e8 75%, /* 浅灰色 */
|
|
6222
|
-
transparent 100%
|
|
6223
|
-
);
|
|
6224
|
-
background-size: 200% 100%;
|
|
6225
|
-
animation: translate_api_in_progress_horizontal-loader 3.5s linear infinite;
|
|
6226
|
-
z-index: 3;
|
|
6227
|
-
transform: translateY(-50%);
|
|
6228
|
-
}
|
|
6229
|
-
|
|
6230
|
-
@keyframes translate_api_in_progress_horizontal-loader {
|
|
6231
|
-
0% {
|
|
6232
|
-
background-position: 200% 0;
|
|
6233
|
-
}
|
|
6234
|
-
100% {
|
|
6235
|
-
background-position: -200% 0;
|
|
6236
|
-
}
|
|
6237
|
-
}
|
|
6238
|
-
`;
|
|
6661
|
+
style.textContent = translate.progress.style;
|
|
6239
6662
|
// 将 style 元素插入到 head 元素中
|
|
6240
6663
|
document.head.appendChild(style);
|
|
6241
6664
|
|
|
@@ -6317,6 +6740,7 @@ var translate = {
|
|
|
6317
6740
|
}
|
|
6318
6741
|
}
|
|
6319
6742
|
},
|
|
6743
|
+
/*js translate.progress end*/
|
|
6320
6744
|
|
|
6321
6745
|
/*js dispose start*/
|
|
6322
6746
|
/*
|
|
@@ -6483,7 +6907,415 @@ var translate = {
|
|
|
6483
6907
|
},
|
|
6484
6908
|
/*js dispose end*/
|
|
6485
6909
|
|
|
6910
|
+
/*js translate.network start*/
|
|
6911
|
+
/*
|
|
6912
|
+
网络请求数据拦截并翻译
|
|
6913
|
+
当用户触发ajax请求时,它可以针对ajax请求中的某个参数,进行获取,并进行翻译,将翻译后的文本赋予这个参数,然后再放开请求。
|
|
6914
|
+
|
|
6915
|
+
使用场景如:
|
|
6916
|
+
搜索场景,原本是中文的页面,翻译为英文后,给美国人使用,美国人使用时,进行搜索,输入的是英文,然后点击搜索按钮,发起搜索。
|
|
6917
|
+
然后此会拦截网络请求,将请求中用户输入的搜索文本的内容提取出来,识别它输入的是中文还是英文,如果不是本地的语种中文,那就将其翻译为中文,然后再赋予此请求的这个参数中,然后再放开这次请求。
|
|
6918
|
+
这样请求真正到达服务端接口时,服务端接受到的搜索的文本内容实际就是翻译后的中文文本,而不是用户输入的英文文本。
|
|
6919
|
+
|
|
6920
|
+
何时自动进行翻译:
|
|
6921
|
+
1. 当前用户没有进行切换语言
|
|
6922
|
+
2. 切换语言了,但是输入的文本的语言是不需要进行翻译的, 输入的文本本身就是本地的语言
|
|
6923
|
+
这两种情况那就不需要拦截翻译
|
|
6924
|
+
|
|
6486
6925
|
|
|
6926
|
+
*/
|
|
6927
|
+
network: {
|
|
6928
|
+
// 原始方法保存
|
|
6929
|
+
originalOpen: XMLHttpRequest.prototype.open,
|
|
6930
|
+
originalSend: XMLHttpRequest.prototype.send,
|
|
6931
|
+
setRequestHeaderOriginal: XMLHttpRequest.prototype.setRequestHeader,
|
|
6932
|
+
|
|
6933
|
+
// 规则配置
|
|
6934
|
+
rules: [
|
|
6935
|
+
{
|
|
6936
|
+
url: /https:\/\/www\.guanleiming\.com\/a\/b\/.html/,
|
|
6937
|
+
methods: ['GET', 'POST'],
|
|
6938
|
+
params: ['a','b1']
|
|
6939
|
+
}
|
|
6940
|
+
],
|
|
6941
|
+
//根据 当前请求的url 跟 method 来判断当前请求是否符合规则,
|
|
6942
|
+
//如果符合,则返回符合的 rule 规则,也就是 translate.network.rules 中配置的某个。
|
|
6943
|
+
//如果没有找到符合的,则返回 null
|
|
6944
|
+
getRuleMatch:function(url, method){
|
|
6945
|
+
for (let i = 0; i < translate.network.rules.length; i++) {
|
|
6946
|
+
const rule = translate.network.rules[i];
|
|
6947
|
+
|
|
6948
|
+
// 检查 URL 是否匹配
|
|
6949
|
+
if(typeof(rule.url) == 'undefined' && rule.url == ''){
|
|
6950
|
+
console.log('WARINNG : translate.network.rule find url is null:');
|
|
6951
|
+
console.log(rule);
|
|
6952
|
+
continue;
|
|
6953
|
+
}
|
|
6954
|
+
//console.log(rule);
|
|
6955
|
+
const isUrlMatch = rule.url.test(url);
|
|
6956
|
+
if(!isUrlMatch){
|
|
6957
|
+
continue;
|
|
6958
|
+
}
|
|
6959
|
+
|
|
6960
|
+
// 检查方法是否匹配(忽略大小写)
|
|
6961
|
+
const isMethodMatch = rule.methods.includes(method.toUpperCase());
|
|
6962
|
+
if(!isMethodMatch){
|
|
6963
|
+
continue;
|
|
6964
|
+
}
|
|
6965
|
+
|
|
6966
|
+
return rule;
|
|
6967
|
+
}
|
|
6968
|
+
|
|
6969
|
+
return null;
|
|
6970
|
+
},
|
|
6971
|
+
use:function(){
|
|
6972
|
+
// 应用Hook
|
|
6973
|
+
XMLHttpRequest.prototype.open = function(...args) {
|
|
6974
|
+
return translate.network.hookOpen.apply(this, args);
|
|
6975
|
+
};
|
|
6976
|
+
|
|
6977
|
+
XMLHttpRequest.prototype.send = function(...args) {
|
|
6978
|
+
return translate.network.hookSend.apply(this, args);
|
|
6979
|
+
};
|
|
6980
|
+
|
|
6981
|
+
// 劫持 setRequestHeader 方法
|
|
6982
|
+
XMLHttpRequest.prototype.setRequestHeader = function(...args) {
|
|
6983
|
+
return translate.network.setRequestHeader.apply(this, args);
|
|
6984
|
+
};
|
|
6985
|
+
|
|
6986
|
+
translate.network.fetch.use();
|
|
6987
|
+
},
|
|
6988
|
+
// 私有工具方法
|
|
6989
|
+
_translateText(text) {
|
|
6990
|
+
if(translate.language.getLocal() == translate.language.getCurrent() || (typeof(text) == 'string' && text.length > 0 && translate.language.recognition(text).languageName == translate.language.getLocal())){
|
|
6991
|
+
/*
|
|
6992
|
+
1. 没有进行切换语言
|
|
6993
|
+
2. 切换语言了,但是输入的文本的语言是不需要进行翻译的, 输入的文本本身就是本地的语言
|
|
6994
|
+
|
|
6995
|
+
这两种情况那就不需要拦截翻译
|
|
6996
|
+
*/
|
|
6997
|
+
|
|
6998
|
+
return new Promise((resolve, reject) => {
|
|
6999
|
+
const obj = {
|
|
7000
|
+
from: 'auto',
|
|
7001
|
+
to: translate.language.getLocal(),
|
|
7002
|
+
text: [text]
|
|
7003
|
+
};
|
|
7004
|
+
|
|
7005
|
+
resolve(obj);
|
|
7006
|
+
});
|
|
7007
|
+
}else{
|
|
7008
|
+
//有进行切换了,那进行翻译,将其他语种翻译为当前的本地语种
|
|
7009
|
+
return new Promise((resolve, reject) => {
|
|
7010
|
+
const obj = {
|
|
7011
|
+
from: 'auto',
|
|
7012
|
+
to: translate.language.getLocal(),
|
|
7013
|
+
texts: [text]
|
|
7014
|
+
};
|
|
7015
|
+
|
|
7016
|
+
//console.log('翻译请求:', obj);
|
|
7017
|
+
translate.request.translateText(obj, function(data) {
|
|
7018
|
+
if (data.result === 1) {
|
|
7019
|
+
resolve(data);
|
|
7020
|
+
} else {
|
|
7021
|
+
reject(data);
|
|
7022
|
+
}
|
|
7023
|
+
});
|
|
7024
|
+
});
|
|
7025
|
+
}
|
|
7026
|
+
|
|
7027
|
+
},
|
|
7028
|
+
//劫持 setRequestHeader
|
|
7029
|
+
setRequestHeader: function(header, value) {
|
|
7030
|
+
if (this._requestContext) {
|
|
7031
|
+
this._requestContext.headers = this._requestContext.headers || {};
|
|
7032
|
+
this._requestContext.headers[header] = value;
|
|
7033
|
+
}
|
|
7034
|
+
|
|
7035
|
+
return translate.network.setRequestHeaderOriginal.call(this, header, value);
|
|
7036
|
+
},
|
|
7037
|
+
// 请求处理工具
|
|
7038
|
+
RequestHandler: {
|
|
7039
|
+
async handleGet(url, rule) {
|
|
7040
|
+
//console.log(url);
|
|
7041
|
+
//console.log(rule);
|
|
7042
|
+
if(typeof(rule.params) == 'undefined' && typeof(rule.params.length) == 'undefined' && rule.params.length < 1){
|
|
7043
|
+
console.log('WARINNG: rule not find params , rule : ');
|
|
7044
|
+
console.log(rule);
|
|
7045
|
+
rule.params = [];
|
|
7046
|
+
}
|
|
7047
|
+
|
|
7048
|
+
|
|
7049
|
+
try {
|
|
7050
|
+
const urlObj = new URL(url, window.location.origin);
|
|
7051
|
+
const params = urlObj.searchParams;
|
|
7052
|
+
//console.log(rule.params);
|
|
7053
|
+
|
|
7054
|
+
//for (const paramName in rule.params) {
|
|
7055
|
+
for(var p = 0; p < rule.params.length; p++){
|
|
7056
|
+
var paramName = rule.params[p];
|
|
7057
|
+
//console.log(paramName);
|
|
7058
|
+
if (params.has(paramName)) {
|
|
7059
|
+
const original = params.get(paramName);
|
|
7060
|
+
const translateResultData = await translate.network._translateText(original);
|
|
7061
|
+
|
|
7062
|
+
if(typeof(translateResultData) == 'undefined'){
|
|
7063
|
+
console.log('WARINNG: translateResultData is undefined');
|
|
7064
|
+
}else if(typeof(translateResultData.result) == 'undefined'){
|
|
7065
|
+
console.log('WARINNG: translateResultData.result is undefined');
|
|
7066
|
+
}else if(translateResultData.result != 1){
|
|
7067
|
+
console.log('WARINNG: translateResultData.result failure : '+translateResultData.info);
|
|
7068
|
+
}else{
|
|
7069
|
+
params.set(paramName, decodeURIComponent(translateResultData.text[0]));
|
|
7070
|
+
}
|
|
7071
|
+
|
|
7072
|
+
}
|
|
7073
|
+
}
|
|
7074
|
+
|
|
7075
|
+
return urlObj.toString();
|
|
7076
|
+
} catch (e) {
|
|
7077
|
+
console.warn('GET处理失败:', e);
|
|
7078
|
+
return url;
|
|
7079
|
+
}
|
|
7080
|
+
},
|
|
7081
|
+
|
|
7082
|
+
async handleForm(body, rule) {
|
|
7083
|
+
try {
|
|
7084
|
+
const params = new URLSearchParams(body);
|
|
7085
|
+
const modified = {...params};
|
|
7086
|
+
|
|
7087
|
+
for (const paramName of rule.params) {
|
|
7088
|
+
if (params.has(paramName)) {
|
|
7089
|
+
const original = params.get(paramName);
|
|
7090
|
+
const translated = await translate.network._translateText(original);
|
|
7091
|
+
modified[paramName] = translated;
|
|
7092
|
+
}
|
|
7093
|
+
}
|
|
7094
|
+
|
|
7095
|
+
return new URLSearchParams(modified).toString();
|
|
7096
|
+
} catch (e) {
|
|
7097
|
+
console.warn('表单处理失败:', e);
|
|
7098
|
+
return body;
|
|
7099
|
+
}
|
|
7100
|
+
},
|
|
7101
|
+
|
|
7102
|
+
async handleJson(body, rule) {
|
|
7103
|
+
try {
|
|
7104
|
+
const json = JSON.parse(body);
|
|
7105
|
+
const modified = {...json};
|
|
7106
|
+
|
|
7107
|
+
for (const paramName of rule.params) {
|
|
7108
|
+
if (modified.hasOwnProperty(paramName)) {
|
|
7109
|
+
const original = modified[paramName];
|
|
7110
|
+
modified[paramName] = await translate.network._translateText(original);
|
|
7111
|
+
}
|
|
7112
|
+
}
|
|
7113
|
+
|
|
7114
|
+
return JSON.stringify(modified);
|
|
7115
|
+
} catch (e) {
|
|
7116
|
+
console.warn('JSON处理失败:', e);
|
|
7117
|
+
return body;
|
|
7118
|
+
}
|
|
7119
|
+
}
|
|
7120
|
+
},
|
|
7121
|
+
|
|
7122
|
+
// 请求上下文管理
|
|
7123
|
+
_requestContext: null,
|
|
7124
|
+
|
|
7125
|
+
|
|
7126
|
+
|
|
7127
|
+
// Hook open 方法
|
|
7128
|
+
hookOpen(method, url, async, user, password) {
|
|
7129
|
+
let matchedRule = null;
|
|
7130
|
+
this._requestContext = {
|
|
7131
|
+
method: method.toUpperCase(),
|
|
7132
|
+
originalUrl: url,
|
|
7133
|
+
async: async,
|
|
7134
|
+
user: user,
|
|
7135
|
+
password: password,
|
|
7136
|
+
matchedRule: translate.network.getRuleMatch(url, method)
|
|
7137
|
+
};
|
|
7138
|
+
|
|
7139
|
+
return translate.network.originalOpen.call(this, method, url, async, user, password);
|
|
7140
|
+
},
|
|
7141
|
+
|
|
7142
|
+
// Hook send 方法
|
|
7143
|
+
hookSend(body) {
|
|
7144
|
+
const ctx = this._requestContext;
|
|
7145
|
+
if (!ctx || !ctx.matchedRule) {
|
|
7146
|
+
return translate.network.originalSend.call(this, body);
|
|
7147
|
+
}
|
|
7148
|
+
|
|
7149
|
+
const processRequest = async () => {
|
|
7150
|
+
let modifiedBody = body;
|
|
7151
|
+
const method = ctx.method;
|
|
7152
|
+
|
|
7153
|
+
try {
|
|
7154
|
+
// 处理GET请求
|
|
7155
|
+
//if (method === 'GET') {
|
|
7156
|
+
const newUrl = await translate.network.RequestHandler.handleGet(ctx.originalUrl, ctx.matchedRule);
|
|
7157
|
+
translate.network.originalOpen.call(this, method, newUrl, ctx.async, ctx.user, ctx.password);
|
|
7158
|
+
//}
|
|
7159
|
+
|
|
7160
|
+
// 恢复请求头
|
|
7161
|
+
if (ctx.headers) {
|
|
7162
|
+
for (const header in ctx.headers) {
|
|
7163
|
+
translate.network.setRequestHeaderOriginal.call(this, header, ctx.headers[header]);
|
|
7164
|
+
}
|
|
7165
|
+
}
|
|
7166
|
+
|
|
7167
|
+
// 处理POST请求
|
|
7168
|
+
if (method === 'POST') {
|
|
7169
|
+
if(typeof(body) != 'undefined' && body != null && body.length < 2000){
|
|
7170
|
+
var isJsonBody = false; //是否是json格式的数据,是否json已经处理了, true 是
|
|
7171
|
+
if(body.trim().indexOf('[') == 0 || body.trim().indexOf('{') == 0){
|
|
7172
|
+
//可能是json
|
|
7173
|
+
try{
|
|
7174
|
+
modifiedBody = await translate.network.RequestHandler.handleJson(body, ctx.matchedRule);
|
|
7175
|
+
isJsonBody = true;
|
|
7176
|
+
}catch(je){
|
|
7177
|
+
isJsonBody = false;
|
|
7178
|
+
}
|
|
7179
|
+
}
|
|
7180
|
+
if(!isJsonBody){
|
|
7181
|
+
try{
|
|
7182
|
+
modifiedBody = await translate.network.RequestHandler.handleForm(body, ctx.matchedRule);
|
|
7183
|
+
}catch(je){
|
|
7184
|
+
}
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
} catch (e) {
|
|
7189
|
+
console.warn('请求处理异常:', e);
|
|
7190
|
+
}
|
|
7191
|
+
|
|
7192
|
+
translate.network.originalSend.call(this, modifiedBody);
|
|
7193
|
+
};
|
|
7194
|
+
|
|
7195
|
+
// 异步处理
|
|
7196
|
+
if (ctx.async !== false) {
|
|
7197
|
+
processRequest.call(this);
|
|
7198
|
+
} else {
|
|
7199
|
+
console.warn('同步请求不支持翻译拦截');
|
|
7200
|
+
translate.network.originalSend.call(this, body);
|
|
7201
|
+
}
|
|
7202
|
+
},
|
|
7203
|
+
//fetch请求
|
|
7204
|
+
fetch:{
|
|
7205
|
+
originalFetch: window.fetch,
|
|
7206
|
+
|
|
7207
|
+
// 保存原始 fetch 方法
|
|
7208
|
+
use: function () {
|
|
7209
|
+
const self = this;
|
|
7210
|
+
window.fetch = function (...args) {
|
|
7211
|
+
return self.hookFetch.apply(self, args);
|
|
7212
|
+
};
|
|
7213
|
+
},
|
|
7214
|
+
|
|
7215
|
+
// 拦截 fetch 请求
|
|
7216
|
+
hookFetch: async function (input, init) {
|
|
7217
|
+
const request = new Request(input, init);
|
|
7218
|
+
const url = request.url;
|
|
7219
|
+
const method = request.method;
|
|
7220
|
+
|
|
7221
|
+
// 获取匹配规则
|
|
7222
|
+
const rule = translate.network.getRuleMatch(url, method);
|
|
7223
|
+
if (!rule) {
|
|
7224
|
+
return this.originalFetch.call(window, request);
|
|
7225
|
+
}
|
|
7226
|
+
|
|
7227
|
+
// 初始化请求上下文
|
|
7228
|
+
const ctx = {
|
|
7229
|
+
method,
|
|
7230
|
+
url,
|
|
7231
|
+
headers: {},
|
|
7232
|
+
rule,
|
|
7233
|
+
isModified: false
|
|
7234
|
+
};
|
|
7235
|
+
|
|
7236
|
+
// 保存请求头
|
|
7237
|
+
request.headers.forEach((value, key) => {
|
|
7238
|
+
ctx.headers[key] = value;
|
|
7239
|
+
});
|
|
7240
|
+
|
|
7241
|
+
this._requestContext = ctx;
|
|
7242
|
+
|
|
7243
|
+
try {
|
|
7244
|
+
const newUrl = await translate.network.RequestHandler.handleGet(url, rule);
|
|
7245
|
+
// 处理 GET 请求
|
|
7246
|
+
if (method === 'GET') {
|
|
7247
|
+
|
|
7248
|
+
const newRequest = new Request(newUrl, {
|
|
7249
|
+
method,
|
|
7250
|
+
headers: new Headers(ctx.headers),
|
|
7251
|
+
mode: request.mode,
|
|
7252
|
+
credentials: request.credentials,
|
|
7253
|
+
cache: request.cache,
|
|
7254
|
+
redirect: request.redirect,
|
|
7255
|
+
referrer: request.referrer,
|
|
7256
|
+
referrerPolicy: request.referrerPolicy
|
|
7257
|
+
});
|
|
7258
|
+
return this.originalFetch.call(window, newRequest);
|
|
7259
|
+
}
|
|
7260
|
+
|
|
7261
|
+
// 处理 POST 请求
|
|
7262
|
+
if (method === 'POST') {
|
|
7263
|
+
let body = null;
|
|
7264
|
+
if (request.body) {
|
|
7265
|
+
body = await request.clone().text();
|
|
7266
|
+
}
|
|
7267
|
+
|
|
7268
|
+
const contentType = request.headers.get('Content-Type');
|
|
7269
|
+
let modifiedBody = body;
|
|
7270
|
+
|
|
7271
|
+
if(typeof(body) != 'undefined' && body != null && body.length < 2000){
|
|
7272
|
+
var isJsonBody = false; //是否是json格式的数据,是否json已经处理了, true 是
|
|
7273
|
+
if(body.trim().indexOf('[') == 0 || body.trim().indexOf('{') == 0){
|
|
7274
|
+
//可能是json
|
|
7275
|
+
try{
|
|
7276
|
+
modifiedBody = await translate.network.RequestHandler.handleJson(body, rule);
|
|
7277
|
+
isJsonBody = true;
|
|
7278
|
+
}catch(je){
|
|
7279
|
+
isJsonBody = false;
|
|
7280
|
+
}
|
|
7281
|
+
}
|
|
7282
|
+
if(!isJsonBody){
|
|
7283
|
+
try{
|
|
7284
|
+
modifiedBody = await translate.network.RequestHandler.handleForm(body, rule);
|
|
7285
|
+
}catch(je){
|
|
7286
|
+
}
|
|
7287
|
+
}
|
|
7288
|
+
}
|
|
7289
|
+
|
|
7290
|
+
const newRequest = new Request(newUrl, {
|
|
7291
|
+
method,
|
|
7292
|
+
headers: new Headers(ctx.headers),
|
|
7293
|
+
body: modifiedBody,
|
|
7294
|
+
mode: request.mode,
|
|
7295
|
+
credentials: request.credentials,
|
|
7296
|
+
cache: request.cache,
|
|
7297
|
+
redirect: request.redirect,
|
|
7298
|
+
referrer: request.referrer,
|
|
7299
|
+
referrerPolicy: request.referrerPolicy
|
|
7300
|
+
});
|
|
7301
|
+
|
|
7302
|
+
return this.originalFetch.call(window, newRequest);
|
|
7303
|
+
}
|
|
7304
|
+
|
|
7305
|
+
// 其他方法直接返回原始请求
|
|
7306
|
+
return this.originalFetch.call(window, request);
|
|
7307
|
+
} catch (e) {
|
|
7308
|
+
console.warn('fetch 请求处理异常:', e);
|
|
7309
|
+
return this.originalFetch.call(window, request);
|
|
7310
|
+
}
|
|
7311
|
+
},
|
|
7312
|
+
// 请求上下文管理
|
|
7313
|
+
_requestContext: null
|
|
7314
|
+
|
|
7315
|
+
}
|
|
7316
|
+
}
|
|
7317
|
+
|
|
7318
|
+
/*js translate.network end*/
|
|
6487
7319
|
|
|
6488
7320
|
}
|
|
6489
7321
|
/*
|
|
@@ -6494,7 +7326,7 @@ var translate = {
|
|
|
6494
7326
|
*/
|
|
6495
7327
|
var nodeuuid = {
|
|
6496
7328
|
index:function(node){
|
|
6497
|
-
var parent = node.
|
|
7329
|
+
var parent = node.parentElement;
|
|
6498
7330
|
if(parent == null){
|
|
6499
7331
|
return '';
|
|
6500
7332
|
}
|
|
@@ -6534,29 +7366,18 @@ var nodeuuid = {
|
|
|
6534
7366
|
uuid = id + uuid;
|
|
6535
7367
|
}
|
|
6536
7368
|
//console.log(uuid)
|
|
6537
|
-
n = n.
|
|
7369
|
+
n = n.parentElement;
|
|
6538
7370
|
}
|
|
6539
7371
|
return uuid;
|
|
6540
|
-
}
|
|
6541
|
-
|
|
6542
|
-
开启远程调试能力,当你使用中遇到问题,需要向开源作者求助时,可以在你项目中主动调用这个方法,也就是 translate.enableRemoteDebug(); 即可启动远程调试能力
|
|
6543
|
-
开源项目作者就可以对你当前出错的页面进行远程调试排查问题所在。当然前提是你的页面要保持别关闭。
|
|
6544
|
-
|
|
6545
|
-
这个能力是通过开源项目 https://github.com/HuolalaTech/page-spy-web 来实现的
|
|
6546
|
-
|
|
6547
|
-
*/
|
|
6548
|
-
enableRemoteDebug:function(){
|
|
6549
|
-
|
|
6550
|
-
/*
|
|
6551
|
-
|
|
6552
|
-
待同事实现
|
|
6553
|
-
*/
|
|
7372
|
+
}
|
|
7373
|
+
}
|
|
6554
7374
|
|
|
6555
|
-
},
|
|
6556
7375
|
|
|
6557
|
-
|
|
7376
|
+
/*js copyright-notice start*/
|
|
6558
7377
|
console.log('------ translate.js ------\nTwo lines of js html automatic translation, page without change, no language configuration file, no API Key, SEO friendly! Open warehouse : https://github.com/xnx3/translate \n两行js实现html全自动翻译。 无需改动页面、无语言配置文件、无API Key、对SEO友好!完全开源,代码仓库:https://gitee.com/mail_osc/translate');
|
|
7378
|
+
/*js copyright-notice end*/
|
|
6559
7379
|
|
|
7380
|
+
/*js amd-cmd-commonjs start*/
|
|
6560
7381
|
/*兼容 AMD、CMD、CommonJS 规范 - start*/
|
|
6561
7382
|
/**
|
|
6562
7383
|
* 兼容 AMD、CMD、CommonJS 规范
|
|
@@ -6573,4 +7394,5 @@ console.log('------ translate.js ------\nTwo lines of js html automatic translat
|
|
|
6573
7394
|
})(this, function () {
|
|
6574
7395
|
return translate;
|
|
6575
7396
|
});
|
|
6576
|
-
/*兼容 AMD、CMD、CommonJS 规范 - end*/
|
|
7397
|
+
/*兼容 AMD、CMD、CommonJS 规范 - end*/
|
|
7398
|
+
/*js amd-cmd-commonjs end*/
|