i18n-jsautotranslate 3.14.0 → 3.15.1

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 +7 -5
  3. package/index.js +499 -326
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -14,7 +14,7 @@ var translate = {
14
14
  * 格式:major.minor.patch.date
15
15
  */
16
16
  // AUTO_VERSION_START
17
- version: '3.14.0.20250326',
17
+ version: '3.15.1.20250506',
18
18
  // AUTO_VERSION_END
19
19
  /*
20
20
  当前使用的版本,默认使用v2. 可使用 setUseVersion2();
@@ -1083,13 +1083,17 @@ var translate = {
1083
1083
 
1084
1084
  /*
1085
1085
  每当触发执行 translate.execute() 时,当缓存中未发现,需要请求翻译API进行翻译时,在发送API请求前,触发此
1086
+
1087
+ @param uuid:translate.nodeQueue[uuid] 这里的
1088
+ @param from 来源语种,翻译前的语种
1089
+ @param to 翻译为的语种
1086
1090
  */
1087
1091
  renderStartByApi : [],
1088
- renderStartByApiRun:function(uuid){
1092
+ renderStartByApiRun:function(uuid, from, to){
1089
1093
  //console.log(translate.nodeQueue[uuid]);
1090
1094
  for(var i = 0; i < translate.listener.execute.renderStartByApi.length; i++){
1091
1095
  try{
1092
- translate.listener.execute.renderStartByApi[i](uuid);
1096
+ translate.listener.execute.renderStartByApi[i](uuid, from, to);
1093
1097
  }catch(e){
1094
1098
  console.log(e);
1095
1099
  }
@@ -1098,14 +1102,17 @@ var translate = {
1098
1102
 
1099
1103
  /*
1100
1104
  每当 translate.execute() 执行完毕(前提是采用API翻译的,API将翻译结果返回,并且界面上的翻译结果也已经渲染完毕)后,触发此方法。
1101
- uuid:translate.nodeQueue[uuid] 这里的
1105
+
1106
+ @param uuid:translate.nodeQueue[uuid] 这里的
1107
+ @param from 来源语种,翻译前的语种
1108
+ @param to 翻译为的语种
1102
1109
  */
1103
1110
  renderFinishByApi : [],
1104
- renderFinishByApiRun:function(uuid){
1111
+ renderFinishByApiRun:function(uuid, from, to){
1105
1112
  //console.log(translate.nodeQueue[uuid]);
1106
1113
  for(var i = 0; i < translate.listener.execute.renderFinishByApi.length; i++){
1107
1114
  try{
1108
- translate.listener.execute.renderFinishByApi[i](uuid);
1115
+ translate.listener.execute.renderFinishByApi[i](uuid, from, to);
1109
1116
  }catch(e){
1110
1117
  console.log(e);
1111
1118
  }
@@ -1402,9 +1409,25 @@ var translate = {
1402
1409
  return null;
1403
1410
  }
1404
1411
  },
1405
- //当前 translate.translateRequest[uuid] 的是否已经全部执行完毕,这里单纯只是对 translate.translateRequest[uuid] 的进行判断,这里要在 translate.json 接口触发完并渲染完毕后触发,当然接口失败时也要触发
1406
- 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);
1407
1429
  for(var lang in translate.translateRequest[uuid]){
1430
+ //console.log(translate.translateRequest[uuid])
1408
1431
  for(var i = 0; i<translate.translateRequest[uuid][lang].length; i++){
1409
1432
  if(translate.translateRequest[uuid][lang][i].executeFinish == 0){
1410
1433
  //这个还没执行完,那么直接退出,不在向后执行了
@@ -1421,7 +1444,7 @@ var translate = {
1421
1444
  translate.state = 0;
1422
1445
  translate.executeNumber++;
1423
1446
 
1424
- translate.listener.execute.renderFinishByApiRun(uuid);
1447
+ translate.listener.execute.renderFinishByApiRun(uuid, from, to);
1425
1448
  }
1426
1449
 
1427
1450
  },
@@ -1996,9 +2019,7 @@ var translate = {
1996
2019
  //状态
1997
2020
  translate.state = 20;
1998
2021
 
1999
- //listener
2000
- translate.listener.execute.renderStartByApiRun(uuid);
2001
-
2022
+
2002
2023
  //进行掉接口翻译
2003
2024
  for(var lang_index in fanyiLangs){ //一维数组,取语言
2004
2025
  var lang = fanyiLangs[lang_index];
@@ -2026,6 +2047,9 @@ var translate = {
2026
2047
  translate.translateRequest[uuid][lang].addtime = Math.floor(Date.now() / 1000);
2027
2048
 
2028
2049
 
2050
+ //listener
2051
+ translate.listener.execute.renderStartByApiRun(uuid, lang, translate.to);
2052
+
2029
2053
  /*** 翻译开始 ***/
2030
2054
  var url = translate.request.api.translate;
2031
2055
  var data = {
@@ -2035,7 +2059,6 @@ var translate = {
2035
2059
  //text:JSON.stringify(translateTextArray[lang])
2036
2060
  text:encodeURIComponent(JSON.stringify(translateTextArray[lang]))
2037
2061
  };
2038
- //console.log(data);
2039
2062
  translate.request.post(url, data, function(data){
2040
2063
  //console.log(data);
2041
2064
  //console.log(translateTextArray[data.from]);
@@ -2047,8 +2070,20 @@ var translate = {
2047
2070
  }else{
2048
2071
  console.log('WARINNG!!! translate.translateRequest[uuid][data.from] is not object');
2049
2072
  }
2050
-
2051
- translate.waitingExecute.isAllExecuteFinish(uuid);
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
+
2052
2087
  console.log('=======ERROR START=======');
2053
2088
  console.log(translateTextArray[data.from]);
2054
2089
  //console.log(encodeURIComponent(JSON.stringify(translateTextArray[data.from])));
@@ -2127,13 +2162,13 @@ var translate = {
2127
2162
  translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
2128
2163
  translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
2129
2164
  setTimeout(function(){
2130
- translate.waitingExecute.isAllExecuteFinish(uuid);
2165
+ translate.waitingExecute.isAllExecuteFinish(uuid, data.from, data.to);
2131
2166
  },10);
2132
2167
  }, function(xhr){
2133
2168
  translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
2134
2169
  translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
2135
2170
  translate.translateRequest[uuid][lang].result = 3;
2136
- translate.waitingExecute.isAllExecuteFinish(uuid);
2171
+ translate.waitingExecute.isAllExecuteFinish(uuid, lang, translate.to);
2137
2172
  });
2138
2173
  /*** 翻译end ***/
2139
2174
  }
@@ -2246,14 +2281,16 @@ var translate = {
2246
2281
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2247
2282
  if(typeof(node[attribute]) != 'undefined'){
2248
2283
  //这种是主流框架,像是vue、element、react 都是用这种 DOM Property 的方式,更快
2249
- 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));
2250
2286
  }
2251
2287
 
2252
2288
  //这种 Html Attribute 方式 是 v3.12 版本之前一直使用的方式,速度上要慢于 上面的,为了向前兼容不至于升级出问题,后面可能会优化掉
2253
2289
  var htmlAttributeValue = node.getAttribute(attribute);
2254
2290
  if(htmlAttributeValue != null && typeof(htmlAttributeValue) != 'undefined'){
2255
2291
  //这个才是在v3.9.2 后要用的,上面的留着只是为了适配以前的
2256
- 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)));
2257
2294
  }
2258
2295
  }
2259
2296
  return result;
@@ -2301,7 +2338,8 @@ var translate = {
2301
2338
  //替换渲染
2302
2339
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2303
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));
2304
- 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));
2305
2343
  }
2306
2344
 
2307
2345
  result['text'] = input_value_node.nodeValue;
@@ -2318,7 +2356,8 @@ var translate = {
2318
2356
  //替换渲染
2319
2357
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2320
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));
2321
- 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));
2322
2361
  }
