inline-translator

Translation inline

当前为 2024-04-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @id inline-translator
  3. // @name inline-translator
  4. // @version 0.1
  5. // @namespace 12425
  6. // @author 12425
  7. // @description Translation inline
  8. // @license MIT
  9. // @include http://*
  10. // @include https://*
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_xmlhttpRequest
  13. // ==/UserScript==
  14.  
  15.  
  16. 'use strict';
  17.  
  18. (function() {
  19.  
  20. GM_registerMenuCommand("Translate", () => {
  21. const root = document.body;
  22. if (root.classList.contains('_myscript_translated')) {
  23. return;
  24. }
  25. root.classList.add('_myscript_translated');
  26. translate(root);
  27. });
  28.  
  29.  
  30. const TranslationTags = new Set([
  31. "blockquote",
  32. "h1",
  33. "h2",
  34. "h3",
  35. "h4",
  36. "h5",
  37. "h6",
  38. "ol",
  39. "p",
  40. "ul",
  41. ]);
  42.  
  43.  
  44. function fetch(text, callback, arg1, arg2) {
  45. GM_xmlhttpRequest({
  46. method: 'GET',
  47. url: `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=zh&dt=t&q=${encodeURIComponent(text)}`,
  48. onload: function(resp) {
  49. let json = null;
  50. try {
  51. json = JSON.parse(resp.responseText);
  52. } catch {
  53. return;
  54. }
  55.  
  56. const data = json[0].map(function(item) {
  57. return item[0];
  58. }).join('');
  59. if (text !== data) {
  60. callback(data, arg1, arg2);
  61. }
  62. },
  63. });
  64. }
  65.  
  66.  
  67. function simplify(node) {
  68. let array = [];
  69. array.push(extractAttrs(node));
  70. Array.from(node.querySelectorAll('*')).forEach(function(el) {
  71. array.push(extractAttrs(el));
  72. });
  73. return array;
  74. }
  75.  
  76.  
  77. function extractAttrs(node) {
  78. let attributes = {};
  79. Array.from(node.attributes).forEach(attr => {
  80. attributes[attr.name] = attr.value;
  81. node.removeAttribute(attr.name);
  82. });
  83. return attributes;
  84. }
  85.  
  86.  
  87. function resumeAttrs(node, attrs) {
  88. Object.keys(attrs).forEach(key => {
  89. node.setAttribute(key, attrs[key]);
  90. });
  91. }
  92.  
  93.  
  94. function updateNode(data, node, attrs) {
  95. const tag = node.tagName.toLowerCase();
  96. let newNode = document.createElement(tag);
  97. newNode.innerHTML = data;
  98. node.insertAdjacentElement('afterend', newNode);
  99. resumeAttrs(newNode, attrs[0]);
  100. let i = 1;
  101. Array.from(node.querySelectorAll('*')).forEach(function(el) {
  102. resumeAttrs(el, attrs[i]);
  103. i++;
  104. });
  105. if (node.parentNode.tagName !== 'SMALL') {
  106. const smallNode = document.createElement('small');
  107. node.insertAdjacentElement('afterend', smallNode);
  108. smallNode.appendChild(node);
  109. }
  110. }
  111.  
  112.  
  113. function translate(node) {
  114. const tag = node.tagName.toLowerCase();
  115. if (!tag) {
  116. return;
  117. }
  118. if (!TranslationTags.has(tag)) {
  119. Array.from(node.children).forEach(translate);
  120. return;
  121. }
  122. const attrs = simplify(node.cloneNode(true));
  123. fetch(node.innerHTML, updateNode, node, attrs);
  124. }
  125.  
  126.  
  127. })();