// ==UserScript== // @name 需要梯子 谷歌划词翻译 translate.google.com // @namespace https://violentmonkey.github.io // @version 1.17 // @description 基于 translate.google.com,中译英,英译中 // @license https://www.apache.org/licenses/LICENSE-2.0 // @author zkrisj // @include * // @exclude https://juejin.cn/editor/drafts/* // @exclude https://translate.google.cn/* // @run-at document-end // @connect translate.google.com // @grant GM_xmlhttpRequest // @downloadURL none // ==/UserScript== (function() { 'use strict'; var googleUrl = 'https://translate.google.com/translate_a/single?client=gtx&dt=t&dt=bd&dj=1&source=input&hl=auto&sl=auto'; // 无需梯子 // var googleUrl = 'https://translate.google.cn/_/TranslateWebserverUi/data/batchexecute?&source-path=%2F&rpcids=MkEWBc&soc-app=1&soc-platform=1&soc-device=1&_reqid=632656&rt=c'; var icon = document.createElement('div'); var word = ''; icon.innerHTML = '' + ''; icon.setAttribute('style', 'width:32px;' + 'height:32px;' + 'display:none;' + 'background:#fff;' + 'border-radius:16px;' + 'box-shadow:4px 4px 8px #888;' + 'position:absolute;' + 'z-index:2147483647;'); // 添加翻译图标到 DOM document.documentElement.appendChild(icon); document.addEventListener('mousedown', function(e) { if (e.target == icon || (e.target.parentNode && e.target.parentNode == icon) || (e.target.parentNode.parentNode && e.target.parentNode .parentNode == icon)) { // 点击翻译图标时阻止选中的文本消失 e.preventDefault(); } }); // 选中变化事件 document.addEventListener("selectionchange", function() { if (!window.getSelection().toString().trim()) { icon.style.display = 'none'; // server.containerDestroy(); } }); // 显示、隐藏翻译图标 document.addEventListener('mouseup', function(e) { if (e.target == icon || (e.target.parentNode && e.target.parentNode == icon) || (e.target.parentNode.parentNode && e.target.parentNode .parentNode == icon)) { // 点击了翻译图标 e.preventDefault(); return; } var text = window.getSelection().toString().trim(); if (text && text.length < 800 && icon.style.display == 'none') { icon.style.top = e.pageY + 12 + 'px'; icon.style.left = e.pageX + 'px'; icon.style.display = 'block'; } else if (!text) { icon.style.display = 'none'; for (var i = 0; i < server.rendered.length; i++) { // 点击了翻译内容面板 if (e.target == server.rendered[i]) return; // 不再创建翻译图标 } server.containerDestroy(); // 销毁翻译内容面板 } }); // 翻译图标点击事件 icon.addEventListener('click', function(e) { var text = window.getSelection().toString().trim(); if (text) { icon.style.display = 'none'; server.containerDestroy(); // 销毁翻译内容面板 // 新建翻译内容面板 var container = server.container(); container.style.top = e.pageY + 'px'; if (e.pageX + 350 <= document.body.clientWidth) // container 面板css最大宽度为250px container.style.left = e.pageX + 'px'; else container.style.left = document.body.clientWidth - 350 + 'px'; document.body.appendChild(container); server.rendered.push(container); if (isChina(text)) { ajax(googleUrl + '&tl=en&q=' + encodeURIComponent(text), container); // ajax(googleUrl, container, 'POST', "f.req=" + JSON.stringify([[["MkEWBc", "[[" + encodeURIComponent(text) + ",'zh-CN','en']]"]]])); } else { ajax(googleUrl + '&tl=zh&dt=t&q=' + encodeURIComponent(text), container); /* text = text.replace(/[A-Z][^A-Z ]/g, function(v) { return ' ' + v.toLowerCase() }).replace(/\p{P}/gu, ' ').replace(/ /g, ' ').trim(); word = text; ajax(googleUrl, container, 'POST', "f.req=" + JSON.stringify([[["MkEWBc", "[[" + encodeURIComponent(text) + ",'auto','zh-CN']]"]]])); */ } } }); function isChina(str) { var reg = /^([\u4E00-\u9FA5]|[\uFF00-\uFF20]|[\u3000-\u301C])+$/; return reg.test(str); } function ajax(url, element, method, data, headers) { if (!method) method = 'GET'; // 因为Tampermonkey跨域访问(a.com)时会自动携带对应域名(a.com)的对应cookie,不会携带当前域名的cookie // 所以,GM_xmlhttpRequest【不存在】cookie跨域访问安全性问题 if (!headers) headers = { "content-type": "application/x-www-form-urlencoded;charset=UTF-8", }; GM_xmlhttpRequest({ method: method, url: url, headers: headers, data: data, onload: function(res) { console.log(url, data, res); google(res.responseText, element); // googleCn(res.responseText, element); }, onerror: function(res) { displaycontainer("连接失败", element); } }); } function googleCn(res, element) { if (res.startsWith('')) { displaycontainer("获取失败", element); } else { res = JSON.parse(JSON.parse(res.match(/^\)]}'\n\n\d+\n(\[\[.*(?!\n\d)\]\])/)[1])[0][2]); var phonetic = res[0][0] ? res[0][0] + "\r\n" : ""; var translation = res[1][0][0][5][0][0]; if (res[3] && word === res[3][0] && res[3][5] && res[3][5][0] && res[3][5][0][0] && res[3][5][0][0][1] && res[3][5][0][0][1][0]) translation = res[3][5][0][0][1][0][0]; displaycontainer(phonetic.toLowerCase() + translation, element); } } function google(res, element) { displaycontainer(JSON.parse(res).sentences.map(item => item.trans).join(), element); } function displaycontainer(text, element) { element.textContent = text; element.style.display = 'block'; // 显示结果 } var server = { // 存放已经生成的翻译内容面板(销毁的时候用) rendered: [], // 销毁已经生成的翻译内容面板 containerDestroy: function() { for (var i = this.rendered.length - 1; i >= 0; i--) { if (this.rendered[i] && this.rendered[i].parentNode) { this.rendered[i].parentNode.removeChild(this.rendered[i]); } } }, // 生成翻译结果面板 DOM (此时还未添加到页面) container: function() { var pre = document.createElement('pre'); pre.setAttribute('style', 'display:none;' + 'position:absolute;' + 'font-size:13px;' + 'overflow:auto;' + 'background:#fff;' + 'font-family:sans-serif,Arial;' + 'font-weight:normal;' + 'text-align:left;' + 'color:#000;' + 'padding:0.5em 1em;' + 'line-height:1.5em;' + 'border-radius:5px;' + 'border:1px solid #ccc;' + 'box-shadow:4px 4px 8px #888;' + 'max-width:350px;' + 'max-height:216px;' + 'z-index:2147483647;'); return pre; } }; })();