2323
2362
 
2324
2363
  result['text'] = node.attributes['placeholder'].nodeValue;
@@ -2343,7 +2382,8 @@ var translate = {
2343
2382
  //替换渲染
2344
2383
  if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
2345
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));
2346
- 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));
2347
2387
  }
2348
2388
 
2349
2389
  result['text'] = node.content;
@@ -2363,7 +2403,8 @@ var translate = {
2363
2403
  //替换渲染
2364
2404
  if(typeof(originalText) != 'undefined' && originalText.length > 0){
2365
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));
2366
- 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));
2367
2408
  }
2368
2409
  result['text'] = node.alt;
2369
2410
  return result;
@@ -2380,7 +2421,8 @@ var translate = {
2380
2421
  //替换渲染
2381
2422
  if(typeof(originalText) != 'undefined' && originalText != null && originalText.length > 0){
2382
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));
2383
- 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));
2384
2426
  }
2385
2427
  result['text'] = node.nodeValue;
2386
2428
  }
@@ -2792,28 +2834,29 @@ var translate = {
2792
2834
  }
2793
2835
  }
2794
2836
 
2795
-
2796
- //判断当前是否是英语及变种,也就是单词之间需要有空格的,如果前后没有空格,要补充上空格
2797
- if(translate.language.wordBlankConnector(translate.to)){
2798
- if(wordKeyIndex > 0){
2799
- //它前面还有文本,判断它前面的文本是否是空格,如果不是,那么要补充上空格
2800
- var before = text.charAt(wordKeyIndex-1);
2801
- //console.log(before);
2802
- if(!(/\s/.test(before))){
2803
- //不是空白字符,补充上一个空格,用于将两个单词隔开
2804
- nomenclatureValue = ' '+nomenclatureValue
2805
- }
2806
- }
2807
- if(wordKeyIndex + nomenclatureKey.length < text.length){
2808
- //它后面还有文本,判断它前面的文本是否是空格,如果不是,那么要补充上空格
2809
- var after = text.charAt(wordKeyIndex + nomenclatureKey.length);
2810
- //console.log(after);
2811
- if(!(/\s/.test(before))){
2812
- //不是空白字符,补充上一个空格,用于将两个单词隔开
2813
- nomenclatureValue = nomenclatureValue+' ';
2814
- }
2815
- }
2816
- }
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
+ // }
2817
2860
 
