翻译

try to translate the world!

当前为 2019-08-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name 翻译
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.3
  5. // @description try to translate the world!
  6. // @author su
  7. // @match http://*/*
  8. // @include https://*/*
  9. // @grant GM_xmlhttpRequest
  10. // @connect fy.iciba.com
  11. // @connect api.ai.qq.com
  12. // @connect translate.google.cn
  13. // @require http://cdn.bootcss.com/blueimp-md5/1.1.0/js/md5.min.js
  14. // ==/UserScript==
  15. (function() {
  16. //金山词霸翻译接口
  17. const cibaUrl = "http://fy.iciba.com/ajax.php?a=fy";
  18. //css样式
  19. const style = {
  20. 'ballStyle': 'position: fixed;top: 100px;right: 0;width: 40px;height: 40px;border-radius: 50%;border: 1px solid #ececec;text-align: center;line-height: 40px;font-size: 24px;ont-weight: 900;color: rgb(103, 192, 192);cursor: pointer;',
  21. 'traStyle': 'z-index:101;position: fixed;top: 100px;right: 0;width: 30%;border-radius: 6px;font: 13px/normal Arial, Helvetica;box-shadow: 0 0 0 1px rgba(0, 0, 0, .05), 0 2px 3px 0 rgba(0, 0, 0, .1);transform: translate(100%, 0);transition: transform .3s linear;',
  22. 'selectStyle': 'width: 60%;margin-top: 3px;border: 1px solid #ececec;height: 28px;border-radius: 2px;color: #666;',
  23. 'textareaStyle': 'height: 96px;top: 40px;width: 100%;font-weight: normal;font-family: "Roboto", Sans-Serif;outline: none;-webkit-appearance: none;white-space: pre-wrap;word-wrap: break-word;z-index: 2;background: transparent;border-width: 0;',
  24. 'dTextStyle': 'height: auto;min-height: 120px;padding: 30px 20px 12px 20px;overflow: hidden;'
  25. }
  26. //下拉框
  27. const select = '<option value="en" selected>英语</option><option value="zh-CN">简体中文</option><option value="ar">阿拉伯语</option><option value="et">爱沙尼亚语</option><option value="bg">保加利亚语</option><option value="is">冰岛语</option><option value="pl">波兰语</option><option value="bs-Latn">波斯尼亚语(拉丁语)</option><option value="fa">波斯语</option><option value="da">丹麦语</option><option value="de">德语</option><option value="ru">俄语</option><option value="fr">法语</option><option value="zh-TW">繁体中文</option><option value="fil">菲律宾语</option><option value="fj">斐济语</option><option value="fi">芬兰语</option><option value="ht">海地克里奥尔语</option><option value="ko">韩语</option><option value="nl">荷兰语</option><option value="ca">加泰罗尼亚语</option><option value="cs">捷克语</option><option value="otq">克雷塔罗奥托米语</option><option value="tlh">克林贡语</option><option value="hr">克罗地亚语</option><option value="lv">拉脱维亚语</option><option value="lt">立陶宛语</option><option value="ro">罗马尼亚语</option><option value="mg">马达加斯加语</option><option value="mt">马耳他语</option><option value="ms">马来语(拉丁语)</option><option value="bn-BD">孟加拉语</option><option value="mww">苗语</option><option value="af">南非荷兰语</option><option value="pt">葡萄牙语</option><option value="ja">日语</option><option value="sv">瑞典语</option><option value="sm">萨摩亚语</option><option value="sr-Latn">塞尔维亚语(拉丁语)</option><option value="sr-Cyrl">塞尔维亚语(西里尔文)</option><option value="no">书面挪威语</option><option value="sk">斯洛伐克语</option><option value="sl">斯洛文尼亚语</option><option value="sw">斯瓦希里语</option><option value="ty">塔希提语</option><option value="te">泰卢固语</option><option value="ta">泰米尔语</option><option value="th">泰语</option><option value="to">汤加语</option><option value="tr">土耳其语</option><option value="cy">威尔士语</option><option value="ur">乌尔都语</option><option value="uk">乌克兰语</option><option value="es">西班牙语</option><option value="he">希伯来语</option><option value="el">希腊语</option><option value="hu">匈牙利语</option><option value="it">意大利语</option><option value="hi">印地语</option><option value="id">印度尼西亚语</option><option value="yua">尤卡坦玛雅语</option><option value="vi">越南语</option>';
  28.  
  29. function Main_Su() {
  30. this.main_s = null;
  31. this.ball = null;
  32. this.tra = null;
  33. this.ori_select = null;
  34. this.tra_select = null;
  35. this.ori_text = null;
  36. this.tra_text = null;
  37. }
  38. /**
  39. * 设置下拉框选中
  40. */
  41. Main_Su.prototype.setSelectChecked = function(select, checkValue) {
  42. for (var i = 0; i < select.options.length; i++) {
  43. if (select.options[i].value == checkValue) {
  44. select.options[i].selected = true;
  45. break;
  46. }
  47. }
  48. };
  49. /**
  50. * 创建小球
  51. */
  52. Main_Su.prototype.createBall = function() {
  53. this.ball = document.createElement('div');
  54. this.ball.setAttribute('id', 'ball');
  55. this.ball.setAttribute('style', style.ballStyle);
  56. this.ball.innerHTML = '译';
  57. return this.ball;
  58. }
  59. /**
  60. * 翻译结果的语言选择下拉框
  61. */
  62. Main_Su.prototype.createOriSelect = function() {
  63. this.ori_select = document.createElement('select');
  64. this.ori_select.setAttribute('id', "ori_select");
  65. this.ori_select.setAttribute('style', style.selectStyle);
  66. this.ori_select.innerHTML = select;
  67. //设置默认选择
  68. this.setSelectChecked(this.ori_select, 'zh-CN');
  69. return this.ori_select;
  70. }
  71. /**
  72. * 需要翻译文本的语言选择下拉框
  73. */
  74. Main_Su.prototype.createTraSelect = function() {
  75. this.tra_select = document.createElement('select');
  76. this.tra_select.setAttribute('id', "tra_select");
  77. this.tra_select.setAttribute('style', style.selectStyle);
  78. this.tra_select.innerHTML = select;
  79. //设置默认选择
  80. this.setSelectChecked(this.tra_select, 'en');
  81. return this.tra_select;
  82. }
  83. /**
  84. * 需要翻译文本的语言输入框
  85. */
  86. Main_Su.prototype.createOriText = function() {
  87. this.ori_text = document.createElement('textarea');
  88. this.ori_text.setAttribute('id', 'ori_text');
  89. this.ori_text.setAttribute('style', style.textareaStyle);
  90. this.ori_text.setAttribute('placeholder', '输入文本');
  91. return this.ori_text;
  92. }
  93. /**
  94. * 翻译结果的语言输入框
  95. */
  96. Main_Su.prototype.createTraText = function() {
  97. this.tra_text = document.createElement('textarea');
  98. this.tra_text.setAttribute('id', 'tra_text');
  99. this.tra_text.setAttribute('style', style.textareaStyle);
  100. this.tra_text.setAttribute('placeholder', '输入文本');
  101. return this.tra_text;
  102. }
  103. /**
  104. * 控制翻译面板的隐藏
  105. */
  106. Main_Su.prototype.hideTra = function() {
  107. tra.style.height = 0;
  108. tra.style.transform = 'translate(100%,0)';
  109. ball.style.visibility = 'visible'
  110. }
  111. /**
  112. * 创建列
  113. */
  114. Main_Su.prototype.createOriTd = function() {
  115. var oriTd = document.createElement('td');
  116. oriTd.setAttribute('id', 'oriTd');
  117. oriTd.setAttribute('style', 'border-right: 1px solid #ececec;background-color: #fff;width: 50%;');
  118. var div = document.createElement('div');
  119. var div_s = document.createElement('div');
  120. var div_t = document.createElement('div');
  121. div_s.setAttribute('style', 'margin: 10px 8px 0 16px;height: 40px;');
  122. div_t.setAttribute('style', style.dTextStyle);
  123. //创建添加下拉框跟输入框
  124. this.createOriSelect();
  125. div_s.appendChild(this.ori_select);
  126. this.createOriText();
  127. div_t.appendChild(this.ori_text);
  128. div.appendChild(div_s);
  129. div.appendChild(div_t);
  130. oriTd.appendChild(div);
  131. return oriTd;
  132. }
  133. /**
  134. * 创建列
  135. */
  136. Main_Su.prototype.createTraTd = function() {
  137. var traTd = document.createElement('td');
  138. traTd.setAttribute('id', 'traTd');
  139. traTd.setAttribute('style', 'width: 50%;background: #f9f9f9;');
  140. var div = document.createElement('div');
  141. var div_s = document.createElement('div');
  142. var div_t = document.createElement('div');
  143. div_s.setAttribute('style', 'margin: 10px 8px 0 16px;height: 40px;');
  144. div_t.setAttribute('style', style.dTextStyle);
  145. this.createTraSelect();
  146. div_s.appendChild(this.tra_select);
  147. this.createTraText();
  148. div_t.appendChild(this.tra_text);
  149. div.appendChild(div_s);
  150. div.appendChild(div_t);
  151. traTd.appendChild(div);
  152. return traTd;
  153. }
  154. /**
  155. * 创建翻译框
  156. */
  157. Main_Su.prototype.createTra = function() {
  158. this.tra = document.createElement('div');
  159. this.tra.setAttribute('id', 'tra');
  160. this.tra.setAttribute('style', style.traStyle)
  161. var table = document.createElement('table');
  162. table.setAttribute('style', "width: 100%");
  163. var tr = document.createElement('tr');
  164. tr.appendChild(this.createOriTd());
  165. tr.appendChild(this.createTraTd());
  166. table.appendChild(tr);
  167. this.tra.appendChild(table);
  168. return this.tra;
  169. }
  170. /**
  171. * 创建翻译主面板
  172. */
  173. Main_Su.prototype.createMain = function() {
  174. this.main_s = document.createElement('div');
  175. this.createBall();
  176. this.createTra();
  177.  
  178. this.main_s.setAttribute('id', 'main_s');
  179. this.main_s.setAttribute('style', 'z-index:101');
  180. this.main_s.appendChild(this.ball);
  181. this.main_s.appendChild(this.tra);
  182. return this.main_s;
  183. }
  184. /**
  185. * ajax 跨域访问公共方法
  186. * @param {*} url
  187. * @param {*} method
  188. * @param {*} data
  189. */
  190. Main_Su.prototype.ajaxFun = function(url, header, method, data) {
  191. if (!!!method)
  192. method = 'GET';
  193. GM_xmlhttpRequest({
  194. method: method,
  195. url: url,
  196. data: data,
  197. header: header,
  198. onload: function(res) {
  199. if (JSON.parse(res.response)[0][0][0]) {
  200. tra_text.value = JSON.parse(res.response)[0][0][0];
  201. tra_text.style.color = 'black'
  202. }
  203. },
  204. onloadstart: function(res) {
  205. tra_text.value = "正在翻译..."
  206. tra_text.style.color = 'grey'
  207. },
  208. onerror: function(res) {
  209. console.log("连接失败:" + res);
  210. }
  211. });
  212. }
  213. /**
  214. * 判断语种:只能判断中英韩日语
  215. * @param {} text
  216. */
  217. Main_Su.prototype.judgeLanguage = function(text) {
  218. if (new RegExp('[\\u4e00-\\u9fa5]').test(text)) {
  219. return 'zh-CN'
  220. } else if (new RegExp('[\\x3130-\\x318F]').test(text)) {
  221. return 'ko'
  222. } else if (new RegExp('[\\u0800-\\u4e00]').test(text)) {
  223. return 'ja'
  224. } else if (new RegExp('[A-Za-z]').test(text)) {
  225. return 'en'
  226. } else {
  227. return 'default'
  228. }
  229. }
  230. /**
  231. * 翻译
  232. * @param {是否关闭自动检测语种} isAuto
  233. */
  234. Main_Su.prototype.translate = function(closeAuto) {
  235. var from = this.ori_select.value;
  236. //判断翻译文本的语种
  237. if (!closeAuto) {
  238. from = this.judgeLanguage(this.ori_text.value) == 'default' ? from : this.judgeLanguage(this.ori_text.value);
  239. this.setSelectChecked(this.ori_select, from);
  240. }
  241. var to = this.tra_select.value;
  242. this.ajaxFun(Translations.googleFun(from, to, this.ori_text.value), {
  243. "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
  244. "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
  245. "Host": "translate.google.cn"
  246. });
  247. }
  248.  
  249. /**
  250. * 添加绑定事件
  251. */
  252. Main_Su.prototype.rigisterEvent = function() {
  253. this.ball.addEventListener('click', function() {
  254. this.tra.style.transform = 'translate(0,0)';
  255. this.tra.style.height = 'auto';
  256. this.ball.style.visibility = 'hidden'
  257. }.bind(this))
  258. this.ori_text.addEventListener('input', function() {
  259. this.translate(false);
  260. }.bind(this));
  261. this.ori_select.addEventListener('change',
  262. function() {
  263. this.translate(true);
  264. }.bind(this));
  265. this.tra_select.addEventListener('change', this.translate.bind(this));
  266. var timeout;
  267. this.main_s.addEventListener('mouseleave', function() {
  268. timeout = setTimeout(this.hideTra, 1000);
  269. }.bind(this))
  270. this.main_s.addEventListener('mouseenter', function() {
  271. clearTimeout(timeout);
  272. })
  273. }
  274. const Translations = {
  275. /**
  276. * 金山词霸翻译
  277. * @param {需要翻译文本的语言} f
  278. * @param {翻译结果的语言} t
  279. * @param {翻译原文} w
  280. */
  281. cibaFun: function(f, t, w) {
  282. var url = cibaUrl + "&f=" + f + "&t=" + t + "&w=" + w;
  283. return url;
  284. },
  285. /**
  286. *
  287. * @param {需要翻译文本的语言} sl
  288. * @param {翻译结果的语言} tl
  289. * @param {翻译原文} q
  290. */
  291. googleFun: function(sl, tl, q) {
  292. function sq(a) {
  293. return function() {
  294. return a
  295. }
  296. }
  297.  
  298. function tq(q, b) {
  299. for (var c = 0; c < b.length - 2; c += 3) {
  300. var d = b.charAt(c + 2);
  301. d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d);
  302. d = "+" == b.charAt(c + 1) ? q >>> d : q << d;
  303. q = "+" == b.charAt(c) ? q + d & 4294967295 : q ^ d
  304. }
  305. return q
  306. }
  307. /**
  308. * 计算tk值
  309. * @param {你要翻译的内容} q
  310. * @param {tkk的值} uq
  311. */
  312. function vq(q, uq = '422388.3876711001') {
  313. if (null !== uq)
  314. var b = uq;
  315. else {
  316. b = sq('T');
  317. var c = sq('K');
  318. b = [b(), c()];
  319. b = (uq = window[b.join(c())] || "") || ""
  320. }
  321. var d = sq('t');
  322. c = sq('k');
  323. d = [d(), c()];
  324. c = "&" + d.join("") + "=";
  325. d = b.split(".");
  326. b = Number(d[0]) || 0;
  327. for (var e = [], f = 0, g = 0; g < q.length; g++) {
  328. var l = q.charCodeAt(g);
  329. 128 > l ? e[f++] = l : (2048 > l ? e[f++] = l >> 6 | 192 : (55296 == (l & 64512) && g + 1 < q.length && 56320 == (q.charCodeAt(g + 1) & 64512) ? (l = 65536 + ((l & 1023) << 10) + (q.charCodeAt(++g) & 1023),
  330. e[f++] = l >> 18 | 240,
  331. e[f++] = l >> 12 & 63 | 128) : e[f++] = l >> 12 | 224,
  332. e[f++] = l >> 6 & 63 | 128),
  333. e[f++] = l & 63 | 128)
  334. }
  335. q = b;
  336. for (f = 0; f < e.length; f++) {
  337. q += e[f],
  338. q = tq(q, "+-a^+6");
  339. }
  340. q = tq(q, "+-3^+b+-f");
  341. q ^= Number(d[1]) || 0;
  342. 0 > q && (q = (q & 2147483647) + 2147483648);
  343. q %= 1000000;
  344. return c + (q.toString() + "." + (q ^ b))
  345. }
  346. window.TTK = '422388.3876711001';
  347. var tk = vq(q);
  348. var url = "https://translate.google.cn/translate_a/single?client=webapp&sl=" + sl + "&tl=" + tl + "&hl=" + sl + "&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&dt=gt&otf=1&ssel=0&tsel=0&kc=3&tk=" + tk + "&q=" + encodeURIComponent(q);
  349. return url;
  350. }
  351. }
  352. //判断当前窗口是否为最顶层窗口,是则创建
  353. if (window.top == window.self) {
  354. var main = new Main_Su();
  355. main.createMain();
  356. main.rigisterEvent();
  357. document.body.appendChild(main.main_s);
  358. }
  359. })()