i18n-jsautotranslate 3.15.6 → 3.17.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 +17 -12
- package/index.js +1715 -266
- 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.17.0.20250703',
|
|
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 选择框,可以通过这个选择切换语言。
|
|
@@ -169,20 +177,17 @@ var translate = {
|
|
|
169
177
|
}
|
|
170
178
|
|
|
171
179
|
//从服务器加载支持的语言库
|
|
172
|
-
translate.request.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}catch(e){ console.log(e);}
|
|
184
|
-
*/
|
|
185
|
-
}, null);
|
|
180
|
+
if(typeof(translate.request.api.language) == 'string' && translate.request.api.language.length > 0){
|
|
181
|
+
translate.request.post(translate.request.api.language, {}, function(data){
|
|
182
|
+
if(data.result == 0){
|
|
183
|
+
console.log('load language list error : '+data.info);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
translate.selectLanguageTag.customUI(data.list);
|
|
188
|
+
}, null);
|
|
189
|
+
}
|
|
190
|
+
|
|
186
191
|
|
|
187
192
|
|
|
188
193
|
}
|
|
@@ -193,8 +198,11 @@ var translate = {
|
|
|
193
198
|
* 已废弃,v1使用的
|
|
194
199
|
*/
|
|
195
200
|
//localLanguage:'zh-CN',
|
|
201
|
+
/*js translate.localLanguage start*/
|
|
196
202
|
localLanguage:'zh-CN',
|
|
203
|
+
/*js translate.localLanguage end*/
|
|
197
204
|
|
|
205
|
+
/*js translate.googleTranslateElementInit start*/
|
|
198
206
|
/**
|
|
199
207
|
* google翻译执行的
|
|
200
208
|
* 已废弃,v1使用的
|
|
@@ -223,6 +231,7 @@ var translate = {
|
|
|
223
231
|
selectId //触发按钮的id
|
|
224
232
|
);
|
|
225
233
|
},
|
|
234
|
+
/*js translate.googleTranslateElementInit end*/
|
|
226
235
|
|
|
227
236
|
/**
|
|
228
237
|
* 初始化,如加载js、css资源
|
|
@@ -244,6 +253,9 @@ var translate = {
|
|
|
244
253
|
|
|
245
254
|
},
|
|
246
255
|
*/
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
/*js translate.execute_v1 start*/
|
|
247
259
|
/**
|
|
248
260
|
* 执行翻译操作
|
|
249
261
|
* 已废弃,v1使用的
|
|
@@ -252,7 +264,9 @@ var translate = {
|
|
|
252
264
|
console.log('=====ERROR======');
|
|
253
265
|
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
266
|
},
|
|
255
|
-
|
|
267
|
+
/*js translate.execute_v1 end*/
|
|
268
|
+
|
|
269
|
+
/*js translate.setCookie start*/
|
|
256
270
|
/**
|
|
257
271
|
* 设置Cookie,失效时间一年。
|
|
258
272
|
* @param name
|
|
@@ -263,7 +277,9 @@ var translate = {
|
|
|
263
277
|
var cookieString=name+"="+escape(value);
|
|
264
278
|
document.cookie=cookieString;
|
|
265
279
|
},
|
|
280
|
+
/*js translate.setCookie end*/
|
|
266
281
|
|
|
282
|
+
/*js translate.getCookie start*/
|
|
267
283
|
//获取Cookie。若是不存再,返回空字符串
|
|
268
284
|
//* 已废弃,v1使用的
|
|
269
285
|
getCookie:function (name){
|
|
@@ -277,11 +293,14 @@ var translate = {
|
|
|
277
293
|
}
|
|
278
294
|
return "";
|
|
279
295
|
},
|
|
296
|
+
/*js translate.getCookie end*/
|
|
280
297
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
298
|
+
|
|
299
|
+
/*js translate.currentLanguage start*/
|
|
300
|
+
/*
|
|
301
|
+
获取当前页面采用的是什么语言
|
|
302
|
+
返回值如 en、zh-CN、zh-TW (如果是第一次用,没有设置过,那么返回的是 translate.localLanguage 设置的值)
|
|
303
|
+
已废弃,v1使用的
|
|
285
304
|
*/
|
|
286
305
|
currentLanguage:function(){
|
|
287
306
|
//translate.check();
|
|
@@ -292,6 +311,7 @@ var translate = {
|
|
|
292
311
|
return translate.localLanguage;
|
|
293
312
|
}
|
|
294
313
|
},
|
|
314
|
+
/*js translate.currentLanguage end*/
|
|
295
315
|
|
|
296
316
|
/**
|
|
297
317
|
* 切换语言,比如切换为英语、法语
|
|
@@ -364,17 +384,27 @@ var translate = {
|
|
|
364
384
|
for (let i = 0; i < iframes.length; i++) {
|
|
365
385
|
const iframe = iframes[i];
|
|
366
386
|
// 获取 iframe 的 window 对象
|
|
367
|
-
const iframeWindow = iframe.contentWindow;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
iframeWindow.translate.to
|
|
372
|
-
|
|
373
|
-
|
|
387
|
+
const iframeWindow = iframe.contentWindow;
|
|
388
|
+
try{
|
|
389
|
+
if(typeof(iframeWindow.translate) == 'object' && typeof(iframeWindow.translate.version) == 'string'){
|
|
390
|
+
//iframe页面中存在 translate,那么也控制iframe中的进行翻译
|
|
391
|
+
if(iframeWindow.translate.to != languageName){
|
|
392
|
+
iframeWindow.translate.to = languageName;
|
|
393
|
+
iframeWindow.translate.storage.set('to',languageName); //设置目标翻译语言
|
|
394
|
+
iframeWindow.translate.execute();
|
|
395
|
+
}
|
|
374
396
|
}
|
|
397
|
+
}catch(e){
|
|
398
|
+
//增加try,避免异常,比如跨域,中断导致无法用
|
|
399
|
+
console.log(e);
|
|
375
400
|
}
|
|
376
401
|
}
|
|
377
402
|
}
|
|
403
|
+
|
|
404
|
+
//当用户代码设置里启用了 translate.listener.start() 然后用户加载页面后并没有翻译(这时listener是不启动的只是把listener.use标记为true),然后手动点击翻译按钮翻译为其他语种(这是不会刷新页面),翻译后也要跟着启动监听
|
|
405
|
+
if(translate.listener.use == true && translate.listener.isStart == false){
|
|
406
|
+
translate.listener.start();
|
|
407
|
+
}
|
|
378
408
|
},
|
|
379
409
|
|
|
380
410
|
/**
|
|
@@ -382,11 +412,13 @@ var translate = {
|
|
|
382
412
|
* english
|
|
383
413
|
* 已废弃,v1使用的
|
|
384
414
|
*/
|
|
415
|
+
/*js translate.check start*/
|
|
385
416
|
check:function(){
|
|
386
417
|
if(window.location.protocol == 'file:'){
|
|
387
418
|
console.log('\r\n---WARNING----\r\ntranslate.js 主动翻译组件自检异常,当前协议是file协议,翻译组件要在正常的线上http、https协议下才能正常使用翻译功能\r\n------------');
|
|
388
419
|
}
|
|
389
420
|
},
|
|
421
|
+
/*js translate.check end*/
|
|
390
422
|
|
|
391
423
|
|
|
392
424
|
/**************************** v2.0 */
|
|
@@ -501,8 +533,24 @@ var translate = {
|
|
|
501
533
|
* 这个其实是借用了 自定义术语 的能力,设置了自定义术语的原字符等于翻译后的字符, 于是这个字符就不会被翻译了
|
|
502
534
|
* 这里可以是多个,数组,如 ['你好','世界']
|
|
503
535
|
*/
|
|
504
|
-
text:[]
|
|
505
|
-
|
|
536
|
+
text:[],
|
|
537
|
+
/*
|
|
538
|
+
下面的 textRegex 、 setTextRegexs 正则方式设置忽略不翻译text的能力,有 https://github.com/wangliangyu 提交贡献, 弥补 translate.ignore.text 固定设置的不足
|
|
539
|
+
*/
|
|
540
|
+
textRegex:[],
|
|
541
|
+
/*
|
|
542
|
+
使用方式如:
|
|
543
|
+
translate.ignore.setTextRegexs([/请求/g, /[\u4a01-\u4a05]+/g]);
|
|
544
|
+
*/
|
|
545
|
+
setTextRegexs: function(arr) {
|
|
546
|
+
if (!Array.isArray(arr)) throw new Error('参数必须为数组');
|
|
547
|
+
for (let i = 0; i < arr.length; i++) {
|
|
548
|
+
if (!(arr[i] instanceof RegExp)) {
|
|
549
|
+
throw new Error('第' + i + '项不是RegExp对象');
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
this.textRegex = [...this.textRegex, ...arr];
|
|
553
|
+
},
|
|
506
554
|
},
|
|
507
555
|
//刷新页面,你可以自定义刷新页面的方式,比如在 uniapp 打包生成 apk 时,apk中的刷新页面就不是h5的这个刷新,而是app的刷新方式,就需要自己进行重写这个刷新页面的方法了
|
|
508
556
|
refreshCurrentPage:function(){
|
|
@@ -619,6 +667,10 @@ var translate = {
|
|
|
619
667
|
}
|
|
620
668
|
//console.log(str)
|
|
621
669
|
for(var originalText in translate.nomenclature.data[translate.language.getLocal()][translate.to]){
|
|
670
|
+
if (!translate.nomenclature.data[translate.language.getLocal()][translate.to].hasOwnProperty(originalText)) {
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
|
|
622
674
|
var translateText = translate.nomenclature.data[translate.language.getLocal()][translate.to][originalText];
|
|
623
675
|
if(typeof(translateText) == 'function'){
|
|
624
676
|
//进行异常的预处理调出
|
|
@@ -718,8 +770,15 @@ var translate = {
|
|
|
718
770
|
|
|
719
771
|
var text = '';
|
|
720
772
|
for(var uuid in translate.nodeQueue){
|
|
773
|
+
if (!translate.nodeQueue.hasOwnProperty(uuid)) {
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
|
|
721
777
|
var queueValue = translate.nodeQueue[uuid];
|
|
722
778
|
for(var lang in translate.nodeQueue[uuid].list){
|
|
779
|
+
if (!translate.nodeQueue[uuid].list.hasOwnProperty(lang)) {
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
723
782
|
//console.log('------'+lang)
|
|
724
783
|
if(typeof(lang) != 'string' || lang.length < 1){
|
|
725
784
|
continue;
|
|
@@ -727,6 +786,9 @@ var translate = {
|
|
|
727
786
|
//if(translate.language.getLocal() == lang){
|
|
728
787
|
//console.log(translate.nodeQueue[uuid].list[lang]);
|
|
729
788
|
for(var hash in translate.nodeQueue[uuid].list[lang]){
|
|
789
|
+
if (!translate.nodeQueue[uuid].list[lang].hasOwnProperty(hash)) {
|
|
790
|
+
continue;
|
|
791
|
+
}
|
|
730
792
|
//console.log(translate.nodeQueue[uuid].list[lang][hash].original);
|
|
731
793
|
//console.log(translate.nodeQueue[uuid].list[lang][hash].original);
|
|
732
794
|
text = text + '\n' + translate.nodeQueue[uuid].list[lang][hash].original + '='+translate.storage.get('hash_'+translate.language.getCurrent()+'_'+hash);
|
|
@@ -823,6 +885,77 @@ var translate = {
|
|
|
823
885
|
translate.storage.set('hash_'+to+'_'+translate.util.hash(key), value);
|
|
824
886
|
}
|
|
825
887
|
},
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
//全部提取能力(整站的离线翻译数据提取)
|
|
891
|
+
fullExtract:{
|
|
892
|
+
/*js translate.office.fullExtract.set start*/
|
|
893
|
+
/*
|
|
894
|
+
将翻译的结果加入
|
|
895
|
+
hash: 翻译前的文本的hash
|
|
896
|
+
originalText: 翻以前的文本,原始文本
|
|
897
|
+
toLanguage: 翻译为什么语言
|
|
898
|
+
translateText: 翻译结果的文本
|
|
899
|
+
*/
|
|
900
|
+
set: async function(hash, originalText, toLanguage, translateText){
|
|
901
|
+
if(typeof(translate.storage.IndexedDB) == 'undefined'){
|
|
902
|
+
console.log('ERROR: translate.storage.IndexedDB not find');
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
var obj = await translate.storage.IndexedDB.get('hash_'+hash);
|
|
906
|
+
if(typeof(obj) == 'undefined' && obj == null){
|
|
907
|
+
obj = {
|
|
908
|
+
originalText:originalText
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
obj[toLanguage] = translateText;
|
|
912
|
+
await translate.storage.IndexedDB.set('hash_'+hash, obj);
|
|
913
|
+
},
|
|
914
|
+
/*js translate.office.fullExtract.set end*/
|
|
915
|
+
|
|
916
|
+
/*js translate.office.fullExtract.export start*/
|
|
917
|
+
/*
|
|
918
|
+
将存储的数据导出为 txt 文件下载下来
|
|
919
|
+
*/
|
|
920
|
+
export: async function(to){
|
|
921
|
+
if(typeof(translate.storage.IndexedDB) == 'undefined'){
|
|
922
|
+
console.log('ERROR: translate.storage.IndexedDB not find');
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
if(typeof(to) != 'string'){
|
|
926
|
+
console.log('error : to param not find, example: "english"');
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
var text = 'translate.office.append(\'';
|
|
930
|
+
|
|
931
|
+
var data = await translate.storage.IndexedDB.list('hash_*');
|
|
932
|
+
for(var i in data){
|
|
933
|
+
if (!data.hasOwnProperty(i)) {
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
var originalText = data[i].value.originalText.replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
937
|
+
text = text + '\n' + originalText + '='+data[i].value.english.replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
938
|
+
}
|
|
939
|
+
text = text + '\n`);'
|
|
940
|
+
|
|
941
|
+
const blob = new Blob([text], { type: "text/plain" });
|
|
942
|
+
const url = URL.createObjectURL(blob);
|
|
943
|
+
const link = document.createElement("a");
|
|
944
|
+
link.href = url;
|
|
945
|
+
link.download = to+".txt";
|
|
946
|
+
link.click();
|
|
947
|
+
URL.revokeObjectURL(url);
|
|
948
|
+
},
|
|
949
|
+
/*js translate.office.fullExtract.export end*/
|
|
950
|
+
|
|
951
|
+
/*
|
|
952
|
+
是否启用全部提取的能力
|
|
953
|
+
true: 启用, 默认是false不启用。
|
|
954
|
+
如果设置为true,则每次通过调用翻译接口进行翻译后,都会将翻译的原文、译文、翻译为什么语种,都会单独记录一次,存入浏览器的 IndexedDB 的 translate.js 数据库
|
|
955
|
+
然后可以浏览所有页面后,把所有翻译一对一的对应翻译结果直接全部导出,用于做离线翻译配置使用。
|
|
956
|
+
*/
|
|
957
|
+
isUse:false,
|
|
958
|
+
}
|
|
826
959
|
},
|
|
827
960
|
setAutoDiscriminateLocalLanguage:function(){
|
|
828
961
|
translate.autoDiscriminateLocalLanguage = true;
|
|
@@ -893,9 +1026,12 @@ var translate = {
|
|
|
893
1026
|
//isExecuteFinish:false,
|
|
894
1027
|
//是否已经使用了 translate.listener.start() 了,如果使用了,那这里为true,多次调用 translate.listener.start() 只有第一次有效
|
|
895
1028
|
isStart:false,
|
|
1029
|
+
//用户的代码里是否启用了 translate.listener.start() ,true:启用
|
|
1030
|
+
//当用户加载页面后,但是未启用翻译时,为了降低性能,监听是不会启动的,但是用户手动点击翻译后,也要把监听启动起来,所以就加了这个参数,来表示当前是否在代码里启用了监听,以便当触发翻译时,监听也跟着触发
|
|
1031
|
+
use:false,
|
|
896
1032
|
//translate.listener.start(); //开启html页面变化的监控,对变化部分会进行自动翻译。注意,这里变化区域,是指使用 translate.setDocuments(...) 设置的区域。如果未设置,那么为监控整个网页的变化
|
|
897
1033
|
start:function(){
|
|
898
|
-
|
|
1034
|
+
translate.listener.use = true;
|
|
899
1035
|
translate.temp_linstenerStartInterval = setInterval(function(){
|
|
900
1036
|
if(document.readyState == 'complete'){
|
|
901
1037
|
//dom加载完成,进行启动
|
|
@@ -945,8 +1081,9 @@ var translate = {
|
|
|
945
1081
|
node 是哪个节点被listener扫描到改动后忽略。
|
|
946
1082
|
可传入 node、也可以传入node的uuid字符串
|
|
947
1083
|
expireTime 过期时间,也就是执行当前方法将 node 加入后,过多长时间失效,这里是毫秒,比如传入 500 则这个node在当前时间往后的500毫秒内,如果被listener监听到改动,是直接被忽略的,不会触发任何翻译操作
|
|
1084
|
+
showResultText 实际显示出来的文本,翻译之后显示出来的文本。如果翻译过程中其他js改动了这个文本内容,导致未能翻译,则 analyse.set 的 resultText 会返回 空字符串设置到这里
|
|
948
1085
|
*/
|
|
949
|
-
addIgnore:function(node, expireTime){
|
|
1086
|
+
addIgnore:function(node, expireTime, showResultText){
|
|
950
1087
|
let nodeid = '';
|
|
951
1088
|
if(typeof(node) == 'string'){
|
|
952
1089
|
nodeid = node;
|
|
@@ -954,7 +1091,10 @@ var translate = {
|
|
|
954
1091
|
nodeid = nodeuuid.uuid(node);
|
|
955
1092
|
}
|
|
956
1093
|
|
|
957
|
-
translate.listener.ignoreNode[nodeid] =
|
|
1094
|
+
translate.listener.ignoreNode[nodeid] = {
|
|
1095
|
+
addtime:Date.now()+expireTime,
|
|
1096
|
+
text:showResultText
|
|
1097
|
+
};
|
|
958
1098
|
|
|
959
1099
|
//translate.listener.renderTaskFinish();
|
|
960
1100
|
},
|
|
@@ -965,7 +1105,7 @@ var translate = {
|
|
|
965
1105
|
//console.log('refresh ignore ,current: '+Object.keys(translate.listener.ignoreNode).length);
|
|
966
1106
|
var currentTime = Date.now();
|
|
967
1107
|
for (const node in translate.listener.ignoreNode) {
|
|
968
|
-
if(translate.listener.ignoreNode[node] < currentTime){
|
|
1108
|
+
if(translate.listener.ignoreNode[node].addtime < currentTime){
|
|
969
1109
|
//console.log('delete : ');
|
|
970
1110
|
//console.log(node);
|
|
971
1111
|
delete translate.listener.ignoreNode[node];
|
|
@@ -977,6 +1117,10 @@ var translate = {
|
|
|
977
1117
|
|
|
978
1118
|
//增加监听,开始监听。这个不要直接调用,需要使用上面的 start() 开启
|
|
979
1119
|
addListener:function(){
|
|
1120
|
+
if(translate.listener.isStart == true){
|
|
1121
|
+
console.log('translate.listener.start() 已经启动了,无需再重复启动监听,增加浏览器负担');
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
980
1124
|
translate.listener.isStart = true; //记录已执行过启动方法了
|
|
981
1125
|
|
|
982
1126
|
// 观察器的配置(需要观察什么变动)
|
|
@@ -1052,8 +1196,8 @@ var translate = {
|
|
|
1052
1196
|
|
|
1053
1197
|
//console.log(node);
|
|
1054
1198
|
let nodeid = nodeuuid.uuid(node);
|
|
1055
|
-
if(typeof(translate.listener.ignoreNode[nodeid])
|
|
1056
|
-
if(translate.listener.ignoreNode[nodeid] > Date.now()){
|
|
1199
|
+
if(typeof(translate.listener.ignoreNode[nodeid]) != 'undefined'){
|
|
1200
|
+
if(translate.listener.ignoreNode[nodeid].addtime > Date.now() && typeof(node.nodeValue) == 'string' && node.nodeValue == translate.listener.ignoreNode[nodeid].text){
|
|
1057
1201
|
//console.log('node 未过忽略期,listener扫描后忽略:'+nodeid);
|
|
1058
1202
|
continue;
|
|
1059
1203
|
}
|
|
@@ -1132,7 +1276,7 @@ var translate = {
|
|
|
1132
1276
|
//console.log(translate.nodeQueue[uuid]);
|
|
1133
1277
|
for(var i = 0; i < translate.listener.execute.renderFinishByApi.length; i++){
|
|
1134
1278
|
try{
|
|
1135
|
-
|
|
1279
|
+
translate.listener.execute.renderFinishByApi[i](uuid, from, to);
|
|
1136
1280
|
}catch(e){
|
|
1137
1281
|
console.log(e);
|
|
1138
1282
|
}
|
|
@@ -1222,6 +1366,10 @@ var translate = {
|
|
|
1222
1366
|
execute(){
|
|
1223
1367
|
//先对tasks任务队列的替换词进行排序,将同一个node的替换词有大到小排列,避免先替换了小的,大的替换时找不到
|
|
1224
1368
|
for(var hash in this.taskQueue){
|
|
1369
|
+
if (!this.taskQueue.hasOwnProperty(hash)) {
|
|
1370
|
+
continue;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1225
1373
|
var tasks = this.taskQueue[hash];
|
|
1226
1374
|
if(typeof(tasks) == 'function'){
|
|
1227
1375
|
//进行异常的预处理调出
|
|
@@ -1244,6 +1392,10 @@ var translate = {
|
|
|
1244
1392
|
|
|
1245
1393
|
//对nodeQueue进行翻译
|
|
1246
1394
|
for(var hash in this.nodes){
|
|
1395
|
+
if (!this.nodes.hasOwnProperty(hash)) {
|
|
1396
|
+
continue;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1247
1399
|
var tasks = this.taskQueue[hash]; //取出当前node元素对应的替换任务
|
|
1248
1400
|
//var tagName = this.nodes[hash][0].nodeName; //以下节点的tag name
|
|
1249
1401
|
//console.log(tasks);
|
|
@@ -1279,12 +1431,10 @@ var translate = {
|
|
|
1279
1431
|
|
|
1280
1432
|
}, 50, ipnode);
|
|
1281
1433
|
|
|
1434
|
+
//渲染页面进行翻译显示
|
|
1435
|
+
var analyseSet = translate.element.nodeAnalyse.set(this.nodes[hash][task_index], task.originalText, task.resultText, task['attribute']);
|
|
1282
1436
|
//加入 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
|
-
|
|
1437
|
+
translate.listener.addIgnore(this.nodes[hash][task_index], translate.listener.translateExecuteNodeIgnoreExpireTime, analyseSet.resultText);
|
|
1288
1438
|
|
|
1289
1439
|
|
|
1290
1440
|
/*
|
|
@@ -1326,12 +1476,20 @@ var translate = {
|
|
|
1326
1476
|
/** 执行完成后,保存翻译的历史node **/
|
|
1327
1477
|
//将当前翻译完成的node进行缓存记录,以node唯一标识为key, node、以及node当前翻译之后的内容为值进行缓存。方便下一次执行 translate.execute() 时,若值未变化则不进行翻译
|
|
1328
1478
|
for(var hash in renderTask.nodes){
|
|
1479
|
+
if (!renderTask.nodes.hasOwnProperty(hash)) {
|
|
1480
|
+
continue;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1329
1483
|
//console.log(translate.nodeQueue[uuid].list[lang][hash])
|
|
1330
1484
|
for(var nodeindex in renderTask.nodes[hash]){
|
|
1485
|
+
if (!renderTask.nodes[hash].hasOwnProperty(nodeindex)) {
|
|
1486
|
+
continue;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1331
1489
|
//console.log(translate.nodeQueue[uuid].list[lang][hash].original);
|
|
1332
1490
|
//var nodename = translate.element.getNodeName(translate.nodeQueue[uuid].list[lang][hash].nodes[0].node);
|
|
1333
1491
|
//console.log("nodename:"+nodename);
|
|
1334
|
-
var analyse = translate.element.nodeAnalyse.get(renderTask.nodes[hash][
|
|
1492
|
+
var analyse = translate.element.nodeAnalyse.get(renderTask.nodes[hash][nodeindex]);
|
|
1335
1493
|
//analyse.text analyse.node
|
|
1336
1494
|
var nodeid = nodeuuid.uuid(analyse.node);
|
|
1337
1495
|
|
|
@@ -1357,7 +1515,15 @@ var translate = {
|
|
|
1357
1515
|
//console.log(analyse.node);
|
|
1358
1516
|
translate.nodeHistory[nodeid] = {};
|
|
1359
1517
|
translate.nodeHistory[nodeid].node = analyse.node;
|
|
1360
|
-
translate.
|
|
1518
|
+
if(translate.whole.isWhole(analyse.node)){
|
|
1519
|
+
//这个元素使用的是整体翻译的方式,那就直接将API接口返回的翻译内容作为node最终显示的结果。
|
|
1520
|
+
//这样即使在翻译过程中其他js对这个元素的内容有改动了,那下次再触发翻译,还能对改动后的文本正常翻译,不至于使这个元素已被标记翻译过了,造成漏翻译。
|
|
1521
|
+
translate.nodeHistory[nodeid].translateText = renderTask.taskQueue[hash][nodeindex].resultText;
|
|
1522
|
+
}else{
|
|
1523
|
+
//时间差会造成漏翻译情况,见if中的注释
|
|
1524
|
+
translate.nodeHistory[nodeid].translateText = analyse.text;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1361
1527
|
}
|
|
1362
1528
|
|
|
1363
1529
|
}
|
|
@@ -1392,6 +1558,7 @@ var translate = {
|
|
|
1392
1558
|
|
|
1393
1559
|
*/
|
|
1394
1560
|
waitingExecute:{
|
|
1561
|
+
use:true, //默认是使用,自有部署场景不担心并发的场景,可以禁用,以提高用户使用体验。
|
|
1395
1562
|
|
|
1396
1563
|
/*
|
|
1397
1564
|
一维数组形态,存放执行的翻译任务
|
|
@@ -1445,8 +1612,13 @@ var translate = {
|
|
|
1445
1612
|
@param to 翻译为的语种
|
|
1446
1613
|
*/
|
|
1447
1614
|
isAllExecuteFinish:function(uuid, from, to){
|
|
1615
|
+
translate.listener.execute.renderFinishByApiRun(uuid, from, to);
|
|
1616
|
+
|
|
1448
1617
|
//console.log('uuid:'+uuid+', from:'+from+', to:'+to);
|
|
1449
1618
|
for(var lang in translate.translateRequest[uuid]){
|
|
1619
|
+
if (!translate.translateRequest[uuid].hasOwnProperty(lang)) {
|
|
1620
|
+
continue;
|
|
1621
|
+
}
|
|
1450
1622
|
//console.log(translate.translateRequest[uuid])
|
|
1451
1623
|
for(var i = 0; i<translate.translateRequest[uuid][lang].length; i++){
|
|
1452
1624
|
if(translate.translateRequest[uuid][lang][i].executeFinish == 0){
|
|
@@ -1460,11 +1632,12 @@ var translate = {
|
|
|
1460
1632
|
}
|
|
1461
1633
|
}
|
|
1462
1634
|
|
|
1635
|
+
//生命周期触发事件
|
|
1636
|
+
translate.lifecycle.execute.renderFinish_Trigger(uuid, to);
|
|
1637
|
+
|
|
1463
1638
|
//都执行完了,那么设置完毕
|
|
1464
1639
|
translate.state = 0;
|
|
1465
1640
|
translate.executeNumber++;
|
|
1466
|
-
|
|
1467
|
-
translate.listener.execute.renderFinishByApiRun(uuid, from, to);
|
|
1468
1641
|
}
|
|
1469
1642
|
|
|
1470
1643
|
},
|
|
@@ -1472,6 +1645,75 @@ var translate = {
|
|
|
1472
1645
|
//execute() 方法已经被执行过多少次了, 只有execute() 完全执行完,也就是界面渲染完毕后,它才会+1
|
|
1473
1646
|
executeNumber:0,
|
|
1474
1647
|
|
|
1648
|
+
lifecycle:{
|
|
1649
|
+
execute:{
|
|
1650
|
+
/*
|
|
1651
|
+
每当触发执行 translate.execute() 时,当缓存中未发现,需要请求翻译API进行翻译时,在发送API请求前,触发此
|
|
1652
|
+
|
|
1653
|
+
@param uuid:translate.nodeQueue[uuid] 这里的
|
|
1654
|
+
@param from 来源语种,翻译前的语种
|
|
1655
|
+
@param to 翻译为的语种
|
|
1656
|
+
*/
|
|
1657
|
+
start : [],
|
|
1658
|
+
startRun:function(uuid, from, to){
|
|
1659
|
+
//console.log(translate.nodeQueue[uuid]);
|
|
1660
|
+
for(var i = 0; i < translate.listener.execute.renderStartByApi.length; i++){
|
|
1661
|
+
try{
|
|
1662
|
+
translate.listener.execute.renderStartByApi[i](uuid, from, to);
|
|
1663
|
+
}catch(e){
|
|
1664
|
+
console.log(e);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
},
|
|
1668
|
+
|
|
1669
|
+
/*
|
|
1670
|
+
当扫描整个节点完成,进行翻译(1. 命中本地缓存、 2.进行网络翻译请求)之前,触发
|
|
1671
|
+
*/
|
|
1672
|
+
scanNodesFinsh: [],
|
|
1673
|
+
|
|
1674
|
+
/*
|
|
1675
|
+
当进行触发网络翻译请求之前,触发此
|
|
1676
|
+
*/
|
|
1677
|
+
translateNetworkBefore:[],
|
|
1678
|
+
|
|
1679
|
+
/*
|
|
1680
|
+
当 translate.execute() 触发网络翻译请求完毕(不管成功还是失败),并将翻译结果渲染到页面完毕后,触发此。
|
|
1681
|
+
@param uuid translate.nodeQueue 的uuid
|
|
1682
|
+
@param to 当前是执行的翻译为什么语种
|
|
1683
|
+
*/
|
|
1684
|
+
translateNetworkFinish:[],
|
|
1685
|
+
translateNetworkAfter_Trigger:function(uuid, to){
|
|
1686
|
+
for(var i = 0; i < translate.lifecycle.execute.translateNetworkAfter.length; i++){
|
|
1687
|
+
try{
|
|
1688
|
+
translate.lifecycle.execute.translateNetworkAfter[i](uuid, to);
|
|
1689
|
+
}catch(e){
|
|
1690
|
+
console.log(e);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
},
|
|
1694
|
+
|
|
1695
|
+
/*
|
|
1696
|
+
translate.execute() 的翻译渲染完毕触发
|
|
1697
|
+
这个完毕是指它当触发 translate.execute() 进行翻译后,无论是全部命中了本地缓存,还是有部分要通过翻译接口发起多个网络请求,当拿到结果(缓存中的翻译结果或多个不同的有xx语种翻译的网络请求全部完成,这个完成是包含所有成功跟失败的响应),并完成将翻译结果渲染到页面中进行显示后,触发此
|
|
1698
|
+
它跟 translateNetworkFinish 的区别是, translateNetworkFinish 仅仅针对有网络请求的才会触发,而 renderFinish 是如果全部命中了浏览器本地缓存,无需发起任何网络翻译请求这种情况时,也会触发。
|
|
1699
|
+
@param uuid translate.nodeQueue 的uuid
|
|
1700
|
+
@param to 当前是执行的翻译为什么语种
|
|
1701
|
+
*/
|
|
1702
|
+
renderFinish:[function(uuid, to){ //这里默认带着一个触发翻译为英文后,自动对英文进行元素视觉处理,追加空格的
|
|
1703
|
+
translate.visual.adjustTranslationSpacesByNodequeueUuid(uuid);
|
|
1704
|
+
}],
|
|
1705
|
+
renderFinish_Trigger:function(uuid, to){
|
|
1706
|
+
for(var i = 0; i < translate.lifecycle.execute.renderFinish.length; i++){
|
|
1707
|
+
try{
|
|
1708
|
+
translate.lifecycle.execute.renderFinish[i](uuid, to);
|
|
1709
|
+
}catch(e){
|
|
1710
|
+
console.log(e);
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
},
|
|
1716
|
+
|
|
1475
1717
|
/*translate.execute() start */
|
|
1476
1718
|
/*
|
|
1477
1719
|
执行翻译操作。翻译的是 nodeQueue 中的
|
|
@@ -1479,11 +1721,14 @@ var translate = {
|
|
|
1479
1721
|
如果不传入或者传入null,则是翻译整个网页所有能翻译的元素
|
|
1480
1722
|
*/
|
|
1481
1723
|
execute:function(docs){
|
|
1482
|
-
if(translate.
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1724
|
+
if(translate.waitingExecute.use){
|
|
1725
|
+
if(translate.state != 0){
|
|
1726
|
+
console.log('当前翻译还未完结,新的翻译任务已加入等待翻译队列中,待翻译结束后便会执行当前翻译任务。');
|
|
1727
|
+
translate.waitingExecute.add(docs);
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1486
1730
|
}
|
|
1731
|
+
|
|
1487
1732
|
translate.state = 1;
|
|
1488
1733
|
//console.log('translate.state = 1');
|
|
1489
1734
|
if(typeof(docs) != 'undefined'){
|
|
@@ -1618,6 +1863,9 @@ var translate = {
|
|
|
1618
1863
|
if(translate.language.translateLanguagesRange.length > 0){
|
|
1619
1864
|
//如果大于0,则是有设置,那么只翻译有设置的语种,不在设置中的语种不会参与翻译
|
|
1620
1865
|
for(var lang in translate.nodeQueue[uuid].list){
|
|
1866
|
+
if (!translate.nodeQueue[uuid].list.hasOwnProperty(lang)) {
|
|
1867
|
+
continue;
|
|
1868
|
+
}
|
|
1621
1869
|
if(translate.language.translateLanguagesRange.indexOf(lang) < 0){
|
|
1622
1870
|
//删除这个语种
|
|
1623
1871
|
delete translate.nodeQueue[uuid].list[lang];
|
|
@@ -1635,13 +1883,23 @@ var translate = {
|
|
|
1635
1883
|
console.log('您使用translate.js时可能放的位置不对,不要吧 translate.js 放在网页最顶部,这样当 translate.js 进行执行,也就是 translate.execute() 执行时,因为网页是从上往下加载,它放在网页最顶部,那么它执行时网页后面的内容都还没加载出来,这个是不会获取到网页任何内容的,也就是它是不起任何作用的');
|
|
1636
1884
|
}
|
|
1637
1885
|
for(var lang in translate.nodeQueue[uuid].list){
|
|
1886
|
+
if (!translate.nodeQueue[uuid].list.hasOwnProperty(lang)) {
|
|
1887
|
+
continue;
|
|
1888
|
+
}
|
|
1638
1889
|
//console.log('lang:'+lang)
|
|
1639
1890
|
for(var hash in translate.nodeQueue[uuid].list[lang]){
|
|
1891
|
+
if (!translate.nodeQueue[uuid].list[lang].hasOwnProperty(hash)) {
|
|
1892
|
+
continue;
|
|
1893
|
+
}
|
|
1640
1894
|
//console.log(hash)
|
|
1641
1895
|
if(typeof(translate.nodeQueue[uuid].list[lang][hash]) == 'function'){
|
|
1642
1896
|
//v2.10增加,避免hash冒出个 Contains 出来导致for中的.length 出错
|
|
1643
1897
|
continue;
|
|
1644
1898
|
}
|
|
1899
|
+
if(typeof(translate.nodeQueue[uuid].list[lang][hash].nodes) == 'undefined' || typeof(translate.nodeQueue[uuid].list[lang][hash].nodes.length) == 'undefined'){
|
|
1900
|
+
//v3.16.2 增加,针对深圳北理莫斯科学校龙老师提出的这里 .length 遇到了 undefined 的情况
|
|
1901
|
+
continue;
|
|
1902
|
+
}
|
|
1645
1903
|
for(var nodeindex = translate.nodeQueue[uuid].list[lang][hash].nodes.length-1; nodeindex > -1; nodeindex--){
|
|
1646
1904
|
//console.log(translate.nodeQueue[uuid].list[lang][hash].nodes);
|
|
1647
1905
|
var analyse = translate.element.nodeAnalyse.get(translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node);
|
|
@@ -1708,6 +1966,9 @@ var translate = {
|
|
|
1708
1966
|
var twoScanNodes = {};
|
|
1709
1967
|
var cacheScanNodes = []; //同上面的 twoScanNodes,只不过 twoScanNodes 是按照lang存的,而这个不再有lang区分
|
|
1710
1968
|
for(var lang in translate.nodeQueue[uuid]['list']){ //二维数组中,取语言
|
|
1969
|
+
if (!translate.nodeQueue[uuid]['list'].hasOwnProperty(lang)) {
|
|
1970
|
+
continue;
|
|
1971
|
+
}
|
|
1711
1972
|
//console.log('lang:'+lang); //lang为english这种语言标识
|
|
1712
1973
|
if(lang == null || typeof(lang) == 'undefined' || lang.length == 0 || lang == 'undefined'){
|
|
1713
1974
|
//console.log('lang is null : '+lang);
|
|
@@ -1723,6 +1984,9 @@ var translate = {
|
|
|
1723
1984
|
twoScanNodes[lang] = [];
|
|
1724
1985
|
//二维数组,取hash、value
|
|
1725
1986
|
for(var hash in translate.nodeQueue[uuid]['list'][lang]){
|
|
1987
|
+
if (!translate.nodeQueue[uuid]['list'][lang].hasOwnProperty(hash)) {
|
|
1988
|
+
continue;
|
|
1989
|
+
}
|
|
1726
1990
|
if(typeof(translate.nodeQueue[uuid]['list'][lang][hash]) == 'function'){
|
|
1727
1991
|
//跳出,增加容错。 正常情况下应该不会这样
|
|
1728
1992
|
continue;
|
|
@@ -1872,6 +2136,10 @@ var translate = {
|
|
|
1872
2136
|
|
|
1873
2137
|
/******* 进行第二次扫描、追加入翻译队列。目的是防止缓存打散扫描的待翻译文本 ********/
|
|
1874
2138
|
for(var lang in twoScanNodes){
|
|
2139
|
+
if (!twoScanNodes.hasOwnProperty(lang)) {
|
|
2140
|
+
continue;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
1875
2143
|
//记录第一次扫描的数据,以便跟第二次扫描后的进行对比
|
|
1876
2144
|
var firstScan = Object.keys(translate.nodeQueue[uuid]['list'][lang]);
|
|
1877
2145
|
var firstScan_lang_langth = firstScan.length; //第一次扫描后的数组长度
|
|
@@ -1953,6 +2221,10 @@ var translate = {
|
|
|
1953
2221
|
var fanyiLangs = [];
|
|
1954
2222
|
//console.log(translateTextArray)
|
|
1955
2223
|
for(var lang in translate.nodeQueue[uuid]['list']){ //二维数组中取语言
|
|
2224
|
+
if (!translate.nodeQueue[uuid]['list'].hasOwnProperty(lang)) {
|
|
2225
|
+
continue;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
1956
2228
|
if(typeof(translateTextArray[lang]) == 'undefined'){
|
|
1957
2229
|
continue;
|
|
1958
2230
|
}
|
|
@@ -1988,6 +2260,10 @@ var translate = {
|
|
|
1988
2260
|
//console.log(translate.nodeQueue[uuid]['list'])
|
|
1989
2261
|
if(fanyiLangs.length == 0){
|
|
1990
2262
|
//没有需要翻译的,直接退出
|
|
2263
|
+
|
|
2264
|
+
//生命周期触发事件
|
|
2265
|
+
translate.lifecycle.execute.renderFinish_Trigger(uuid, translate.to);
|
|
2266
|
+
|
|
1991
2267
|
translate.state = 0;
|
|
1992
2268
|
translate.executeNumber++;
|
|
1993
2269
|
return;
|
|
@@ -1995,6 +2271,9 @@ var translate = {
|
|
|
1995
2271
|
|
|
1996
2272
|
//加入 translate.inProgressNodes -- start
|
|
1997
2273
|
for(var lang in translateHashArray){
|
|
2274
|
+
if (!translateHashArray.hasOwnProperty(lang)) {
|
|
2275
|
+
continue;
|
|
2276
|
+
}
|
|
1998
2277
|
if(typeof(translateHashArray[lang]) == 'undefined'){
|
|
1999
2278
|
continue;
|
|
2000
2279
|
}
|
|
@@ -2008,6 +2287,11 @@ var translate = {
|
|
|
2008
2287
|
//console.log('translate.nodeQueue[\''+uuid+'\'][\'list\'][\'chinese_simplified\'][\''+thhash+'\']');
|
|
2009
2288
|
//console.log(lang);
|
|
2010
2289
|
//console.log(translate.nodeQueue[uuid]['list'][lang][thhash].nodes);
|
|
2290
|
+
if(typeof(translate.nodeQueue[uuid]['list'][lang][thhash].nodes) == 'undefined' || typeof(translate.nodeQueue[uuid]['list'][lang][thhash].nodes.length) == 'undefined'){
|
|
2291
|
+
console.log('translate.nodeQueue[\''+uuid+'\'][\'list\'][\''+lang+'\'][\''+thhash+'\'].nodes.length is null ,理论上不应该存在,进行异常报出,但不影响使用,已容错。');
|
|
2292
|
+
continue;
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2011
2295
|
for(var ipni = 0; ipni < translate.nodeQueue[uuid]['list'][lang][thhash].nodes.length; ipni++){
|
|
2012
2296
|
//取得这个翻译的node
|
|
2013
2297
|
var ipnode = translate.nodeQueue[uuid]['list'][lang][thhash].nodes[ipni].node;
|
|
@@ -2039,14 +2323,21 @@ var translate = {
|
|
|
2039
2323
|
//状态
|
|
2040
2324
|
translate.state = 20;
|
|
2041
2325
|
|
|
2042
|
-
|
|
2043
2326
|
//进行掉接口翻译
|
|
2044
2327
|
for(var lang_index in fanyiLangs){ //一维数组,取语言
|
|
2328
|
+
if (!fanyiLangs.hasOwnProperty(lang_index)) {
|
|
2329
|
+
continue;
|
|
2330
|
+
}
|
|
2045
2331
|
var lang = fanyiLangs[lang_index];
|
|
2046
|
-
|
|
2332
|
+
if(typeof(lang) != 'string'){
|
|
2333
|
+
continue;
|
|
2334
|
+
}
|
|
2047
2335
|
|
|
2048
2336
|
if(typeof(translateTextArray[lang]) == 'undefined' || translateTextArray[lang].length < 1){
|
|
2049
|
-
console.log('
|
|
2337
|
+
console.log('异常,理论上不应该存在, lang:'+lang+', translateTextArray:');
|
|
2338
|
+
console.log(translateTextArray);
|
|
2339
|
+
console.log('你无需担心,这个只是个提示,它并不影响你翻译的正常进行,只是个异常提示而已,它会自动容错处理的,不会影响翻译的使用。');
|
|
2340
|
+
|
|
2050
2341
|
translate.state = 0;
|
|
2051
2342
|
translate.executeNumber++;
|
|
2052
2343
|
return;
|
|
@@ -2174,6 +2465,10 @@ var translate = {
|
|
|
2174
2465
|
|
|
2175
2466
|
//将翻译结果以 key:hash value翻译结果的形式缓存
|
|
2176
2467
|
translate.storage.set('hash_'+data.to+'_'+cacheHash,text);
|
|
2468
|
+
//如果离线翻译启用了全部提取,那么还要存入离线翻译指定存储
|
|
2469
|
+
if(translate.office.fullExtract.isUse){
|
|
2470
|
+
translate.office.fullExtract.set(hash, originalWord, data.to, text);
|
|
2471
|
+
}
|
|
2177
2472
|
}
|
|
2178
2473
|
task.execute(); //执行渲染任务
|
|
2179
2474
|
//translate.temp_executeFinishNumber++; //记录执行完的次数
|
|
@@ -2185,10 +2480,10 @@ var translate = {
|
|
|
2185
2480
|
translate.waitingExecute.isAllExecuteFinish(uuid, data.from, data.to);
|
|
2186
2481
|
},10);
|
|
2187
2482
|
}, function(xhr){
|
|
2188
|
-
translate.translateRequest[uuid][
|
|
2189
|
-
translate.translateRequest[uuid][
|
|
2190
|
-
translate.translateRequest[uuid][
|
|
2191
|
-
translate.waitingExecute.isAllExecuteFinish(uuid,
|
|
2483
|
+
translate.translateRequest[uuid][xhr.data.from].executeFinish = 1; //1是执行完毕
|
|
2484
|
+
translate.translateRequest[uuid][xhr.data.from].stoptime = Math.floor(Date.now() / 1000);
|
|
2485
|
+
translate.translateRequest[uuid][xhr.data.from].result = 3;
|
|
2486
|
+
translate.waitingExecute.isAllExecuteFinish(uuid, xhr.data.from, translate.to);
|
|
2192
2487
|
});
|
|
2193
2488
|
/*** 翻译end ***/
|
|
2194
2489
|
}
|
|
@@ -2268,9 +2563,12 @@ var translate = {
|
|
|
2268
2563
|
originalText 翻译之前的内容文本
|
|
2269
2564
|
resultText 翻译之后的内容文本
|
|
2270
2565
|
attribute 存放要替换的属性,比如 a标签的title属性。 如果是直接替换node.nodeValue ,那这个没有
|
|
2566
|
+
返回结果是一个数组,其中:
|
|
2567
|
+
resultText: 翻译完成之后的text内容文本,注意,如果返回的是空字符串,那么则是翻译结果进行替换时,并没有成功替换,应该是翻译的过程中,这个node的值被其他js又赋予其他内容了。
|
|
2568
|
+
node: 进行翻译的目标node
|
|
2271
2569
|
*/
|
|
2272
2570
|
set:function(node, originalText, resultText, attribute){
|
|
2273
|
-
translate.element.nodeAnalyse.analyse(node,originalText,resultText, attribute);
|
|
2571
|
+
return translate.element.nodeAnalyse.analyse(node,originalText,resultText, attribute);
|
|
2274
2572
|
},
|
|
2275
2573
|
/*
|
|
2276
2574
|
|
|
@@ -2285,6 +2583,11 @@ var translate = {
|
|
|
2285
2583
|
则是进行翻译之后的渲染显示
|
|
2286
2584
|
|
|
2287
2585
|
attribute : 进行替换渲染时使用,存放要替换的属性,比如 a标签的title属性。 如果是直接替换node.nodeValue ,那这个没有
|
|
2586
|
+
|
|
2587
|
+
返回结果是一个数组,其中:
|
|
2588
|
+
resultText: 翻译完成之后的text内容文本。 当使用 translate.element.nodeAnalyse.set 时才会有这个参数返回。 注意,如果返回的是空字符串,那么则是翻译结果进行替换时,并没有成功替换,应该是翻译的过程中,这个node的值被其他js又赋予其他内容了。
|
|
2589
|
+
text : 要进行翻译的text内容文本,当使用 translate.element.nodeAnalyse.get 时才会有这个参数的返回
|
|
2590
|
+
node: 进行翻译的目标node
|
|
2288
2591
|
*/
|
|
2289
2592
|
analyse:function(node, originalText, resultText, attribute){
|
|
2290
2593
|
var result = new Array(); //返回的结果
|
|
@@ -2301,16 +2604,26 @@ var translate = {
|
|
|
2301
2604
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2302
2605
|
if(typeof(node[attribute]) != 'undefined'){
|
|
2303
2606
|
//这种是主流框架,像是vue、element、react 都是用这种 DOM Property 的方式,更快
|
|
2304
|
-
|
|
2305
|
-
|
|
2607
|
+
var resultShowText = translate.util.textReplace(node[attribute], originalText, resultText, translate.to);
|
|
2608
|
+
node[attribute] = resultShowText; //2025.4.26 变更为此方式
|
|
2609
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2610
|
+
result['resultText'] = resultShowText;
|
|
2611
|
+
}else{
|
|
2612
|
+
result['resultText'] = '';
|
|
2613
|
+
}
|
|
2306
2614
|
}
|
|
2307
2615
|
|
|
2308
2616
|
//这种 Html Attribute 方式 是 v3.12 版本之前一直使用的方式,速度上要慢于 上面的,为了向前兼容不至于升级出问题,后面可能会优化掉
|
|
2309
2617
|
var htmlAttributeValue = node.getAttribute(attribute);
|
|
2310
2618
|
if(htmlAttributeValue != null && typeof(htmlAttributeValue) != 'undefined'){
|
|
2619
|
+
var resultShowText = translate.util.textReplace(htmlAttributeValue, originalText, resultText, translate.to);
|
|
2311
2620
|
//这个才是在v3.9.2 后要用的,上面的留着只是为了适配以前的
|
|
2312
|
-
node.setAttribute(attribute,
|
|
2313
|
-
|
|
2621
|
+
node.setAttribute(attribute, resultShowText);
|
|
2622
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2623
|
+
result['resultText'] = resultShowText;
|
|
2624
|
+
}else{
|
|
2625
|
+
result['resultText'] = '';
|
|
2626
|
+
}
|
|
2314
2627
|
}
|
|
2315
2628
|
}
|
|
2316
2629
|
return result;
|
|
@@ -2357,9 +2670,13 @@ var translate = {
|
|
|
2357
2670
|
if(input_value_node != null && typeof(input_value_node) != 'undefined' && typeof(input_value_node.nodeValue) != 'undefined' && input_value_node.nodeValue.length > 0){
|
|
2358
2671
|
//替换渲染
|
|
2359
2672
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2360
|
-
|
|
2361
|
-
input_value_node.nodeValue =
|
|
2362
|
-
|
|
2673
|
+
var resultShowText = translate.util.textReplace(input_value_node.nodeValue, originalText, resultText, translate.to);
|
|
2674
|
+
input_value_node.nodeValue = resultShowText; //2025.4.26 变更为此方式
|
|
2675
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2676
|
+
result['resultText'] = resultShowText;
|
|
2677
|
+
}else{
|
|
2678
|
+
result['resultText'] = '';
|
|
2679
|
+
}
|
|
2363
2680
|
}
|
|
2364
2681
|
|
|
2365
2682
|
result['text'] = input_value_node.nodeValue;
|
|
@@ -2375,9 +2692,13 @@ var translate = {
|
|
|
2375
2692
|
//console.log(node);
|
|
2376
2693
|
//替换渲染
|
|
2377
2694
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2378
|
-
|
|
2379
|
-
node.attributes['placeholder'].nodeValue =
|
|
2380
|
-
|
|
2695
|
+
var resultShowText = translate.util.textReplace(node.attributes['placeholder'].nodeValue, originalText, resultText, translate.to);
|
|
2696
|
+
node.attributes['placeholder'].nodeValue = resultShowText; //2025.4.26 变更为此方式
|
|
2697
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2698
|
+
result['resultText'] = resultShowText;
|
|
2699
|
+
}else{
|
|
2700
|
+
result['resultText'] = '';
|
|
2701
|
+
}
|
|
2381
2702
|
}
|
|
2382
2703
|
|
|
2383
2704
|
result['text'] = node.attributes['placeholder'].nodeValue;
|
|
@@ -2401,9 +2722,13 @@ var translate = {
|
|
|
2401
2722
|
if(nodeAttributeName == 'keywords' || nodeAttributeName == 'description' || nodeAttributeName == 'sharetitle' || nodeAttributeProperty == 'og:title' || nodeAttributeProperty == 'og:description' || nodeAttributeProperty == 'og:site_name' || nodeAttributeProperty == 'og:novel:latest_chapter_name'){
|
|
2402
2723
|
//替换渲染
|
|
2403
2724
|
if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
|
|
2404
|
-
|
|
2405
|
-
node.content =
|
|
2406
|
-
|
|
2725
|
+
var resultShowText = translate.util.textReplace(node.content, originalText, resultText, translate.to);
|
|
2726
|
+
node.content = resultShowText; //2025.4.26 变更为此方式
|
|
2727
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2728
|
+
result['resultText'] = resultShowText;
|
|
2729
|
+
}else{
|
|
2730
|
+
result['resultText'] = '';
|
|
2731
|
+
}
|
|
2407
2732
|
}
|
|
2408
2733
|
|
|
2409
2734
|
result['text'] = node.content;
|
|
@@ -2422,9 +2747,13 @@ var translate = {
|
|
|
2422
2747
|
|
|
2423
2748
|
//替换渲染
|
|
2424
2749
|
if(typeof(originalText) != 'undefined' && originalText.length > 0){
|
|
2425
|
-
|
|
2426
|
-
node.alt =
|
|
2427
|
-
|
|
2750
|
+
var resultShowText = translate.util.textReplace(node.alt, originalText, resultText, translate.to);
|
|
2751
|
+
node.alt = resultShowText; //2025.4.26 变更为此方式
|
|
2752
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2753
|
+
result['resultText'] = resultShowText;
|
|
2754
|
+
}else{
|
|
2755
|
+
result['resultText'] = '';
|
|
2756
|
+
}
|
|
2428
2757
|
}
|
|
2429
2758
|
result['text'] = node.alt;
|
|
2430
2759
|
return result;
|
|
@@ -2440,9 +2769,15 @@ var translate = {
|
|
|
2440
2769
|
}else{
|
|
2441
2770
|
//替换渲染
|
|
2442
2771
|
if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
|
|
2443
|
-
//
|
|
2444
|
-
|
|
2445
|
-
//
|
|
2772
|
+
//console.log(originalText+'|');
|
|
2773
|
+
var resultShowText = translate.util.textReplace(node.nodeValue, originalText, resultText, translate.to);
|
|
2774
|
+
//console.log(resultShowText+'|');
|
|
2775
|
+
node.nodeValue = resultShowText; //2025.4.26 变更为此方式
|
|
2776
|
+
if(resultShowText.indexOf(resultText) > -1){
|
|
2777
|
+
result['resultText'] = resultShowText;
|
|
2778
|
+
}else{
|
|
2779
|
+
result['resultText'] = '';
|
|
2780
|
+
}
|
|
2446
2781
|
}
|
|
2447
2782
|
result['text'] = node.nodeValue;
|
|
2448
2783
|
}
|
|
@@ -2460,8 +2795,17 @@ var translate = {
|
|
|
2460
2795
|
}
|
|
2461
2796
|
|
|
2462
2797
|
var nodename = node.nodeName;
|
|
2463
|
-
|
|
2464
|
-
|
|
2798
|
+
if(typeof(node.nodeName) == 'string'){
|
|
2799
|
+
return node.nodeName;
|
|
2800
|
+
}else{
|
|
2801
|
+
if(typeof(node.tagName) == 'string' && node.tagName.length > 0){
|
|
2802
|
+
return node.tagName;
|
|
2803
|
+
}else{
|
|
2804
|
+
console.log('warn : get nodeName is null, this node ignore translate. node : ');
|
|
2805
|
+
console.log(node);
|
|
2806
|
+
return '';
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2465
2809
|
},
|
|
2466
2810
|
//向下遍历node
|
|
2467
2811
|
whileNodes:function(uuid, node){
|
|
@@ -2500,6 +2844,9 @@ var translate = {
|
|
|
2500
2844
|
//console.log(translate.element.tagAttribute[nodeNameLowerCase]);
|
|
2501
2845
|
|
|
2502
2846
|
for(var attributeName_index in translate.element.tagAttribute[nodeNameLowerCase]){
|
|
2847
|
+
if (!translate.element.tagAttribute[nodeNameLowerCase].hasOwnProperty(attributeName_index)) {
|
|
2848
|
+
continue;
|
|
2849
|
+
}
|
|
2503
2850
|
|
|
2504
2851
|
var attributeName = translate.element.tagAttribute[nodeNameLowerCase][attributeName_index];
|
|
2505
2852
|
//console.log(attributeName);
|
|
@@ -2526,9 +2873,12 @@ var translate = {
|
|
|
2526
2873
|
// //这个tag标签没有这个 attribute,忽略
|
|
2527
2874
|
// continue
|
|
2528
2875
|
//}
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
translate.
|
|
2876
|
+
|
|
2877
|
+
//判断当前元素是否在ignore忽略的tag、id、class name中 v3.15.7 增加
|
|
2878
|
+
if(!translate.ignore.isIgnore(node)){
|
|
2879
|
+
//加入翻译
|
|
2880
|
+
translate.addNodeToQueue(uuid, node, attributeValue, attributeName);
|
|
2881
|
+
}
|
|
2532
2882
|
}
|
|
2533
2883
|
|
|
2534
2884
|
}
|
|
@@ -2734,6 +3084,16 @@ var translate = {
|
|
|
2734
3084
|
textArray.push(text); //先将主 text 赋予 ,后面如果对主text进行加工分割,分割后会将主text给删除掉
|
|
2735
3085
|
//console.log(textArray);
|
|
2736
3086
|
|
|
3087
|
+
// 处理 ignore.regex
|
|
3088
|
+
for (var ri = 0; ri < translate.ignore.textRegex.length; ri++) {
|
|
3089
|
+
var regex = translate.ignore.textRegex[ri];
|
|
3090
|
+
for (var tai = 0; tai < textArray.length; tai++) {
|
|
3091
|
+
var text = textArray[tai];
|
|
3092
|
+
var ignoreTexts = text.match(regex) || []
|
|
3093
|
+
translate.ignore.text = translate.ignore.text.concat(ignoreTexts)
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
|
|
2737
3097
|
/**** v3.10.2.20241206 - 增加自定义忽略翻译的文本,忽略翻译的文本不会被翻译 - 当然这样会打乱翻译之后阅读的连贯性 ****/
|
|
2738
3098
|
for(var ti = 0; ti<translate.ignore.text.length; ti++){
|
|
2739
3099
|
if(translate.ignore.text[ti].trim().length == 0){
|
|
@@ -2746,7 +3106,6 @@ var translate = {
|
|
|
2746
3106
|
}
|
|
2747
3107
|
|
|
2748
3108
|
|
|
2749
|
-
|
|
2750
3109
|
/**** v3.10.2.20241206 - 自定义术语能力全面优化 - 当然这样会打乱翻译之后阅读的连贯性 ****/
|
|
2751
3110
|
//判断是否进行了翻译,也就是有设置目标语种,并且跟当前语种不一致
|
|
2752
3111
|
if(typeof(translate.temp_nomenclature) == 'undefined'){
|
|
@@ -2758,6 +3117,9 @@ var translate = {
|
|
|
2758
3117
|
if(typeof(translate.nomenclature.data[translate.language.getLocal()]) != 'undefined' && typeof(translate.nomenclature.data[translate.language.getLocal()][translate.to]) != 'undefined'){
|
|
2759
3118
|
var nomenclatureKeyArray;
|
|
2760
3119
|
for(var nomenclatureKey in translate.nomenclature.data[translate.language.getLocal()][translate.to]){
|
|
3120
|
+
if (!translate.nomenclature.data[translate.language.getLocal()][translate.to].hasOwnProperty(nomenclatureKey)) {
|
|
3121
|
+
continue;
|
|
3122
|
+
}
|
|
2761
3123
|
//nomenclatureKey 便是自定义术语的原始文本,值是要替换为的文本
|
|
2762
3124
|
//console.log(nomenclatureKey);
|
|
2763
3125
|
//自定义属于的指定的结果字符串
|
|
@@ -2969,6 +3331,9 @@ var translate = {
|
|
|
2969
3331
|
//console.log(langs);
|
|
2970
3332
|
|
|
2971
3333
|
for(var lang in langs) {
|
|
3334
|
+
if (!langs.hasOwnProperty(lang)) {
|
|
3335
|
+
continue;
|
|
3336
|
+
}
|
|
2972
3337
|
//创建二维数组, key为语种,如 english
|
|
2973
3338
|
/*
|
|
2974
3339
|
放到了 translate.addNodeQueueItem 进行判断
|
|
@@ -3165,6 +3530,10 @@ var translate = {
|
|
|
3165
3530
|
*/
|
|
3166
3531
|
isWhole:function(ele){
|
|
3167
3532
|
|
|
3533
|
+
if(translate.whole.isEnableAll){
|
|
3534
|
+
return true;
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3168
3537
|
//如果设置了 class|tag|id 其中某个,或者 all=true ,那么就是启用,反之未启用
|
|
3169
3538
|
if((translate.whole.class.length == 0 && translate.whole.tag.length == 0 && translate.whole.id.length == 0) && translate.whole.isEnableAll == false){
|
|
3170
3539
|
//未设置,那么直接返回false
|
|
@@ -3173,9 +3542,7 @@ var translate = {
|
|
|
3173
3542
|
if(ele == null || typeof(ele) == 'undefined'){
|
|
3174
3543
|
return false;
|
|
3175
3544
|
}
|
|
3176
|
-
|
|
3177
|
-
return true;
|
|
3178
|
-
}
|
|
3545
|
+
|
|
3179
3546
|
|
|
3180
3547
|
var parentNode = ele;
|
|
3181
3548
|
var maxnumber = 100; //最大循环次数,避免死循环
|
|
@@ -3231,7 +3598,7 @@ var translate = {
|
|
|
3231
3598
|
}
|
|
3232
3599
|
|
|
3233
3600
|
//赋予判断的元素向上一级
|
|
3234
|
-
parentNode = parentNode.
|
|
3601
|
+
parentNode = parentNode.parentElement;
|
|
3235
3602
|
}
|
|
3236
3603
|
|
|
3237
3604
|
return false;
|
|
@@ -3332,21 +3699,32 @@ var translate = {
|
|
|
3332
3699
|
autoRecognitionLocalLanguage:function(){
|
|
3333
3700
|
if(translate.language.local != null && translate.language.local.length > 2){
|
|
3334
3701
|
//已设置过了,不需要再设置
|
|
3335
|
-
return;
|
|
3702
|
+
return translate.language.local;
|
|
3703
|
+
}
|
|
3704
|
+
|
|
3705
|
+
//v3.16.1 优化,获取本地语种,针对开源中国只对 readme 部分进行翻译的场景,将针对设置的 translate.setDocument() 区域的元素的显示文本进行判定语种
|
|
3706
|
+
var translateAreaText = ''; //翻译区域内当前的文本
|
|
3707
|
+
var docs = translate.getDocuments();
|
|
3708
|
+
for(var docs_index = 0; docs_index < docs.length; docs_index++){
|
|
3709
|
+
var doc = docs[docs_index];
|
|
3710
|
+
if(typeof(doc) != 'undefined' && doc != null && typeof(doc.innerText) != 'undefined' && doc.innerText != null && doc.innerText.length > 0){
|
|
3711
|
+
translateAreaText = translateAreaText + doc.innerText;
|
|
3712
|
+
}
|
|
3336
3713
|
}
|
|
3337
3714
|
|
|
3338
|
-
|
|
3339
|
-
|
|
3715
|
+
|
|
3716
|
+
//var bodyText = document.body.outerText;
|
|
3717
|
+
if(translateAreaText == null || typeof(translateAreaText) == 'undefined' || translateAreaText.length < 1){
|
|
3340
3718
|
//未取到,默认赋予简体中文
|
|
3341
3719
|
translate.language.local = 'chinese_simplified';
|
|
3342
3720
|
return;
|
|
3343
3721
|
}
|
|
3344
3722
|
|
|
3345
|
-
|
|
3723
|
+
translateAreaText = translateAreaText.replace(/\n|\t|\r/g,''); //将回车换行等去掉
|
|
3346
3724
|
|
|
3347
3725
|
//默认赋予简体中文
|
|
3348
3726
|
translate.language.local = 'chinese_simplified';
|
|
3349
|
-
var recognition = translate.language.recognition(
|
|
3727
|
+
var recognition = translate.language.recognition(translateAreaText);
|
|
3350
3728
|
translate.language.local = recognition.languageName;
|
|
3351
3729
|
return translate.language.local;
|
|
3352
3730
|
/* v3.1优化
|
|
@@ -3532,6 +3910,9 @@ var translate = {
|
|
|
3532
3910
|
var langsNumberOriginal = []; //同上,只不过这个不会进行清空字符数
|
|
3533
3911
|
var allNumber = 0;//总字数
|
|
3534
3912
|
for(var key in langs){
|
|
3913
|
+
if (!langs.hasOwnProperty(key)) {
|
|
3914
|
+
continue;
|
|
3915
|
+
}
|
|
3535
3916
|
if(typeof(langs[key]) != 'object'){
|
|
3536
3917
|
continue;
|
|
3537
3918
|
}
|
|
@@ -3547,6 +3928,9 @@ var translate = {
|
|
|
3547
3928
|
//过滤 语种的字符数小于总字符数 百分之五的,低于这个数,将忽略
|
|
3548
3929
|
var langkeys = [];
|
|
3549
3930
|
for(var lang in langsNumber){
|
|
3931
|
+
if (!langsNumber.hasOwnProperty(lang)) {
|
|
3932
|
+
continue;
|
|
3933
|
+
}
|
|
3550
3934
|
if(langsNumber[lang]/allNumber > 0.01){
|
|
3551
3935
|
langkeys[langkeys.length] = lang+'';
|
|
3552
3936
|
}
|
|
@@ -3590,6 +3974,9 @@ var translate = {
|
|
|
3590
3974
|
var maxLang = ''; //字数最多的语种
|
|
3591
3975
|
var maxNumber = 0;
|
|
3592
3976
|
for(var lang in langsNumber){
|
|
3977
|
+
if (!langsNumber.hasOwnProperty(lang)) {
|
|
3978
|
+
continue;
|
|
3979
|
+
}
|
|
3593
3980
|
if(langsNumber[lang] > maxNumber){
|
|
3594
3981
|
maxLang = lang;
|
|
3595
3982
|
maxNumber = langsNumber[lang];
|
|
@@ -3599,6 +3986,9 @@ var translate = {
|
|
|
3599
3986
|
//重新组合返回值的 languageArray
|
|
3600
3987
|
var languageArray = {};
|
|
3601
3988
|
for(var lang in langs){
|
|
3989
|
+
if (!langs.hasOwnProperty(lang)) {
|
|
3990
|
+
continue;
|
|
3991
|
+
}
|
|
3602
3992
|
languageArray[lang] = {};
|
|
3603
3993
|
languageArray[lang].number = langsNumberOriginal[lang];
|
|
3604
3994
|
languageArray[lang].list = langs[lang];
|
|
@@ -4059,7 +4449,7 @@ var translate = {
|
|
|
4059
4449
|
},
|
|
4060
4450
|
//希伯来语
|
|
4061
4451
|
hebrew:function(str){
|
|
4062
|
-
return
|
|
4452
|
+
return /^[\u0590-\u05FF]$/.test(str);
|
|
4063
4453
|
},
|
|
4064
4454
|
//0-9 阿拉伯数字
|
|
4065
4455
|
number:function(str){
|
|
@@ -4268,6 +4658,10 @@ var translate = {
|
|
|
4268
4658
|
return;
|
|
4269
4659
|
}
|
|
4270
4660
|
|
|
4661
|
+
if(typeof(translate.request.api.ip) != 'string' || translate.request.api.ip == null || translate.request.api.ip.length < 1){
|
|
4662
|
+
return;
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4271
4665
|
//如果用户浏览器没读到默认语言,或者默认语言没有对应到translate.js支持的语种,那么在采用ip识别的方式
|
|
4272
4666
|
translate.request.post(translate.request.api.ip, {}, function(data){
|
|
4273
4667
|
//console.log(data);
|
|
@@ -4301,7 +4695,7 @@ var translate = {
|
|
|
4301
4695
|
var text = '你世好word世界';
|
|
4302
4696
|
var translateOriginal = '世';
|
|
4303
4697
|
var translateResult = '世杰'; //翻译结果
|
|
4304
|
-
translate.
|
|
4698
|
+
translate.util.textReplace(text, translateOriginal, translateResult, 'english');
|
|
4305
4699
|
|
|
4306
4700
|
*/
|
|
4307
4701
|
textReplace:function(text, translateOriginal, translateResult, language){
|
|
@@ -4329,7 +4723,7 @@ var translate = {
|
|
|
4329
4723
|
let replaceOriginalText = '' + translateOriginal;
|
|
4330
4724
|
|
|
4331
4725
|
//根据不同的语种,如果有的语种需要加空格来进行区分单词,那么也要进行空格的判定
|
|
4332
|
-
if(translate.language.wordBlankConnector(
|
|
4726
|
+
if(translate.language.wordBlankConnector(language)){
|
|
4333
4727
|
let originalIndex = text.indexOf(translateOriginal, currentReplaceEndIndex); //翻译之前,翻译的单词在字符串中的起始坐标(0开始)
|
|
4334
4728
|
//console.log("originalIndex: "+originalIndex);
|
|
4335
4729
|
|
|
@@ -4345,21 +4739,40 @@ var translate = {
|
|
|
4345
4739
|
}else if(/,/.test(char)){
|
|
4346
4740
|
replaceResultText = replaceResultText + ', ';
|
|
4347
4741
|
replaceOriginalText = translateOriginal + ',';
|
|
4348
|
-
}else if(
|
|
4349
|
-
|
|
4350
|
-
|
|
4742
|
+
}else if(/:/.test(char)){
|
|
4743
|
+
replaceResultText = replaceResultText + ': ';
|
|
4744
|
+
replaceOriginalText = translateOriginal + ':';
|
|
4745
|
+
}else if([' ', '\n','\t',']','|', '_','-','/'].indexOf(char) !== -1){
|
|
4746
|
+
// 如果后面的字符是 这些字符,那么不用添加空格隔开
|
|
4747
|
+
}else{
|
|
4748
|
+
//补充上一个空格,用于将两个单词隔开
|
|
4351
4749
|
replaceResultText = replaceResultText + ' ';
|
|
4750
|
+
//console.log('after add space : '+replaceResultText);
|
|
4352
4751
|
}
|
|
4752
|
+
|
|
4353
4753
|
}
|
|
4354
4754
|
|
|
4355
4755
|
//判断它前面是否还有文本
|
|
4356
4756
|
if(originalIndex > 0){
|
|
4357
4757
|
let char = text.charAt(originalIndex-1);
|
|
4358
4758
|
//console.log(char);
|
|
4359
|
-
|
|
4360
|
-
|
|
4759
|
+
|
|
4760
|
+
if(/。/.test(char)){
|
|
4761
|
+
replaceResultText = '. '+replaceResultText;
|
|
4762
|
+
replaceOriginalText = '。'+replaceOriginalText;
|
|
4763
|
+
}else if(/,/.test(char)){
|
|
4764
|
+
replaceResultText = ', '+replaceResultText;
|
|
4765
|
+
replaceOriginalText = ','+replaceOriginalText;
|
|
4766
|
+
}else if(/:/.test(char)){
|
|
4767
|
+
replaceResultText = ': '+replaceResultText;
|
|
4768
|
+
replaceOriginalText = ':'+replaceOriginalText;
|
|
4769
|
+
}else if([' ', '\n','\t','[', '|', '_','-','/'].indexOf(char) !== -1){
|
|
4770
|
+
// 如果前面的字符是 这些字符,那么不用添加空格隔开
|
|
4771
|
+
}else{
|
|
4772
|
+
//补充上一个空格,用于将两个单词隔开
|
|
4361
4773
|
//text = text.replace(translateOriginal, ' '+translateResult);
|
|
4362
|
-
|
|
4774
|
+
replaceResultText = ' '+replaceResultText;
|
|
4775
|
+
//console.log('before add space : '+replaceResultText);
|
|
4363
4776
|
}
|
|
4364
4777
|
}
|
|
4365
4778
|
}else{
|
|
@@ -4461,6 +4874,9 @@ var translate = {
|
|
|
4461
4874
|
}
|
|
4462
4875
|
|
|
4463
4876
|
for(var item in numbers){
|
|
4877
|
+
if (!numbers.hasOwnProperty(item)) {
|
|
4878
|
+
continue;
|
|
4879
|
+
}
|
|
4464
4880
|
if(numbers[item]===maxNum){
|
|
4465
4881
|
maxStr.push(item)
|
|
4466
4882
|
}
|
|
@@ -4577,6 +4993,8 @@ var translate = {
|
|
|
4577
4993
|
return false;
|
|
4578
4994
|
}
|
|
4579
4995
|
},
|
|
4996
|
+
|
|
4997
|
+
/*js translate.util.loadMsgJs start*/
|
|
4580
4998
|
//加载 msg.js
|
|
4581
4999
|
loadMsgJs:function(){
|
|
4582
5000
|
if(typeof(msg) != 'undefined'){
|
|
@@ -4584,6 +5002,7 @@ var translate = {
|
|
|
4584
5002
|
}
|
|
4585
5003
|
translate.util.synchronizesLoadJs('https://res.zvo.cn/msg/msg.js');
|
|
4586
5004
|
},
|
|
5005
|
+
/*js translate.util.loadMsgJs end*/
|
|
4587
5006
|
/*
|
|
4588
5007
|
对一个对象,按照对象的key的长度进行排序,越长越在前面
|
|
4589
5008
|
*/
|
|
@@ -4998,7 +5417,43 @@ var translate = {
|
|
|
4998
5417
|
}
|
|
4999
5418
|
|
|
5000
5419
|
return result;
|
|
5420
|
+
},
|
|
5421
|
+
|
|
5422
|
+
/*js translate.util.getElementPosition start*/
|
|
5423
|
+
/*
|
|
5424
|
+
计算一个元素在浏览器中的坐标系,其绝对定位、以及实际显示出来所占用的区域,宽、高
|
|
5425
|
+
*/
|
|
5426
|
+
getElementPosition:function (node) {
|
|
5427
|
+
// 获取元素的边界矩形信息(相对于视口)
|
|
5428
|
+
const rect = node.getBoundingClientRect();
|
|
5429
|
+
|
|
5430
|
+
// 获取当前页面的滚动位置(兼容不同浏览器)
|
|
5431
|
+
const scrollX = window.scrollX || document.documentElement.scrollLeft;
|
|
5432
|
+
const scrollY = window.scrollY || document.documentElement.scrollTop;
|
|
5433
|
+
|
|
5434
|
+
// 计算元素在文档中的起始坐标
|
|
5435
|
+
const startX = rect.left + scrollX;
|
|
5436
|
+
const startY = rect.top + scrollY;
|
|
5437
|
+
|
|
5438
|
+
// 计算元素的宽度和高度
|
|
5439
|
+
const width = rect.right - rect.left;
|
|
5440
|
+
const height = rect.bottom - rect.top;
|
|
5441
|
+
|
|
5442
|
+
// 计算元素在文档中的结束坐标
|
|
5443
|
+
const endX = startX + width;
|
|
5444
|
+
const endY = startY + height;
|
|
5445
|
+
|
|
5446
|
+
// 返回包含所有信息的对象
|
|
5447
|
+
return {
|
|
5448
|
+
startX,
|
|
5449
|
+
startY,
|
|
5450
|
+
endX,
|
|
5451
|
+
endY,
|
|
5452
|
+
width,
|
|
5453
|
+
height
|
|
5454
|
+
};
|
|
5001
5455
|
}
|
|
5456
|
+
/*js translate.util.getElementPosition end*/
|
|
5002
5457
|
},
|
|
5003
5458
|
//机器翻译采用哪种翻译服务
|
|
5004
5459
|
service:{
|
|
@@ -5007,6 +5462,7 @@ var translate = {
|
|
|
5007
5462
|
*/
|
|
5008
5463
|
name:'translate.service',
|
|
5009
5464
|
|
|
5465
|
+
/*js translate.service.use start*/
|
|
5010
5466
|
/*
|
|
5011
5467
|
其实就是设置 translate.service.name
|
|
5012
5468
|
可以设置为:
|
|
@@ -5014,19 +5470,27 @@ var translate = {
|
|
|
5014
5470
|
translate.service 自行部署的translate.service 翻译API服务,部署参考: https://translate.zvo.cn/391129.html
|
|
5015
5471
|
client.edge 使用无服务器的翻译,有edge浏览器接口提供翻译服务
|
|
5016
5472
|
siliconflow 使用指点云提供的服务器、硅基流动提供的AI算力进行大模型翻译
|
|
5473
|
+
giteeAI 使用 giteeAI , 亚洲、美洲、欧洲 网络节点覆盖
|
|
5017
5474
|
|
|
5018
5475
|
*/
|
|
5019
5476
|
use: function(serviceName){
|
|
5020
|
-
if(translate.enterprise.isUse == true){
|
|
5477
|
+
if(typeof(translate.enterprise) != 'undefined' && translate.enterprise.isUse == true){
|
|
5021
5478
|
console.log('您已启用了企业级翻译通道 translate.enterprise.use(); (文档:https://translate.zvo.cn/4087.html) , 所以您设置的 translate.service.use(\''+serviceName+'\'); (文档:https://translate.zvo.cn/4081.html) 将失效不起作用,有企业级翻译通道全部接管。');
|
|
5022
5479
|
return;
|
|
5023
5480
|
}
|
|
5481
|
+
//console.log('--'+serviceName);
|
|
5024
5482
|
if(typeof(serviceName) == 'string'){
|
|
5025
5483
|
translate.service.name = serviceName;
|
|
5026
5484
|
if(serviceName != 'translate.service'){
|
|
5027
|
-
if(serviceName == '
|
|
5485
|
+
if(serviceName.toLowerCase() == 'giteeai'){
|
|
5486
|
+
//设定翻译接口为GiteeAI的
|
|
5487
|
+
translate.request.api.host=['https://giteeai.zvo.cn/','https://deutsch.enterprise.api.translate.zvo.cn:1000/','https://api.translate.zvo.cn:1000/'];
|
|
5488
|
+
return;
|
|
5489
|
+
}
|
|
5490
|
+
if(serviceName.toLowerCase() == 'siliconflow'){
|
|
5028
5491
|
//设定翻译接口为硅基流动的
|
|
5029
5492
|
translate.request.api.host=['https://siliconflow.zvo.cn/','https://america.api.translate.zvo.cn:1414/','https://deutsch.enterprise.api.translate.zvo.cn:1414/'];
|
|
5493
|
+
return;
|
|
5030
5494
|
}
|
|
5031
5495
|
|
|
5032
5496
|
//增加元素整体翻译能力
|
|
@@ -5034,6 +5498,9 @@ var translate = {
|
|
|
5034
5498
|
}
|
|
5035
5499
|
}
|
|
5036
5500
|
},
|
|
5501
|
+
/*js translate.service.use end*/
|
|
5502
|
+
|
|
5503
|
+
/*js translate.service.edge start*/
|
|
5037
5504
|
//客户端方式的edge提供机器翻译服务
|
|
5038
5505
|
edge:{
|
|
5039
5506
|
api:{ //edge浏览器的翻译功能
|
|
@@ -5161,6 +5628,7 @@ var translate = {
|
|
|
5161
5628
|
|
|
5162
5629
|
}
|
|
5163
5630
|
}
|
|
5631
|
+
/*js translate.service.edge end*/
|
|
5164
5632
|
},
|
|
5165
5633
|
//request请求来源于 https://github.com/xnx3/request
|
|
5166
5634
|
request:{
|
|
@@ -5182,6 +5650,34 @@ var translate = {
|
|
|
5182
5650
|
connectTest:'connectTest.json', //用于 translate.js 多节点翻译自动检测网络连通情况
|
|
5183
5651
|
init:'init.json', //获取最新版本号,跟当前版本进行比对,用于提醒版本升级等使用
|
|
5184
5652
|
|
|
5653
|
+
},
|
|
5654
|
+
/*
|
|
5655
|
+
追加参数, v3.15.9.20250527 增加
|
|
5656
|
+
所有通过 translate.request.send 进行网络请求的,都会追加上这个参数
|
|
5657
|
+
默认是空,没有任何追加参数。
|
|
5658
|
+
|
|
5659
|
+
设置方式: https://translate.zvo.cn/471711.html
|
|
5660
|
+
translate.request.appendParams = {
|
|
5661
|
+
key1:'key1',
|
|
5662
|
+
key2:'key2'
|
|
5663
|
+
}
|
|
5664
|
+
*/
|
|
5665
|
+
appendParams:{
|
|
5666
|
+
|
|
5667
|
+
},
|
|
5668
|
+
/*
|
|
5669
|
+
追加header头的参数, v3.15.13 增加
|
|
5670
|
+
所有通过 translate.request.send 进行网络请求的,都会追加上这个参数
|
|
5671
|
+
默认是空,没有任何追加参数。
|
|
5672
|
+
|
|
5673
|
+
设置方式: https://translate.zvo.cn/471711.html
|
|
5674
|
+
translate.request.appendHeaders = {
|
|
5675
|
+
key1:'key1',
|
|
5676
|
+
Aauthorization:'Bearer xxxxxxxxxx'
|
|
5677
|
+
}
|
|
5678
|
+
*/
|
|
5679
|
+
appendHeaders:{
|
|
5680
|
+
|
|
5185
5681
|
},
|
|
5186
5682
|
/*
|
|
5187
5683
|
请求后端接口的响应。无论是否成功,都会触发此处。
|
|
@@ -5195,6 +5691,7 @@ var translate = {
|
|
|
5195
5691
|
//console.log(xhr);
|
|
5196
5692
|
},
|
|
5197
5693
|
|
|
5694
|
+
|
|
5198
5695
|
/*
|
|
5199
5696
|
速度检测控制中心, 检测主备翻译接口的响应速度进行排列,真正请求时,按照排列的顺序进行请求
|
|
5200
5697
|
v2.8.2增加
|
|
@@ -5328,6 +5825,10 @@ var translate = {
|
|
|
5328
5825
|
'content-type':'application/x-www-form-urlencoded',
|
|
5329
5826
|
};
|
|
5330
5827
|
|
|
5828
|
+
if(typeof(translate.request.api.connectTest) != 'string' || translate.request.api.connectTest == null || translate.request.api.connectTest.length < 1){
|
|
5829
|
+
return;
|
|
5830
|
+
}
|
|
5831
|
+
|
|
5331
5832
|
|
|
5332
5833
|
translate.request.speedDetectionControl.checkHostQueue = []; //用于实际存储
|
|
5333
5834
|
translate.request.speedDetectionControl.checkHostQueueMap = []; //只是map,通过key取值,无其他作用
|
|
@@ -5381,7 +5882,7 @@ var translate = {
|
|
|
5381
5882
|
headers,
|
|
5382
5883
|
function(data){
|
|
5383
5884
|
//translate.request.speedDetectionControl.checkResponseSpeed_Storage(host, time);
|
|
5384
|
-
var hostUrl = data.requestURL.replace(
|
|
5885
|
+
var hostUrl = data.requestURL.replace(translate.request.api.connectTest,'');
|
|
5385
5886
|
translate.request.speedDetectionControl.checkResponseSpeed_Storage(hostUrl, translate.request.speedDetectionControl.disableTime);
|
|
5386
5887
|
},
|
|
5387
5888
|
false
|
|
@@ -5460,8 +5961,10 @@ var translate = {
|
|
|
5460
5961
|
}
|
|
5461
5962
|
|
|
5462
5963
|
//企业级翻译自动检测
|
|
5463
|
-
translate.enterprise
|
|
5464
|
-
|
|
5964
|
+
if(typeof(translate.enterprise) != 'undefined'){
|
|
5965
|
+
translate.enterprise.automaticAdaptationService();
|
|
5966
|
+
}
|
|
5967
|
+
|
|
5465
5968
|
// ------- edge start --------
|
|
5466
5969
|
var url = translate.request.getUrl(path);
|
|
5467
5970
|
//if(url.indexOf('edge') > -1 && path == translate.request.api.translate){
|
|
@@ -5512,13 +6015,26 @@ var translate = {
|
|
|
5512
6015
|
//加入浏览器默认语种 v3.6.1 增加,以便更好的进行自动切换语种
|
|
5513
6016
|
data.browserDefaultLanguage = translate.util.browserDefaultLanguage();
|
|
5514
6017
|
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
6018
|
+
//追加附加参数
|
|
6019
|
+
for(var apindex in translate.request.appendParams){
|
|
6020
|
+
if (!translate.request.appendParams.hasOwnProperty(apindex)) {
|
|
6021
|
+
continue;
|
|
6022
|
+
}
|
|
6023
|
+
data[apindex] = translate.request.appendParams[apindex];
|
|
6024
|
+
}
|
|
6025
|
+
|
|
6026
|
+
if(typeof(translate.enterprise) != 'undefined'){
|
|
6027
|
+
//加入key
|
|
6028
|
+
if(typeof(translate.enterprise.key) != 'undefined' && typeof(translate.enterprise.key) == 'string' && translate.enterprise.key.length > 0){
|
|
6029
|
+
data.key = translate.enterprise.key;
|
|
6030
|
+
}
|
|
5518
6031
|
}
|
|
5519
6032
|
|
|
5520
6033
|
//组合参数
|
|
5521
6034
|
for(var index in data){
|
|
6035
|
+
if (!data.hasOwnProperty(index)) {
|
|
6036
|
+
continue;
|
|
6037
|
+
}
|
|
5522
6038
|
if(params.length > 0){
|
|
5523
6039
|
params = params + '&';
|
|
5524
6040
|
}
|
|
@@ -5539,14 +6055,27 @@ var translate = {
|
|
|
5539
6055
|
}catch(e){
|
|
5540
6056
|
xhr=new ActiveXObject("Microsoft.XMLHTTP");
|
|
5541
6057
|
}
|
|
6058
|
+
xhr.data=data;
|
|
5542
6059
|
//2.调用open方法(true----异步)
|
|
5543
6060
|
xhr.open(method,url,isAsynchronize);
|
|
5544
6061
|
//设置headers
|
|
5545
6062
|
if(headers != null){
|
|
5546
6063
|
for(var index in headers){
|
|
6064
|
+
if (!headers.hasOwnProperty(index)) {
|
|
6065
|
+
continue;
|
|
6066
|
+
}
|
|
5547
6067
|
xhr.setRequestHeader(index,headers[index]);
|
|
5548
6068
|
}
|
|
5549
6069
|
}
|
|
6070
|
+
|
|
6071
|
+
//追加附加参数
|
|
6072
|
+
for(var ahindex in translate.request.appendHeaders){
|
|
6073
|
+
if (!translate.request.appendHeaders.hasOwnProperty(ahindex)) {
|
|
6074
|
+
continue;
|
|
6075
|
+
}
|
|
6076
|
+
xhr.setRequestHeader(ahindex,translate.request.appendHeaders[ahindex]);
|
|
6077
|
+
}
|
|
6078
|
+
|
|
5550
6079
|
if(translate.service.name == 'translate.service'){
|
|
5551
6080
|
xhr.setRequestHeader('currentpage', window.location.href+'');
|
|
5552
6081
|
}
|
|
@@ -5586,8 +6115,8 @@ var translate = {
|
|
|
5586
6115
|
|
|
5587
6116
|
//判断是否是v2版本的翻译,如果是 translate.service 模式并且没有使用企业级翻译,参会提示
|
|
5588
6117
|
//2024.3月底开始,翻译使用量增加的太快,开源的翻译服务器有点扛不住经常出故障,所以直接把这个提示加到这里
|
|
5589
|
-
if(translate.service.name == 'translate.service'
|
|
5590
|
-
console.log('----- translate.js 提示 -----\n
|
|
6118
|
+
if(translate.service.name == 'translate.service'){
|
|
6119
|
+
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
6120
|
}
|
|
5592
6121
|
|
|
5593
6122
|
//console.log(xhr);
|
|
@@ -5681,6 +6210,19 @@ var translate = {
|
|
|
5681
6210
|
}
|
|
5682
6211
|
}
|
|
5683
6212
|
|
|
6213
|
+
/*
|
|
6214
|
+
for(var i = texts.length - 1; i >= 0; i--){
|
|
6215
|
+
console.log(texts[i]);
|
|
6216
|
+
|
|
6217
|
+
//判断是否在浏览器缓存中出现了
|
|
6218
|
+
var cacheHash = translate.util.hash(texts[i]);
|
|
6219
|
+
var cache = translate.storage.get('hash_'+translate.to+'_'+cacheHash);
|
|
6220
|
+
if(cache != null && cache.length > 0){
|
|
6221
|
+
//缓存中发现了这个得结果,那这个就不需要再进行翻译了
|
|
6222
|
+
}
|
|
6223
|
+
}
|
|
6224
|
+
*/
|
|
6225
|
+
|
|
5684
6226
|
|
|
5685
6227
|
var url = translate.request.api.translate;
|
|
5686
6228
|
var data = {
|
|
@@ -5787,6 +6329,10 @@ var translate = {
|
|
|
5787
6329
|
}
|
|
5788
6330
|
}
|
|
5789
6331
|
}, 100);
|
|
6332
|
+
if(typeof(PerformanceObserver) == 'undefined'){
|
|
6333
|
+
console.log('因浏览器版本较低, translate.request.listener.start() 中 PerformanceObserver 对象不存在,浏览器不支持,所以 translate.request.listener.start() 未生效。');
|
|
6334
|
+
return;
|
|
6335
|
+
}
|
|
5790
6336
|
|
|
5791
6337
|
const observer = new PerformanceObserver((list) => {
|
|
5792
6338
|
var translateExecute = false; //是否需要执行翻译 true 要执行
|
|
@@ -5810,8 +6356,8 @@ var translate = {
|
|
|
5810
6356
|
break;
|
|
5811
6357
|
}
|
|
5812
6358
|
}
|
|
5813
|
-
//client.edge 判断
|
|
5814
|
-
if(url.indexOf(translate.service.edge.api.auth) > -1){
|
|
6359
|
+
//client.edge 判断 translate.service.edge可能会被精简translate.js定制时给直接干掉,所以提前加个判断
|
|
6360
|
+
if(typeof(translate.service.edge) != 'undefined' && url.indexOf(translate.service.edge.api.auth) > -1){
|
|
5815
6361
|
ignoreUrl = true;
|
|
5816
6362
|
}
|
|
5817
6363
|
if(url.indexOf('.microsofttranslator.com/translate') > -1){
|
|
@@ -5838,19 +6384,157 @@ var translate = {
|
|
|
5838
6384
|
translate.request.listener.addExecute();
|
|
5839
6385
|
}
|
|
5840
6386
|
});
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
6387
|
+
|
|
6388
|
+
//v3.15.14.20250617 增加
|
|
6389
|
+
// 优先使用 entryTypes 兼容 ES5 的写法
|
|
6390
|
+
|
|
6391
|
+
var supportedTypes = PerformanceObserver.supportedEntryTypes;
|
|
6392
|
+
if (supportedTypes) {
|
|
6393
|
+
var hasResource = false;
|
|
6394
|
+
for (var i = 0; i < supportedTypes.length; i++) {
|
|
6395
|
+
if (supportedTypes[i] === "resource") {
|
|
6396
|
+
hasResource = true;
|
|
6397
|
+
break;
|
|
6398
|
+
}
|
|
6399
|
+
}
|
|
6400
|
+
if (hasResource) {
|
|
6401
|
+
try {
|
|
6402
|
+
observer.observe({ entryTypes: ["resource"] });
|
|
6403
|
+
return;
|
|
6404
|
+
} catch (e) {
|
|
6405
|
+
console.log("PerformanceObserver entryTypes 失败,尝试 type 参数");
|
|
6406
|
+
}
|
|
6407
|
+
}
|
|
6408
|
+
}
|
|
6409
|
+
|
|
6410
|
+
|
|
6411
|
+
// 回退到 type 参数
|
|
6412
|
+
try {
|
|
6413
|
+
observer.observe({ type: "resource", buffered: true });
|
|
6414
|
+
console.log("使用 PerformanceObserver type");
|
|
6415
|
+
} catch (e) {
|
|
6416
|
+
console.log("当前浏览器不支持 PerformanceObserver 的任何参数, translate.request.listener.start() 未启动");
|
|
6417
|
+
}
|
|
6418
|
+
|
|
6419
|
+
}
|
|
6420
|
+
}
|
|
6421
|
+
},
|
|
6422
|
+
//存储,本地缓存
|
|
6423
|
+
storage:{
|
|
6424
|
+
/*js translate.storage.IndexedDB start*/
|
|
6425
|
+
//对浏览器的 IndexedDB 操作
|
|
6426
|
+
IndexedDB:{
|
|
6427
|
+
db: null,
|
|
6428
|
+
// 初始化数据库
|
|
6429
|
+
initDB: function () {
|
|
6430
|
+
const self = this;
|
|
6431
|
+
return new Promise((resolve, reject) => {
|
|
6432
|
+
const DB_NAME = 'translate.js';
|
|
6433
|
+
const STORE_NAME = 'kvStore';
|
|
6434
|
+
const DB_VERSION = 1;
|
|
6435
|
+
|
|
6436
|
+
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
|
6437
|
+
|
|
6438
|
+
request.onupgradeneeded = function(event) {
|
|
6439
|
+
const upgradedDb = event.target.result;
|
|
6440
|
+
if (!upgradedDb.objectStoreNames.contains(STORE_NAME)) {
|
|
6441
|
+
upgradedDb.createObjectStore(STORE_NAME, { keyPath: 'key' });
|
|
6442
|
+
}
|
|
6443
|
+
};
|
|
6444
|
+
|
|
6445
|
+
request.onsuccess = function(event) {
|
|
6446
|
+
self.db = event.target.result;
|
|
6447
|
+
resolve();
|
|
6448
|
+
};
|
|
6449
|
+
|
|
6450
|
+
request.onerror = function(event) {
|
|
6451
|
+
reject('IndexedDB 打开失败');
|
|
6452
|
+
};
|
|
6453
|
+
});
|
|
6454
|
+
},
|
|
6455
|
+
/*
|
|
6456
|
+
存储键值对
|
|
6457
|
+
使用方式:
|
|
6458
|
+
await translate.storage.indexedDB.set("user_001", { name: "Alice" });
|
|
6459
|
+
*/
|
|
6460
|
+
set: async function (key, value) {
|
|
6461
|
+
if (!this.db) await this.initDB();
|
|
6462
|
+
|
|
6463
|
+
return new Promise((resolve, reject) => {
|
|
6464
|
+
const tx = this.db.transaction('kvStore', 'readwrite');
|
|
6465
|
+
const store = tx.objectStore('kvStore');
|
|
6466
|
+
const item = { key, value };
|
|
6467
|
+
const request = store.put(item);
|
|
6468
|
+
|
|
6469
|
+
request.onsuccess = () => resolve();
|
|
6470
|
+
request.onerror = () => reject('写入失败');
|
|
6471
|
+
});
|
|
6472
|
+
},
|
|
6473
|
+
/*
|
|
6474
|
+
获取键对应的值
|
|
6475
|
+
使用方式:
|
|
6476
|
+
var user = await translate.storage.indexedDB.get("user_001");
|
|
6477
|
+
*/
|
|
6478
|
+
get: async function (key) {
|
|
6479
|
+
if (!this.db) await this.initDB();
|
|
6480
|
+
|
|
6481
|
+
return new Promise((resolve, reject) => {
|
|
6482
|
+
const tx = this.db.transaction('kvStore', 'readonly');
|
|
6483
|
+
const store = tx.objectStore('kvStore');
|
|
6484
|
+
const request = store.get(key);
|
|
6485
|
+
|
|
6486
|
+
request.onsuccess = () => {
|
|
6487
|
+
const result = request.result;
|
|
6488
|
+
resolve(result ? result.value : undefined);
|
|
6489
|
+
};
|
|
6490
|
+
|
|
6491
|
+
request.onerror = () => reject('读取失败');
|
|
6492
|
+
});
|
|
6493
|
+
},
|
|
6494
|
+
/*
|
|
6495
|
+
列出针对key进行模糊匹配的所有键值对
|
|
6496
|
+
使用方式:
|
|
6497
|
+
const users = await translate.storage.indexedDB.list("*us*r*");
|
|
6498
|
+
其中传入的key可以模糊搜索,其中的 * 标识另个或多个
|
|
6499
|
+
*/
|
|
6500
|
+
list: async function (key = '') {
|
|
6501
|
+
if (!this.db) await this.initDB();
|
|
6502
|
+
|
|
6503
|
+
return new Promise((resolve, reject) => {
|
|
6504
|
+
const tx = this.db.transaction('kvStore', 'readonly');
|
|
6505
|
+
const store = tx.objectStore('kvStore');
|
|
6506
|
+
const request = store.openCursor();
|
|
6507
|
+
const results = [];
|
|
6508
|
+
|
|
6509
|
+
// 将通配符 pattern 转换为正则表达式
|
|
6510
|
+
const regexStr = '^' + key.replace(/\*/g, '.*') + '$';
|
|
6511
|
+
const regex = new RegExp(regexStr);
|
|
6512
|
+
|
|
6513
|
+
request.onsuccess = (event) => {
|
|
6514
|
+
const cursor = event.target.result;
|
|
6515
|
+
if (cursor) {
|
|
6516
|
+
if (regex.test(cursor.key)) {
|
|
6517
|
+
results.push({ key: cursor.key, value: cursor.value.value });
|
|
6518
|
+
}
|
|
6519
|
+
cursor.continue();
|
|
6520
|
+
} else {
|
|
6521
|
+
resolve(results);
|
|
6522
|
+
}
|
|
6523
|
+
};
|
|
6524
|
+
|
|
6525
|
+
request.onerror = () => reject('游标读取失败');
|
|
6526
|
+
});
|
|
6527
|
+
}
|
|
6528
|
+
},
|
|
6529
|
+
/*js translate.storage.IndexedDB end*/
|
|
6530
|
+
|
|
6531
|
+
set:function(key,value){
|
|
6532
|
+
localStorage.setItem(key,value);
|
|
6533
|
+
},
|
|
5851
6534
|
get:function(key){
|
|
5852
6535
|
return localStorage.getItem(key);
|
|
5853
6536
|
}
|
|
6537
|
+
|
|
5854
6538
|
},
|
|
5855
6539
|
//针对图片进行相关的语种图片替换
|
|
5856
6540
|
images:{
|
|
@@ -5881,6 +6565,9 @@ var translate = {
|
|
|
5881
6565
|
}
|
|
5882
6566
|
*/
|
|
5883
6567
|
for(var key in queueArray){
|
|
6568
|
+
if (!queueArray.hasOwnProperty(key)) {
|
|
6569
|
+
continue;
|
|
6570
|
+
}
|
|
5884
6571
|
translate.images.queues[key] = queueArray[key];
|
|
5885
6572
|
}
|
|
5886
6573
|
},
|
|
@@ -5971,60 +6658,94 @@ var translate = {
|
|
|
5971
6658
|
return str;
|
|
5972
6659
|
}
|
|
5973
6660
|
},
|
|
6661
|
+
/*js translate.reset start*/
|
|
5974
6662
|
//对翻译结果进行复原。比如当前网页是简体中文的,被翻译为了英文,执行此方法即可复原为网页本身简体中文的状态,而无需在通过刷新页面来实现
|
|
5975
6663
|
reset:function(){
|
|
5976
6664
|
var currentLanguage = translate.language.getCurrent(); //获取当前翻译至的语种
|
|
6665
|
+
|
|
6666
|
+
var lastUuid = ''; //最后一次的uuid
|
|
5977
6667
|
for(var queue in translate.nodeQueue){
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
6668
|
+
if (!translate.nodeQueue.hasOwnProperty(queue)) {
|
|
6669
|
+
continue;
|
|
6670
|
+
}
|
|
6671
|
+
lastUuid = queue;
|
|
6672
|
+
}
|
|
6673
|
+
//console.log(queue);
|
|
6674
|
+
|
|
6675
|
+
if(lastUuid == ''){
|
|
6676
|
+
console.log('提示,你当前还未执行过翻译,所以你无需执行 translate.reset(); 进行还原。');
|
|
6677
|
+
return;
|
|
6678
|
+
}
|
|
6679
|
+
|
|
6680
|
+
for(var lang in translate.nodeQueue[lastUuid].list){
|
|
6681
|
+
if (!translate.nodeQueue[lastUuid].list.hasOwnProperty(lang)) {
|
|
6682
|
+
continue;
|
|
6683
|
+
}
|
|
6684
|
+
//console.log(lang);
|
|
6685
|
+
|
|
6686
|
+
for(var hash in translate.nodeQueue[lastUuid].list[lang]){
|
|
6687
|
+
if (!translate.nodeQueue[lastUuid].list[lang].hasOwnProperty(hash)) {
|
|
6688
|
+
continue;
|
|
6689
|
+
}
|
|
6690
|
+
var item = translate.nodeQueue[lastUuid].list[lang][hash];
|
|
6691
|
+
//console.log(item);
|
|
6692
|
+
for(var index in item.nodes){
|
|
6693
|
+
if (!item.nodes.hasOwnProperty(index)) {
|
|
6694
|
+
continue;
|
|
6695
|
+
}
|
|
6696
|
+
//console.log(item.nodes[index]);
|
|
6697
|
+
//item.nodes[index].node.nodeValue = item.original;
|
|
6698
|
+
var currentShow = translate.storage.get('hash_'+currentLanguage+'_'+hash); //当前显示出来的文字,也就是已经翻译后的文字
|
|
6699
|
+
//console.log('hash_'+lang+'_'+hash+' -- '+currentShow);
|
|
6700
|
+
if(typeof(currentShow) == 'undefined'){
|
|
6701
|
+
continue;
|
|
6702
|
+
}
|
|
6703
|
+
if(currentShow == null){
|
|
6704
|
+
continue;
|
|
6705
|
+
}
|
|
6706
|
+
if(currentShow.length == 0){
|
|
6707
|
+
continue;
|
|
6708
|
+
}
|
|
5999
6709
|
/*
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6710
|
+
if(item.beforeText.length > 0 || item.afterText.length > 0){
|
|
6711
|
+
console.log('----'+currentShow);
|
|
6712
|
+
console.log(item);
|
|
6713
|
+
}
|
|
6714
|
+
|
|
6715
|
+
if(item.beforeText.length > 0){
|
|
6716
|
+
currentShow = currentShow.substring(currentShow.lastIndexOf(item.beforeText)+1, currentShow.length);
|
|
6717
|
+
}
|
|
6718
|
+
if(item.afterText.length > 0){
|
|
6719
|
+
currentShow = currentShow.substring(0, currentShow.lastIndexOf(item.afterText));
|
|
6720
|
+
}
|
|
6721
|
+
if(item.beforeText.length > 0 || item.afterText.length > 0){
|
|
6722
|
+
console.log(currentShow);
|
|
6723
|
+
}
|
|
6014
6724
|
*/
|
|
6015
|
-
|
|
6725
|
+
// v3.16.5 针对gitee 的 readme 接入优化
|
|
6726
|
+
if(typeof(item.nodes[index].node) == 'undefined'){
|
|
6727
|
+
continue;
|
|
6016
6728
|
}
|
|
6729
|
+
|
|
6730
|
+
var attribute = typeof(item.nodes[index].node.attribute) == 'undefined' ? null:item.nodes[index].node.attribute;
|
|
6731
|
+
var analyse = translate.element.nodeAnalyse.analyse(item.nodes[index].node, '', '', attribute);
|
|
6732
|
+
translate.element.nodeAnalyse.analyse(item.nodes[index].node, analyse.text, item.original, attribute);
|
|
6017
6733
|
}
|
|
6018
6734
|
}
|
|
6019
6735
|
}
|
|
6020
6736
|
|
|
6737
|
+
|
|
6738
|
+
|
|
6739
|
+
|
|
6021
6740
|
//清除设置storage中的翻译至的语种
|
|
6022
6741
|
translate.storage.set('to', '');
|
|
6023
6742
|
translate.to = null;
|
|
6024
6743
|
//重新渲染select
|
|
6025
6744
|
translate.selectLanguageTag.render();
|
|
6026
6745
|
},
|
|
6746
|
+
/*js translate.reset end*/
|
|
6027
6747
|
|
|
6748
|
+
/*js translate.selectionTranslate start*/
|
|
6028
6749
|
/*
|
|
6029
6750
|
划词翻译,鼠标在网页中选中一段文字,会自动出现对应翻译后的文本
|
|
6030
6751
|
有网友 https://gitee.com/huangguishen 提供。
|
|
@@ -6071,7 +6792,9 @@ var translate = {
|
|
|
6071
6792
|
document.addEventListener('click', (event)=>{ document.querySelector('#translateTooltip').style.display = "none"}, false);
|
|
6072
6793
|
}
|
|
6073
6794
|
},
|
|
6795
|
+
/*js translate.selectionTranslate end*/
|
|
6074
6796
|
|
|
6797
|
+
/*js translate.enterprise start*/
|
|
6075
6798
|
/*
|
|
6076
6799
|
企业级翻译服务
|
|
6077
6800
|
注意,这个企业级翻译中的不在开源免费之中,企业级翻译服务追求的是高稳定,这个是收费的!详情可参考:http://translate.zvo.cn/43262.html
|
|
@@ -6113,6 +6836,7 @@ var translate = {
|
|
|
6113
6836
|
/* 企业级翻译通道的key, v3.12.3.20250107 增加,针对打包成APP的场景 */
|
|
6114
6837
|
key:'',
|
|
6115
6838
|
},
|
|
6839
|
+
/*js translate.enterprise end*/
|
|
6116
6840
|
|
|
6117
6841
|
/*
|
|
6118
6842
|
如果使用的是 translate.service 翻译通道,那么翻译后的语种会自动以小写的方式进行显示。
|
|
@@ -6126,6 +6850,7 @@ var translate = {
|
|
|
6126
6850
|
},
|
|
6127
6851
|
*/
|
|
6128
6852
|
|
|
6853
|
+
/*js translate.init start*/
|
|
6129
6854
|
/*
|
|
6130
6855
|
初始化,如版本检测、初始数据加载等。 v2.11.11.20240124 增加
|
|
6131
6856
|
会自动在 translate.js 加载后的 200毫秒后 执行,进行初始化。同时也是节点测速
|
|
@@ -6135,6 +6860,10 @@ var translate = {
|
|
|
6135
6860
|
return;
|
|
6136
6861
|
}
|
|
6137
6862
|
translate.init_execute = '已进行';
|
|
6863
|
+
|
|
6864
|
+
if(typeof(translate.request.api.init) != 'string' || translate.request.api.init == null || translate.request.api.init.length < 1){
|
|
6865
|
+
return;
|
|
6866
|
+
}
|
|
6138
6867
|
try{
|
|
6139
6868
|
translate.request.send(
|
|
6140
6869
|
translate.request.api.init,
|
|
@@ -6167,12 +6896,66 @@ var translate = {
|
|
|
6167
6896
|
}catch(e){
|
|
6168
6897
|
}
|
|
6169
6898
|
},
|
|
6899
|
+
/*js translate.init end*/
|
|
6170
6900
|
|
|
6901
|
+
/*js translate.progress start*/
|
|
6171
6902
|
/*
|
|
6172
6903
|
翻译执行的进展相关
|
|
6173
6904
|
比如,浏览器本地缓存没有,需要走API接口的文本所在的元素区域,出现 记载中的动画蒙版,给用户以友好的使用提示
|
|
6174
6905
|
*/
|
|
6175
6906
|
progress:{
|
|
6907
|
+
style: `
|
|
6908
|
+
/* CSS部分 */
|
|
6909
|
+
/* 灰色水平加载动画 */
|
|
6910
|
+
.translate_api_in_progress {
|
|
6911
|
+
position: relative;
|
|
6912
|
+
overflow: hidden; /* 隐藏超出部分的动画 */
|
|
6913
|
+
}
|
|
6914
|
+
|
|
6915
|
+
/* 蒙版层 */
|
|
6916
|
+
.translate_api_in_progress::after {
|
|
6917
|
+
content: '';
|
|
6918
|
+
position: absolute;
|
|
6919
|
+
top: 0;
|
|
6920
|
+
left: 0;
|
|
6921
|
+
width: 100%;
|
|
6922
|
+
height: 100%;
|
|
6923
|
+
background: rgba(255, 255, 255, 1); /* 半透明白色遮罩 */
|
|
6924
|
+
z-index: 2;
|
|
6925
|
+
}
|
|
6926
|
+
|
|
6927
|
+
/* 水平加载条动画 */
|
|
6928
|
+
.translate_api_in_progress::before {
|
|
6929
|
+
content: '';
|
|
6930
|
+
position: absolute;
|
|
6931
|
+
top: 50%;
|
|
6932
|
+
left: 0;
|
|
6933
|
+
width: 100%;
|
|
6934
|
+
height:100%; /* 细线高度 */
|
|
6935
|
+
background: linear-gradient(
|
|
6936
|
+
90deg,
|
|
6937
|
+
transparent 0%,
|
|
6938
|
+
#e8e8e8 25%, /* 浅灰色 */
|
|
6939
|
+
#d0d0d0 50%, /* 中灰色 */
|
|
6940
|
+
#e8e8e8 75%, /* 浅灰色 */
|
|
6941
|
+
transparent 100%
|
|
6942
|
+
);
|
|
6943
|
+
background-size: 200% 100%;
|
|
6944
|
+
animation: translate_api_in_progress_horizontal-loader 3.5s linear infinite;
|
|
6945
|
+
z-index: 3;
|
|
6946
|
+
transform: translateY(-50%);
|
|
6947
|
+
}
|
|
6948
|
+
|
|
6949
|
+
@keyframes translate_api_in_progress_horizontal-loader {
|
|
6950
|
+
0% {
|
|
6951
|
+
background-position: 200% 0;
|
|
6952
|
+
}
|
|
6953
|
+
100% {
|
|
6954
|
+
background-position: -200% 0;
|
|
6955
|
+
}
|
|
6956
|
+
}
|
|
6957
|
+
`,
|
|
6958
|
+
|
|
6176
6959
|
/*
|
|
6177
6960
|
通过文本翻译API进行的
|
|
6178
6961
|
*/
|
|
@@ -6181,110 +6964,107 @@ var translate = {
|
|
|
6181
6964
|
setUITip:function(tip){
|
|
6182
6965
|
translate.progress.api.isTip = tip;
|
|
6183
6966
|
},
|
|
6967
|
+
//移除子元素(无限级别)中的所有 class name 的loading 遮罩
|
|
6968
|
+
//level 层级,数字,比如第一次调用,传入1, 第一次里面产生的第二次调用,这里就是2
|
|
6969
|
+
removeChildClass:function(node, level){
|
|
6970
|
+
|
|
6971
|
+
//判断是否有子元素,判断其两级子元素,是否有加了loading遮罩了
|
|
6972
|
+
var childNodes = node.childNodes;
|
|
6973
|
+
if(childNodes == null || typeof(childNodes) == 'undefined'){
|
|
6974
|
+
|
|
6975
|
+
}else if(childNodes.length > 0){
|
|
6976
|
+
for(var i = 0; i<childNodes.length; i++){
|
|
6977
|
+
translate.progress.api.removeChildClass(childNodes[i], level+1);
|
|
6978
|
+
}
|
|
6979
|
+
}
|
|
6980
|
+
|
|
6981
|
+
if(level == 1){
|
|
6982
|
+
//第一次调用,是不删除本身的class name
|
|
6983
|
+
return;
|
|
6984
|
+
}
|
|
6985
|
+
if(typeof(node) == 'undefined'){
|
|
6986
|
+
return;
|
|
6987
|
+
}
|
|
6988
|
+
if(typeof(node.className) != 'string'){
|
|
6989
|
+
return;
|
|
6990
|
+
}
|
|
6991
|
+
if(node.className.indexOf('translate_api_in_progress') < -1){
|
|
6992
|
+
return;
|
|
6993
|
+
}
|
|
6994
|
+
node.className = node.className.replace(/translate_api_in_progress/g, '');
|
|
6995
|
+
},
|
|
6184
6996
|
startUITip:function(){
|
|
6185
6997
|
// 创建一个 style 元素
|
|
6186
6998
|
const style = document.createElement('style');
|
|
6187
6999
|
// 设置 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
|
-
`;
|
|
7000
|
+
style.textContent = translate.progress.style;
|
|
6239
7001
|
// 将 style 元素插入到 head 元素中
|
|
6240
7002
|
document.head.appendChild(style);
|
|
6241
7003
|
|
|
6242
7004
|
|
|
6243
7005
|
if(translate.progress.api.isTip){
|
|
6244
7006
|
translate.listener.execute.renderStartByApi.push(function(uuid, from, to){
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
7007
|
+
|
|
7008
|
+
for(var hash in translate.nodeQueue[uuid].list[from]){
|
|
7009
|
+
if (!translate.nodeQueue[uuid].list[from].hasOwnProperty(hash)) {
|
|
7010
|
+
continue;
|
|
7011
|
+
}
|
|
7012
|
+
for(var nodeindex in translate.nodeQueue[uuid].list[from][hash].nodes){
|
|
7013
|
+
if (!translate.nodeQueue[uuid].list[from][hash].nodes.hasOwnProperty(nodeindex)) {
|
|
7014
|
+
continue;
|
|
7015
|
+
}
|
|
7016
|
+
var node = translate.nodeQueue[uuid].list[from][hash].nodes[nodeindex].node;
|
|
7017
|
+
|
|
7018
|
+
if(typeof(node) == 'undefined' || typeof(node.parentNode) == 'undefined'){
|
|
7019
|
+
continue;
|
|
7020
|
+
}
|
|
7021
|
+
var nodeParent = node.parentNode;
|
|
7022
|
+
if(nodeParent == null){
|
|
7023
|
+
continue;
|
|
7024
|
+
}
|
|
7025
|
+
/* 这里先不考虑多隐藏的问题,只要符合的都隐藏,宁愿吧一些不需要隐藏的也会跟着一起隐藏
|
|
7026
|
+
if(nodeParent.childNodes.length != 1){
|
|
7027
|
+
//这个文本节点所在的元素里,不止有这一个文本元素,还有别的文本元素
|
|
7028
|
+
continue;
|
|
7029
|
+
}
|
|
7030
|
+
*/
|
|
7031
|
+
|
|
7032
|
+
|
|
7033
|
+
//判断其在上一层的父级是否已经加了,如果父级加了,那作为子集就不需要在加了,免得出现两个重合的 loading 遮罩
|
|
7034
|
+
var nodeParentParent = node.parentNode;
|
|
7035
|
+
if(nodeParentParent != null && typeof(nodeParentParent.className) != 'undefined' && nodeParentParent.className != null && nodeParent.className.indexOf('translate_api_in_progress') > -1){
|
|
7036
|
+
//父有了,那么子就不需要再加了
|
|
7037
|
+
continue;
|
|
7038
|
+
}
|
|
7039
|
+
//判断是否有子元素,判断其两级子元素,是否有加了loading遮罩了
|
|
7040
|
+
translate.progress.api.removeChildClass(nodeParent, 1);
|
|
7041
|
+
|
|
6275
7042
|
|
|
6276
|
-
|
|
7043
|
+
if(typeof(nodeParent.className) == 'undefined' || nodeParent.className == null || nodeParent.className == ''){
|
|
7044
|
+
nodeParent.className = ' translate_api_in_progress';
|
|
7045
|
+
}else{
|
|
7046
|
+
//这个元素本身有class了,那就追加
|
|
7047
|
+
if(nodeParent.className.indexOf('translate_api_in_progress') > -1){
|
|
7048
|
+
continue;
|
|
6277
7049
|
}
|
|
7050
|
+
nodeParent.className = nodeParent.className+' translate_api_in_progress';
|
|
7051
|
+
}
|
|
6278
7052
|
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
7053
|
+
}
|
|
7054
|
+
}
|
|
7055
|
+
|
|
6282
7056
|
});
|
|
6283
7057
|
translate.listener.execute.renderFinishByApi.push(function(uuid, from, to){
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
7058
|
+
for(var hash in translate.nodeQueue[uuid].list[from]){
|
|
7059
|
+
if (!translate.nodeQueue[uuid].list[from].hasOwnProperty(hash)) {
|
|
7060
|
+
continue;
|
|
7061
|
+
}
|
|
7062
|
+
|
|
6287
7063
|
for(var nodeindex in translate.nodeQueue[uuid].list[from][hash].nodes){
|
|
7064
|
+
if (!translate.nodeQueue[uuid].list[from][hash].nodes.hasOwnProperty(nodeindex)) {
|
|
7065
|
+
continue;
|
|
7066
|
+
}
|
|
7067
|
+
|
|
6288
7068
|
var node = translate.nodeQueue[uuid].list[from][hash].nodes[nodeindex].node;
|
|
6289
7069
|
var nodeParent = node.parentNode;
|
|
6290
7070
|
if(nodeParent == null){
|
|
@@ -6306,6 +7086,7 @@ var translate = {
|
|
|
6306
7086
|
continue;
|
|
6307
7087
|
}
|
|
6308
7088
|
|
|
7089
|
+
|
|
6309
7090
|
nodeParent.className = parentClassName.replace(/translate_api_in_progress/g, '');
|
|
6310
7091
|
//nodeParent.className = parentClassName.replace(/loading/g, '');
|
|
6311
7092
|
}
|
|
@@ -6317,6 +7098,7 @@ var translate = {
|
|
|
6317
7098
|
}
|
|
6318
7099
|
}
|
|
6319
7100
|
},
|
|
7101
|
+
/*js translate.progress end*/
|
|
6320
7102
|
|
|
6321
7103
|
/*js dispose start*/
|
|
6322
7104
|
/*
|
|
@@ -6483,7 +7265,684 @@ var translate = {
|
|
|
6483
7265
|
},
|
|
6484
7266
|
/*js dispose end*/
|
|
6485
7267
|
|
|
7268
|
+
/*js translate.network start*/
|
|
7269
|
+
/*
|
|
7270
|
+
网络请求数据拦截并翻译
|
|
7271
|
+
当用户触发ajax请求时,它可以针对ajax请求中的某个参数,进行获取,并进行翻译,将翻译后的文本赋予这个参数,然后再放开请求。
|
|
7272
|
+
|
|
7273
|
+
使用场景如:
|
|
7274
|
+
搜索场景,原本是中文的页面,翻译为英文后,给美国人使用,美国人使用时,进行搜索,输入的是英文,然后点击搜索按钮,发起搜索。
|
|
7275
|
+
然后此会拦截网络请求,将请求中用户输入的搜索文本的内容提取出来,识别它输入的是中文还是英文,如果不是本地的语种中文,那就将其翻译为中文,然后再赋予此请求的这个参数中,然后再放开这次请求。
|
|
7276
|
+
这样请求真正到达服务端接口时,服务端接受到的搜索的文本内容实际就是翻译后的中文文本,而不是用户输入的英文文本。
|
|
7277
|
+
|
|
7278
|
+
何时自动进行翻译:
|
|
7279
|
+
1. 当前用户没有进行切换语言
|
|
7280
|
+
2. 切换语言了,但是输入的文本的语言是不需要进行翻译的, 输入的文本本身就是本地的语言
|
|
7281
|
+
这两种情况那就不需要拦截翻译
|
|
7282
|
+
|
|
6486
7283
|
|
|
7284
|
+
*/
|
|
7285
|
+
network: {
|
|
7286
|
+
// 原始方法保存
|
|
7287
|
+
originalOpen: XMLHttpRequest.prototype.open,
|
|
7288
|
+
originalSend: XMLHttpRequest.prototype.send,
|
|
7289
|
+
setRequestHeaderOriginal: XMLHttpRequest.prototype.setRequestHeader,
|
|
7290
|
+
|
|
7291
|
+
// 规则配置
|
|
7292
|
+
rules: [
|
|
7293
|
+
{
|
|
7294
|
+
url: /https:\/\/www\.guanleiming\.com\/a\/b\/.html/,
|
|
7295
|
+
methods: ['GET', 'POST'],
|
|
7296
|
+
params: ['a','b1']
|
|
7297
|
+
}
|
|
7298
|
+
],
|
|
7299
|
+
//根据 当前请求的url 跟 method 来判断当前请求是否符合规则,
|
|
7300
|
+
//如果符合,则返回符合的 rule 规则,也就是 translate.network.rules 中配置的某个。
|
|
7301
|
+
//如果没有找到符合的,则返回 null
|
|
7302
|
+
getRuleMatch:function(url, method){
|
|
7303
|
+
for (let i = 0; i < translate.network.rules.length; i++) {
|
|
7304
|
+
const rule = translate.network.rules[i];
|
|
7305
|
+
|
|
7306
|
+
// 检查 URL 是否匹配
|
|
7307
|
+
if(typeof(rule.url) == 'undefined' && rule.url == ''){
|
|
7308
|
+
console.log('WARINNG : translate.network.rule find url is null:');
|
|
7309
|
+
console.log(rule);
|
|
7310
|
+
continue;
|
|
7311
|
+
}
|
|
7312
|
+
//console.log(rule);
|
|
7313
|
+
const isUrlMatch = rule.url.test(url);
|
|
7314
|
+
if(!isUrlMatch){
|
|
7315
|
+
continue;
|
|
7316
|
+
}
|
|
7317
|
+
|
|
7318
|
+
// 检查方法是否匹配(忽略大小写)
|
|
7319
|
+
const isMethodMatch = rule.methods.includes(method.toUpperCase());
|
|
7320
|
+
if(!isMethodMatch){
|
|
7321
|
+
continue;
|
|
7322
|
+
}
|
|
7323
|
+
|
|
7324
|
+
return rule;
|
|
7325
|
+
}
|
|
7326
|
+
|
|
7327
|
+
return null;
|
|
7328
|
+
},
|
|
7329
|
+
use:function(){
|
|
7330
|
+
// 应用Hook
|
|
7331
|
+
XMLHttpRequest.prototype.open = function(...args) {
|
|
7332
|
+
return translate.network.hookOpen.apply(this, args);
|
|
7333
|
+
};
|
|
7334
|
+
|
|
7335
|
+
XMLHttpRequest.prototype.send = function(...args) {
|
|
7336
|
+
return translate.network.hookSend.apply(this, args);
|
|
7337
|
+
};
|
|
7338
|
+
|
|
7339
|
+
// 劫持 setRequestHeader 方法
|
|
7340
|
+
XMLHttpRequest.prototype.setRequestHeader = function(...args) {
|
|
7341
|
+
return translate.network.setRequestHeader.apply(this, args);
|
|
7342
|
+
};
|
|
7343
|
+
|
|
7344
|
+
translate.network.fetch.use();
|
|
7345
|
+
},
|
|
7346
|
+
// 私有工具方法
|
|
7347
|
+
_translateText(text) {
|
|
7348
|
+
if(translate.language.getLocal() == translate.language.getCurrent() || (typeof(text) == 'string' && text.length > 0 && translate.language.recognition(text).languageName == translate.language.getLocal())){
|
|
7349
|
+
/*
|
|
7350
|
+
1. 没有进行切换语言
|
|
7351
|
+
2. 切换语言了,但是输入的文本的语言是不需要进行翻译的, 输入的文本本身就是本地的语言
|
|
7352
|
+
|
|
7353
|
+
这两种情况那就不需要拦截翻译
|
|
7354
|
+
*/
|
|
7355
|
+
|
|
7356
|
+
return new Promise((resolve, reject) => {
|
|
7357
|
+
const obj = {
|
|
7358
|
+
from: 'auto',
|
|
7359
|
+
to: translate.language.getLocal(),
|
|
7360
|
+
text: [text]
|
|
7361
|
+
};
|
|
7362
|
+
|
|
7363
|
+
resolve(obj);
|
|
7364
|
+
});
|
|
7365
|
+
}else{
|
|
7366
|
+
//有进行切换了,那进行翻译,将其他语种翻译为当前的本地语种
|
|
7367
|
+
return new Promise((resolve, reject) => {
|
|
7368
|
+
const obj = {
|
|
7369
|
+
from: 'auto',
|
|
7370
|
+
to: translate.language.getLocal(),
|
|
7371
|
+
texts: [text]
|
|
7372
|
+
};
|
|
7373
|
+
|
|
7374
|
+
//console.log('翻译请求:', obj);
|
|
7375
|
+
translate.request.translateText(obj, function(data) {
|
|
7376
|
+
if (data.result === 1) {
|
|
7377
|
+
resolve(data);
|
|
7378
|
+
} else {
|
|
7379
|
+
reject(data);
|
|
7380
|
+
}
|
|
7381
|
+
});
|
|
7382
|
+
});
|
|
7383
|
+
}
|
|
7384
|
+
|
|
7385
|
+
},
|
|
7386
|
+
//劫持 setRequestHeader
|
|
7387
|
+
setRequestHeader: function(header, value) {
|
|
7388
|
+
if (this._requestContext) {
|
|
7389
|
+
this._requestContext.headers = this._requestContext.headers || {};
|
|
7390
|
+
this._requestContext.headers[header] = value;
|
|
7391
|
+
}
|
|
7392
|
+
|
|
7393
|
+
return translate.network.setRequestHeaderOriginal.call(this, header, value);
|
|
7394
|
+
},
|
|
7395
|
+
// 请求处理工具
|
|
7396
|
+
RequestHandler: {
|
|
7397
|
+
async handleGet(url, rule) {
|
|
7398
|
+
//console.log(url);
|
|
7399
|
+
//console.log(rule);
|
|
7400
|
+
if(typeof(rule.params) == 'undefined' && typeof(rule.params.length) == 'undefined' && rule.params.length < 1){
|
|
7401
|
+
console.log('WARINNG: rule not find params , rule : ');
|
|
7402
|
+
console.log(rule);
|
|
7403
|
+
rule.params = [];
|
|
7404
|
+
}
|
|
7405
|
+
|
|
7406
|
+
|
|
7407
|
+
try {
|
|
7408
|
+
const urlObj = new URL(url, window.location.origin);
|
|
7409
|
+
const params = urlObj.searchParams;
|
|
7410
|
+
//console.log(rule.params);
|
|
7411
|
+
|
|
7412
|
+
//for (const paramName in rule.params) {
|
|
7413
|
+
for(var p = 0; p < rule.params.length; p++){
|
|
7414
|
+
var paramName = rule.params[p];
|
|
7415
|
+
//console.log(paramName);
|
|
7416
|
+
if (params.has(paramName)) {
|
|
7417
|
+
const original = params.get(paramName);
|
|
7418
|
+
const translateResultData = await translate.network._translateText(original);
|
|
7419
|
+
|
|
7420
|
+
if(typeof(translateResultData) == 'undefined'){
|
|
7421
|
+
console.log('WARINNG: translateResultData is undefined');
|
|
7422
|
+
}else if(typeof(translateResultData.result) == 'undefined'){
|
|
7423
|
+
console.log('WARINNG: translateResultData.result is undefined');
|
|
7424
|
+
}else if(translateResultData.result != 1){
|
|
7425
|
+
console.log('WARINNG: translateResultData.result failure : '+translateResultData.info);
|
|
7426
|
+
}else{
|
|
7427
|
+
params.set(paramName, decodeURIComponent(translateResultData.text[0]));
|
|
7428
|
+
}
|
|
7429
|
+
|
|
7430
|
+
}
|
|
7431
|
+
}
|
|
7432
|
+
|
|
7433
|
+
return urlObj.toString();
|
|
7434
|
+
} catch (e) {
|
|
7435
|
+
console.warn('GET处理失败:', e);
|
|
7436
|
+
return url;
|
|
7437
|
+
}
|
|
7438
|
+
},
|
|
7439
|
+
|
|
7440
|
+
async handleForm(body, rule) {
|
|
7441
|
+
try {
|
|
7442
|
+
const params = new URLSearchParams(body);
|
|
7443
|
+
const modified = {...params};
|
|
7444
|
+
|
|
7445
|
+
for (const paramName of rule.params) {
|
|
7446
|
+
if (params.has(paramName)) {
|
|
7447
|
+
const original = params.get(paramName);
|
|
7448
|
+
const translated = await translate.network._translateText(original);
|
|
7449
|
+
modified[paramName] = translated;
|
|
7450
|
+
}
|
|
7451
|
+
}
|
|
7452
|
+
|
|
7453
|
+
return new URLSearchParams(modified).toString();
|
|
7454
|
+
} catch (e) {
|
|
7455
|
+
console.warn('表单处理失败:', e);
|
|
7456
|
+
return body;
|
|
7457
|
+
}
|
|
7458
|
+
},
|
|
7459
|
+
|
|
7460
|
+
async handleJson(body, rule) {
|
|
7461
|
+
try {
|
|
7462
|
+
const json = JSON.parse(body);
|
|
7463
|
+
const modified = {...json};
|
|
7464
|
+
|
|
7465
|
+
for (const paramName of rule.params) {
|
|
7466
|
+
if (modified.hasOwnProperty(paramName)) {
|
|
7467
|
+
const original = modified[paramName];
|
|
7468
|
+
modified[paramName] = await translate.network._translateText(original);
|
|
7469
|
+
}
|
|
7470
|
+
}
|
|
7471
|
+
|
|
7472
|
+
return JSON.stringify(modified);
|
|
7473
|
+
} catch (e) {
|
|
7474
|
+
console.warn('JSON处理失败:', e);
|
|
7475
|
+
return body;
|
|
7476
|
+
}
|
|
7477
|
+
}
|
|
7478
|
+
},
|
|
7479
|
+
|
|
7480
|
+
// 请求上下文管理
|
|
7481
|
+
_requestContext: null,
|
|
7482
|
+
|
|
7483
|
+
|
|
7484
|
+
|
|
7485
|
+
// Hook open 方法
|
|
7486
|
+
hookOpen(method, url, async, user, password) {
|
|
7487
|
+
let matchedRule = null;
|
|
7488
|
+
this._requestContext = {
|
|
7489
|
+
method: method.toUpperCase(),
|
|
7490
|
+
originalUrl: url,
|
|
7491
|
+
async: async,
|
|
7492
|
+
user: user,
|
|
7493
|
+
password: password,
|
|
7494
|
+
matchedRule: translate.network.getRuleMatch(url, method)
|
|
7495
|
+
};
|
|
7496
|
+
|
|
7497
|
+
return translate.network.originalOpen.call(this, method, url, async, user, password);
|
|
7498
|
+
},
|
|
7499
|
+
|
|
7500
|
+
// Hook send 方法
|
|
7501
|
+
hookSend(body) {
|
|
7502
|
+
const ctx = this._requestContext;
|
|
7503
|
+
if (!ctx || !ctx.matchedRule) {
|
|
7504
|
+
return translate.network.originalSend.call(this, body);
|
|
7505
|
+
}
|
|
7506
|
+
|
|
7507
|
+
const processRequest = async () => {
|
|
7508
|
+
let modifiedBody = body;
|
|
7509
|
+
const method = ctx.method;
|
|
7510
|
+
|
|
7511
|
+
try {
|
|
7512
|
+
// 处理GET请求
|
|
7513
|
+
//if (method === 'GET') {
|
|
7514
|
+
const newUrl = await translate.network.RequestHandler.handleGet(ctx.originalUrl, ctx.matchedRule);
|
|
7515
|
+
translate.network.originalOpen.call(this, method, newUrl, ctx.async, ctx.user, ctx.password);
|
|
7516
|
+
//}
|
|
7517
|
+
|
|
7518
|
+
// 恢复请求头
|
|
7519
|
+
if (ctx.headers) {
|
|
7520
|
+
for (const header in ctx.headers) {
|
|
7521
|
+
translate.network.setRequestHeaderOriginal.call(this, header, ctx.headers[header]);
|
|
7522
|
+
}
|
|
7523
|
+
}
|
|
7524
|
+
|
|
7525
|
+
// 处理POST请求
|
|
7526
|
+
if (method === 'POST') {
|
|
7527
|
+
if(typeof(body) != 'undefined' && body != null && body.length < 2000){
|
|
7528
|
+
var isJsonBody = false; //是否是json格式的数据,是否json已经处理了, true 是
|
|
7529
|
+
if(body.trim().indexOf('[') == 0 || body.trim().indexOf('{') == 0){
|
|
7530
|
+
//可能是json
|
|
7531
|
+
try{
|
|
7532
|
+
modifiedBody = await translate.network.RequestHandler.handleJson(body, ctx.matchedRule);
|
|
7533
|
+
isJsonBody = true;
|
|
7534
|
+
}catch(je){
|
|
7535
|
+
isJsonBody = false;
|
|
7536
|
+
}
|
|
7537
|
+
}
|
|
7538
|
+
if(!isJsonBody){
|
|
7539
|
+
try{
|
|
7540
|
+
modifiedBody = await translate.network.RequestHandler.handleForm(body, ctx.matchedRule);
|
|
7541
|
+
}catch(je){
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
}
|
|
7545
|
+
}
|
|
7546
|
+
} catch (e) {
|
|
7547
|
+
console.warn('请求处理异常:', e);
|
|
7548
|
+
}
|
|
7549
|
+
|
|
7550
|
+
translate.network.originalSend.call(this, modifiedBody);
|
|
7551
|
+
};
|
|
7552
|
+
|
|
7553
|
+
// 异步处理
|
|
7554
|
+
if (ctx.async !== false) {
|
|
7555
|
+
processRequest.call(this);
|
|
7556
|
+
} else {
|
|
7557
|
+
console.warn('同步请求不支持翻译拦截');
|
|
7558
|
+
translate.network.originalSend.call(this, body);
|
|
7559
|
+
}
|
|
7560
|
+
},
|
|
7561
|
+
//fetch请求
|
|
7562
|
+
fetch:{
|
|
7563
|
+
originalFetch: window.fetch,
|
|
7564
|
+
|
|
7565
|
+
// 保存原始 fetch 方法
|
|
7566
|
+
use: function () {
|
|
7567
|
+
const self = this;
|
|
7568
|
+
window.fetch = function (...args) {
|
|
7569
|
+
return self.hookFetch.apply(self, args);
|
|
7570
|
+
};
|
|
7571
|
+
},
|
|
7572
|
+
|
|
7573
|
+
// 拦截 fetch 请求
|
|
7574
|
+
hookFetch: async function (input, init) {
|
|
7575
|
+
const request = new Request(input, init);
|
|
7576
|
+
const url = request.url;
|
|
7577
|
+
const method = request.method;
|
|
7578
|
+
|
|
7579
|
+
// 获取匹配规则
|
|
7580
|
+
const rule = translate.network.getRuleMatch(url, method);
|
|
7581
|
+
if (!rule) {
|
|
7582
|
+
return this.originalFetch.call(window, request);
|
|
7583
|
+
}
|
|
7584
|
+
|
|
7585
|
+
// 初始化请求上下文
|
|
7586
|
+
const ctx = {
|
|
7587
|
+
method,
|
|
7588
|
+
url,
|
|
7589
|
+
headers: {},
|
|
7590
|
+
rule,
|
|
7591
|
+
isModified: false
|
|
7592
|
+
};
|
|
7593
|
+
|
|
7594
|
+
// 保存请求头
|
|
7595
|
+
request.headers.forEach((value, key) => {
|
|
7596
|
+
ctx.headers[key] = value;
|
|
7597
|
+
});
|
|
7598
|
+
|
|
7599
|
+
this._requestContext = ctx;
|
|
7600
|
+
|
|
7601
|
+
try {
|
|
7602
|
+
const newUrl = await translate.network.RequestHandler.handleGet(url, rule);
|
|
7603
|
+
// 处理 GET 请求
|
|
7604
|
+
if (method === 'GET') {
|
|
7605
|
+
|
|
7606
|
+
const newRequest = new Request(newUrl, {
|
|
7607
|
+
method,
|
|
7608
|
+
headers: new Headers(ctx.headers),
|
|
7609
|
+
mode: request.mode,
|
|
7610
|
+
credentials: request.credentials,
|
|
7611
|
+
cache: request.cache,
|
|
7612
|
+
redirect: request.redirect,
|
|
7613
|
+
referrer: request.referrer,
|
|
7614
|
+
referrerPolicy: request.referrerPolicy
|
|
7615
|
+
});
|
|
7616
|
+
return this.originalFetch.call(window, newRequest);
|
|
7617
|
+
}
|
|
7618
|
+
|
|
7619
|
+
// 处理 POST 请求
|
|
7620
|
+
if (method === 'POST') {
|
|
7621
|
+
let body = null;
|
|
7622
|
+
if (request.body) {
|
|
7623
|
+
body = await request.clone().text();
|
|
7624
|
+
}
|
|
7625
|
+
|
|
7626
|
+
const contentType = request.headers.get('Content-Type');
|
|
7627
|
+
let modifiedBody = body;
|
|
7628
|
+
|
|
7629
|
+
if(typeof(body) != 'undefined' && body != null && body.length < 2000){
|
|
7630
|
+
var isJsonBody = false; //是否是json格式的数据,是否json已经处理了, true 是
|
|
7631
|
+
if(body.trim().indexOf('[') == 0 || body.trim().indexOf('{') == 0){
|
|
7632
|
+
//可能是json
|
|
7633
|
+
try{
|
|
7634
|
+
modifiedBody = await translate.network.RequestHandler.handleJson(body, rule);
|
|
7635
|
+
isJsonBody = true;
|
|
7636
|
+
}catch(je){
|
|
7637
|
+
isJsonBody = false;
|
|
7638
|
+
}
|
|
7639
|
+
}
|
|
7640
|
+
if(!isJsonBody){
|
|
7641
|
+
try{
|
|
7642
|
+
modifiedBody = await translate.network.RequestHandler.handleForm(body, rule);
|
|
7643
|
+
}catch(je){
|
|
7644
|
+
}
|
|
7645
|
+
}
|
|
7646
|
+
}
|
|
7647
|
+
|
|
7648
|
+
const newRequest = new Request(newUrl, {
|
|
7649
|
+
method,
|
|
7650
|
+
headers: new Headers(ctx.headers),
|
|
7651
|
+
body: modifiedBody,
|
|
7652
|
+
mode: request.mode,
|
|
7653
|
+
credentials: request.credentials,
|
|
7654
|
+
cache: request.cache,
|
|
7655
|
+
redirect: request.redirect,
|
|
7656
|
+
referrer: request.referrer,
|
|
7657
|
+
referrerPolicy: request.referrerPolicy
|
|
7658
|
+
});
|
|
7659
|
+
|
|
7660
|
+
return this.originalFetch.call(window, newRequest);
|
|
7661
|
+
}
|
|
7662
|
+
|
|
7663
|
+
// 其他方法直接返回原始请求
|
|
7664
|
+
return this.originalFetch.call(window, request);
|
|
7665
|
+
} catch (e) {
|
|
7666
|
+
console.warn('fetch 请求处理异常:', e);
|
|
7667
|
+
return this.originalFetch.call(window, request);
|
|
7668
|
+
}
|
|
7669
|
+
},
|
|
7670
|
+
// 请求上下文管理
|
|
7671
|
+
_requestContext: null
|
|
7672
|
+
|
|
7673
|
+
}
|
|
7674
|
+
},
|
|
7675
|
+
|
|
7676
|
+
/*js translate.network end*/
|
|
7677
|
+
|
|
7678
|
+
|
|
7679
|
+
/*js translate.visual start*/
|
|
7680
|
+
/*
|
|
7681
|
+
人眼所看到的纯视觉层的处理
|
|
7682
|
+
*/
|
|
7683
|
+
visual: {
|
|
7684
|
+
/**
|
|
7685
|
+
* 获取一组节点的视觉矩形信息
|
|
7686
|
+
* @param {Node[]} nodes - 节点数组,格式如
|
|
7687
|
+
* [node1,node2,node3]
|
|
7688
|
+
* @returns {Object[]} - 矩形信息数组,与输入节点一一对应
|
|
7689
|
+
*/
|
|
7690
|
+
getRects:function(nodes){
|
|
7691
|
+
return nodes.map(node => {
|
|
7692
|
+
if (!node) return null;
|
|
7693
|
+
|
|
7694
|
+
let rect;
|
|
7695
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
7696
|
+
const range = document.createRange();
|
|
7697
|
+
range.selectNodeContents(node);
|
|
7698
|
+
const rects = range.getClientRects();
|
|
7699
|
+
//console.log(rect);
|
|
7700
|
+
rect = rects.length > 0 ? rects[0] : null;
|
|
7701
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
7702
|
+
rect = node.getBoundingClientRect();
|
|
7703
|
+
}
|
|
7704
|
+
|
|
7705
|
+
return rect ? {
|
|
7706
|
+
node,
|
|
7707
|
+
left: rect.left,
|
|
7708
|
+
top: rect.top,
|
|
7709
|
+
right: rect.right,
|
|
7710
|
+
bottom: rect.bottom,
|
|
7711
|
+
width: rect.width,
|
|
7712
|
+
height: rect.height
|
|
7713
|
+
} : null;
|
|
7714
|
+
});
|
|
7715
|
+
},
|
|
7716
|
+
/*
|
|
7717
|
+
对一组坐标进行排序
|
|
7718
|
+
按开始坐标从左到右、从上到下排序
|
|
7719
|
+
@param rects translate.visual.getRects获取到的坐标数据
|
|
7720
|
+
*/
|
|
7721
|
+
coordinateSort:function(rects){
|
|
7722
|
+
// 按从左到右、从上到下排序
|
|
7723
|
+
const sortedRects = rects
|
|
7724
|
+
.filter(rect => rect !== null)
|
|
7725
|
+
.sort((a, b) => {
|
|
7726
|
+
if (Math.abs(a.top - b.top) < 5) { // 同一行
|
|
7727
|
+
return a.left - b.left;
|
|
7728
|
+
}
|
|
7729
|
+
return a.top - b.top;
|
|
7730
|
+
});
|
|
7731
|
+
return sortedRects;
|
|
7732
|
+
},
|
|
7733
|
+
/**
|
|
7734
|
+
* 查找左右紧邻的矩形对
|
|
7735
|
+
* @param rects translate.visual.getRects获取到的坐标数据
|
|
7736
|
+
* @returns {Array<{before: Object, after: Object}>} - 左右紧邻的矩形对数组
|
|
7737
|
+
*/
|
|
7738
|
+
afterAdjacent:function(rects){
|
|
7739
|
+
var sortedRects = translate.visual.coordinateSort(rects);
|
|
7740
|
+
|
|
7741
|
+
const adjacentPairs = [];
|
|
7742
|
+
const lineGroups = translate.visual.groupRectsByLine(sortedRects);
|
|
7743
|
+
|
|
7744
|
+
// 检查每行中的所有紧邻元素对
|
|
7745
|
+
lineGroups.forEach(line => {
|
|
7746
|
+
for (let i = 0; i < line.length; i++) {
|
|
7747
|
+
for (let j = i + 1; j < line.length; j++) {
|
|
7748
|
+
const prev = line[i];
|
|
7749
|
+
const next = line[j];
|
|
7750
|
+
|
|
7751
|
+
// 如果后续元素与当前元素不紧邻,则后续其他元素也不可能紧邻
|
|
7752
|
+
if (!translate.visual.areHorizontallyAdjacent(prev, next)) {
|
|
7753
|
+
break;
|
|
7754
|
+
}
|
|
7755
|
+
|
|
7756
|
+
adjacentPairs.push({ before: prev, after: next });
|
|
7757
|
+
}
|
|
7758
|
+
}
|
|
7759
|
+
});
|
|
7760
|
+
|
|
7761
|
+
return adjacentPairs;
|
|
7762
|
+
},
|
|
7763
|
+
/**
|
|
7764
|
+
* 按行分组矩形
|
|
7765
|
+
* @param rects - 排序后的矩形数组 @param rects translate.visual.coordinateSort 获取到的坐标数据
|
|
7766
|
+
* @returns {Object[][]} - 按行分组的矩形
|
|
7767
|
+
*/
|
|
7768
|
+
groupRectsByLine:function(rects){
|
|
7769
|
+
const lineGroups = [];
|
|
7770
|
+
let currentLine = [];
|
|
7771
|
+
|
|
7772
|
+
rects.forEach(rect => {
|
|
7773
|
+
if (currentLine.length === 0) {
|
|
7774
|
+
currentLine.push(rect);
|
|
7775
|
+
} else {
|
|
7776
|
+
const lastRect = currentLine[currentLine.length - 1];
|
|
7777
|
+
// 如果在同一行,则添加到当前行
|
|
7778
|
+
if (Math.abs(rect.top - lastRect.top) < 5) {
|
|
7779
|
+
currentLine.push(rect);
|
|
7780
|
+
} else {
|
|
7781
|
+
// 否则开始新的一行
|
|
7782
|
+
lineGroups.push(currentLine);
|
|
7783
|
+
currentLine = [rect];
|
|
7784
|
+
}
|
|
7785
|
+
}
|
|
7786
|
+
});
|
|
7787
|
+
|
|
7788
|
+
// 添加最后一行
|
|
7789
|
+
if (currentLine.length > 0) {
|
|
7790
|
+
lineGroups.push(currentLine);
|
|
7791
|
+
}
|
|
7792
|
+
|
|
7793
|
+
return lineGroups;
|
|
7794
|
+
},
|
|
7795
|
+
/**
|
|
7796
|
+
* 判断两个矩形是否水平紧邻
|
|
7797
|
+
* @param {Object} rect1 - 第一个矩形
|
|
7798
|
+
* @param {Object} rect2 - 第二个矩形
|
|
7799
|
+
* @returns {boolean} - 是否水平紧邻
|
|
7800
|
+
*/
|
|
7801
|
+
areHorizontallyAdjacent:function(rect1, rect2){
|
|
7802
|
+
// 检查垂直方向是否有重叠(在同一行)
|
|
7803
|
+
const verticalOverlap = Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top);
|
|
7804
|
+
|
|
7805
|
+
// 检查水平间距是否在阈值范围内
|
|
7806
|
+
const horizontalGap = rect2.left - rect1.right;
|
|
7807
|
+
|
|
7808
|
+
return verticalOverlap > 0 && Math.abs(horizontalGap) < 1; // 允许1px误差
|
|
7809
|
+
},
|
|
7810
|
+
/**
|
|
7811
|
+
* 找到需要在节点文本末尾添加空格的节点
|
|
7812
|
+
* @param {Array<{before: Object, after: Object}>} adjacentPairs - 左右紧邻的矩形对数组
|
|
7813
|
+
* @returns {Node[]} - 需要添加空格的节点数组
|
|
7814
|
+
*/
|
|
7815
|
+
afterAddSpace:function(adjacentPairs){
|
|
7816
|
+
|
|
7817
|
+
const nodesToAddSpace = [];
|
|
7818
|
+
|
|
7819
|
+
adjacentPairs.forEach(pair => {
|
|
7820
|
+
const { before, after } = pair;
|
|
7821
|
+
const beforeNode = before.node;
|
|
7822
|
+
const afterNode = after.node;
|
|
7823
|
+
|
|
7824
|
+
// 获取计算样式
|
|
7825
|
+
const beforeStyle = window.getComputedStyle(
|
|
7826
|
+
beforeNode.nodeType === Node.TEXT_NODE ? beforeNode.parentElement : beforeNode
|
|
7827
|
+
);
|
|
7828
|
+
|
|
7829
|
+
const afterStyle = window.getComputedStyle(
|
|
7830
|
+
afterNode.nodeType === Node.TEXT_NODE ? afterNode.parentElement : afterNode
|
|
7831
|
+
);
|
|
7832
|
+
|
|
7833
|
+
// 检查间距是否由CSS属性引起
|
|
7834
|
+
const hasRightSpacing = parseFloat(beforeStyle.marginRight) > 0 ||
|
|
7835
|
+
parseFloat(beforeStyle.paddingRight) > 0;
|
|
7836
|
+
|
|
7837
|
+
const hasLeftSpacing = parseFloat(afterStyle.marginLeft) > 0 ||
|
|
7838
|
+
parseFloat(afterStyle.paddingLeft) > 0;
|
|
7839
|
+
|
|
7840
|
+
// 如果没有明确的间距,且后一个节点的开始非空白符,则需要添加空格
|
|
7841
|
+
if (!hasRightSpacing && !hasLeftSpacing) {
|
|
7842
|
+
//判断 before 节点的最后一个字符是否是空白符
|
|
7843
|
+
if(typeof(beforeNode.textContent) == 'string' && typeof(afterNode.textContent) == 'string'){
|
|
7844
|
+
if(/\s$/.test(beforeNode.textContent)){
|
|
7845
|
+
//before 最后一个字符是空格,则不需要追加空格符了
|
|
7846
|
+
}else if(/^\s/.test(afterNode.textContent)){
|
|
7847
|
+
//after 节点的开始第一个字符是空白符,那么也不需要追加空格符了
|
|
7848
|
+
}else{
|
|
7849
|
+
//这里就需要对 beforeNode 追加空格了
|
|
7850
|
+
nodesToAddSpace.push(beforeNode);
|
|
7851
|
+
}
|
|
7852
|
+
}
|
|
7853
|
+
}
|
|
7854
|
+
});
|
|
7855
|
+
|
|
7856
|
+
return nodesToAddSpace;
|
|
7857
|
+
},
|
|
7858
|
+
/**
|
|
7859
|
+
* 主函数:处理翻译后的空格调整
|
|
7860
|
+
* @param {Node[]} nodes - 节点数组
|
|
7861
|
+
*/
|
|
7862
|
+
adjustTranslationSpaces:function(nodes){
|
|
7863
|
+
|
|
7864
|
+
//先判断当前要显示的语种,是否需要用空格进行间隔单词,如果本身不需要空格间隔,像是中文,那就根本不需要去计算视觉距离
|
|
7865
|
+
if(!translate.language.wordBlankConnector(translate.to)){
|
|
7866
|
+
return;
|
|
7867
|
+
}
|
|
7868
|
+
|
|
7869
|
+
//var startTime = Date.now();
|
|
7870
|
+
// 1. 获取节点视觉矩形
|
|
7871
|
+
const rects = translate.visual.getRects(nodes);
|
|
7872
|
+
//console.log('rects:');
|
|
7873
|
+
//console.log(rects);
|
|
7874
|
+
|
|
7875
|
+
// 2. 查找左右紧邻的矩形对
|
|
7876
|
+
const adjacentPairs = translate.visual.afterAdjacent(rects);
|
|
7877
|
+
//console.log('adjacentPairs:');
|
|
7878
|
+
//console.log(adjacentPairs);
|
|
7879
|
+
|
|
7880
|
+
// 3. 确定需要添加空格的节点
|
|
7881
|
+
const nodesToAddSpace = translate.visual.afterAddSpace(adjacentPairs);
|
|
7882
|
+
//console.log('nodesToAddSpace:');
|
|
7883
|
+
//console.log(nodesToAddSpace);
|
|
7884
|
+
|
|
7885
|
+
// 4. 添加非断行空格
|
|
7886
|
+
nodesToAddSpace.forEach(node => {
|
|
7887
|
+
// 确保只修改文本内容,不影响HTML结构
|
|
7888
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
7889
|
+
node.textContent = node.textContent + '\u00A0';
|
|
7890
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
7891
|
+
// 如果是元素节点,修改其最后一个子节点(假设是文本节点)
|
|
7892
|
+
const lastChild = node.lastChild;
|
|
7893
|
+
if (lastChild && lastChild.nodeType === Node.TEXT_NODE) {
|
|
7894
|
+
lastChild.textContent = lastChild.textContent + '\u00A0';
|
|
7895
|
+
}
|
|
7896
|
+
}
|
|
7897
|
+
});
|
|
7898
|
+
//var endTime = Date.now();
|
|
7899
|
+
//console.log('visual recognition time: '+(endTime-startTime)+'ms');
|
|
7900
|
+
},
|
|
7901
|
+
/*
|
|
7902
|
+
通过 translate.nodeQueue[uuid] 中的uuid,来传入这个 translate.nodeQueue[uuid] 中所包含涉及到的所有node (除特殊字符外 ,也就是 translate.nodeQueue[uuid].list 下 特殊字符那一类是不会使用的)
|
|
7903
|
+
*/
|
|
7904
|
+
adjustTranslationSpacesByNodequeueUuid:function(uuid){
|
|
7905
|
+
var nodes = [];
|
|
7906
|
+
for(var from in translate.nodeQueue[uuid].list){
|
|
7907
|
+
if (!translate.nodeQueue[uuid].list.hasOwnProperty(from)) {
|
|
7908
|
+
continue;
|
|
7909
|
+
}
|
|
7910
|
+
if(from.length < 1){
|
|
7911
|
+
continue;
|
|
7912
|
+
}
|
|
7913
|
+
for(var hash in translate.nodeQueue[uuid].list[from]){
|
|
7914
|
+
if (!translate.nodeQueue[uuid].list[from].hasOwnProperty(hash)) {
|
|
7915
|
+
continue;
|
|
7916
|
+
}
|
|
7917
|
+
for(var nodeindex in translate.nodeQueue[uuid].list[from][hash].nodes){
|
|
7918
|
+
if (!translate.nodeQueue[uuid].list[from][hash].nodes.hasOwnProperty(nodeindex)) {
|
|
7919
|
+
continue;
|
|
7920
|
+
}
|
|
7921
|
+
var node = translate.nodeQueue[uuid].list[from][hash].nodes[nodeindex].node;
|
|
7922
|
+
nodes.push(node);
|
|
7923
|
+
}
|
|
7924
|
+
}
|
|
7925
|
+
}
|
|
7926
|
+
translate.visual.adjustTranslationSpaces(nodes);
|
|
7927
|
+
},
|
|
7928
|
+
/*
|
|
7929
|
+
通过 translate.nodeQueue 中最后一次执行的 uuid,来获取这个 translate.nodeQueue[uuid] 中所包含涉及到的所有node (除特殊字符外 ,也就是 translate.nodeQueue[uuid].list 下 特殊字符那一类是不会使用的)
|
|
7930
|
+
*/
|
|
7931
|
+
adjustTranslationSpacesByLastNodequeueUuid:function(uuid){
|
|
7932
|
+
var uuid = '';
|
|
7933
|
+
for(var uuid_index in translate.nodeQueue){
|
|
7934
|
+
uuid = uuid_index;
|
|
7935
|
+
break;
|
|
7936
|
+
}
|
|
7937
|
+
if(typeof(uuid) == 'string' && uuid.length > 1){
|
|
7938
|
+
translate.visual.adjustTranslationSpacesByNodequeueUuid(uuid);
|
|
7939
|
+
}
|
|
7940
|
+
}
|
|
7941
|
+
|
|
7942
|
+
|
|
7943
|
+
|
|
7944
|
+
}
|
|
7945
|
+
/*js translate.visual end*/
|
|
6487
7946
|
|
|
6488
7947
|
}
|
|
6489
7948
|
/*
|
|
@@ -6494,7 +7953,7 @@ var translate = {
|
|
|
6494
7953
|
*/
|
|
6495
7954
|
var nodeuuid = {
|
|
6496
7955
|
index:function(node){
|
|
6497
|
-
var parent = node.
|
|
7956
|
+
var parent = node.parentElement;
|
|
6498
7957
|
if(parent == null){
|
|
6499
7958
|
return '';
|
|
6500
7959
|
}
|
|
@@ -6534,29 +7993,18 @@ var nodeuuid = {
|
|
|
6534
7993
|
uuid = id + uuid;
|
|
6535
7994
|
}
|
|
6536
7995
|
//console.log(uuid)
|
|
6537
|
-
n = n.
|
|
7996
|
+
n = n.parentElement;
|
|
6538
7997
|
}
|
|
6539
7998
|
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
|
-
*/
|
|
7999
|
+
}
|
|
8000
|
+
}
|
|
6554
8001
|
|
|
6555
|
-
},
|
|
6556
8002
|
|
|
6557
|
-
|
|
8003
|
+
/*js copyright-notice start*/
|
|
6558
8004
|
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');
|
|
8005
|
+
/*js copyright-notice end*/
|
|
6559
8006
|
|
|
8007
|
+
/*js amd-cmd-commonjs start*/
|
|
6560
8008
|
/*兼容 AMD、CMD、CommonJS 规范 - start*/
|
|
6561
8009
|
/**
|
|
6562
8010
|
* 兼容 AMD、CMD、CommonJS 规范
|
|
@@ -6573,4 +8021,5 @@ console.log('------ translate.js ------\nTwo lines of js html automatic translat
|
|
|
6573
8021
|
})(this, function () {
|
|
6574
8022
|
return translate;
|
|
6575
8023
|
});
|
|
6576
|
-
/*兼容 AMD、CMD、CommonJS 规范 - end*/
|
|
8024
|
+
/*兼容 AMD、CMD、CommonJS 规范 - end*/
|
|
8025
|
+
/*js amd-cmd-commonjs end*/
|