2818
2861
  //如果是自定义术语的key等于value,则是属于指定的某些文本不进行翻译的情况,所以这里要单独判断一下
2819
2862
  //console.log(nomenclatureKey+':'+nomenclatureValue);
@@ -2859,6 +2902,7 @@ var translate = {
2859
2902
  }
2860
2903
  }
2861
2904
 
2905
+ //console.log(textArray);
2862
2906
  return textArray;
2863
2907
  },
2864
2908
 
@@ -3455,7 +3499,8 @@ var translate = {
3455
3499
  languageName 是当前字符串最终判定结果是什么语种。它的识别有以下特点:
3456
3500
  1. 如果出现英语跟中文、罗曼语族、德语等混合的情况,也就是不纯粹英语的情况,那么会以其他语种为准,而不是识别为英语。不论英语字符出现的比例占多少。
3457
3501
  2. 如果出现简体中文跟繁体中文混合的情况,那么识别为繁体中文。不论简体中文字符出现的比例占多少。
3458
- 3. 除了以上两种规则外,如果出现了多个语种,那么会识别为出现字符数量最多的语种当做当前句子的语种。(注意是字符数,而不是语种的数组数)
3502
+ 3. 如果出现简体中文、繁体中文、日语混合的情况,那么识别为日语。不论简体中文、繁体中文出现的比例占多少。 2025.4.19 增加
3503
+ 4. 除了以上两种规则外,如果出现了多个语种,那么会识别为出现字符数量最多的语种当做当前句子的语种。(注意是字符数,而不是语种的数组数)
3459
3504
  languageArray 对传入字符串进行分析,识别出都有哪些语种,每个语种的字符是什么
3460
3505
  *
3461
3506
  */
@@ -3506,13 +3551,21 @@ var translate = {
3506
3551
  }
3507
3552
  }
3508
3553
 
3554
+ //如果简体中文跟繁体中文一起出现,那么会判断当前句子为繁体中文,将简体中文字符数置0
3509
3555
  if(langkeys.indexOf('chinese_simplified') > -1 && langkeys.indexOf('chinese_traditional') > -1){
3510
- //如果简体中文跟繁体中文一起出现,那么会判断当前句子为繁体中文。
3511
3556
  //langkeys.splice(langkeys.indexOf('chinese_simplified'), 1);
3512
3557
  langsNumber['chinese_simplified'] = 0;
3513
3558
  }
3514
3559
 
3515
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
+
3516
3569
  //从 langsNumber 中找出字数最多的来
3517
3570
  var maxLang = ''; //字数最多的语种
3518
3571
  var maxNumber = 0;
