i18n-jsautotranslate 3.18.63 → 3.18.71

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/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.18.63.20250928',
17
+ version: '3.18.71.20251010',
18
18
  // AUTO_VERSION_END
19
19
  /*
20
20
  当前使用的版本,默认使用v2. 可使用 setUseVersion2();
@@ -73,6 +73,11 @@ var translate = {
73
73
  */
74
74
  languages:'',
75
75
  alreadyRender:false, //当前是否已渲染过了 true为是 v2.2增加
76
+
77
+ changeLanguageBeforeLoadOfflineFile: function(path){
78
+
79
+ },
80
+
76
81
  selectOnChange:function(event){
77
82
  var language = event.target.value;
78
83
  translate.changeLanguage(language);
@@ -518,6 +523,12 @@ var translate = {
518
523
  if(ele == null || typeof(ele) == 'undefined'){
519
524
  return false;
520
525
  }
526
+ if(ele.nodeType === 2){ //是属性,将其转为元素判断,因为当前忽略配置,是针对元素配置的
527
+ ele = ele.ownerElement;
528
+ }else if(ele.nodeType === 3){
529
+ //文本节点,转为元素
530
+ ele = ele.parentNode;
531
+ }
521
532
 
522
533
  var parentNode = ele;
523
534
  var maxnumber = 100; //最大循环次数,避免死循环
@@ -765,8 +776,7 @@ var translate = {
765
776
  * 如果传入 null,则不进行任何替换操作
766
777
  * 如果传入具体的值,则是:
767
778
  * {
768
- * node: node节点
769
- * attribute: 要替换的node的attribute名称。如果传入 null,则是直接对 nodeValue 生效
779
+ * node: node节点 ,要改动的文字所在的node节点。 如果改动的文字比如是 div 的title中,那么这里传入的node应该是 title 的node,而不是 div 的node
770
780
  * }
771
781
  *
772
782
  * @returns {
@@ -899,8 +909,7 @@ var translate = {
899
909
  如果传入 null,则不进行任何替换操作
900
910
  如果传入具体的值,则是:
901
911
  {
902
- node: node节点
903
- attribute: 要替换的node的attribute名称。如果传入 null,则是直接对 nodeValue 生效
912
+ node: node节点 ,要改动的文字所在的node节点。 如果改动的文字比如是 div 的title中,那么这里传入的node应该是 title 的node,而不是 div 的node
904
913
  }
905
914
 
906
915
 
@@ -946,7 +955,22 @@ var translate = {
946
955
  },
947
956
  },
948
957
 
958
+ //已转为 offline ,这个是对旧版做兼容
949
959
  office:{
960
+ export:function(){
961
+ console.log('请使用最新版本的 translate.offline.export , 而不是 translate.office.export');
962
+ },
963
+ showPanel:function(){
964
+ console.log('请使用最新版本的 translate.offline.showPanel , 而不是 translate.office.export');
965
+ },
966
+ append:function(to, properties){
967
+ translate.offline.append(to, properties);
968
+ },
969
+ fullExtract:{
970
+ isUse:false
971
+ }
972
+ },
973
+ offline:{
950
974
  /*
951
975
  网页上翻译之后,自动导出当前页面的术语库
952
976
 
@@ -992,7 +1016,7 @@ var translate = {
992
1016
 
993
1017
  if(text.length > 0){
994
1018
  //有内容
995
- text = 'translate.office.append(\''+translate.language.getCurrent()+'\',`'+text+'\n`);';
1019
+ text = 'translate.offline.append(\''+translate.language.getCurrent()+'\',`'+text+'\n`);';
996
1020
  //console.log(text);
997
1021
  translate.util.loadMsgJs();
998
1022
  msg.popups({
@@ -1017,7 +1041,7 @@ var translate = {
1017
1041
  //导出按钮
1018
1042
  let button = document.createElement('button');
1019
1043
  button.onclick = function() {
1020
- translate.office.export();
1044
+ translate.offline.export();
1021
1045
  };
1022
1046
  button.innerHTML = '导出配置信息';
1023
1047
  button.setAttribute('style', 'margin-left: 72px; margin-top: 30px; margin-bottom: 20px; font-size: 25px; background-color: blue; padding: 15px; padding-top: 3px; padding-bottom: 3px; border-radius: 3px;');
@@ -1080,7 +1104,7 @@ var translate = {
1080
1104
 
1081
1105
  //全部提取能力(整站的离线翻译数据提取)
1082
1106
  fullExtract:{
1083
- /*js translate.office.fullExtract.set start*/
1107
+ /*js translate.offline.fullExtract.set start*/
1084
1108
  /*
1085
1109
  将翻译的结果加入
1086
1110
  hash: 翻译前的文本的hash
@@ -1102,9 +1126,9 @@ var translate = {
1102
1126
  obj[toLanguage] = translateText;
1103
1127
  await translate.storage.IndexedDB.set('hash_'+hash, obj);
1104
1128
  },
1105
- /*js translate.office.fullExtract.set end*/
1129
+ /*js translate.offline.fullExtract.set end*/
1106
1130
 
1107
- /*js translate.office.fullExtract.export start*/
1131
+ /*js translate.offline.fullExtract.export start*/
1108
1132
  /*
1109
1133
  将存储的数据导出为 txt 文件下载下来
1110
1134
  */
@@ -1117,7 +1141,7 @@ var translate = {
1117
1141
  translate.log('error : to param not find, example: "english"');
1118
1142
  return;
1119
1143
  }
1120
- var text = 'translate.office.append(\'';
1144
+ var text = 'translate.offline.append(\''+to+'\',`';
1121
1145
 
1122
1146
  var data = await translate.storage.IndexedDB.list('hash_*');
1123
1147
  for(var i in data){
@@ -1137,7 +1161,7 @@ var translate = {
1137
1161
  link.click();
1138
1162
  URL.revokeObjectURL(url);
1139
1163
  },
1140
- /*js translate.office.fullExtract.export end*/
1164
+ /*js translate.offline.fullExtract.export end*/
1141
1165
 
1142
1166
  /*
1143
1167
  是否启用全部提取的能力
@@ -1309,6 +1333,54 @@ var translate = {
1309
1333
  //console.log('refresh ignore finish: '+Object.keys(translate.listener.ignoreNode).length);
1310
1334
  },
1311
1335
 
1336
+ /*
1337
+ 用于监听发生改变的这个 node 是否有正常需要翻译的内容、以及是否是非translate.js触发的需要被翻译。
1338
+ 注意,传入进行判断的node中的文本必须是 node.nodeValue ,也就是这个必须是 node.nodeType == 2(某个元素的属性,比如 input 的 placeholder) 或 3(文本节点), 这样他们才会有正常的 node.nodeValue,而且文本也存在于 node.nodeValue 中
1339
+ 比如 div title="你好" ,要对 title 的 你好 这个值进行判定,传入的node必须是 title 的 node,而非 div 的 node
1340
+ 它主要是为了给 translate.listener.addListener 中的动态监听node改变所服务的
1341
+
1342
+ @param node 要判断的这个是否需要触发翻译的node
1343
+ @return boolean true:需要触发 translate.execute(node) 进行翻译
1344
+ */
1345
+ nodeValueChangeNeedTranslate: function(node){
1346
+ //是否是要加入翻译扫描触发执行,是则是true
1347
+ var addTranslateExecute = true;
1348
+
1349
+ /*
1350
+ 不会进入翻译的情况 -
1351
+ 1. 认为是有 translate.js 本身翻译导致的改变,不进行翻译
1352
+ 取 translate.node.data 中的数据,当改变的node节点在其中找到了对应的数据后,进行判定
1353
+ 1. 是整体翻译,且当前node改变后的内容,跟上次翻译后的结果一样,那说明当前node改变事件
1354
+ 2. 不是整体翻译,可能是触发自定义术语、或直接没启用整体翻译能力,那就要根据最后翻译时间这个来判定了。如果这个node元素,已经被翻译过了,最后一次翻译渲染时间,距离当前时间不超过500毫秒
1355
+ 2. 其他的情况如果后续发现有遗漏,再加入,当前没有这种考虑
1356
+ */
1357
+ if(translate.node.get(node) != null){
1358
+ if(typeof(translate.node.get(node).whole) !== 'undefined' && translate.node.get(node).whole == true){
1359
+ //整体翻译
1360
+ if(typeof(translate.node.get(node).resultText) !== 'undefined' && translate.node.get(node).resultText === node.nodeValue){
1361
+ //当前改变后的内容,跟上次翻译后的结果一样,那说明当前node改变事件,是有translate.js 本身翻译导致的,不进行翻译
1362
+ addTranslateExecute = false;
1363
+ }
1364
+ }else{
1365
+ //不是整体翻译,可能是触发自定义术语、或直接没启用整体翻译能力
1366
+ //这就要根据最后翻译时间这个来判定了
1367
+ if(typeof(translate.node.get(node).lastTranslateRenderTime) == 'number' && translate.node.get(node).lastTranslateRenderTime + 500 > Date.now()){
1368
+ //如果这个node元素,已经被翻译过了,最后一次翻译渲染时间,距离当前时间不超过500毫秒,那认为这个元素动态改变,是有translate.js 本身引起的,将不做任何动作
1369
+ addTranslateExecute = false;
1370
+ }
1371
+ }
1372
+ }
1373
+
1374
+ //如果新的里面没有非空白字符的值,那也不再触发翻译
1375
+ if(addTranslateExecute === true){
1376
+ if(node.nodeValue.trim().length === 0){
1377
+ addTranslateExecute = false;
1378
+ }
1379
+ }
1380
+
1381
+ return addTranslateExecute;
1382
+ },
1383
+
1312
1384
 
1313
1385
  //增加监听,开始监听。这个不要直接调用,需要使用上面的 start() 开启
1314
1386
  addListener:function(){
@@ -1345,61 +1417,47 @@ var translate = {
1345
1417
  }
1346
1418
  }
1347
1419
  }else if (mutation.type === 'attributes') {
1348
- //console.log(mutation);
1349
- if(mutation.attributeName === 'class'){
1350
- //如果是class,不做任何改变,直接跳出
1420
+ if(mutation.attributeName === 'class' || mutation.attributeName === 'style'){
1421
+ //如果是class/ style 这种常见的,不做任何改变,直接跳出
1351
1422
  continue;
1352
1423
  }
1353
- //console.log('listener attributes change --> ' + mutation.target.nodeName+'['+ mutation.attributeName + '] oldValue :'+mutation.oldValue);
1354
1424
 
1355
- if(translate.node.get(mutation.target) != null){
1356
-
1357
- if(typeof(translate.node.get(mutation.target).lastTranslateRenderTime) == 'number' && translate.node.get(mutation.target).lastTranslateRenderTime + 1000 > Date.now()){
1358
- //如果这个node元素,已经被翻译过了,最后一次翻译渲染时间,距离当前时间不超过1秒,那认为这个元素动态改变,是有translate.js 本身引起的,将不做任何动作
1425
+ /*
1426
+ 这里要判断一些允许翻译的属性
1427
+ input placeholder 属性 ,直接判断 placeholder 就行了,也就 input、textarea 有这个属性
1428
+ img 的 alt 属性
1429
+ 所有标签的 title 属性
1430
+ */
1431
+
1432
+ if(mutation.attributeName === 'placeholder' || mutation.attributeName === 'alt' || mutation.attributeName === 'title'){
1433
+ //允许翻译
1434
+ }else{
1435
+ //判断是否是 translate.element.tagAttribute 自定义翻译属性的
1436
+ var divTagAttribute = translate.element.tagAttribute[mutation.target.nodeName.toLowerCase()];
1437
+ if(typeof(divTagAttribute) !== 'undefined' && divTagAttribute.attribute.indexOf(mutation.attributeName) > -1 && divTagAttribute.condition(mutation.target)){
1438
+ //是自定义翻译这个属性的,以及判定是否达到翻译条件
1439
+ //条件满足,允许翻译
1359
1440
  }else{
1360
- //不是 translate.js 触发的改动
1361
- var nodeAttribute = translate.node.getAttribute(mutation.attributeName);
1362
- //console.log(translate.node.get(mutation.target)[nodeAttribute.key])
1363
- if(typeof(translate.node.get(mutation.target)[nodeAttribute.key]) != 'undefined'){
1364
- //从翻译历史中删掉,使这个属性还能继续被翻译
1365
- //console.log('delete translate.node.get(mutation.target)[nodeAttribute.key] -> '+mutation.attributeName);
1366
- delete translate.node.get(mutation.target)[nodeAttribute.key];
1367
- }
1441
+ //条件不满足,不在翻译的属性范围
1442
+ continue;
1368
1443
  }
1369
1444
  }
1370
1445
 
1371
- //最后,将这个属性加入待翻译
1372
- addNodes.push(mutation.target);
1446
+ //这里出现的 mutation.target 是定位到了元素上面,而不是变化的这个 attributes 属性上,需要用 mutation.attributeName 获取到这个属性的node
1447
+ var node = mutation.target.getAttributeNode(mutation.attributeName);
1448
+
1449
+ //是否是要加入翻译扫描触发执行,是则是true
1450
+ var addTranslateExecute = translate.listener.nodeValueChangeNeedTranslate(node);
1451
+ if(addTranslateExecute){ //不是 translate.js 翻译引起的改变,那么
1452
+ //console.log('listener attributes change ' + mutation.target.nodeName+'['+ mutation.attributeName + '] '+mutation.oldValue+' --> '+node.nodeValue);
1453
+ translate.node.delete(node);
1454
+ addNodes = [node]; //将这个属性转为的node加入待翻译
1455
+ }
1373
1456
  }else if(mutation.type === 'characterData'){
1374
1457
  //内容改变
1375
1458
 
1376
1459
  //是否是要加入翻译扫描触发执行,是则是true
1377
- var addTranslateExecute = true;
1378
-
1379
- /*
1380
- 不会进入翻译的情况 -
1381
- 1. 认为是有 translate.js 本身翻译导致的改变,不进行翻译
1382
- 取 translate.node.data 中的数据,当改变的node节点在其中找到了对应的数据后,进行判定
1383
- 1. 是整体翻译,且当前node改变后的内容,跟上次翻译后的结果一样,那说明当前node改变事件
1384
- 2. 不是整体翻译,可能是触发自定义术语、或直接没启用整体翻译能力,那就要根据最后翻译时间这个来判定了。如果这个node元素,已经被翻译过了,最后一次翻译渲染时间,距离当前时间不超过500毫秒
1385
- 2. 其他的情况如果后续发现有遗漏,再加入,当前没有这种考虑
1386
- */
1387
- if(translate.node.get(mutation.target) != null && typeof(translate.node.get(mutation.target).translate_default_value) != 'undefined'){
1388
- if(typeof(translate.node.get(mutation.target).translate_default_value.whole) != 'undefined' && translate.node.get(mutation.target).translate_default_value.whole == true){
1389
- //整体翻译
1390
- if(typeof(translate.node.get(mutation.target).translate_default_value.resultText) != 'undefined' && translate.node.get(mutation.target).translate_default_value.resultText === mutation.target.nodeValue){
1391
- //当前改变后的内容,跟上次翻译后的结果一样,那说明当前node改变事件,是有translate.js 本身翻译导致的,不进行翻译
1392
- addTranslateExecute = false;
1393
- }
1394
- }else{
1395
- //不是整体翻译,可能是触发自定义术语、或直接没启用整体翻译能力
1396
- //这就要根据最后翻译时间这个来判定了
1397
- if(typeof(translate.node.get(mutation.target).lastTranslateRenderTime) == 'number' && translate.node.get(mutation.target).lastTranslateRenderTime + 500 > Date.now()){
1398
- //如果这个node元素,已经被翻译过了,最后一次翻译渲染时间,距离当前时间不超过500毫秒,那认为这个元素动态改变,是有translate.js 本身引起的,将不做任何动作
1399
- addTranslateExecute = false;
1400
- }
1401
- }
1402
- }
1460
+ var addTranslateExecute = translate.listener.nodeValueChangeNeedTranslate(mutation.target);
1403
1461
 
1404
1462
  if(addTranslateExecute){ //不是 translate.js 翻译引起的改变,那么
1405
1463
  translate.node.delete(mutation.target);
@@ -1428,10 +1486,8 @@ var translate = {
1428
1486
  }
1429
1487
  }
1430
1488
 
1431
- //console.log(documents.length);
1432
1489
  if(documents.length > 0){
1433
1490
  //有变动,需要看看是否需要翻译,延迟10毫秒执行
1434
-
1435
1491
  translate.time.log('监听到元素发生变化,'+documents.length+'个元素');
1436
1492
 
1437
1493
  //判断是否属于在正在翻译的节点,重新组合出新的要翻译的node集合
@@ -1473,7 +1529,7 @@ var translate = {
1473
1529
  //console.log('translateNodeslength: '+translateNodes.length);
1474
1530
 
1475
1531
  translate.time.log('将监听到的发生变化的元素进行整理,得到'+translateNodes.length+'个元素,对其进行翻译');
1476
- //console.log(translateNodes[0]);
1532
+ //console.log(translateNodes);
1477
1533
 
1478
1534
  translate.execute(translateNodes);
1479
1535
  //setTimeout(function() {
@@ -1694,12 +1750,25 @@ var translate = {
1694
1750
 
1695
1751
 
1696
1752
  // translate.node 记录
1697
- var nodeAttribute = translate.node.getAttribute(task['attribute']);
1698
- if(translate.node.data.get(this.nodes[hash][task_index]) != null){
1753
+
1754
+ var translateNode; //当前操作的,要记录入 translate.node 中的,进行翻译的node
1755
+ var translateNode_attribute = ''; //当前操作的是node中的哪个attribute,如果没有是node本身则是空字符串
1756
+ if(typeof(task['attribute']) === 'string' && task['attribute'].length > 0){
1757
+ //当前渲染任务是针对的元素的某个属性,这是要取出这个元素的具体属性,作为一个目的 node 来进行加入 translate.node
1758
+ //是操作的元素的某个属性
1759
+ translateNode = this.nodes[hash][node_index].getAttributeNode(task['attribute']);
1760
+ translateNode_attribute = task['attribute'];
1761
+ }else{
1762
+ //操作的就是node本身
1763
+ translateNode = this.nodes[hash][node_index];
1764
+ }
1765
+ //console.log(translateNode)
1766
+ //var nodeAttribute = translate.node.getAttribute(task['attribute']);
1767
+ if(translate.node.data.get(translateNode) != null){
1699
1768
  // 记录当前有 translate.js 所触发翻译之后渲染到dom界面显示的时间,13位时间戳
1700
- translate.node.get(this.nodes[hash][task_index]).lastTranslateRenderTime = Date.now();
1769
+ translate.node.get(translateNode).lastTranslateRenderTime = Date.now();
1701
1770
  }else{
1702
- translate.log('执行异常,渲染时,node未在 nodeHistory 中找到, 这个理论上是不应该存在的,当前异常已被容错。 node:'+this.nodes[hash][task_index]);
1771
+ translate.log('执行异常,渲染时,node 未在 translate.node 中找到, 这个理论上是不应该存在的,当前异常已被容错。 node:'+translateNode);
1703
1772
  translate.log(this.nodes[hash][task_index]);
1704
1773
  }
1705
1774
 
@@ -1708,22 +1777,14 @@ var translate = {
1708
1777
  var analyseSet = translate.element.nodeAnalyse.set(this.nodes[hash][task_index], task.originalText, task.resultText, task['attribute']);
1709
1778
  //console.log(analyseSet);
1710
1779
 
1711
- if(translate.node.data.get(this.nodes[hash][task_index]) != null){
1712
- if(typeof(translate.node.get(this.nodes[hash][task_index])[nodeAttribute.key]) == 'undefined'){
1713
- //这里不应该的
1714
- translate.log('执行异常,渲染时,node 的 '+(nodeAttribute.attribute.length == 0? 'nodeValue':'attribute : '+nodeAttribute.attribute)+' 未在 nodeHistory 中找到, 这个理论上是不应该存在的,当前异常已被容错。 node:'+this.nodes[hash][task_index]);
1715
- }else{
1716
- //将具体通过文本翻译接口进行翻译的文本记录到 translate.node.data
1717
- translate.node.get(this.nodes[hash][task_index])[nodeAttribute.key].translateTexts[task.originalText] = task.resultText;
1718
- //将翻译完成后要显示出的文本进行记录
1719
- translate.node.get(this.nodes[hash][task_index])[nodeAttribute.key].resultText = analyseSet.resultText;
1780
+ if(translate.node.data.get(translateNode) != null){
1781
+ //将具体通过文本翻译接口进行翻译的文本记录到 translate.node.data
1782
+ translate.node.get(translateNode).translateTexts[task.originalText] = task.resultText;
1783
+ //将翻译完成后要显示出的文本进行记录
1784
+ translate.node.get(translateNode).resultText = analyseSet.resultText;
1720
1785
 
1721
- //将其加入 translate.history.translateTexts
1722
- translate.history.translateText.add(translate.node.get(this.nodes[hash][task_index])[nodeAttribute.key].originalText ,analyseSet.resultText);
1723
- }
1724
- }else{
1725
- translate.log('执行异常,渲染时,node未在 nodeHistory 中找到, 这个理论上是不应该存在的,当前异常已被容错。 node:'+this.nodes[hash][task_index]);
1726
- translate.log(this.nodes[hash][task_index]);
1786
+ //将其加入 translate.history.translateTexts
1787
+ translate.history.translateText.add(translate.node.get(translateNode).originalText ,analyseSet.resultText);
1727
1788
  }
1728
1789
 
1729
1790
  //加入 translate.listener.ignoreNode
@@ -1856,12 +1917,14 @@ var translate = {
1856
1917
  translate.listener.execute.renderFinishByApiRun(uuid, from, to);
1857
1918
 
1858
1919
  //通过 uuid、from 取得本次翻译相关的 texts、nodes , 触发 translateNetworkAfter_Trigger 钩子
1920
+ //获取请求日志
1921
+ var requestData = translate.request.data[uuid].list[from][to];
1859
1922
  translate.lifecycle.execute.translateNetworkAfter_Trigger({
1860
1923
  uuid: uuid,
1861
1924
  from: from,
1862
1925
  to: to,
1863
- texts: translate.request.data[uuid].list[from].texts,
1864
- nodes: translate.request.data[uuid].list[from].nodes,
1926
+ texts: requestData.texts,
1927
+ nodes: requestData.nodes,
1865
1928
  result: result,
1866
1929
  info: info
1867
1930
  });
@@ -2229,8 +2292,8 @@ var translate = {
2229
2292
  if(sliceDoc[di].getAttribute('class') != null && typeof(sliceDoc[di].getAttribute('class')) == 'string' && sliceDoc[di].getAttribute('class').length > 0){
2230
2293
  sliceDocString = sliceDocString + " class="+sliceDoc[di].getAttribute('class');
2231
2294
  }
2232
- }else if(sliceDoc[di].nodeType === 3){
2233
- //node
2295
+ }else if(sliceDoc[di].nodeType === 2 || sliceDoc[di].nodeType === 3){
2296
+ //2属性 或 3文本节点
2234
2297
  sliceDocString = sliceDocString + sliceDoc[di].nodeValue.replaceAll(/\r?\n/g, '[换行符]');
2235
2298
  }
2236
2299
  }
@@ -2239,7 +2302,6 @@ var translate = {
2239
2302
 
2240
2303
 
2241
2304
  translate.log('当前翻译未完结,新翻译任务已加入等待翻译队列,待上个翻译任务结束后便会执行当前翻译任务'+sliceDocString);
2242
- //console.log(docs);
2243
2305
  translate.waitingExecute.add(docs);
2244
2306
 
2245
2307
  //钩子
@@ -2371,7 +2433,7 @@ var translate = {
2371
2433
 
2372
2434
  if(all.length > 500){
2373
2435
  translate.log('------tip------');
2374
- translate.log('translate.execute( docs ) 传入的docs.length 过大,超过500,这很不正常,当前 docs.length : '+all.length+' ,如果你感觉真的没问题,请联系作者 http://translate.zvo.cn/43006.html 说明情况,根据你的情况进行分析。 当前只取前500个元素进行翻译');
2436
+ translate.log('translate.execute( docs ) 传入的docs.length 过大,超过1500,这很不正常,当前 docs.length : '+all.length+' ,如果你感觉真的没问题,请联系作者 http://translate.zvo.cn/43006.html 说明情况,根据你的情况进行分析。 当前只取前1500个元素进行翻译');
2375
2437
  }
2376
2438
 
2377
2439
  //初始化 translate.element.tagAttribute ,主要针对 v3.17.10 版本的适配调整,对 translate.element.tagAttribute 的设置做了改变,做旧版本的适配
@@ -2397,7 +2459,7 @@ var translate = {
2397
2459
 
2398
2460
  translate.time.log('开始扫描要翻译区域的元素');
2399
2461
  //检索目标内的node元素
2400
- for(var i = 0; i< all.length & i < 500; i++){
2462
+ for(var i = 0; i< all.length & i < 1500; i++){
2401
2463
  var node = all[i];
2402
2464
  translate.element.whileNodes(uuid, node);
2403
2465
  }
@@ -2928,6 +2990,11 @@ var translate = {
2928
2990
  将翻译请求的信息记录到 translate.js 本身中
2929
2991
  uuid 每次 translate.execute() 触发生成的uuid
2930
2992
  time: 触发后加入到 data 中的时间,13位时间戳
2993
+ list: 记录当前uuid下发起的网络请求
2994
+ from: 从什么语种进行的翻译,如: chinese_simplified
2995
+ to: 翻译为什么语种,如 : english
2996
+ nodes: 当前网络请求有哪些node节点,值为 [node1, node2, ...]
2997
+ texts: 当前网络请求有哪些文本进行翻译,值为 [text1, text2, ...]
2931
2998
 
2932
2999
  */
2933
3000
  translate.request.data[uuid] = {
@@ -2998,8 +3065,10 @@ var translate = {
2998
3065
  });
2999
3066
 
3000
3067
  //记入请求日志
3001
- translate.request.data[uuid].list[lang] = {
3002
- to: translate.to,
3068
+ if(typeof(translate.request.data[uuid].list[lang]) === 'undefined'){
3069
+ translate.request.data[uuid].list[lang] = {};
3070
+ }
3071
+ translate.request.data[uuid].list[lang][translate.to] = {
3003
3072
  texts: translateTextArray[lang],
3004
3073
  nodes: translateTextNodes,
3005
3074
  };
@@ -3113,8 +3182,8 @@ var translate = {
3113
3182
  //将翻译结果以 key:hash value翻译结果的形式缓存
3114
3183
  translate.storage.set('hash_'+data.to+'_'+cacheHash,text);
3115
3184
  //如果离线翻译启用了全部提取,那么还要存入离线翻译指定存储
3116
- if(translate.office.fullExtract.isUse){
3117
- translate.office.fullExtract.set(hash, originalWord, data.to, text);
3185
+ if(translate.offline.fullExtract.isUse){
3186
+ translate.offline.fullExtract.set(hash, originalWord, data.to, text);
3118
3187
  }
3119
3188
  }
3120
3189
  task.execute(); //执行渲染任务
@@ -3193,7 +3262,7 @@ var translate = {
3193
3262
  将已扫描的节点进行记录,这里是只要进行扫描到了,也就是在加入 translate.nodeQueue 时就也要加入到这里。
3194
3263
  这是一个map,为了兼容es5,这里设置为null,在 translate.execute 中在进行初始化
3195
3264
 
3196
- key: node
3265
+ key: node ,进行翻译的文本的node, 如果是 div 的 title属性进行的翻译,那这个node是定位在 title 上的node,而不是 div 这个依附的元素
3197
3266
  value: 这是一个对像
3198
3267
  其中,key的取值有这几种:
3199
3268
  translate_default_value: 如果当前翻译的是元素本身的值或node节点本身的值(nodeValue),那么这里的key就是固定的 translate_default_value
@@ -3246,7 +3315,7 @@ var translate = {
3246
3315
  key: translate.node 中 translate.node.get(node)[attribute] 所使用的 attribute 的字符串,如 attribute_title 、translate_default_value
3247
3316
  attribute: 这里是attribute具体的内容,比如 key 是 attribute_title 那么这里就是 title , key 是 translate_default_value 这里就是 '' 空字符串
3248
3317
  }
3249
- */
3318
+
3250
3319
  getAttribute:function(attribute){
3251
3320
  var history_attribute;
3252
3321
  if(typeof(attribute) != 'undefined' && attribute.length > 0){
@@ -3262,6 +3331,7 @@ var translate = {
3262
3331
  attribute:attribute
3263
3332
  }
3264
3333
  },
3334
+ */
3265
3335
  /*
3266
3336
  刷新 translate.node.data 中的数据,剔除过时的(node已经不存在于dom的)
3267
3337
  */
@@ -3360,6 +3430,147 @@ var translate = {
3360
3430
  get:function(node, attribute){
3361
3431
  return translate.element.nodeAnalyse.analyse(node,'','', attribute);
3362
3432
  },
3433
+ /*
3434
+ 同上,只不过这个是扫描 element/node 下的所有可翻译的子节点(下层节点),返回数组形态。
3435
+ 这里面的数组,已经经过判断, text 必然是有不为空的值的。
3436
+ 所以它的返回值,有可能是一个空的数组
3437
+
3438
+ [
3439
+ {
3440
+ node: 当前扫描出的node (传入的node、或下层node)
3441
+ attribute: 是否是下层属性,比如 alt、placeholder , 如果是传入的node本身,不是任何下层属性,则这里是空白字符串 ''
3442
+ text: 可进行翻译的文本,也就是当前数组中 node 的值的文本
3443
+ },
3444
+ ...
3445
+ ]
3446
+ */
3447
+ gets:function(node){
3448
+ var resultArray = [];
3449
+
3450
+ var nodename = translate.element.getNodeName(node).toUpperCase();
3451
+ switch (nodename) {
3452
+ case 'META': //meta标签,如是关键词、描述等
3453
+ var nodeAttributeName = node.name.toLowerCase(); //取meta 标签的name 属性
3454
+ var nodeAttributePropertyOri = node.getAttribute('property'); //取 property的值
3455
+ var nodeAttributeProperty = '';
3456
+ if(typeof(nodeAttributePropertyOri) === 'string' && nodeAttributePropertyOri.length > 0){
3457
+ nodeAttributeProperty = nodeAttributePropertyOri.toLowerCase();
3458
+ }
3459
+
3460
+ if(nodeAttributeName == 'keywords' || nodeAttributeName == 'description' || nodeAttributeName == 'sharetitle' || nodeAttributeProperty == 'og:title' || nodeAttributeProperty == 'og:description' || nodeAttributeProperty == 'og:site_name' || nodeAttributeProperty == 'og:novel:latest_chapter_name'){
3461
+ if(typeof(node.content) === 'string' && node.content.trim().length > 0){
3462
+ resultArray.push({
3463
+ text: node.content,
3464
+ attribute: 'content',
3465
+ node: node.getAttributeNode('content')
3466
+ });
3467
+ }
3468
+ }
3469
+ break;
3470
+ case 'IMG':
3471
+ if(typeof(node.alt) === 'string' && node.alt.trim().length > 0){
3472
+ resultArray.push({
3473
+ text: node.alt,
3474
+ attribute: 'alt',
3475
+ node: node.getAttributeNode('alt')
3476
+ });
3477
+ }
3478
+ break;
3479
+ case 'INPUT':
3480
+ /*
3481
+ input,要对以下情况进行翻译
3482
+ placeholder
3483
+ type=button、submit 的情况下的 value
3484
+ */
3485
+
3486
+ //针对 type=button、submit 的情况下的 value
3487
+ if(typeof(node.attributes.type) !== 'undefined' && node.attributes.type !== null && typeof(node.attributes.type.nodeValue) === 'string' && (node.attributes.type.nodeValue.toLowerCase() == 'button' || node.attributes.type.nodeValue.toLowerCase() == 'submit')){
3488
+ //取它的value
3489
+ var input_value_node = node.attributes.value;
3490
+ if(typeof(input_value_node) !== 'undefined' && input_value_node !== null && typeof(input_value_node.nodeValue) === 'string' && input_value_node.nodeValue.trim().length > 0){
3491
+ resultArray.push({
3492
+ text: input_value_node.nodeValue,
3493
+ attribute: 'value',
3494
+ node: input_value_node
3495
+ });
3496
+ }
3497
+ }
3498
+
3499
+ //针对 placeholder
3500
+ if(typeof(node.attributes['placeholder']) !== 'undefined' && typeof(node.attributes['placeholder'].nodeValue) === 'string' && node.attributes['placeholder'].nodeValue.trim().length > 0){
3501
+ resultArray.push({
3502
+ text: node.attributes['placeholder'].nodeValue,
3503
+ attribute: 'placeholder',
3504
+ node: node.attributes['placeholder']
3505
+ });
3506
+ }
3507
+ break;
3508
+ case 'TEXTAREA':
3509
+ //针对 placeholder
3510
+ if(typeof(node.attributes['placeholder']) !== 'undefined' && typeof(node.attributes['placeholder'].nodeValue) === 'string' && node.attributes['placeholder'].nodeValue.trim().length > 0){
3511
+ resultArray.push({
3512
+ text: node.attributes['placeholder'].nodeValue,
3513
+ attribute: 'placeholder',
3514
+ node: node.attributes['placeholder']
3515
+ });
3516
+ }
3517
+ break;
3518
+ }
3519
+
3520
+ //判断是否是 translate.element.tagAttribute 自定义翻译属性的
3521
+ var divTagAttribute = translate.element.tagAttribute[nodename.toLowerCase()];
3522
+ if(typeof(divTagAttribute) !== 'undefined'){
3523
+ //有这个标签的自定义翻译某个属性
3524
+ for(var ai = 0; ai<node.attributes.length; ai++){
3525
+ var arrtibuteNodeName = translate.element.getNodeName(node.attributes[ai]).toLowerCase();
3526
+ if(divTagAttribute.attribute.indexOf(arrtibuteNodeName) > -1 && divTagAttribute.condition(node)){
3527
+ //包含这个属性,且自定义判断条件满足,允许翻译
3528
+ //判定一下是否已经加入过了,如果没有加入过,才会加入。这里主要是针对input 标签进行判断,比如 input type="submit" 的,value值如果也被用户自定义翻译,那上面的value就已经加上了,不需要在加了
3529
+ var isAlreadyAdd = false; //true已经加入过了
3530
+ for(var ri = 0; ri < resultArray.length; ri++){
3531
+ if(resultArray[ri].node === node.attributes[ai]){
3532
+ //相同,则不在加入了
3533
+ isAlreadyAdd = true;
3534
+ }
3535
+ }
3536
+ if(!isAlreadyAdd){
3537
+ resultArray.push({
3538
+ text: node.attributes[ai].nodeValue,
3539
+ attribute: arrtibuteNodeName,
3540
+ node: node.attributes[ai]
3541
+ });
3542
+ }
3543
+ }
3544
+ }
3545
+ }else{
3546
+ //条件不满足,不在翻译的属性范围
3547
+ }
3548
+
3549
+
3550
+ //所有元素都要判定的属性 - title 属性
3551
+ if(typeof(node['title']) === 'string' && node['title'].trim().length > 0){
3552
+ var titleNode = node.getAttributeNode('title');
3553
+ resultArray.push({
3554
+ text: titleNode.nodeValue,
3555
+ attribute: 'title',
3556
+ node: titleNode
3557
+ });
3558
+ }
3559
+
3560
+
3561
+ //最后判定 node 本身
3562
+ if(typeof(node.nodeValue) === 'string' && node.nodeValue.trim().length > 0){
3563
+ //返回传入的node本身
3564
+ resultArray.push({
3565
+ text: node.nodeValue,
3566
+ attribute: '',
3567
+ node: node
3568
+ });
3569
+ }
3570
+
3571
+
3572
+ return resultArray;
3573
+ },
3363
3574
  /*
3364
3575
  进行翻译之后的渲染显示
3365
3576
  注意,它会对node本身进行扫描的,需要进行通过文本翻译接口进行翻译的文本进行识别,比如 这个 node 其内容为:
@@ -3467,6 +3678,7 @@ var translate = {
3467
3678
 
3468
3679
  //正常的node ,typeof 都是 object
3469
3680
 
3681
+ /* 这里是通用方法,不应该有限制
3470
3682
  //console.log(typeof(node)+node);
3471
3683
  if(nodename == '#text'){
3472
3684
  //如果是普通文本,判断一下上层是否是包含在textarea标签中
@@ -3480,7 +3692,7 @@ var translate = {
3480
3692
  }
3481
3693
  }
3482
3694
  }
3483
-
3695
+ */
3484
3696
 
3485
3697
 
3486
3698
  //console.log(nodename)
@@ -3639,11 +3851,23 @@ var translate = {
3639
3851
  resultShowText: translate.element.nodeAnalyse.analyse 进行设置翻译后的文本渲染时,提前计算好这个node显示的所有文本,然后在赋予 dom,这里是计算好的node要整体显示的文本
3640
3852
  */
3641
3853
  analyseReplaceBefore_DateToTranslateNode:function(node, attribute, resultShowText){
3642
- if(translate.node.find(node)){
3643
- if(typeof(translate.node.get(node).translateResults) == 'undefined'){
3644
- translate.node.get(node).translateResults = {};
3854
+ var translateNode; //当前操作的,要记录入 translate.node 中的,进行翻译的node
3855
+ var translateNode_attribute = ''; //当前操作的是node中的哪个attribute,如果没有是node本身则是空字符串
3856
+
3857
+ if(typeof(attribute) === 'string' && attribute.length > 0){
3858
+ //是操作的元素的某个属性
3859
+ translateNode = node.getAttributeNode(attribute);
3860
+ translateNode_attribute = attribute;
3861
+ }else{
3862
+ //操作的就是node本身
3863
+ translateNode = node;
3864
+ }
3865
+
3866
+ if(translate.node.find(translateNode)){
3867
+ if(typeof(translate.node.get(translateNode).translateResults) == 'undefined'){
3868
+ translate.node.get(translateNode).translateResults = {};
3645
3869
  }
3646
- translate.node.get(node).translateResults[resultShowText] = 1;
3870
+ translate.node.get(translateNode).translateResults[resultShowText] = 1;
3647
3871
  }else{
3648
3872
  //翻译过程中,会有时间差,比如通过文本翻译api请求,这时node元素本身被其他js改变了,导致翻译完成后,原本的node不存在了
3649
3873
  //console.log('[debug] 数据异常,analyse - set 中发现 translate.node 中的 node 不存在,理论上应该只要被扫描了,被翻译了,到这里就一定会存在的,不存在怎么会扫描到交给去翻译呢');
@@ -3690,7 +3914,7 @@ var translate = {
3690
3914
 
3691
3915
  //console.log('---'+typeof(node)+', ');
3692
3916
  //判断是否是有title属性,title属性也要翻译
3693
- if(typeof(node) == 'object' && typeof(node['title']) == 'string' && node['title'].length > 0){
3917
+ if(typeof(node) == 'object' && typeof(node['title']) == 'string' && node['title'].trim().length > 0){
3694
3918
  //将title加入翻译队列
3695
3919
  //console.log('---'+node.title+'\t'+node.tagName);
3696
3920
  //console.log(node)
@@ -3699,7 +3923,8 @@ var translate = {
3699
3923
  //判断当前元素是否在ignore忽略的tag、id、class name中
3700
3924
  if(!translate.ignore.isIgnore(node)){
3701
3925
  //不在忽略的里面,才会加入翻译
3702
- translate.addNodeToQueue(uuid, node, node['title'], 'title');
3926
+ //translate.addNodeToQueue(uuid, node, node['title'], 'title');
3927
+ translate.addNodeToQueue(uuid, node.getAttributeNode('title'), node['title'], '');
3703
3928
  }
3704
3929
  }
3705
3930
 
@@ -3753,7 +3978,7 @@ var translate = {
3753
3978
  //判断当前元素是否在ignore忽略的tag、id、class name中 v3.15.7 增加
3754
3979
  if(!translate.ignore.isIgnore(node)){
3755
3980
  //加入翻译
3756
- translate.addNodeToQueue(uuid, node, attributeValue, attributeName);
3981
+ translate.addNodeToQueue(uuid, node.getAttributeNode(attributeName), attributeValue, '');
3757
3982
  }
3758
3983
  }
3759
3984
  }
@@ -3776,22 +4001,16 @@ var translate = {
3776
4001
  if(node == null || typeof(node) == 'undefined'){
3777
4002
  return;
3778
4003
  }
3779
- if(node.parentNode == null){
3780
- return;
3781
- }
3782
-
3783
- //console.log('-----parent')
3784
- var parentNodeName = translate.element.getNodeName(node.parentNode);
3785
- //node.parentNode.nodeName;
3786
- if(parentNodeName == ''){
3787
- return;
3788
- }
3789
- if(translate.ignore.tag.indexOf(parentNodeName.toLowerCase()) > -1){
3790
- //忽略tag
3791
- //console.log('忽略tag:'+parentNodeName);
3792
- return;
4004
+ if(node.nodeType === 2){ //是属性node,比如 div 的 title 属性的 node
4005
+ if(node.ownerElement == null){
4006
+ return;
4007
+ }
4008
+ }else{ //是元素了
4009
+ if(node.parentNode == null){
4010
+ return;
4011
+ }
3793
4012
  }
3794
-
4013
+
3795
4014
  /****** 判断忽略的class ******/
3796
4015
  /*
3797
4016
  这段理论上不需要了,因为在 translate.ignore.isIgnore 判断了
@@ -3825,13 +4044,21 @@ var translate = {
3825
4044
  return;
3826
4045
  }
3827
4046
 
3828
- //node分析
4047
+ //node分析,分析这个node的所有可翻译属性(包含自定义翻译属性 translate.element.tagAttribute )
4048
+ var nodeAnalyChild = translate.element.nodeAnalyse.gets(node);
4049
+ //console.log(nodeAnalyChild);
4050
+ for(var nci = 0; nci < nodeAnalyChild.length; nci++){
4051
+ translate.addNodeToQueue(uuid, nodeAnalyChild[nci].node, nodeAnalyChild[nci].text, '');
4052
+ }
4053
+ /*
3829
4054
  var nodeAnaly = translate.element.nodeAnalyse.get(node);
3830
4055
  if(nodeAnaly['text'].length > 0){
3831
4056
  //有要翻译的目标内容,加入翻译队列
3832
- //console.log('addNodeToQueue -- '+nodeAnaly['node']+', text:' + nodeAnaly['text']);
3833
- translate.addNodeToQueue(uuid, nodeAnaly['node'], nodeAnaly['text']);
4057
+ console.log(nodeAnaly)
4058
+ console.log('addNodeToQueue -- '+nodeAnaly['node']+', text:' + nodeAnaly['text']);
4059
+ translate.addNodeToQueue(uuid, nodeAnaly['node'], nodeAnaly['text'], '');
3834
4060
  }
4061
+ */
3835
4062
 
3836
4063
  //console.log(nodeAnaly);
3837
4064
  /*
@@ -3892,6 +4119,56 @@ var translate = {
3892
4119
  */
3893
4120
 
3894
4121
  },
4122
+ /*
4123
+ 将node转为element输出。
4124
+ 如果node是文本元素,则转化为这个文本元素所在的element元素
4125
+ 如果node是属性,则转化为这个属性所在的element元素
4126
+ 如果node本身就是元素标签,那就还是这样返回。
4127
+
4128
+
4129
+ nodes: node数组,传入如 [node1,node2, ...] 它里面可能包含 node.nodeType 1\2\3 等值
4130
+
4131
+ 返回这些node转化为所在元素后的数组,返回如 [element1, element2, ...]
4132
+ 注意的是
4133
+ 1. 输出的一定是 element 元素,也就是 node.nodeType 一定等于1
4134
+ 2. 输出的元素数组不一定等于传入的nodes数组,也就是他们的数量跟下标并不是对应相等的
4135
+
4136
+ */
4137
+ nodeToElement: function(nodes){
4138
+ var elements = new Array(); //要改动的元素
4139
+
4140
+ //遍历所有node组合到 nodes. 这个不单纯只是遍历组合,它会判断如果是文本节点,则取它的父级元素。它组合的结果是元素的集合
4141
+ for(var r = 0; r<nodes.length; r++){
4142
+ var node = nodes[r];
4143
+ if(typeof(node) == 'undefined' || typeof(node.parentNode) == 'undefined'){
4144
+ continue;
4145
+ }
4146
+ if(node.nodeType === 2){
4147
+ //是属性节点,可能是input、textarea 的 placeholder ,获取它的父元素
4148
+ var nodeParentElement = node.ownerElement;
4149
+ if(nodeParentElement == null){
4150
+ continue;
4151
+ }
4152
+ elements.push(nodeParentElement);
4153
+ }else if(node.nodeType === 3){
4154
+ //是文本节点
4155
+ var nodeParentElement = node.parentNode;
4156
+ if(nodeParentElement == null){
4157
+ continue;
4158
+ }
4159
+ elements.push(nodeParentElement);
4160
+ }else if(node.nodeType === 1){
4161
+ //元素节点了,直接加入
4162
+ elements.push(node);
4163
+ }else{
4164
+ //1\2\3 都不是,这不应该是 translate.js 中应该出现的
4165
+ translate.log('translate.element.nodeToElement 中,发现传入的node.nodeType 类型有异常,理论上不应该存在, node.nodeType:'+node.nodeType);
4166
+ translate.log(node);
4167
+ }
4168
+ }
4169
+
4170
+ return elements;
4171
+ }
3895
4172
  },
3896
4173
 
3897
4174
 
@@ -3957,27 +4234,34 @@ var translate = {
3957
4234
 
3958
4235
 
3959
4236
  /***** 记录这个node 到 translate.node.data,这也是node进入 translate.node.data 记录的第一入口 *****/
3960
- if(translate.node.get(node) == null){
3961
- translate.node.set(node, {});
4237
+ var translateNode; //当前操作的,要记录入 translate.node 中的,进行翻译的node
4238
+ var translateNode_attribute = ''; //当前操作的是node中的哪个attribute,如果没有是node本身则是空字符串
4239
+ if(typeof(attribute) === 'string' && attribute.length > 0){
4240
+ //是操作的元素的某个属性
4241
+ translateNode = node.getAttributeNode(attribute);
4242
+ translateNode_attribute = attribute;
4243
+ }else{
4244
+ //操作的就是node本身
4245
+ translateNode = node;
3962
4246
  }
3963
-
3964
-
3965
- var nodeAttribute = translate.node.getAttribute(attribute);
4247
+ if(translate.node.get(translateNode) == null){
4248
+ translate.node.set(translateNode, {});
4249
+ }
4250
+
4251
+ //var nodeAttribute = translate.node.getAttribute(attribute);
3966
4252
  //console.log(text+'-----:');
3967
4253
  //console.log(nodeAttribute);
3968
- if(typeof(translate.node.get(node)[nodeAttribute.key]) == 'undefined'){
3969
- translate.node.get(node)[nodeAttribute.key] = {};
3970
- //console.log(typeof(translate.node.get(node)[nodeAttribute.key]));
3971
- }
3972
- translate.node.get(node)[nodeAttribute.key].attribute = nodeAttribute.attribute;
3973
- if(typeof(translate.node.get(node)[nodeAttribute.key].originalText) == 'string'){
4254
+ //if(typeof(translate.node.get(translateNode)[nodeAttribute.key]) == 'undefined'){
4255
+ // translate.node.get(node)[nodeAttribute.key] = {};
4256
+ //}
4257
+ translate.node.get(translateNode).attribute = translateNode_attribute;
4258
+ if(typeof(translate.node.get(translateNode).originalText) === 'string'){
3974
4259
  //这个节点有过记录原始显示的文本了,那么不再对其进行后续的扫描,除非它有被触发过动态监听元素改变, --- 至于它有被触发过动态监听元素改变--后续想怎么判定
3975
4260
  //console.log(translate.node.get(node)[nodeAttribute.key].originalText+'\t又过了,不在翻译');
3976
4261
  return;
3977
4262
  }else{
3978
4263
  //没有过,是第一次,那么赋予值
3979
- translate.node.get(node)[nodeAttribute.key].originalText = text;
3980
- //console.log(translate.node.get(node));
4264
+ translate.node.get(translateNode).originalText = text;
3981
4265
  }
3982
4266
  //console.log(translate.node.get(node)[nodeAttribute.key]);
3983
4267
  /*
@@ -4007,13 +4291,12 @@ var translate = {
4007
4291
  return;
4008
4292
  }
4009
4293
  */
4010
- if(typeof(translate.node.get(node)[nodeAttribute.key].translateTexts) == 'undefined'){
4011
- translate.node.get(node)[nodeAttribute.key].translateTexts = {};
4294
+ if(typeof(translate.node.get(translateNode).translateTexts) === 'undefined'){
4295
+ translate.node.get(translateNode).translateTexts = {};
4012
4296
  }
4013
4297
  /***** 自检完毕,准备进行翻译了 *****/
4014
4298
 
4015
4299
 
4016
-
4017
4300
  //原本传入的text会被切割为多个小块
4018
4301
  var textArray = new Array();
4019
4302
  textArray.push(text); //先将主 text 赋予 ,后面如果对主text进行加工分割,分割后会将主text给删除掉
@@ -4053,8 +4336,8 @@ var translate = {
4053
4336
 
4054
4337
  //console.log(textArray);
4055
4338
  textArray = translate.nomenclature.dispose(textArray, temporaryIgnoreTexts[ti], temporaryIgnoreTexts[ti], {
4056
- node:node,
4057
- attribute:attribute
4339
+ node:translateNode,
4340
+ attribute:''
4058
4341
  }).texts;
4059
4342
  //console.log(textArray);
4060
4343
  }
@@ -4082,8 +4365,8 @@ var translate = {
4082
4365
  //console.log('----translate.nomenclature.dispose---');
4083
4366
  //console.log(textArray);
4084
4367
  var nomenclatureDispose = translate.nomenclature.dispose(textArray, nomenclatureKey, nomenclatureValue, {
4085
- node:node,
4086
- attribute:attribute
4368
+ node:translateNode,
4369
+ attribute:''
4087
4370
  });
4088
4371
 
4089
4372
  textArray = nomenclatureDispose.texts;
@@ -4107,10 +4390,10 @@ var translate = {
4107
4390
 
4108
4391
  //记录 nodeHistory - 判断text是否已经被拆分了
4109
4392
  if(textArray.length > 0 && textArray[0] != text){ //主要是后面的是否相等,前面的>0只是避免代码报错
4110
- translate.node.get(node)[nodeAttribute.key].whole = false; //已经被拆分了,不是整体翻译了
4393
+ translate.node.get(translateNode).whole = false; //已经被拆分了,不是整体翻译了
4111
4394
  //这时,也默认给其赋值操作,将自定义术语匹配后的结果进行赋予
4112
4395
  }else{
4113
- translate.node.get(node)[nodeAttribute.key].whole = true; //未拆分,是整体翻译
4396
+ translate.node.get(translateNode).whole = true; //未拆分,是整体翻译
4114
4397
  }
4115
4398
  //成功加入到 nodeQueue 的对象。 如果长度为0,那就是还没有加入到 translate.nodeQueue 中,可能全被自定义术语命中了
4116
4399
  var addQueueObjectArray = [];
@@ -4151,14 +4434,14 @@ var translate = {
4151
4434
  // translate.node 记录
4152
4435
 
4153
4436
  // 记录当前有 translate.js 所触发翻译之后渲染到dom界面显示的时间,13位时间戳
4154
- translate.node.get(node).lastTranslateRenderTime = Date.now();
4437
+ translate.node.get(translateNode).lastTranslateRenderTime = Date.now();
4155
4438
  //将具体通过文本翻译接口进行翻译的文本记录到 translate.node.data
4156
- translate.node.get(node)[nodeAttribute.key].translateTexts = {}; //这里全部命中了,所以根本没有走翻译接口的文本
4439
+ translate.node.get(translateNode).translateTexts = {}; //这里全部命中了,所以根本没有走翻译接口的文本
4157
4440
  //将翻译完成后要显示出的文本进行记录
4158
- translate.node.get(node)[nodeAttribute.key].resultText = translate.element.nodeAnalyse.get(node).text; //直接获取当前node显示出来的文本作为最后的结果的文本
4441
+ translate.node.get(translateNode).resultText = translate.element.nodeAnalyse.get(node, attribute).text; //直接获取当前node显示出来的文本作为最后的结果的文本
4159
4442
 
4160
4443
  //将其加入 translate.history.translateTexts 中
4161
- translate.history.translateText.add(translate.node.get(node)[nodeAttribute.key].originalText, translate.node.get(node)[nodeAttribute.key].resultText);
4444
+ translate.history.translateText.add(translate.node.get(translateNode).originalText, translate.node.get(translateNode).resultText);
4162
4445
  }
4163
4446
 
4164
4447
  },
@@ -7875,8 +8158,8 @@ var translate = {
7875
8158
  var hash = translate.util.hash(apiTranslateText[i]);
7876
8159
  translate.storage.set('hash_'+to+'_'+hash, resultData.text[i]);
7877
8160
  //如果离线翻译启用了全部提取,那么还要存入离线翻译指定存储
7878
- if(translate.office.fullExtract.isUse){
7879
- translate.office.fullExtract.set(hash, apiTranslateText[i], data.to, resultData.text[i]);
8161
+ if(translate.offline.fullExtract.isUse){
8162
+ translate.offline.fullExtract.set(hash, apiTranslateText[i], data.to, resultData.text[i]);
7880
8163
  }
7881
8164
 
7882
8165
  //进行组合数据到 translateResultArray
@@ -8341,24 +8624,7 @@ var translate = {
8341
8624
  config.notTranslateTip = true;
8342
8625
  }
8343
8626
 
8344
- var currentLanguage = translate.language.getCurrent(); //获取当前翻译至的语种
8345
-
8346
- var lastUuid = ''; //最后一次的uuid
8347
- for(var queue in translate.nodeQueue){
8348
- if (!translate.nodeQueue.hasOwnProperty(queue)) {
8349
- continue;
8350
- }
8351
- lastUuid = queue;
8352
- }
8353
- //console.log(queue);
8354
-
8355
- if(lastUuid == ''){
8356
- if(config.selectLanguageRefreshRender){
8357
- translate.log('提示,当前还未执行过翻译,所以 translate.reset(); 还原至翻译前的执行指令忽略');
8358
- }
8359
- return;
8360
- }
8361
-
8627
+
8362
8628
  /*
8363
8629
  for(var lang in translate.nodeQueue[lastUuid].list){
8364
8630
  if (!translate.nodeQueue[lastUuid].list.hasOwnProperty(lang)) {
@@ -8419,16 +8685,20 @@ var translate = {
8419
8685
  if (!translate.node.get(key) == null) {
8420
8686
  continue;
8421
8687
  }
8422
- for(var attr in translate.node.get(key)){
8423
- if (!translate.node.get(key).hasOwnProperty(attr)) {
8424
- continue;
8425
- }
8426
- var analyse = translate.element.nodeAnalyse.get(key,translate.node.get(key)[attr].attribute);
8427
- if(typeof(translate.node.get(key)[attr].originalText) != 'string'){
8688
+ //for(var attr in translate.node.get(key)){
8689
+ //if (!translate.node.get(key).hasOwnProperty(attr)) {
8690
+ // continue;
8691
+ //}
8692
+
8693
+ //var analyse = translate.element.nodeAnalyse.get(key,translate.node.get(key).attribute);
8694
+ if(typeof(translate.node.get(key).originalText) !== 'string'){
8428
8695
  continue;
8429
8696
  }
8430
- translate.element.nodeAnalyse.analyse(key, analyse.text, translate.node.get(key)[attr].originalText, translate.node.get(key)[attr].attribute);
8431
- }
8697
+ //translate.element.nodeAnalyse.analyse(key, analyse.text, translate.node.get(key).originalText, translate.node.get(key).attribute);
8698
+
8699
+ //标注此次改动是有 translate.js 导致的 -- 这里就不用标记了,因为先已经移除了 translate.listener.observer 监听,所以不会再监听到还原的操作了
8700
+ key.nodeValue = translate.node.get(key).originalText;
8701
+ //}
8432
8702
  }
8433
8703
 
8434
8704
 
@@ -8449,6 +8719,15 @@ var translate = {
8449
8719
  translate.storage.set('to', '');
8450
8720
  translate.to = null;
8451
8721
 
8722
+ //清除文本翻译记录
8723
+ if(translate.history.translateText.originalMap !== null){
8724
+ translate.history.translateText.originalMap.clear();
8725
+ }
8726
+ if(translate.history.translateText.resultMap !== null){
8727
+ translate.history.translateText.resultMap.clear();
8728
+ }
8729
+
8730
+
8452
8731
  //重新绘制 select 选择语言
8453
8732
  if(config.selectLanguageRefreshRender){
8454
8733
  translate.selectLanguageTag.refreshRender();
@@ -8677,7 +8956,7 @@ var translate = {
8677
8956
  if(typeof(translatejsTextElementHidden) == 'undefined' || translatejsTextElementHidden == null){
8678
8957
  const style = document.createElement('style');
8679
8958
  // 设置 style 元素的文本内容为要添加的 CSS 规则
8680
- style.textContent = ' .translatejs-text-element-hidden{color: transparent !important; text-shadow: none !important;}';
8959
+ style.textContent = ' .translatejs-text-element-hidden, .translatejs-text-element-hidden[type="text"]::placeholder{color: transparent !important; -webkit-text-fill-color: transparent !important; text-shadow: none !important;} ';
8681
8960
  style.id = 'translatejs-text-element-hidden';
8682
8961
  // 将 style 元素插入到 head 元素中
8683
8962
  document.head.appendChild(style);
@@ -8698,38 +8977,16 @@ var translate = {
8698
8977
  if(translate.progress.api.isTip){
8699
8978
  //translate.listener.execute.renderStartByApi.push(function(uuid, from, to){
8700
8979
  translate.lifecycle.execute.translateNetworkBefore.push(function(data){
8701
- var nodes = new Array(); //要改动的元素节点
8702
-
8703
- //遍历所有node组合到 nodes
8704
- for(var r = 0; r<data.nodes.length; r++){
8705
- var node = data.nodes[r];
8706
- if(typeof(node) == 'undefined' || typeof(node.parentNode) == 'undefined'){
8707
- continue;
8708
- }
8709
- nodes.push(node);
8710
- }
8980
+ //取出当前变动的node,对应的元素
8981
+ var elements = translate.element.nodeToElement(data.nodes);
8982
+ //console.log(elements)
8711
8983
 
8712
8984
  //隐藏所有node的文本
8713
- for(var r = 0; r<nodes.length; r++){
8714
- if(nodes[r].nodeType === 1){
8715
- nodes[r].className = nodes[r].className+' translatejs-text-element-hidden';
8716
- }else{
8717
- //不是元素,那么就取父级了 -- 这里即使翻译的属性,也要进行,比如 value 的 placeholder
8718
- var nodeParent = nodes[r].parentNode;
8719
- if(nodeParent == null){
8720
- continue;
8721
- }
8722
- if(typeof(nodeParent.className) != 'undefined' && nodeParent.className != null && nodeParent.className.indexOf('translatejs-text-element-hidden') > -1){
8723
- //父有了,那么子就不需要再加了
8724
- continue;
8725
- }else{
8726
- //没有,添加
8727
- nodeParent.className = nodeParent.className+' translatejs-text-element-hidden';
8728
- }
8729
- }
8985
+ for(var r = 0; r<elements.length; r++){
8986
+ elements[r].className = elements[r].className+' translatejs-text-element-hidden';
8730
8987
  }
8731
8988
 
8732
- var rects = translate.visual.getRects(nodes);
8989
+ var rects = translate.visual.getRects(elements);
8733
8990
  //console.log(rects)
8734
8991
  var rectsOneArray = translate.visual.rectsToOneArray(rects);
8735
8992
 
@@ -8743,70 +9000,29 @@ var translate = {
8743
9000
 
8744
9001
  var rectLineSplit = translate.visual.filterRectsByLineInterval(rectsOneArray, 2);
8745
9002
  for(var r = 0; r<rectLineSplit.length; r++){
8746
- if(rectLineSplit[r].node.nodeType === 1){
8747
- rectLineSplit[r].node.className = rectLineSplit[r].node.className+' translate_api_in_progress';
8748
- }else{
8749
- //不是元素,那么就取父级了
8750
- var nodeParent = rectLineSplit[r].node.parentNode;
8751
- if(nodeParent == null){
8752
- continue;
8753
- }
8754
- if(typeof(nodeParent.className) != 'undefined' && nodeParent.className != null && nodeParent.className.indexOf('translate_api_in_progress') > -1){
8755
- //父有了,那么子就不需要再加了
8756
- continue;
8757
- }else{
8758
- //没有,添加
8759
- nodeParent.className = nodeParent.className+' translate_api_in_progress';
8760
- }
8761
- }
9003
+ if(typeof(rectLineSplit[r].node.className) === 'string' && rectLineSplit[r].node.className.indexOf('translate_api_in_progress') > -1){
9004
+ //已经存在了,就不继续加了
9005
+ }else{
9006
+ rectLineSplit[r].node.className = rectLineSplit[r].node.className+' translate_api_in_progress';
9007
+ }
8762
9008
  }
8763
-
8764
9009
  });
8765
9010
 
8766
- translate.listener.execute.renderFinishByApi.push(function(uuid, from, to){
8767
- //translate.lifecycle.execute.renderFinish.push(function(uuid, to){ 这个是所有的全完成,得用单一的from完成就要立即对完成的from的显示,不然全完成就太慢了
8768
- for(var hash in translate.nodeQueue[uuid].list[from]){
8769
- if (!translate.nodeQueue[uuid].list[from].hasOwnProperty(hash)) {
8770
- continue;
8771
- }
8772
-
8773
- for(var nodeindex in translate.nodeQueue[uuid].list[from][hash].nodes){
8774
- if (!translate.nodeQueue[uuid].list[from][hash].nodes.hasOwnProperty(nodeindex)) {
8775
- continue;
8776
- }
8777
-
8778
- var node = translate.nodeQueue[uuid].list[from][hash].nodes[nodeindex].node;
8779
-
8780
- var operationNode;
8781
- if(node.nodeType === 1){
8782
- //是元素
8783
- operationNode = node;
8784
- }else{
8785
- //节点,如 #text
8786
- operationNode = node.parentNode;
8787
- if(operationNode == null){
8788
- continue;
8789
- }
8790
- }
8791
-
8792
-
8793
-
8794
-
8795
- if(typeof(operationNode.className) != 'undefined' && operationNode.className != null){
8796
-
8797
- if(operationNode.className.indexOf('translatejs-text-element-hidden') > -1){
8798
- operationNode.className = operationNode.className.replace(/translatejs-text-element-hidden/g, '');
8799
- }
8800
- if(operationNode.className.indexOf('translate_api_in_progress') > -1){
8801
- operationNode.className = operationNode.className.replace(/translate_api_in_progress/g, '');
8802
- }
9011
+ translate.lifecycle.execute.translateNetworkAfter.push(function(data){
9012
+ //取出当前变动的node,对应的元素
9013
+ var elements = translate.element.nodeToElement(data.nodes);
9014
+
9015
+ for(var r = 0; r<elements.length; r++){
9016
+ if(typeof(elements[r].className) === 'string'){
9017
+ if(elements[r].className.indexOf('translatejs-text-element-hidden') > -1){
9018
+ elements[r].className = elements[r].className.replace(/translatejs-text-element-hidden/g, '');
9019
+ }
9020
+ if(elements[r].className.indexOf('translate_api_in_progress') > -1){
9021
+ elements[r].className = elements[r].className.replace(/translate_api_in_progress/g, '');
8803
9022
  }
8804
-
8805
-
8806
- //nodeParent.className = parentClassName.replace(/translate_api_in_progress/g, '');
8807
-
8808
- }
8809
- }
9023
+ }
9024
+ }
9025
+
8810
9026
 
8811
9027
  });
8812
9028
 
@@ -9119,20 +9335,99 @@ var translate = {
9119
9335
 
9120
9336
  obj: js对象
9121
9337
  formatSupplementaryCharLength: 对这个js对象进行格式化自动补充字符的长度,比如 2、 4
9338
+
9339
+ 2025.10.10 优化传入参数
9340
+ obj:{
9341
+ jsObject: 原本的obj参数, 也就是js对象
9342
+ formatSupplementaryCharLength: 对这个js对象进行格式化自动补充字符的长度,比如 2、 4 ,默认不设置则是4
9343
+ functionBodyHandle: 针对值是function函数类型时,可以自定义对函数体的源码进行处理,它是传入 function 类型的,比如:
9344
+ functionBodyHandle: function(functionBody){
9345
+ functionBody = functionBody+'123';
9346
+ return functionBody;
9347
+ }
9348
+ 传入值是函数体的string类型的源码内容
9349
+ 返回值是修改过后最新的函数体的string类型的源码内容
9350
+ 这是 2025.10.10 新增参数,应对layui的 i18n 全自动翻译函数体中的字符串文本
9351
+ }
9122
9352
  */
9123
9353
  objToString:function(obj, formatSupplementaryCharLength){
9354
+ if(typeof(obj) === 'object'){
9355
+ if(typeof(obj.jsObject) === 'object'){
9356
+ //是 2025.10.10 以后的新版本
9357
+ }else{
9358
+ //是 2025.10.10 以前的旧版本
9359
+ var newObj = {
9360
+ jsObject: obj
9361
+ }
9362
+ obj = newObj;
9363
+ }
9364
+ }else{
9365
+ obj = {};
9366
+ }
9367
+ if(typeof(formatSupplementaryCharLength) === 'number'){
9368
+ obj.formatSupplementaryCharLength = formatSupplementaryCharLength;
9369
+ }
9370
+ //未设置,就赋予默认值4
9371
+ if(typeof(obj.formatSupplementaryCharLength) !== 'number'){
9372
+ obj.formatSupplementaryCharLength = 4;
9373
+ }
9374
+
9124
9375
  // 自定义replacer函数,将函数转换为字符串
9125
- const jsonStr = JSON.stringify(obj, (key, value) => {
9376
+ let jsonStr = JSON.stringify(obj.jsObject, (key, value) => {
9126
9377
  if (typeof value === 'function') {
9127
9378
  // 将函数转换为其源代码字符串
9128
- return value.toString();
9379
+ var funcString = value.toString();
9380
+ if(typeof(funcString) === 'string' && funcString.length > 0){
9381
+ funcString = funcString.replace(/\n/g, '___TRANSLATEJS_LINE_BREAK___');
9382
+ }
9383
+ return funcString;
9384
+ }else{
9385
+ return value;
9129
9386
  }
9130
- return value;
9131
- }, formatSupplementaryCharLength);
9132
9387
 
9133
- // 将转义的\n替换为实际的换行符
9134
- const formattedStr = jsonStr.replace(/\\n/g, '\n');
9135
- return formattedStr;
9388
+ return result;
9389
+ }, obj.formatSupplementaryCharLength);
9390
+
9391
+
9392
+ //对 function 的函数体进行处理
9393
+ // 将转义的\n替换为实际的换行符 -- 20251009 优化,去掉换行符替换,layui 工具中发现这样会将原本文本中的换行符替换掉,而是调整为仅仅针对function方法进行针对替换
9394
+ // 逐行判断,判断其中哪一行的value是function,要将function的字符串格式变为function函数格式
9395
+ if(jsonStr.indexOf('___TRANSLATEJS_LINE_BREAK___') > -1){
9396
+ const lines = jsonStr.split('\n');
9397
+ for(var li = 0; li<lines.length; li++){
9398
+ // 检查当前行是否包含特定标记
9399
+ if (lines[li].includes('___TRANSLATEJS_LINE_BREAK___')) {
9400
+ lines[li] = lines[li].replace(/___TRANSLATEJS_LINE_BREAK___/g, '\n'); //将其替换为原本的换行符
9401
+
9402
+ // 查找值部分(假设格式是 "key": "function...")
9403
+ const valueMatch = lines[li].match(/"[^"]+":\s*"([^"]+)"/);
9404
+ if (valueMatch && valueMatch[1]) {
9405
+ // 替换换行标记为实际换行
9406
+ let functionStr = valueMatch[1].replace(/___TRANSLATEJS_LINE_BREAK___/g, '\n');
9407
+
9408
+ // 将函数字符串转换为实际函数
9409
+ try {
9410
+ // 使用Function构造函数创建函数更安全一些
9411
+ const functionParts = functionStr.match(/function\s*([^\(]*)\(([^)]*)\)\s*\{([\s\S]*)\}/);
9412
+
9413
+ if (functionParts) {
9414
+ var [, name, params, body] = functionParts;
9415
+ if(typeof(obj.functionBodyHandle) === 'function'){
9416
+ body = obj.functionBodyHandle(body);
9417
+ }
9418
+ // 替换原行中的字符串为函数表达式
9419
+ lines[li] = lines[li].replace(`"${valueMatch[1]}"`, `function${name}(${params}){${body}}`);
9420
+ }
9421
+ } catch (e) {
9422
+ console.error('转换函数时出错:', e);
9423
+ }
9424
+ }
9425
+ }
9426
+ }
9427
+ jsonStr = lines.join('\n');
9428
+ }
9429
+
9430
+ return jsonStr;
9136
9431
  }
9137
9432
  },
9138
9433
  /*js dispose end*/
@@ -10455,13 +10750,11 @@ var translate = {
10455
10750
  });
10456
10751
  //将其记录到 translate.node.data
10457
10752
  translate.node.set(textNode,{
10458
- translate_default_value:{
10459
- attribute:"",
10460
- originalText: originalText,
10461
- resultText: text,
10462
- translateTexts: {}, //这里因为直接从缓存中取的,没有走网络接口,所以这里直接空
10463
- whole: true
10464
- },
10753
+ attribute:"",
10754
+ originalText: originalText,
10755
+ resultText: text,
10756
+ translateTexts: {}, //这里因为直接从缓存中取的,没有走网络接口,所以这里直接空
10757
+ whole: true,
10465
10758
  translateResults: {
10466
10759
  [originalText]:1
10467
10760
  },
@@ -10743,7 +11036,7 @@ var nodeuuid = {
10743
11036
  //延迟触发,方便拦截自定义
10744
11037
  setTimeout(function(){
10745
11038
  translate.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');
10746
- }, 1000);
11039
+ }, 3000);
10747
11040
  /*js copyright-notice end*/
10748
11041
 
10749
11042
  //初始化