i18n-jsautotranslate 3.13.12 → 3.15.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.
Files changed (4) hide show
  1. package/LICENSE +21 -201
  2. package/README.md +17 -35
  3. package/index.js +585 -284
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -13,8 +13,8 @@ var translate = {
13
13
  * 由 npm 脚本自动更新,无需手动修改
14
14
  * 格式:major.minor.patch.date
15
15
  */
16
- // AUTO_VERSION_START
17
- version: '3.13.12.20250307',
16
+ // AUTO_VERSION_START
17
+ version: '3.15.0.20250429',
18
18
  // AUTO_VERSION_END
19
19
  /*
20
20
  当前使用的版本,默认使用v2. 可使用 setUseVersion2();
@@ -895,7 +895,8 @@ var translate = {
895
895
  translate.listener.addListener();
896
896
  }
897
897
 
898
- //if(translate.listener.isExecuteFinish){ //执行完过一次,那才能使用
898
+ //执行完过一次,那才能使用
899
+ //if(translate.listener.isExecuteFinish){
899
900
  /*if(translate.listener.isStart){
900
901
  //已开启了
901
902
  return;
@@ -1082,13 +1083,17 @@ var translate = {
1082
1083
 
1083
1084
  /*
1084
1085
  每当触发执行 translate.execute() 时,当缓存中未发现,需要请求翻译API进行翻译时,在发送API请求前,触发此
1086
+
1087
+ @param uuid:translate.nodeQueue[uuid] 这里的
1088
+ @param from 来源语种,翻译前的语种
1089
+ @param to 翻译为的语种
1085
1090
  */
1086
1091
  renderStartByApi : [],
1087
- renderStartByApiRun:function(uuid){
1092
+ renderStartByApiRun:function(uuid, from, to){
1088
1093
  //console.log(translate.nodeQueue[uuid]);
1089
1094
  for(var i = 0; i < translate.listener.execute.renderStartByApi.length; i++){
1090
1095
  try{
1091
- translate.listener.execute.renderStartByApi[i](uuid);
1096
+ translate.listener.execute.renderStartByApi[i](uuid, from, to);
1092
1097
  }catch(e){
1093
1098
  console.log(e);
1094
1099
  }
@@ -1097,14 +1102,17 @@ var translate = {
1097
1102
 
1098
1103
  /*
1099
1104
  每当 translate.execute() 执行完毕(前提是采用API翻译的,API将翻译结果返回,并且界面上的翻译结果也已经渲染完毕)后,触发此方法。
1100
- uuid:translate.nodeQueue[uuid] 这里的
1105
+
1106
+ @param uuid:translate.nodeQueue[uuid] 这里的
1107
+ @param from 来源语种,翻译前的语种
1108
+ @param to 翻译为的语种
1101
1109
  */
1102
1110
  renderFinishByApi : [],
1103
- renderFinishByApiRun:function(uuid){
1111
+ renderFinishByApiRun:function(uuid, from, to){
1104
1112
  //console.log(translate.nodeQueue[uuid]);
1105
1113
  for(var i = 0; i < translate.listener.execute.renderFinishByApi.length; i++){
1106
1114
  try{
1107
- translate.listener.execute.renderFinishByApi[i](uuid);
1115
+ translate.listener.execute.renderFinishByApi[i](uuid, from, to);
1108
1116
  }catch(e){
1109
1117
  console.log(e);
1110
1118
  }
@@ -1401,9 +1409,25 @@ var translate = {
1401
1409
  return null;
1402
1410
  }
1403
1411
  },
1404
- //当前 translate.translateRequest[uuid] 的是否已经全部执行完毕,这里单纯只是对 translate.translateRequest[uuid] 的进行判断,这里要在 translate.json 接口触发完并渲染完毕后触发,当然接口失败时也要触发
1405
- isAllExecuteFinish:function(uuid){
1412
+ /*
1413
+ 当前 translate.translateRequest[uuid] 的是否已经全部执行完毕
1414
+ 这里单纯只是对 translate.translateRequest[uuid] 的进行判断
1415
+ 这里要在 translate.json 接口触发完并渲染完毕后触发,当然接口失败时也要触发。
1416
+
1417
+ 正常情况下,是根据本地语言不同,进行分别请求翻译的,比如本地中包含中文、英文、俄语三种语种,要翻译为韩语,那么
1418
+ * 中文->韩语会请求一次api
1419
+ * 英文->韩语会请求一次APi
1420
+ * 俄语->韩语会请求一次APi
1421
+ 也就会触发三次
1422
+
1423
+ @param uuid translate.translateRequest[uuid]中的uuid,也是 translate.nodeQueue 中的uuid
1424
+ @param from 来源语种,翻译前的语种
1425
+ @param to 翻译为的语种
1426
+ */
1427
+ isAllExecuteFinish:function(uuid, from, to){
1428
+ //console.log('uuid:'+uuid+', from:'+from+', to:'+to);
1406
1429
  for(var lang in translate.translateRequest[uuid]){
1430
+ //console.log(translate.translateRequest[uuid])
1407
1431
  for(var i = 0; i<translate.translateRequest[uuid][lang].length; i++){
1408
1432
  if(translate.translateRequest[uuid][lang][i].executeFinish == 0){
1409
1433
  //这个还没执行完,那么直接退出,不在向后执行了
@@ -1420,14 +1444,15 @@ var translate = {
1420
1444
  translate.state = 0;
1421
1445
  translate.executeNumber++;
1422
1446
 
1423
- translate.listener.execute.renderFinishByApiRun(uuid);
1447
+ translate.listener.execute.renderFinishByApiRun(uuid, from, to);
1424
1448
  }
1425
1449
 
1426
1450
  },
1427
1451
 
1428
1452
  //execute() 方法已经被执行过多少次了, 只有execute() 完全执行完,也就是界面渲染完毕后,它才会+1
1429
1453
  executeNumber:0,
1430
-
1454
+
1455
+ /*translate.execute() start */
1431
1456
  /*
1432
1457
  执行翻译操作。翻译的是 nodeQueue 中的
1433
1458
  docs 如果传入,那么翻译的只是传入的这个docs的。传入如 [document.getElementById('xxx'),document.getElementById('xxx'),...]
@@ -1994,9 +2019,7 @@ var translate = {
1994
2019
  //状态
1995
2020
  translate.state = 20;
1996
2021
 
1997
- //listener
1998
- translate.listener.execute.renderStartByApiRun(uuid);
1999
-
2022
+
2000
2023
  //进行掉接口翻译
2001
2024
  for(var lang_index in fanyiLangs){ //一维数组,取语言
2002
2025
  var lang = fanyiLangs[lang_index];
@@ -2024,6 +2047,9 @@ var translate = {
2024
2047
  translate.translateRequest[uuid][lang].addtime = Math.floor(Date.now() / 1000);
2025
2048
 
2026
2049
 
2050
+ //listener
2051
+ translate.listener.execute.renderStartByApiRun(uuid, lang, translate.to);
2052
+
2027
2053
  /*** 翻译开始 ***/
2028
2054
  var url = translate.request.api.translate;
2029
2055
  var data = {
@@ -2033,23 +2059,37 @@ var translate = {
2033
2059
  //text:JSON.stringify(translateTextArray[lang])
2034
2060
  text:encodeURIComponent(JSON.stringify(translateTextArray[lang]))
2035
2061
  };
2036
- //console.log(data);
2037
2062
  translate.request.post(url, data, function(data){
2038
2063
  //console.log(data);
2039
2064
  //console.log(translateTextArray[data.from]);
2040
2065
  if(data.result == 0){
2041
- translate.translateRequest[uuid][lang].result = 2;
2042
- translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
2043
- translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
2044
- translate.waitingExecute.isAllExecuteFinish(uuid);
2066
+ if(typeof(translate.translateRequest[uuid]) == 'object' && typeof(translate.translateRequest[uuid][data.from]) == 'object'){
2067
+ translate.translateRequest[uuid][data.from]['result'] = 2;
2068
+ translate.translateRequest[uuid][data.from].executeFinish = 1; //1是执行完毕
2069
+ translate.translateRequest[uuid][data.from].stoptime = Math.floor(Date.now() / 1000);
2070
+ }else{
2071
+ console.log('WARINNG!!! translate.translateRequest[uuid][data.from] is not object');
2072
+ }
2073
+
2074
+ //为了兼容 v3.14以前的translate.service 版本,做了判断
2075
+ var from = '';
2076
+ if(typeof(data.from) != 'undefined' && data.from != null){
2077
+ from = data.from;
2078
+ }
2079
+ var to = '';
2080
+ if(typeof(data.to) != 'undefined' && data.to != null){
2081
+ to = data.to;
2082
+ }else{
2083
+ to = translate.to;
2084
+ }
2085
+ translate.waitingExecute.isAllExecuteFinish(uuid, from, to);
2086
+
2045
2087
  console.log('=======ERROR START=======');
2046
2088
  console.log(translateTextArray[data.from]);
2047
2089
  //console.log(encodeURIComponent(JSON.stringify(translateTextArray[data.from])));
2048
-
2049
2090
  console.log('response : '+data.info);
2050
2091
  console.log('=======ERROR END =======');
2051
2092
  //translate.temp_executeFinishNumber++; //记录执行完的次数
2052
-
2053
2093
  return;
2054
2094
  }
2055
2095
 
@@ -2122,17 +2162,18 @@ var translate = {
2122
2162
  translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
2123
2163
  translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
2124
2164
  setTimeout(function(){
2125
- translate.waitingExecute.isAllExecuteFinish(uuid);
2165
+ translate.waitingExecute.isAllExecuteFinish(uuid, data.from, data.to);
2126
2166
  },10);
2127
2167
  }, function(xhr){
2128
2168
  translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
2129
2169
  translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
2130
2170
  translate.translateRequest[uuid][lang].result = 3;
2131
- translate.waitingExecute.isAllExecuteFinish(uuid);
2171
+ translate.waitingExecute.isAllExecuteFinish(uuid, lang, translate.to);
2132
2172
  });
2133
2173
  /*** 翻译end ***/
2134
2174
  }
2135
2175
  },
2176
+ /*translate.execute() end */
2136
2177
 
2137
2178
  /**
2138
2179
  * 翻译请求记录
@@ -2240,14 +2281,16 @@ var translate = {
2240
2281
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2241
2282
  if(typeof(node[attribute]) != 'undefined'){
2242
2283
  //这种是主流框架,像是vue、element、react 都是用这种 DOM Property 的方式,更快
2243
- node[attribute] = node[attribute].replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2284
+ node[attribute] = translate.util.textReplace(node[attribute], originalText, resultText, translate.to); //2025.4.26 变更为此方式
2285
+ //node[attribute] = node[attribute].replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2244
2286
  }
2245
2287
 
2246
2288
  //这种 Html Attribute 方式 是 v3.12 版本之前一直使用的方式,速度上要慢于 上面的,为了向前兼容不至于升级出问题,后面可能会优化掉
2247
2289
  var htmlAttributeValue = node.getAttribute(attribute);
2248
2290
  if(htmlAttributeValue != null && typeof(htmlAttributeValue) != 'undefined'){
2249
2291
  //这个才是在v3.9.2 后要用的,上面的留着只是为了适配以前的
2250
- node.setAttribute(attribute, htmlAttributeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText)));
2292
+ node.setAttribute(attribute, translate.util.textReplace(htmlAttributeValue, originalText, resultText, translate.to)); //2025.4.26 变更为此方式
2293
+ //node.setAttribute(attribute, htmlAttributeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText)));
2251
2294
  }
2252
2295
  }
2253
2296
  return result;
@@ -2295,7 +2338,8 @@ var translate = {
2295
2338
  //替换渲染
2296
2339
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2297
2340
  //this.nodes[hash][task_index].nodeValue = this.nodes[hash][task_index].nodeValue.replace(new RegExp(translate.util.regExp.pattern(task.originalText),'g'), translate.util.regExp.resultText(task.resultText));
2298
- input_value_node.nodeValue = input_value_node.nodeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2341
+ input_value_node.nodeValue = translate.util.textReplace(input_value_node.nodeValue, originalText, resultText, translate.to); //2025.4.26 变更为此方式
2342
+ //input_value_node.nodeValue = input_value_node.nodeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2299
2343
  }
2300
2344
 
2301
2345
  result['text'] = input_value_node.nodeValue;
@@ -2312,7 +2356,8 @@ var translate = {
2312
2356
  //替换渲染
2313
2357
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2314
2358
  //this.nodes[hash][task_index].nodeValue = this.nodes[hash][task_index].nodeValue.replace(new RegExp(translate.util.regExp.pattern(task.originalText),'g'), translate.util.regExp.resultText(task.resultText));
2315
- node.attributes['placeholder'].nodeValue = node.attributes['placeholder'].nodeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2359
+ node.attributes['placeholder'].nodeValue = translate.util.textReplace(node.attributes['placeholder'].nodeValue, originalText, resultText, translate.to); //2025.4.26 变更为此方式
2360
+ //node.attributes['placeholder'].nodeValue = node.attributes['placeholder'].nodeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2316
2361
  }
2317
2362
 
2318
2363
  result['text'] = node.attributes['placeholder'].nodeValue;
@@ -2337,7 +2382,8 @@ var translate = {
2337
2382
  //替换渲染
2338
2383
  if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
2339
2384
  //this.nodes[hash][task_index].nodeValue = this.nodes[hash][task_index].nodeValue.replace(new RegExp(translate.util.regExp.pattern(task.originalText),'g'), translate.util.regExp.resultText(task.resultText));
2340
- node.content = node.content.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2385
+ node.content = translate.util.textReplace(node.content, originalText, resultText, translate.to); //2025.4.26 变更为此方式
2386
+ //node.content = node.content.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2341
2387
  }
2342
2388
 
2343
2389
  result['text'] = node.content;
@@ -2357,7 +2403,8 @@ var translate = {
2357
2403
  //替换渲染
2358
2404
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2359
2405
  //this.nodes[hash][task_index].nodeValue = this.nodes[hash][task_index].nodeValue.replace(new RegExp(translate.util.regExp.pattern(task.originalText),'g'), translate.util.regExp.resultText(task.resultText));
2360
- node.alt = node.alt.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2406
+ node.alt = translate.util.textReplace(node.alt, originalText, resultText, translate.to); //2025.4.26 变更为此方式
2407
+ //node.alt = node.alt.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2361
2408
  }
2362
2409
  result['text'] = node.alt;
2363
2410
  return result;
@@ -2374,7 +2421,8 @@ var translate = {
2374
2421
  //替换渲染
2375
2422
  if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
2376
2423
  //this.nodes[hash][task_index].nodeValue = this.nodes[hash][task_index].nodeValue.replace(new RegExp(translate.util.regExp.pattern(task.originalText),'g'), translate.util.regExp.resultText(task.resultText));
2377
- node.nodeValue = node.nodeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2424
+ node.nodeValue = translate.util.textReplace(node.nodeValue, originalText, resultText, translate.to); //2025.4.26 变更为此方式
2425
+ //node.nodeValue = node.nodeValue.replace(new RegExp(translate.util.regExp.pattern(originalText),'g'), translate.util.regExp.resultText(resultText));
2378
2426
  }
2379
2427
  result['text'] = node.nodeValue;
2380
2428
  }
@@ -2786,28 +2834,29 @@ var translate = {
2786
2834
  }
2787
2835
  }
2788
2836
 
2789
-
2790
- //判断当前是否是英语及变种,也就是单词之间需要有空格的,如果前后没有空格,要补充上空格
2791
- if(translate.language.wordBlankConnector(translate.to)){
2792
- if(wordKeyIndex > 0){
2793
- //它前面还有文本,判断它前面的文本是否是空格,如果不是,那么要补充上空格
2794
- var before = text.charAt(wordKeyIndex-1);
2795
- //console.log(before);
2796
- if(!(/\s/.test(before))){
2797
- //不是空白字符,补充上一个空格,用于将两个单词隔开
2798
- nomenclatureValue = ' '+nomenclatureValue
2799
- }
2800
- }
2801
- if(wordKeyIndex + nomenclatureKey.length < text.length){
2802
- //它后面还有文本,判断它前面的文本是否是空格,如果不是,那么要补充上空格
2803
- var after = text.charAt(wordKeyIndex + nomenclatureKey.length);
2804
- //console.log(after);
2805
- if(!(/\s/.test(before))){
2806
- //不是空白字符,补充上一个空格,用于将两个单词隔开
2807
- nomenclatureValue = nomenclatureValue+' ';
2808
- }
2809
- }
2810
- }
2837
+ // 2025.4.26 优化,将不再在此处进行处理,交有 translate.util.textReplace 在页面最终渲染前处理
2838
+ // //判断当前是否是英语及变种,也就是单词之间需要有空格的,如果前后没有空格,要补充上空格
2839
+ // if(translate.language.wordBlankConnector(translate.to)){
2840
+ // if(wordKeyIndex > 0){
2841
+ // //它前面还有文本,判断它前面的文本是否是空格,如果不是,那么要补充上空格
2842
+ // var before = text.charAt(wordKeyIndex-1);
2843
+ // //console.log(before);
2844
+ // if(!(/\s/.test(before))){
2845
+ // //不是空白字符,补充上一个空格,用于将两个单词隔开
2846
+ // nomenclatureValue = ' '+nomenclatureValue
2847
+ // }
2848
+ // }
2849
+ // if(wordKeyIndex + nomenclatureKey.length < text.length){
2850
+ // //它后面还有文本,判断它前面的文本是否是空格,如果不是,那么要补充上空格
2851
+ // var after = text.charAt(wordKeyIndex + nomenclatureKey.length);
2852
+ // //console.log(after);
2853
+ // // 2025.4.23 woodsway提出bug修复 https://gitee.com/mail_osc/translate/issues/IC34VN
2854
+ // if(!(/\s/.test(after))){
2855
+ // //不是空白字符,补充上一个空格,用于将两个单词隔开
2856
+ // nomenclatureValue = nomenclatureValue+' ';
2857
+ // }
2858
+ // }
2859
+ // }
2811
2860
 
2812
2861
  //如果是自定义术语的key等于value,则是属于指定的某些文本不进行翻译的情况,所以这里要单独判断一下
2813
2862
  //console.log(nomenclatureKey+':'+nomenclatureValue);
@@ -2853,6 +2902,7 @@ var translate = {
2853
2902
  }
2854
2903
  }
2855
2904
 
2905
+ console.log(textArray);
2856
2906
  return textArray;
2857
2907
  },
2858
2908
 
@@ -3449,7 +3499,8 @@ var translate = {
3449
3499
  languageName 是当前字符串最终判定结果是什么语种。它的识别有以下特点:
3450
3500
  1. 如果出现英语跟中文、罗曼语族、德语等混合的情况,也就是不纯粹英语的情况,那么会以其他语种为准,而不是识别为英语。不论英语字符出现的比例占多少。
3451
3501
  2. 如果出现简体中文跟繁体中文混合的情况,那么识别为繁体中文。不论简体中文字符出现的比例占多少。
3452
- 3. 除了以上两种规则外,如果出现了多个语种,那么会识别为出现字符数量最多的语种当做当前句子的语种。(注意是字符数,而不是语种的数组数)
3502
+ 3. 如果出现简体中文、繁体中文、日语混合的情况,那么识别为日语。不论简体中文、繁体中文出现的比例占多少。 2025.4.19 增加
3503
+ 4. 除了以上两种规则外,如果出现了多个语种,那么会识别为出现字符数量最多的语种当做当前句子的语种。(注意是字符数,而不是语种的数组数)
3453
3504
  languageArray 对传入字符串进行分析,识别出都有哪些语种,每个语种的字符是什么
3454
3505
  *
3455
3506
  */
@@ -3500,13 +3551,21 @@ var translate = {
3500
3551
  }
3501
3552
  }
3502
3553
 
3554
+ //如果简体中文跟繁体中文一起出现,那么会判断当前句子为繁体中文,将简体中文字符数置0
3503
3555
  if(langkeys.indexOf('chinese_simplified') > -1 && langkeys.indexOf('chinese_traditional') > -1){
3504
- //如果简体中文跟繁体中文一起出现,那么会判断当前句子为繁体中文。
3505
3556
  //langkeys.splice(langkeys.indexOf('chinese_simplified'), 1);
3506
3557
  langsNumber['chinese_simplified'] = 0;
3507
3558
  }
3508
3559
 
3509
3560
 
3561
+ //如果发现日语字符,那么将发现的简体中文、繁体中文字符数量置零
3562
+ if(langkeys.length > 1 && langkeys.indexOf('japanese') > -1){
3563
+ langsNumber['chinese_simplified'] = 0;
3564
+ langsNumber['chinese_traditional'] = 0;
3565
+ }
3566
+
3567
+
3568
+
3510
3569
  //从 langsNumber 中找出字数最多的来
3511
3570
  var maxLang = ''; //字数最多的语种
3512
3571
  var maxNumber = 0;
@@ -3554,6 +3613,10 @@ var translate = {
3554
3613
  number 阿拉伯数字
3555
3614
  japanese 日语
3556
3615
  korean 韩语
3616
+ greek 希腊语
3617
+ thai 泰语
3618
+ arabic 阿拉伯语
3619
+ romanian 罗马尼亚语
3557
3620
  */
3558
3621
  getCharLanguage:function(charstr){
3559
3622
  if(charstr == null || typeof(charstr) == 'undefined'){
@@ -3590,7 +3653,18 @@ var translate = {
3590
3653
  if(this.korean(charstr)){
3591
3654
  return 'korean';
3592
3655
  }
3593
-
3656
+ if(this.greek(charstr)){
3657
+ return 'greek';
3658
+ }
3659
+ if(this.thai(charstr)){
3660
+ return 'thai';
3661
+ }
3662
+ if(this.arabic(charstr)){
3663
+ return 'arabic';
3664
+ }
3665
+ if(this.romanian(charstr)){
3666
+ return 'romanian';
3667
+ }
3594
3668
  //未识别是什么语种
3595
3669
  //console.log('not find is language , char : '+charstr+', unicode: '+charstr.charCodeAt(0).toString(16));
3596
3670
  return '';
@@ -3857,6 +3931,7 @@ var translate = {
3857
3931
  return false;
3858
3932
  },
3859
3933
  //语种的单词连接符是否需要空格,比如中文简体、繁体、韩文、日语都不需要空格,则返回false, 但是像是英文的单词间需要空格进行隔开,则返回true
3934
+ //另外这也是区分是否使用标点符号 ,。还是 ,. 的
3860
3935
  //如果未匹配到,默认返回true
3861
3936
  //language:语种,传入如 english
3862
3937
  wordBlankConnector:function(language){
@@ -3914,8 +3989,44 @@ var translate = {
3914
3989
  },
3915
3990
  //是否包含俄语
3916
3991
  russian:function(str){
3992
+ // 正则表达式匹配俄语大小写字母(包含 Ё/ё,排除其他语言特有的西里尔字符)
3993
+ //АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЮюЯя
3994
+ if(/^[А-Яа-яЁё]$/.test(str)){
3995
+ return true
3996
+ } else {
3997
+ return false;
3998
+ }
3999
+ },
4000
+ //是否包含泰语
4001
+ thai:function(str){
4002
+ if(/^[\u0E01-\u0E59]$/.test(str)){
4003
+ return true
4004
+ } else {
4005
+ return false;
4006
+ }
4007
+ },
4008
+ //是否包含阿拉伯语
4009
+ arabic:function(str){
4010
+ /*
4011
+ 阿拉伯语基本区块(U+0600–U+06FF)
4012
+ 阿拉伯语补充区块(U+0750–U+077F)
4013
+ */
4014
+ return /^[\u0600-\u06FF\u0750-\u077F]$/.test(str);
4015
+ },
4016
+ //是否包含 罗马尼亚语
4017
+ romanian:function(str) {
4018
+ /*
4019
+ U+00C0–U+00FF:Latin-1 Supplement (包含带变音符号的字母,如 Ă/ă 的部分形式)
4020
+ U+0100–U+017F:Latin Extended-A (包含罗马尼亚语特有字母 Ă/ă、Â/â、Î/î 等);
4021
+ U+0218–U+021B:Latin Extended-B (包含 Ș/ș 和 Ț/ț,这是罗马尼亚语标志性字母)
4022
+ */
4023
+ return /^[\u00C0-\u00FF\u0100-\u017F\u0218-\u021B]$/.test(str);
4024
+ },
4025
+ //是否包含希腊语
4026
+ greek:function(str){
4027
+ const greekRegex = /^[\u0391-\u03A9\u03B1-\u03C9]$/;
3917
4028
  //判断字符有 БВДЖЗИЙЛМНОПСТУФХЦЧШЩЪЫЬЮЯЇІ
3918
- if(/.*[\u0411\u0412\u0414\u0416\u0417\u0418\u0419\u041B\u041C\u041D\u041E\u041F\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042A\u042B\u042C\u042E\u042F\u0407\u0406]+.*$/.test(str)){
4029
+ if(/^[\u0391-\u03A9\u03B1-\u03C9]$/.test(str)){
3919
4030
  return true
3920
4031
  } else {
3921
4032
  return false;
@@ -3994,6 +4105,7 @@ var translate = {
3994
4105
 
3995
4106
  return maxLang || '';
3996
4107
  },
4108
+ /**romanceSentenceAnaly end**/
3997
4109
 
3998
4110
  //是否包含特殊字符,包含,则是true
3999
4111
  specialCharacter:function(str){
@@ -4027,12 +4139,7 @@ var translate = {
4027
4139
  return true;
4028
4140
  }
4029
4141
 
4030
- /*
4031
- //阿拉伯数字 0-9
4032
- if(/.*[\u0030-\u0039]+.*$/.test(str)){
4033
- return true;
4034
- }
4035
- */
4142
+
4036
4143
 
4037
4144
  /*
4038
4145
  U+0020 空格
@@ -4087,139 +4194,40 @@ var translate = {
4087
4194
  }
4088
4195
 
4089
4196
  /*
4090
- 拉丁字母
4091
- 代码 显示 描述
4092
- U+00A1 ¡ 倒转的叹号
4093
- U+00A2 ¢ (货币单位)分钱、毫子
4094
- U+00A3 £ (货币)英镑
4095
- U+00A4 ¤ (货币)当货币未有符号时以此替代
4096
- U+00A5 ¥ (货币)日元
4097
- U+00A6 ¦ 两条断开的直线
4098
- U+00A7 § 文件分不同部分
4099
- U+00A8 ¨ (语言)分音
4100
- U+00A9 © 版权符
4101
- U+00AA ª (意大利文、葡萄牙文、西班牙文)阴性序数
4102
- U+00AB « 双重角形引号
4103
- U+00AC ¬ 逻辑非
4104
- U+00AE ® 商标
4105
- U+00AF ¯ 长音
4106
- U+00B0 ° 角度
4107
- U+00B1 ± 正负号
4108
- U+00B2 ² 二次方
4109
- U+00B3 ³ 三次方
4110
- U+00B4 ´ 锐音符
4111
- U+00B5 µ 百万分之一,10?6
4112
- U+00B6 ¶ 文章分段
4113
- U+00B7 · 间隔号
4114
- U+00B8 ¸ 软音符
4115
- U+00B9 ¹ 一次方
4116
- U+00BA º (意大利文、葡萄牙文、西班牙文)阳性序数
4117
- U+00BB » 指向右的双箭头
4118
- U+00BC ¼ 四分之一
4119
- U+00BD ½ 二分之一
4120
- U+00BE ¾ 四分之三
4121
- U+00BF ¿ 倒转的问号
4122
- U+00C1 Á 在拉丁字母 A 上加锐音符
4123
- U+00C2 Â 在拉丁字母 A 上加抑扬符“^”
4124
- U+00C3 Ã 在拉丁字母 A 上加“~”
4125
- U+00C4 Ä 在拉丁字母 A 上加分音符“..”
4126
- U+00C5 Å 在拉丁字母 A 上加角度符“°”
4127
- U+00C6 Æ 拉丁字母 A、E 的混合
4128
- U+00C7 Ç 在拉丁字母 C 下加软音符
4129
- U+00C8 È 在拉丁字母 E 上加重音符
4130
- U+00C9 É 在拉丁字母 E 上加锐音符
4131
- U+00CA Ê 在拉丁字母 E 上加抑扬符
4132
- U+00CB Ë 在拉丁字母 E 上加分音符
4133
- U+00CC Ì 在拉丁字母 I 上加重音符
4134
- U+00CD Í 在拉丁字母 I 上加锐音符
4135
- U+00CE Î 在拉丁字母 I 上加抑扬符
4136
- U+00CF Ï 在拉丁字母 I 上加分音符
4137
- U+00D0 Ð 古拉丁字母,现只有法罗文和冰岛文和越南语使用
4138
- U+00D1 Ñ 在拉丁字母 N 上加波浪纹“~”
4139
- U+00D2 Ò 在拉丁字母 O 上加重音符
4140
- U+00D3 Ó 在拉丁字母 O 上加锐音符
4141
- U+00D4 Ô 在拉丁字母 O 上加抑扬符
4142
- U+00D5 Õ 在拉丁字母 O 上加波浪纹“~”
4143
- U+00D6 Ö 在拉丁字母 O 上加分音符
4144
- U+00D7 × 乘号,亦可拖按“Alt”键,同时按“41425”五键
4145
- U+00D8 Ø 在拉丁字母 O 由右上至左下加对角斜线“/”
4146
- U+00D9 Ù 在拉丁字母 U 上加重音符
4147
- U+00DA Ú 在拉丁字母 U 上加锐音符
4148
- U+00DB Û 在拉丁字母 U 上加抑扬符
4149
- U+00DC Ü 在拉丁字母 U 上加分音符
4150
- U+00DD Ý 在拉丁字母 Y 上加锐音符
4151
- U+00DE Þ 古拉丁字母,现已被“Th”取替
4152
- U+00DF ß 德文字母
4153
- U+00E0 à 在拉丁字母 a 上加重音符
4154
- U+00E1 á 在拉丁字母 a 上加锐音符
4155
- U+00E2 â 在拉丁字母 a 上加抑扬符
4156
- U+00E3 ã 在拉丁字母 a 上加波浪纹“~”
4157
- U+00E4 ä 在拉丁字母 a 上加分音符
4158
- U+00E5 å 在拉丁字母 a 上加角度符“°”
4159
- U+00E6 æ 拉丁字母 a、e 的混合
4160
- U+00E7 ç 在拉丁字母 c 下加软音符
4161
- U+00E8 è 在拉丁字母 e 上加锐音符
4162
- U+00E9 é 在拉丁字母 e 上加重音符
4163
- U+00EA ê 在拉丁字母 e 上加抑扬符
4164
- U+00EB ë 在拉丁字母 e 上加分音符
4165
- U+00EC ì 在拉丁字母 i 上加重音符
4166
- U+00ED í 在拉丁字母 i 上加锐音符
4167
- U+00EE î 在拉丁字母 i 上加抑扬符
4168
- U+00EF ï 在拉丁字母 i 上加分音符
4169
- U+00F0 ð 古拉丁字母
4170
- U+00F1 ñ 在拉丁字母 n 上加波浪纹“~”
4171
- U+00F2 ò 在拉丁字母 o 上加重音符
4172
- U+00F3 ó 在拉丁字母 o 上加锐音符
4173
- U+00F4 ô 在拉丁字母 o 上加抑扬符
4174
- U+00F5 õ 在拉丁字母 o 上加波浪纹“~”
4175
- U+00F6 ö 在拉丁字母 o 上加分音符
4176
- U+00F7 ÷ 除号,亦可拖按“Alt”键,同时按“41426”五键
4177
- U+00F8 ø 在拉丁字母 o 由右上至左下加对角斜线“/”
4178
- U+00F9 ù 在拉丁字母 u 上加重音符
4179
- U+00FA ú 在拉丁字母 u 上加锐音符
4180
- U+00FB ? 在拉丁字母 u 上加抑扬符
4181
- U+00FC ü 在拉丁字母 u 上加分音符
4182
- U+00FD ý 在拉丁字母 y 上加锐音符
4183
- U+00FE þ 古拉丁字母,现已被“th”取替
4184
- U+00FF ü 在拉丁字母 u 上加分音符
4185
- 拉丁字母(扩展 A)
4186
- 代码 显示 描述
4187
- U+0100 Ā 在拉丁字母 A 上加长音符
4188
- U+0101 ā 在拉丁字母 a 上加长音符
4189
- U+0102 Ă 在拉丁字母 A 上加短音符
4190
- U+0103 ă 在拉丁字母 a 上加短音符
4191
- U+0104 Ą 在拉丁字母 A 上加反尾形符
4192
- U+0105 ą 在拉丁字母 a 上加反尾形符
4193
- 拉丁字母(扩展 C)
4194
- 代码 显示 描述
4195
- U+2C60 Ⱡ 在拉丁字母“L”中间加两条横线“=”
4196
- U+2C61 ⱡ 在拉丁字母“l”(L 的小写)中间加两条横线“=”
4197
- U+2C62 Ɫ 在拉丁字母“L”(大写)中间加一条波浪线“~”
4198
- U+2C63 Ᵽ 在拉丁字母“P”中间加一条横线“-”
4199
- U+2C64 Ɽ 在拉丁字母“R”下加一条尾巴
4200
- U+2C65 ⱥ 在拉丁字母“a”上加一条对角斜线“/”
4201
- U+2C66 ⱦ 在拉丁字母“t”上加一条对角斜线“/”
4202
- U+2C67 Ⱨ 在拉丁字母“H”下加一条尾巴
4203
- U+2C68 ⱨ 在拉丁字母“h”下加一条尾巴
4204
- U+2C69 Ⱪ 在拉丁字母“K”下加一条尾巴
4205
- U+2C6A ⱪ 在拉丁字母“k”下加一条尾巴
4206
- U+2C6B Ⱬ 在拉丁字母“Z”下加一条尾巴
4207
- U+2C6C ⱬ 在拉丁字母“z”下加一条尾巴
4208
- U+2C74 ⱴ 在拉丁字母“v”的起笔加一个弯勾
4209
- U+2C75 Ⱶ 拉丁字母“H”的左半部
4210
- U+2C76 ⱶ 拉丁字母“h”的左半部
4211
- U+2C77 ⱷ 希腊字母“φ”的上半部
4197
+ 这些字符主要是 罕见的拉丁字母变体 ,通常用于:
4198
+ 某些非洲语言或方言;
4199
+ 古文字、语音学符号;
4200
+ 特殊排版或装饰性字体。
4212
4201
  */
4213
- if(/.*[\u00A1-\u0105]+.*$/.test(str)){
4214
- return true;
4215
- }
4216
4202
  if(/.*[\u2C60-\u2C77]+.*$/.test(str)){
4217
4203
  return true;
4218
4204
  }
4219
4205
 
4220
4206
 
4221
4207
  return false;
4222
- }
4208
+ },
4209
+ /*
4210
+ 文本翻译的替换。
4211
+
4212
+ @Deprecated 2025.4.26 最新的在 translate.util.textReplace
4213
+
4214
+ text: 原始文本,翻译的某句或者某个词就在这个文本之中
4215
+ translateOriginal: 翻译的某个词或句,在翻译之前的文本
4216
+ translateResult: 翻译的某个词或句,在翻译之后的文本,翻译结果
4217
+ language: 显示的语种,这里是对应的 translateResult 这个文本的语种。 也就是最终替换之后要显示给用户的语种。比如将中文翻译为英文,这里也就是英文。 这里会根据显示的语种不同,来自主决定是否前后加空格进行分割。 另外这里传入的语种也是 translate.js 的语种标识
4218
+
4219
+ (注意,如果 translateResult 中发现 translateOriginal 的存在,将不进行任何处理,因为没必要了,还会造成死循环。直接将 text 返回)
4220
+
4221
+ 使用此方法:
4222
+ var text = '你世好word世界';
4223
+ var translateOriginal = '世';
4224
+ var translateResult = '世杰'; //翻译结果
4225
+ translate.language.textTranslateReplace(text, translateOriginal, translateResult, 'english');
4226
+
4227
+ */
4228
+ textTranslateReplace:function(text, translateOriginal, translateResult, language){
4229
+ return translate.util.textReplace(text, translateOriginal, translateResult, language);
4230
+ }
4223
4231
  },
4224
4232
  //用户第一次打开网页时,自动判断当前用户所在国家使用的是哪种语言,来自动进行切换为用户所在国家的语种。
4225
4233
  //如果使用后,第二次在用,那就优先以用户所选择的为主
@@ -4248,6 +4256,138 @@ var translate = {
4248
4256
  },
4249
4257
 
4250
4258
  util:{
4259
+ /*
4260
+ 文本替换,将替换完毕的结果返回
4261
+ 自定义术语等都是通过这个来进行替换
4262
+ 2025.4.26 从 language 中 拿到这里
4263
+
4264
+ text: 原始文本,翻译的某句或者某个词就在这个文本之中
4265
+ translateOriginal: 翻译的某个词或句,在翻译之前的文本
4266
+ translateResult: 翻译的某个词或句,在翻译之后的文本,翻译结果
4267
+ language: 显示的语种,这里是对应的 translateResult 这个文本的语种。 也就是最终替换之后要显示给用户的语种。比如将中文翻译为英文,这里也就是英文。 这里会根据显示的语种不同,来自主决定是否前后加空格进行分割。 另外这里传入的语种也是 translate.js 的语种标识
4268
+
4269
+ (注意,如果 translateResult 中发现 translateOriginal 的存在,将不进行任何处理,因为没必要了,还会造成死循环。直接将 text 返回)
4270
+
4271
+ 使用此方法:
4272
+ var text = '你世好word世界';
4273
+ var translateOriginal = '世';
4274
+ var translateResult = '世杰'; //翻译结果
4275
+ translate.language.textTranslateReplace(text, translateOriginal, translateResult, 'english');
4276
+
4277
+ */
4278
+ textReplace:function(text, translateOriginal, translateResult, language){
4279
+
4280
+ //如果要替换的源文本直接就是整个文本,那也就不用在做什么判断了,直接将 翻译的结果文本返回就好了
4281
+ if(text == translateOriginal){
4282
+ return translateResult;
4283
+ }
4284
+
4285
+ //当前替换后,替换结果结束位置的下标。
4286
+ //一开始还没进行替换,那么这个下标就是 0
4287
+ //比如 你好吗 中的 好 替换为 "好的" 那最后结果为 "你好的吗" ,这里是 “的” 的下标 2
4288
+ let currentReplaceEndIndex = 0;
4289
+
4290
+ //while最大循环次数30次,免得出现未知异常导致死循环
4291
+ let maxWhileNumber = 30;
4292
+
4293
+ //因为text中可能有多个位置要被替换,所以使用循环
4294
+ while(text.indexOf(translateOriginal, currentReplaceEndIndex) > -1 && maxWhileNumber-- > 0){
4295
+ //console.log('text:'+text+'\tcurrentReplaceEndIndex:'+currentReplaceEndIndex);
4296
+
4297
+ //要替换的结果文本(这个文本可能前面有加空格或者后面有加空格的)
4298
+ let replaceResultText = ''+translateResult;
4299
+ //替换的文本 ,这里有可能会追加上某些标点符号,所以单独也列出来,而不是使用方法中传入的 translateOriginal
4300
+ let replaceOriginalText = '' + translateOriginal;
4301
+
4302
+ //根据不同的语种,如果有的语种需要加空格来进行区分单词,那么也要进行空格的判定
4303
+ if(translate.language.wordBlankConnector(translate.to)){
4304
+ let originalIndex = text.indexOf(translateOriginal, currentReplaceEndIndex); //翻译之前,翻译的单词在字符串中的起始坐标(0开始)
4305
+ //console.log("originalIndex: "+originalIndex);
4306
+
4307
+ //要先判断后面,不然先判断前面,加了后它的长度就又变了
4308
+
4309
+ //判断它后面是否还有文本
4310
+ if(originalIndex+1 < text.length){
4311
+ let char = text.charAt(originalIndex+translateOriginal.length);
4312
+ //console.log(char);
4313
+ if(/。/.test(char)){
4314
+ replaceResultText = replaceResultText + '. ';
4315
+ replaceOriginalText = translateOriginal + '。';
4316
+ }else if(/,/.test(char)){
4317
+ replaceResultText = replaceResultText + ', ';
4318
+ replaceOriginalText = translateOriginal + ',';
4319
+ }else if(!(/\s/.test(char))){
4320
+ //不是空白字符,补充上一个空格,用于将两个单词隔开
4321
+ //text = text.replace(translateOriginal, translateResult+' ');
4322
+ replaceResultText = replaceResultText + ' ';
4323
+ }
4324
+ }
4325
+
4326
+ //判断它前面是否还有文本
4327
+ if(originalIndex > 0){
4328
+ let char = text.charAt(originalIndex-1);
4329
+ //console.log(char);
4330
+ if(!(/\s/.test(char))){
4331
+ //不是空白字符,补充上一个空格,用于将两个单词隔开
4332
+ //text = text.replace(translateOriginal, ' '+translateResult);
4333
+ replaceResultText = ' '+replaceResultText;
4334
+ }
4335
+ }
4336
+ }else{
4337
+ //如果是其他语种比如英语法语翻译为中文、日文,那么标点符号也要判断的,这个因为目前这个场景还没咋遇到,就不判断了,遇到了在加。
4338
+
4339
+ }
4340
+
4341
+ let replaceResult = translate.util.replaceFromIndex(text, currentReplaceEndIndex, replaceOriginalText, replaceResultText);
4342
+ if(replaceResult.replaceEndIndex < 1){
4343
+ console.log('while中已经 indexOf发现了,但是实际没有替换,出现异常了!理论上这是不应该出现的。 text:'+text+' , translateOriginal:'+translateOriginal);
4344
+ }else{
4345
+ currentReplaceEndIndex = replaceResult.replaceEndIndex;
4346
+ text = replaceResult.text;
4347
+ }
4348
+
4349
+ }
4350
+
4351
+ //console.log(resultText);
4352
+ return text;
4353
+ },
4354
+ /*
4355
+ js 的 replace 能力,这个是可以指定从第几个字符开始进行replace
4356
+ 1. 这里可以 replaceText 本身包含着 originalText
4357
+ 2. originalText 可以出现多次
4358
+
4359
+ @param
4360
+ text 要进行替换的原始文本
4361
+ index 要从 text 的哪个下标开始。 (第一个字符下标是0)
4362
+ originalText 要替换的文本,被替换的文本
4363
+ replaceText 替换为的文本,将 originalText 替换为什么
4364
+ replaceFromIndex('你好吗?你也好?', 0, '你', '你是谁');
4365
+
4366
+ @return 对象
4367
+ text 替换的结果
4368
+ replaceEndIndex 当前替换后,替换结果结束位置的下标。
4369
+ 如果没进行替换,那么这个下标就是 0
4370
+ 比如 你好吗 中的 好 替换为 "好的" 那最后结果为 "你好的吗" ,这里是 “的” 的下标 2
4371
+ */
4372
+ replaceFromIndex:function(text, index, originalText, replaceText){
4373
+ const before = text.slice(0, index);
4374
+ const after = text.slice(index);
4375
+ const originalTextIndex = after.indexOf(originalText);
4376
+ if(originalTextIndex > -1){
4377
+ const replacedAfter = after.replace(originalText, replaceText);
4378
+ return {
4379
+ text: before + replacedAfter,
4380
+ replaceEndIndex: index + originalTextIndex + replaceText.length
4381
+ }
4382
+ }else{
4383
+ //没有发现可替换的字符,那么就原样返回
4384
+ return {
4385
+ text: before + replacedAfter,
4386
+ replaceEndIndex: 0
4387
+ };
4388
+ }
4389
+ },
4390
+
4251
4391
  /* 生成一个随机UUID,复制于 https://gitee.com/mail_osc/kefu.js */
4252
4392
  uuid:function() {
4253
4393
  var d = new Date().getTime();
@@ -4421,6 +4561,7 @@ var translate = {
4421
4561
  objSort:function(obj){
4422
4562
  // 获取对象数组的所有 key,并转换为普通数组
4423
4563
  var keys = Array.from(Object.keys(obj));
4564
+ //var keys = [].slice.call(Object.keys(obj)); //适配es5
4424
4565
 
4425
4566
  // 对 key 数组进行排序
4426
4567
  keys.sort(function(a, b){
@@ -4790,6 +4931,44 @@ var translate = {
4790
4931
 
4791
4932
  //将其转化为 translate.js 的语言id,比如简体中文是 chinese_simplified 、 英语是 english
4792
4933
  return '';
4934
+ },
4935
+ /*
4936
+ 对输入的文本 text 进行判断,判断它里面是否有url存在。如果有url存在,对其进行截取,将url跟非url进行截取处理。
4937
+ 比如传入 “这个示例:https://www.ungm.org/Public/Notice/261001,其他得示例是 http://api.translate.zvo.cn 我呢”
4938
+ 那么返回的截取结果为:
4939
+ {
4940
+ "https://www.ungm.org/Public/Notice/261001":"1",
4941
+ "http://api.translate.zvo.cn":"1",
4942
+ ",其他得示例是 ":"0",
4943
+ "这个示例:":"0"
4944
+ " 我呢":"0"
4945
+ }
4946
+ 其中的key 为截取的文本,value 的值是1或0, 1代表当前key的文本是网址,0则不是网址
4947
+ */
4948
+ urlSplitByText:function(text){
4949
+ // 匹配 http/https 的 URL 正则表达式(包含常见 URL 符号,排除中文等非 ASCII 字符)
4950
+ const urlRegex = /(https?:\/\/[\w\-._~:\/?#[\]@!$&'()*+;=%]+(?=[\s\u4e00-\u9fa5,。;,!?]|$))/gi;
4951
+
4952
+ // 使用正则表达式分割文本,保留URL
4953
+ const parts = text.split(urlRegex);
4954
+
4955
+ // 结果对象
4956
+ let result = {};
4957
+
4958
+ // 添加非URL部分,并标记为 0
4959
+ for (let i = 0; i < parts.length; i++) {
4960
+ if (i % 2 === 0) {
4961
+ // 非URL部分
4962
+ if (parts[i] !== "") {
4963
+ result[parts[i]] = "0";
4964
+ }
4965
+ } else {
4966
+ // URL部分
4967
+ result[parts[i]] = "1";
4968
+ }
4969
+ }
4970
+
4971
+ return result;
4793
4972
  }
4794
4973
  },
4795
4974
  //机器翻译采用哪种翻译服务
@@ -4975,6 +5154,7 @@ var translate = {
4975
5154
  //console.log('response------');
4976
5155
  //console.log(xhr);
4977
5156
  },
5157
+
4978
5158
  /*
4979
5159
  速度检测控制中心, 检测主备翻译接口的响应速度进行排列,真正请求时,按照排列的顺序进行请求
4980
5160
  v2.8.2增加
@@ -5021,6 +5201,16 @@ var translate = {
5021
5201
  hostQueueIndex:-1, //当前使用的 hostQueue的数组下标, -1表示还未初始化赋予值,不可直接使用,通过 getHostQueueIndex() 使用
5022
5202
  disableTime:1000000, //不可用的时间,storage中存储的 speedDetectionControl_hostQueue 其中 time 这里,如果值是 这个,便是代表这个host处于不可用状态
5023
5203
 
5204
+ /*
5205
+ 设置当前使用的翻译通道 host
5206
+ 适用于 进行中时,中途切临时换翻译通道。
5207
+ */
5208
+ setCurrentHost:function(host){
5209
+ translate.storage.set('speedDetectionControl_hostQueue','');
5210
+ translate.request.api.host=host;
5211
+ translate.request.speedDetectionControl.checkHostQueue = new Array();
5212
+ translate.request.speedDetectionControl.checkResponseSpeed_Storage(host, 0);
5213
+ },
5024
5214
 
5025
5215
  //获取 host queue 队列
5026
5216
  getHostQueue:function(){
@@ -5028,7 +5218,7 @@ var translate = {
5028
5218
  //还没有,先从本地存储中取,看之前是否已经设置过了
5029
5219
  // 只有经过真正的网络测速后,才会加入 storage 的 hostQueue
5030
5220
  var storage_hostQueue = translate.storage.get('speedDetectionControl_hostQueue');
5031
- if(storage_hostQueue == null || typeof(storage_hostQueue) == 'undefined'){
5221
+ if(storage_hostQueue == null || typeof(storage_hostQueue) == 'undefined' || storage_hostQueue == ''){
5032
5222
  //本地存储中没有,也就是之前没设置过,是第一次用,那么直接讲 translate.request.api.host 赋予之
5033
5223
  //translate.request.api.host
5034
5224
 
@@ -5940,6 +6130,7 @@ var translate = {
5940
6130
 
5941
6131
  /*
5942
6132
  翻译执行的进展相关
6133
+ 比如,浏览器本地缓存没有,需要走API接口的文本所在的元素区域,出现 记载中的动画蒙版,给用户以友好的使用提示
5943
6134
  */
5944
6135
  progress:{
5945
6136
  /*
@@ -6010,28 +6201,34 @@ var translate = {
6010
6201
 
6011
6202
 
6012
6203
  if(translate.progress.api.isTip){
6013
- translate.listener.execute.renderStartByApi.push(function(uuid){
6204
+ translate.listener.execute.renderStartByApi.push(function(uuid, from, to){
6014
6205
  for(var lang in translate.nodeQueue[uuid].list){
6015
- if(translate.language.getCurrent() == lang){
6016
- //忽略这个语种
6017
- continue;
6018
- }
6206
+ //console.log('lang:'+lang);
6207
+ //console.log(translate.nodeQueue[uuid].list[lang]);
6208
+ if(translate.language.getCurrent() == lang){
6209
+ //忽略这个语种
6210
+ //console.log('ignore-------');
6211
+ continue;
6212
+ }
6213
+
6019
6214
  for(var hash in translate.nodeQueue[uuid].list[lang]){
6020
6215
  for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
6021
6216
  var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
6217
+ //console.log(node);
6022
6218
  var nodeParent = node.parentNode;
6023
6219
  if(nodeParent == null){
6024
6220
  continue;
6025
6221
  }
6222
+ /* 这里先不考虑多隐藏的问题,只要符合的都隐藏,宁愿吧一些不需要隐藏的也会跟着一起隐藏
6026
6223
  if(nodeParent.childNodes.length != 1){
6224
+ //这个文本节点所在的元素里,不止有这一个文本元素,还有别的文本元素
6027
6225
  continue;
6028
6226
  }
6029
-
6227
+ */
6030
6228
  if(typeof(nodeParent.className) == 'undefined' || nodeParent.className == null || nodeParent.className == ''){
6031
6229
  nodeParent.className = ' translate_api_in_progress';
6032
6230
  }else{
6033
6231
  //这个元素本身有class了,那就追加
6034
-
6035
6232
  if(nodeParent.className.indexOf('translate_api_in_progress') > -1){
6036
6233
  continue;
6037
6234
  }
@@ -6043,106 +6240,208 @@ var translate = {
6043
6240
  }
6044
6241
  }
6045
6242
  });
6046
- translate.listener.execute.renderFinishByApi.push(function(uuid){
6047
- for(var lang in translate.nodeQueue[uuid].list){
6048
- if(translate.language.getCurrent() == lang){
6049
- //忽略这个语种
6050
- continue;
6051
- }
6052
- for(var hash in translate.nodeQueue[uuid].list[lang]){
6053
- for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
6054
- var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
6055
- var nodeParent = node.parentNode;
6056
- if(nodeParent == null){
6057
- continue;
6058
- }
6059
-
6060
- /*
6061
- 注释这个,因为可能是给这个元素动态追加删除导致其子元素不是11
6062
- if(nodeParent.childNodes.length != 1){
6063
- continue;
6064
- }
6065
- */
6243
+ translate.listener.execute.renderFinishByApi.push(function(uuid, from, to){
6244
+ //console.log('uuid:'+uuid+', from:'+from+', to:'+to);
6245
+
6246
+ for(var hash in translate.nodeQueue[uuid].list[from]){
6247
+ for(var nodeindex in translate.nodeQueue[uuid].list[from][hash].nodes){
6248
+ var node = translate.nodeQueue[uuid].list[from][hash].nodes[nodeindex].node;
6249
+ var nodeParent = node.parentNode;
6250
+ if(nodeParent == null){
6251
+ continue;
6252
+ }
6253
+
6254
+ /*
6255
+ 注释这个,因为可能是给这个元素动态追加删除导致其子元素不是11
6256
+ if(nodeParent.childNodes.length != 1){
6257
+ continue;
6258
+ }
6259
+ */
6066
6260
 
6067
- var parentClassName = nodeParent.className;
6068
- if(typeof(parentClassName) == 'undefined' || parentClassName == null || parentClassName == ''){
6069
- continue;
6070
- }
6071
- if(parentClassName.indexOf('translate_api_in_progress') < -1){
6072
- continue;
6073
- }
6074
-
6075
- nodeParent.className = parentClassName.replace(/translate_api_in_progress/g, '');
6076
- //nodeParent.className = parentClassName.replace(/loading/g, '');
6077
- }
6078
- }
6079
- }
6261
+ var parentClassName = nodeParent.className;
6262
+ if(typeof(parentClassName) == 'undefined' || parentClassName == null || parentClassName == ''){
6263
+ continue;
6264
+ }
6265
+ if(parentClassName.indexOf('translate_api_in_progress') < -1){
6266
+ continue;
6267
+ }
6268
+
6269
+ nodeParent.className = parentClassName.replace(/translate_api_in_progress/g, '');
6270
+ //nodeParent.className = parentClassName.replace(/loading/g, '');
6271
+ }
6272
+ }
6273
+
6080
6274
  });
6081
6275
 
6082
6276
  }
6083
6277
  }
6084
6278
  }
6085
6279
  },
6280
+
6281
+ /*js dispose start*/
6086
6282
  /*
6087
- 对js对象进行翻译
6088
- obj: 可以是JS定义的 对象、数组、甚至是单个具体的值
6283
+ 对js对象内的值进行翻译,可以是JS定义的 对象、数组、甚至是单个具体的值
6089
6284
  */
6090
- jsObject:function (obj, parentKey = '') {
6285
+ js:{
6286
+
6091
6287
  /*
6092
- 存放扫描的结果
6093
- key 存放要被翻译的文本,也就是对象里面某个具体属性的值
6094
- value 存放 obj 中的 key (的调取路径),比如 series[0].data[0].name 这个是个数组形态,因为同一个翻译的文本内容有可能会在obj中出现多次
6288
+ jsString 传入的js对象的字符串格式
6289
+ targetLanguage 翻译为的目标语言
6290
+ successFunction 执行成功后触发,传入格式 function(obj){ console.log(obj); } 其中 obj 是翻译之后的结果
6291
+ failureFunction 执行失败后触发,传入格式 function(failureInfo){ console.log(failureInfo); } 其中 failureInfo 是失败原因
6292
+
6293
+ 示例:
6294
+
6295
+ var str = `
6296
+ {
6297
+ "hello":"你好",
6298
+ "word":"单词",
6299
+ "你是谁": [
6300
+ "世界",
6301
+ "大海"
6302
+ ]
6303
+ }
6304
+ `
6305
+ translate.js.transString(str,'english',function(obj){ console.log(obj); }, function(failureInfo){ console.log(failureInfo); });
6306
+
6095
6307
  */
6096
- var kvs = {};
6097
-
6098
- if (typeof obj === 'object' && obj!== null) {
6099
- if (Array.isArray(obj)) {
6100
- // 处理数组
6101
- obj.forEach((item, index) => {
6102
- const currentKey = parentKey? `${parentKey}[${index}]` : `[${index}]`;
6103
- translate.jsObject(item, currentKey);
6104
- });
6105
- } else {
6106
- // 处理普通对象
6107
- for (const key in obj) {
6108
- const currentKey = parentKey? `${parentKey}.${key}` : key;
6109
- if (typeof obj[key] === 'object' && obj[key]!== null) {
6110
- // 如果值是对象,递归调用函数
6111
- translate.jsObject(obj[key], currentKey);
6112
- } else {
6113
- // 打印键值对
6114
-
6115
- if(typeof(obj[key]) == 'string'){
6116
- //console.log(`${currentKey}: ${obj[key]}`);
6117
- //console.log(obj[key]);
6118
- //console.log(typeof(kvs[obj[key]]));
6119
- if(typeof(kvs[obj[key]]) == 'undefined'){
6120
- kvs[obj[key]] = new Array();
6121
- }
6122
- //kvs[obj[key].push(currentKey);
6123
- }
6124
-
6125
- }
6126
- }
6127
- }
6128
- } else {
6129
- // 如果不是对象,直接打印
6130
- if(typeof(obj) == 'string'){
6131
-
6132
- if(typeof(obj) == 'string'){
6133
- //console.log(`${parentKey}: ${obj}`);
6134
- if(typeof(kvs[obj]) == 'undefined'){
6135
- kvs[obj] = new Array();
6136
- }
6137
- kvs[obj].push('not key');
6138
- }
6308
+ transString: function (jsString, targetLanguage, successFunction, failureFunction) {
6309
+ let jsObject;
6310
+ try{
6311
+ jsObject = JSON.parse(jsString);
6312
+ }catch(e){
6313
+ failureFunction(e);
6314
+ return;
6315
+ }
6316
+ translate.js.transObject(jsObject, targetLanguage, successFunction, failureFunction);
6317
+ },
6318
+
6319
+ /*
6320
+ jsObject 传入的js对象,支持对象、数组等
6321
+ targetLanguage 翻译为的目标语言
6322
+ successFunction 执行成功后触发,传入格式 function(obj){ console.log(obj); } 其中 obj 是翻译之后的结果
6323
+ failureFunction 执行失败后触发,传入格式 function(failureInfo){ console.log(failureInfo); } 其中 failureInfo 是失败原因
6139
6324
 
6140
-
6141
- }
6142
- }
6325
+ 示例:
6326
+
6327
+ var obj = {
6328
+ "hello":"你好",
6329
+ "word":"单词",
6330
+ "世界":["世界","大海"]
6331
+ };
6332
+ translate.js.transObject(obj,'english',function(obj){ console.log(obj); }, function(failureInfo){ console.log(failureInfo); });
6143
6333
 
6144
- return kvs;
6145
- }
6334
+ */
6335
+ transObject: function (jsObject, targetLanguage, successFunction, failureFunction) {
6336
+ let kvs = translate.js.find(jsObject);
6337
+ //console.log(JSON.stringify(kvs, null, 2));
6338
+
6339
+ /**** 第二步,将文本值进行翻译 ***/
6340
+ //先将其 kvs 的key 取出来
6341
+ var texts = new Array();
6342
+ for (const key in kvs) {
6343
+ texts.push(key);
6344
+ }
6345
+
6346
+ var obj = {
6347
+ from:'auto',
6348
+ to: targetLanguage,
6349
+ texts: texts
6350
+ }
6351
+ translate.request.translateText(obj, function (data) {
6352
+ //打印翻译结果
6353
+ //console.log(data);
6354
+ if(typeof(data.result) == 'undefined' || data.result == 0){
6355
+ failureFunction('network connect failure');
6356
+ return;
6357
+ }
6358
+ if(data.result == 0){
6359
+ failureFunction(data.info);
6360
+ return;
6361
+ }
6362
+
6363
+ /**** 第三步,将翻译结果赋予 jsObject ***/
6364
+ const translatedTexts = data.text; // 获取翻译结果数组
6365
+ if (translatedTexts && translatedTexts.length === texts.length) {
6366
+ texts.forEach((originalText, index) => {
6367
+ const translatedText = translatedTexts[index]; // 根据索引获取翻译结果
6368
+ const paths = kvs[originalText]; // 获取该文本的路径数组
6369
+ if (paths && paths.length > 0) {
6370
+ paths.forEach(path => {
6371
+ translate.js.setValueByPath(jsObject, path, translatedText); // 更新 jsObject
6372
+ });
6373
+ }
6374
+ });
6375
+ } else {
6376
+ console.error("翻译结果长度不匹配或为空");
6377
+ }
6378
+ successFunction(jsObject);
6379
+ //console.log("翻译后的 jsObject:", jsObject);
6380
+ });
6381
+ },
6382
+ setValueByPath: function(obj, path, value){
6383
+ const parts = path.replace(/\[(\d+)\]/g, '.$1').split('.');
6384
+ let current = obj;
6385
+ for (let i = 0; i < parts.length - 1; i++) {
6386
+ current = current[parts[i]];
6387
+ }
6388
+ current[parts[parts.length - 1]] = value;
6389
+ },
6390
+ /*
6391
+ 对js对象进行翻译
6392
+ obj: 可以是JS定义的 对象、数组、甚至是单个具体的值
6393
+
6394
+ var obj = {
6395
+ "hello":"你好",
6396
+ "word":"单词",
6397
+ "世界":["世界","大海"]
6398
+ };
6399
+ translate.js.find(obj);
6400
+
6401
+ */
6402
+ find: function (obj, parentKey = '') {
6403
+ let kvs = {};
6404
+ if (typeof obj === 'object' && obj !== null) {
6405
+ if (Array.isArray(obj)) {
6406
+ obj.forEach((item, index) => {
6407
+ const currentKey = parentKey ? `${parentKey}[${index}]` : `[${index}]`;
6408
+ const subKvs = translate.js.find(item, currentKey);
6409
+ for (const [text, paths] of Object.entries(subKvs)) {
6410
+ if (!kvs[text]) {
6411
+ kvs[text] = [];
6412
+ }
6413
+ kvs[text] = kvs[text].concat(paths);
6414
+ }
6415
+ });
6416
+ } else {
6417
+ for (const key in obj) {
6418
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
6419
+ if (typeof obj[key] === 'object' && obj[key] !== null) {
6420
+ const subKvs = translate.js.find(obj[key], currentKey);
6421
+ for (const [text, paths] of Object.entries(subKvs)) {
6422
+ if (!kvs[text]) {
6423
+ kvs[text] = [];
6424
+ }
6425
+ kvs[text] = kvs[text].concat(paths);
6426
+ }
6427
+ } else if (typeof obj[key] === 'string') {
6428
+ if (typeof kvs[obj[key]] === 'undefined') {
6429
+ kvs[obj[key]] = [];
6430
+ }
6431
+ kvs[obj[key]].push(currentKey);
6432
+ }
6433
+ }
6434
+ }
6435
+ } else if (typeof obj === 'string') {
6436
+ if (typeof kvs[obj] === 'undefined') {
6437
+ kvs[obj] = [];
6438
+ }
6439
+ kvs[obj].push(parentKey);
6440
+ }
6441
+ return kvs;
6442
+ }
6443
+ },
6444
+ /*js dispose end*/
6146
6445
 
6147
6446
 
6148
6447
 
@@ -6218,6 +6517,7 @@ var nodeuuid = {
6218
6517
  }
6219
6518
  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');
6220
6519
 
6520
+ /*兼容 AMD、CMD、CommonJS 规范 - start*/
6221
6521
  /**
6222
6522
  * 兼容 AMD、CMD、CommonJS 规范
6223
6523
  * node 环境使用:`npm i i18n-jsautotranslate` 安装包
@@ -6233,3 +6533,4 @@ console.log('------ translate.js ------\nTwo lines of js html automatic translat
6233
6533
  })(this, function () {
6234
6534
  return translate;
6235
6535
  });
6536
+ /*兼容 AMD、CMD、CommonJS 规范 - end*/