@@ -3561,6 +3614,9 @@ var translate = {
3561
3614
  japanese 日语
3562
3615
  korean 韩语
3563
3616
  greek 希腊语
3617
+ thai 泰语
3618
+ arabic 阿拉伯语
3619
+ romanian 罗马尼亚语
3564
3620
  */
3565
3621
  getCharLanguage:function(charstr){
3566
3622
  if(charstr == null || typeof(charstr) == 'undefined'){
@@ -3600,7 +3656,15 @@ var translate = {
3600
3656
  if(this.greek(charstr)){
3601
3657
  return 'greek';
3602
3658
  }
3603
-
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
+ }
3604
3668
  //未识别是什么语种
3605
3669
  //console.log('not find is language , char : '+charstr+', unicode: '+charstr.charCodeAt(0).toString(16));
3606
3670
  return '';
@@ -3867,6 +3931,7 @@ var translate = {
3867
3931
  return false;
3868
3932
  },
3869
3933
  //语种的单词连接符是否需要空格,比如中文简体、繁体、韩文、日语都不需要空格,则返回false, 但是像是英文的单词间需要空格进行隔开,则返回true
3934
+ //另外这也是区分是否使用标点符号 ,。还是 ,. 的
3870
3935
  //如果未匹配到,默认返回true
3871
3936
  //language:语种,传入如 english
3872
3937
  wordBlankConnector:function(language){
@@ -3924,13 +3989,39 @@ var translate = {
3924
3989
  },
3925
3990
  //是否包含俄语
3926
3991
  russian:function(str){
3927
- //判断字符有 БВДЖЗИЙЛМНОПСТУФХЦЧШЩЪЫЬЮЯЇІ
3928
- 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)){
3992
+ // 正则表达式匹配俄语大小写字母(包含 Ё/ё,排除其他语言特有的西里尔字符)
3993
+ //АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЮюЯя
3994
+ if(/^[А-Яа-яЁё]$/.test(str)){
3929
3995
  return true
3930
3996
  } else {
3931
3997
  return false;
3932
3998
  }
3933
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
+ },
3934
4025
  //是否包含希腊语
3935
4026
  greek:function(str){
3936
4027
  const greekRegex = /^[\u0391-\u03A9\u03B1-\u03C9]$/;
@@ -4048,12 +4139,7 @@ var translate = {
4048
4139
  return true;
4049
4140
  }
4050
4141
 
4051
- /*
4052
- //阿拉伯数字 0-9
4053
- if(/.*[\u0030-\u0039]+.*$/.test(str)){
4054
- return true;
4055
- }
4056
- */
4142
+
4057
4143
 
4058
4144
  /*
4059
4145
  U+0020 空格
@@ -4108,132 +4194,11 @@ var translate = {
4108
4194
  }
4109
4195
 
4110
4196
  /*
4111
- 拉丁字母
4112
- 代码 显示 描述
4113
- U+00A1 ¡ 倒转的叹号
4114
- U+00A2 ¢ (货币单位)分钱、毫子
4115
- U+00A3 £ (货币)英镑
4116
- U+00A4 ¤ (货币)当货币未有符号时以此替代
4117
- U+00A5 ¥ (货币)日元
4118
- U+00A6 ¦ 两条断开的直线
4119
- U+00A7 § 文件分不同部分
4120
- U+00A8 ¨ (语言)分音
4121
- U+00A9 © 版权符
4122
- U+00AA ª (意大利文、葡萄牙文、西班牙文)阴性序数
4123
- U+00AB « 双重角形引号
4124
- U+00AC ¬ 逻辑非
4125
- U+00AE ® 商标
4126
- U+00AF ¯ 长音
4127
- U+00B0 ° 角度
4128
- U+00B1 ± 正负号
4129
- U+00B2 ² 二次方
4130
- U+00B3 ³ 三次方
4131
- U+00B4 ´ 锐音符
4132
- U+00B5 µ 百万分之一,10?6
4133
- U+00B6 ¶ 文章分段
4134
- U+00B7 · 间隔号
4135
- U+00B8 ¸ 软音符
4136
- U+00B9 ¹ 一次方
4137
- U+00BA º (意大利文、葡萄牙文、西班牙文)阳性序数
4138
- U+00BB » 指向右的双箭头
4139
- U+00BC ¼ 四分之一
4140
- U+00BD ½ 二分之一
4141
- U+00BE ¾ 四分之三
4142
- U+00BF ¿ 倒转的问号
4143
- U+00C1 Á 在拉丁字母 A 上加锐音符
4144
- U+00C2 Â 在拉丁字母 A 上加抑扬符“^”
4145
- U+00C3 Ã 在拉丁字母 A 上加“~”
4146
- U+00C4 Ä 在拉丁字母 A 上加分音符“..”
4147
- U+00C5 Å 在拉丁字母 A 上加角度符“°”
4148
- U+00C6 Æ 拉丁字母 A、E 的混合
4149
- U+00C7 Ç 在拉丁字母 C 下加软音符
4150
- U+00C8 È 在拉丁字母 E 上加重音符
4151
- U+00C9 É 在拉丁字母 E 上加锐音符
4152
- U+00CA Ê 在拉丁字母 E 上加抑扬符
4153
- U+00CB Ë 在拉丁字母 E 上加分音符
4154
- U+00CC Ì 在拉丁字母 I 上加重音符
4155
- U+00CD Í 在拉丁字母 I 上加锐音符
4156
- U+00CE Î 在拉丁字母 I 上加抑扬符
4157
- U+00CF Ï 在拉丁字母 I 上加分音符
4158
- U+00D0 Ð 古拉丁字母,现只有法罗文和冰岛文和越南语使用
4159
- U+00D1 Ñ 在拉丁字母 N 上加波浪纹“~”
4160
- U+00D2 Ò 在拉丁字母 O 上加重音符
4161
- U+00D3 Ó 在拉丁字母 O 上加锐音符
4162
- U+00D4 Ô 在拉丁字母 O 上加抑扬符
4163
- U+00D5 Õ 在拉丁字母 O 上加波浪纹“~”
4164
- U+00D6 Ö 在拉丁字母 O 上加分音符
4165
- U+00D7 × 乘号,亦可拖按“Alt”键,同时按“41425”五键
4166
- U+00D8 Ø 在拉丁字母 O 由右上至左下加对角斜线“/”
4167
- U+00D9 Ù 在拉丁字母 U 上加重音符
4168
- U+00DA Ú 在拉丁字母 U 上加锐音符
4169
- U+00DB Û 在拉丁字母 U 上加抑扬符
4170
- U+00DC Ü 在拉丁字母 U 上加分音符
4171
- U+00DD Ý 在拉丁字母 Y 上加锐音符
4172
- U+00DE Þ 古拉丁字母,现已被“Th”取替
4173
- U+00DF ß 德文字母
4174
- U+00E0 à 在拉丁字母 a 上加重音符
4175
- U+00E1 á 在拉丁字母 a 上加锐音符
4176
- U+00E2 â 在拉丁字母 a 上加抑扬符
4177
- U+00E3 ã 在拉丁字母 a 上加波浪纹“~”
4178
- U+00E4 ä 在拉丁字母 a 上加分音符
4179
- U+00E5 å 在拉丁字母 a 上加角度符“°”
4180
- U+00E6 æ 拉丁字母 a、e 的混合
4181
- U+00E7 ç 在拉丁字母 c 下加软音符
4182
- U+00E8 è 在拉丁字母 e 上加锐音符
4183
- U+00E9 é 在拉丁字母 e 上加重音符
4184
- U+00EA ê 在拉丁字母 e 上加抑扬符
4185
- U+00EB ë 在拉丁字母 e 上加分音符
4186
- U+00EC ì 在拉丁字母 i 上加重音符
4187
- U+00ED í 在拉丁字母 i 上加锐音符
4188
- U+00EE î 在拉丁字母 i 上加抑扬符
4189
- U+00EF ï 在拉丁字母 i 上加分音符
4190
- U+00F0 ð 古拉丁字母
4191
- U+00F1 ñ 在拉丁字母 n 上加波浪纹“~”
4192
- U+00F2 ò 在拉丁字母 o 上加重音符
4193
- U+00F3 ó 在拉丁字母 o 上加锐音符
4194
- U+00F4 ô 在拉丁字母 o 上加抑扬符
4195
- U+00F5 õ 在拉丁字母 o 上加波浪纹“~”
4196
- U+00F6 ö 在拉丁字母 o 上加分音符
4197
- U+00F7 ÷ 除号,亦可拖按“Alt”键,同时按“41426”五键
4198
- U+00F8 ø 在拉丁字母 o 由右上至左下加对角斜线“/”
4199
- U+00F9 ù 在拉丁字母 u 上加重音符
4200
- U+00FA ú 在拉丁字母 u 上加锐音符
4201
- U+00FB ? 在拉丁字母 u 上加抑扬符
4202
- U+00FC ü 在拉丁字母 u 上加分音符
4203
- U+00FD ý 在拉丁字母 y 上加锐音符
4204
- U+00FE þ 古拉丁字母,现已被“th”取替
4205
- U+00FF ü 在拉丁字母 u 上加分音符
4206
- 拉丁字母(扩展 A)
4207
- 代码 显示 描述
4208
- U+0100 Ā 在拉丁字母 A 上加长音符
4209
- U+0101 ā 在拉丁字母 a 上加长音符
4210
- U+0102 Ă 在拉丁字母 A 上加短音符
4211
- U+0103 ă 在拉丁字母 a 上加短音符
4212
- U+0104 Ą 在拉丁字母 A 上加反尾形符
4213
- U+0105 ą 在拉丁字母 a 上加反尾形符
4214
- 拉丁字母(扩展 C)
4215
- 代码 显示 描述
4216
- U+2C60 Ⱡ 在拉丁字母“L”中间加两条横线“=”
4217
- U+2C61 ⱡ 在拉丁字母“l”(L 的小写)中间加两条横线“=”
4218
- U+2C62 Ɫ 在拉丁字母“L”(大写)中间加一条波浪线“~”
4219
- U+2C63 Ᵽ 在拉丁字母“P”中间加一条横线“-”
4220
- U+2C64 Ɽ 在拉丁字母“R”下加一条尾巴
4221
- U+2C65 ⱥ 在拉丁字母“a”上加一条对角斜线“/”
4222
- U+2C66 ⱦ 在拉丁字母“t”上加一条对角斜线“/”
4223
- U+2C67 Ⱨ 在拉丁字母“H”下加一条尾巴
4224
- U+2C68 ⱨ 在拉丁字母“h”下加一条尾巴
4225
- U+2C69 Ⱪ 在拉丁字母“K”下加一条尾巴
4226
- U+2C6A ⱪ 在拉丁字母“k”下加一条尾巴
4227
- U+2C6B Ⱬ 在拉丁字母“Z”下加一条尾巴
4228
- U+2C6C ⱬ 在拉丁字母“z”下加一条尾巴
4229
- U+2C74 ⱴ 在拉丁字母“v”的起笔加一个弯勾
4230
- U+2C75 Ⱶ 拉丁字母“H”的左半部
4231
- U+2C76 ⱶ 拉丁字母“h”的左半部
4232
- U+2C77 ⱷ 希腊字母“φ”的上半部
4197
+ 这些字符主要是 罕见的拉丁字母变体 ,通常用于:
4198
+ 某些非洲语言或方言;
4199
+ 古文字、语音学符号;
4200
+ 特殊排版或装饰性字体。
4233
4201
  */
4234
- if(/.*[\u00A1-\u0105]+.*$/.test(str)){
4235
- return true;
4236
- }
4237
4202
  if(/.*[\u2C60-\u2C77]+.*$/.test(str)){
4238
4203
  return true;
4239
4204
  }
@@ -4244,7 +4209,8 @@ var translate = {
4244
4209
  /*
4245
4210
  文本翻译的替换。
4246
4211
 
4247
-
4212
+ @Deprecated 2025.4.26 最新的在 translate.util.textReplace
4213
+
4248
4214
  text: 原始文本,翻译的某句或者某个词就在这个文本之中
4249
4215
  translateOriginal: 翻译的某个词或句,在翻译之前的文本
4250
4216
  translateResult: 翻译的某个词或句,在翻译之后的文本,翻译结果
@@ -4255,56 +4221,12 @@ var translate = {
4255
4221
  使用此方法:
4256
4222
  var text = '你世好word世界';
4257
4223
  var translateOriginal = '世';
4258
- var translateResult = 'shi'; //翻译结果
4224
+ var translateResult = '世杰'; //翻译结果
4259
4225
  translate.language.textTranslateReplace(text, translateOriginal, translateResult, 'english');
4260
-
4226
+
4261
4227
  */
4262
4228
  textTranslateReplace:function(text, translateOriginal, translateResult, language){
4263
- if(translateResult.indexOf(translateOriginal) > -1){
4264
- return text;
4265
- }
4266
-
4267
-
4268
- let replaceResultText = ''+translateResult; //要替换的结果文本(这个文本可能前面有加空格或者后面有加空格的)
4269
-
4270
- if(translate.language.wordBlankConnector(translate.to)){
4271
- let originalIndex = text.indexOf(translateOriginal); //翻译之前,翻译的单词在字符串中的其实坐标(0开始)
4272
- //console.log("originalIndex: "+originalIndex);
4273
-
4274
- //要先判断后面,不然先判断前面,加了后它的长度就又变了
4275
-
4276
- //判断它后面是否还有文本
4277
- if(originalIndex+1 < text.length){
4278
- let char = text.charAt(originalIndex+translateOriginal.length);
4279
- //console.log(char);
4280
- if(!(/\s/.test(char))){
4281
- //不是空白字符,补充上一个空格,用于将两个单词隔开
4282
- //text = text.replace(translateOriginal, translateResult+' ');
4283
- replaceResultText = replaceResultText + ' ';
4284
- }
4285
- }
4286
-
4287
- //判断它前面是否还有文本
4288
- if(originalIndex > 0){
4289
- let char = text.charAt(originalIndex-1);
4290
- //console.log(char);
4291
- if(!(/\s/.test(char))){
4292
- //不是空白字符,补充上一个空格,用于将两个单词隔开
4293
- //text = text.replace(translateOriginal, ' '+translateResult);
4294
- replaceResultText = ' '+replaceResultText;
4295
- }
4296
- }
4297
- }
4298
- let resultText = text.replace(translateOriginal, replaceResultText);
4299
-
4300
- if(resultText.indexOf(translateOriginal) > -1){
4301
- //还有第二个、第三个单词一样,也要替换
4302
- //console.log(this);
4303
- resultText = this.textTranslateReplace(resultText, translateOriginal, translateResult, language);
4304
- }
4305
-
4306
- //console.log(resultText);
4307
- return resultText;
4229
+ return translate.util.textReplace(text, translateOriginal, translateResult, language);
4308
4230
  }
4309
4231
  },
4310
4232
  //用户第一次打开网页时,自动判断当前用户所在国家使用的是哪种语言,来自动进行切换为用户所在国家的语种。
@@ -4334,6 +4256,138 @@ var translate = {
4334
4256
  },
4335
4257
 
4336
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
+
4337
4391
  /* 生成一个随机UUID,复制于 https://gitee.com/mail_osc/kefu.js */
4338
4392
  uuid:function() {
4339
4393
  var d = new Date().getTime();
@@ -5100,6 +5154,7 @@ var translate = {
5100
5154
  //console.log('response------');
5101
5155
  //console.log(xhr);
5102
5156
  },
5157
+
5103
5158
  /*
5104
5159
  速度检测控制中心, 检测主备翻译接口的响应速度进行排列,真正请求时,按照排列的顺序进行请求
5105
5160
  v2.8.2增加
@@ -5146,6 +5201,16 @@ var translate = {
5146
5201
  hostQueueIndex:-1, //当前使用的 hostQueue的数组下标, -1表示还未初始化赋予值,不可直接使用,通过 getHostQueueIndex() 使用
5147
5202
  disableTime:1000000, //不可用的时间,storage中存储的 speedDetectionControl_hostQueue 其中 time 这里,如果值是 这个,便是代表这个host处于不可用状态
5148
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
+ },
5149
5214
 
5150
5215
  //获取 host queue 队列
5151
5216
  getHostQueue:function(){
@@ -5153,7 +5218,7 @@ var translate = {
5153
5218
  //还没有,先从本地存储中取,看之前是否已经设置过了
5154
5219
  // 只有经过真正的网络测速后,才会加入 storage 的 hostQueue
5155
5220
  var storage_hostQueue = translate.storage.get('speedDetectionControl_hostQueue');
5156
- if(storage_hostQueue == null || typeof(storage_hostQueue) == 'undefined'){
5221
+ if(storage_hostQueue == null || typeof(storage_hostQueue) == 'undefined' || storage_hostQueue == ''){
5157
5222
  //本地存储中没有,也就是之前没设置过,是第一次用,那么直接讲 translate.request.api.host 赋予之
5158
5223
  //translate.request.api.host
5159
5224
 
@@ -6136,28 +6201,34 @@ var translate = {
6136
6201
 
6137
6202
 
6138
6203
  if(translate.progress.api.isTip){
6139
- translate.listener.execute.renderStartByApi.push(function(uuid){
6204
+ translate.listener.execute.renderStartByApi.push(function(uuid, from, to){
6140
6205
  for(var lang in translate.nodeQueue[uuid].list){
6141
- if(translate.language.getCurrent() == lang){
6142
- //忽略这个语种
6143
- continue;
6144
- }
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
+
6145
6214
  for(var hash in translate.nodeQueue[uuid].list[lang]){
6146
6215
  for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
6147
6216
  var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
6217
+ //console.log(node);
6148
6218
  var nodeParent = node.parentNode;
6149
6219
  if(nodeParent == null){
6150
6220
  continue;
6151
6221
  }
6222
+ /* 这里先不考虑多隐藏的问题,只要符合的都隐藏,宁愿吧一些不需要隐藏的也会跟着一起隐藏
6152
6223
  if(nodeParent.childNodes.length != 1){
6224
+ //这个文本节点所在的元素里,不止有这一个文本元素,还有别的文本元素
6153
6225
  continue;
6154
6226
  }
6155
-
6227
+ */
6156
6228
  if(typeof(nodeParent.className) == 'undefined' || nodeParent.className == null || nodeParent.className == ''){
6157
6229
  nodeParent.className = ' translate_api_in_progress';
6158
6230
  }else{
6159
6231
  //这个元素本身有class了,那就追加
6160
-
6161
6232
  if(nodeParent.className.indexOf('translate_api_in_progress') > -1){
6162
6233
  continue;
6163
6234
  }
@@ -6169,107 +6240,209 @@ var translate = {
6169
6240
  }
6170
6241
  }
6171
6242
  });
6172
- translate.listener.execute.renderFinishByApi.push(function(uuid){
6173
- for(var lang in translate.nodeQueue[uuid].list){
6174
- if(translate.language.getCurrent() == lang){
6175
- //忽略这个语种
6176
- continue;
6177
- }
6178
- for(var hash in translate.nodeQueue[uuid].list[lang]){
6179
- for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
6180
- var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
6181
- var nodeParent = node.parentNode;
6182
- if(nodeParent == null){
6183
- continue;
6184
- }
6185
-
6186
- /*
6187
- 注释这个,因为可能是给这个元素动态追加删除导致其子元素不是11
6188
- if(nodeParent.childNodes.length != 1){
6189
- continue;
6190
- }
6191
- */
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
+ */
6192
6260
 
6193
- var parentClassName = nodeParent.className;
6194
- if(typeof(parentClassName) == 'undefined' || parentClassName == null || parentClassName == ''){
6195
- continue;
6196
- }
6197
- if(parentClassName.indexOf('translate_api_in_progress') < -1){
6198
- continue;
6199
- }
6200
-
6201
- nodeParent.className = parentClassName.replace(/translate_api_in_progress/g, '');
6202
- //nodeParent.className = parentClassName.replace(/loading/g, '');
6203
- }
6204
- }
6205
- }
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
+
6206
6274
  });
6207
6275
 
6208
6276
  }
6209
6277
  }
6210
6278
  }
6211
6279
  },
6280
+
6281
+ /*js dispose start*/
6212
6282
  /*
6213
- 对js对象进行翻译
6214
- obj: 可以是JS定义的 对象、数组、甚至是单个具体的值
6283
+ 对js对象内的值进行翻译,可以是JS定义的 对象、数组、甚至是单个具体的值
6215
6284
  */
6216
- jsObject:function (obj, parentKey = '') {
6285
+ js:{
6286
+
6217
6287
  /*
6218
- 存放扫描的结果
6219
- key 存放要被翻译的文本,也就是对象里面某个具体属性的值
6220
- 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
+
6221
6307
  */
6222
- var kvs = {};
6223
-
6224
- if (typeof obj === 'object' && obj!== null) {
6225
- if (Array.isArray(obj)) {
6226
- // 处理数组
6227
- obj.forEach((item, index) => {
6228
- const currentKey = parentKey? `${parentKey}[${index}]` : `[${index}]`;
6229
- translate.jsObject(item, currentKey);
6230
- });
6231
- } else {
6232
- // 处理普通对象
6233
- for (const key in obj) {
6234
- const currentKey = parentKey? `${parentKey}.${key}` : key;
6235
- if (typeof obj[key] === 'object' && obj[key]!== null) {
6236
- // 如果值是对象,递归调用函数
6237
- translate.jsObject(obj[key], currentKey);
6238
- } else {
6239
- // 打印键值对
6240
-
6241
- if(typeof(obj[key]) == 'string'){
6242
- //console.log(`${currentKey}: ${obj[key]}`);
6243
- //console.log(obj[key]);
6244
- //console.log(typeof(kvs[obj[key]]));
6245
- if(typeof(kvs[obj[key]]) == 'undefined'){
6246
- kvs[obj[key]] = new Array();
6247
- }
6248
- //kvs[obj[key].push(currentKey);
6249
- }
6250
-
6251
- }
6252
- }
6253
- }
6254
- } else {
6255
- // 如果不是对象,直接打印
6256
- if(typeof(obj) == 'string'){
6257
-
6258
- if(typeof(obj) == 'string'){
6259
- //console.log(`${parentKey}: ${obj}`);
6260
- if(typeof(kvs[obj]) == 'undefined'){
6261
- kvs[obj] = new Array();
6262
- }
6263
- kvs[obj].push('not key');
6264
- }
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 是失败原因
6324
+
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); });
6333
+
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
+ }
6265
6345
 
6266
-
6267
- }
6268
- }
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*/
6269
6445
 
6270
- return kvs;
6271
- }
6272
- /*jsObject end*/
6273
6446
 
6274
6447
 
6275
6448
  }