Translate

划词翻译调用“必应翻译(必应词典)、谷歌翻译、有道词典(有道翻译)、百度翻译”网页翻译

目前為 2017-12-15 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Translate
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  划词翻译调用“必应翻译(必应词典)、谷歌翻译、有道词典(有道翻译)、百度翻译”网页翻译
// @author       barrer
// @match        http://*/*
// @include      https://*/*
// @include      file:///*
// @run-at document-end
// @connect      dict.youdao.com
// @connect      cn.bing.com
// @connect      translate.googleapis.com
// @connect      fanyi.baidu.com
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function () {
    'use strict';

    // Your code here...
    /**日志输出*/
    function log() {
        var debug = false;
        if (!debug)
            return;
        if (arguments) {
            for (var i = 0; i < arguments.length; i++) {
                console.log(arguments[i]);
            }
        }
    }

    log('url:' + window.location.href);
    // 翻译图标
    var icon = document.createElement('div'), style = '' +
        'font-family:Arial,sans-serif!important;' +
        'font-weight:normal!important;' +
        'background:#f60!important;' +
        'color:#fff!important;' +
        'border-radius:3px!important;' +
        'font-size:13px!important;' +
        'line-height:100%!important;' +
        'padding:2px 4px!important;' +
        'margin:0 4px!important;' +
        'display:inline-block!important;' +
        'text-decoration:none!important;' +
        '';
    icon.innerHTML = '' +
        '<a href="javascript:void(0)" style="' + style + '"  type="bing">必应</a>' +
        '<a href="javascript:void(0)" style="' + style + '"  type="google">谷歌</a>' +
        '<a href="javascript:void(0)" style="' + style + '" type="youdao">有道</a>' +
        '<a href="javascript:void(0)" style="' + style + '"  type="baidu_translator">百度</a>' +
        '';
    icon.setAttribute('style', '' +
        'display:none!important;' +
        'position:absolute!important;' +
        'font-size:13px!important;' +
        'text-align:left!important;' +
        'z-index:2147483647!important;' +
        '');
    // 添加翻译图标到 DOM
    document.documentElement.appendChild(icon);
    // 鼠标事件:防止选中的文本消失
    document.addEventListener('mousedown', function (e) {
        if (e.target == icon || (e.target.parentNode && e.target.parentNode == icon)) {// 点击了翻译图标
            e.preventDefault();
        }
    });
    // 选中变化事件:当点击已经选中的文本的时候,隐藏翻译图标和翻译面板(此时浏览器动作是:选中的文本已经取消选中了)
    document.addEventListener("selectionchange", function () {
        log('selectionchange:' + window.getSelection().toString());
        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.preventDefault();
            return;
        }
        for (var i = 0; i < server.rendered.length; i++) {// 点击了翻译内容面板
            if (e.target == server.rendered[i])
                return;// 不再创建翻译图标
        }
        var text = window.getSelection().toString().trim();
        log('text:' + text);
        if (text && icon.style.display == 'none') {
            log('show icon');
            log(text + '|' + e.pageX + '|' + e.pageY);
            icon.style.top = e.pageY + 10 + 'px';
            icon.style.left = e.pageX + 10 + 'px';
            icon.style.display = 'block';
        } else if (!text) {
            log('hide icon');
            icon.style.display = 'none';
            server.containerDestroy();// 销毁翻译内容面板
        }
    });
    // 翻译图标点击事件
    icon.addEventListener('click', function (e) {
        var text = window.getSelection().toString().trim();
        if (text) {
            log('click:' + text);
            server.containerDestroy();// 销毁翻译内容面板
            // 新建翻译内容面板
            var container = server.container();
            container.style.top = e.pageY + 16 + 'px';
            if (e.pageX + 250 + 16 <= document.body.clientWidth)// container 面板css最大宽度为250px
                container.style.left = e.pageX + 16 + 'px';
            else
                container.style.left = document.body.clientWidth - 250 + 'px';
            document.body.appendChild(container);
            server.rendered.push(container);
            // 判断用户选择的翻译引擎
            var engine = e.target.hasAttribute('type') ? e.target.getAttribute('type') : '';
            log('engine:' + engine);
            switch (engine) {
                case 'bing':
                    server.bing(text, container);
                    break;
                case 'google':
                    server.google(text, container);
                    break;
                case 'baidu_translator':
                    server.baidu_translator(text, container);
                    break;
                default:
                    server.youdao(text, container);
            }
        }
    });
    // 翻译server
    var server = {
        // 存放已经生成的翻译内容面板(销毁的时候用)
        rendered: [],
        // 有道翻译 引擎
        youdao: function (text, element) {
            this.ajax('http://dict.youdao.com/w/eng/' + encodeURIComponent(text), function (rst, ele) {
                var parser = new DOMParser(), doc = parser.parseFromString(rst, 'text/html'), html = '';
                var word = doc.querySelector('#phrsListTab .wordbook-js .keyword'),
                    pronounce = doc.querySelector('#phrsListTab .wordbook-js .baav'),
                    trans = doc.querySelector('#phrsListTab .trans-container'),
                    webTrans = doc.querySelectorAll('#tWebTrans .wt-container .title');
                if (!!!pronounce) // 中文拼音
                    pronounce = doc.querySelector('#phrsListTab .wordbook-js .phonetic');
                // 排版
                var pos = trans && trans.querySelectorAll('ul li,ul .wordGroup');
                for (var i = 0; pos && i < pos.length; i++) {
                    pos[i].innerHTML = pos[i].innerHTML + '▓';
                }
                html += word ? word.innerText.trim() : '';
                html += pronounce ? ' ' + pronounce.innerText.replace(/(\s)+/g, ' ').trim() : '';
                html += trans && trans.querySelector('ul') ? '\n' +
                    trans.querySelector('ul').innerText
                        .replace(/(\s)+/g, ' ')
                        .replace(/(▓)+/g, '\n').trim()
                    : '';
                html += trans && trans.querySelector('.additional') ?
                    '\n' + trans.querySelector('.additional').innerText.trim().replace(/\n/g, '') : '';
                if (!!webTrans.length) {
                    html += '\n网络释义:\n';
                    for (var j = 0; j < webTrans.length; j++) {
                        if (j !== 0)
                            html += ';';
                        html += webTrans[j].innerText.replace(/\n/g, '').trim();
                    }
                }
                ele.innerText = html;
                ele.style.display = 'block';// 显示结果
            }, function (rst, ele) {
                ele.innerText = '有道翻译 无法连接!';
                ele.style.display = 'block';// 显示结果
            }, element);
        },
        // Bing词典 引擎
        bing: function (text, element) {
            this.ajax('http://cn.bing.com/dict/search?q=' + encodeURIComponent(text), function (rst, ele) {
                var parser = new DOMParser(), doc = parser.parseFromString(rst, 'text/html'), html = '';
                var word = doc.querySelector('.hd_area'),
                    trans = doc.querySelector('.qdef ul'),
                    forms = doc.querySelector('.qdef .hd_if');
                // 排版
                var headword = doc.querySelector('#headword');
                if (headword)
                    headword.innerHTML = headword.innerHTML + '<br>';
                var pos = doc.querySelectorAll('.qdef ul li .pos');
                for (var i = 0; i < pos.length; i++) {
                    pos[i].innerText = '\n【' + pos[i].innerText + '】';
                }
                html += word ? word.innerText.replace(/\n/g, ' ').trim() : '';
                html += trans ? '\n' + trans.innerText.trim() : '';
                html += forms ? '\n' + forms.innerText.trim() : '';
                ele.innerText = html;
                ele.style.display = 'block';// 显示结果
            }, function (rst, ele) {
                ele.innerText = 'Bing词典 无法连接!';
                ele.style.display = 'block';// 显示结果
            }, element);
        },
        // 谷歌翻译 引擎
        google: function (text, element) {
            var apiUrl = 'https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&dt=bd&dj=1&source=input&sl=en&tl=zh-CN&hl=en&q=';
            this.ajax(apiUrl + encodeURIComponent(text), function (rst, ele) {
                var json = JSON.parse(rst), html = '';
                for (var i = 0; i < json.sentences.length; i++) {
                    html += json.sentences[i].orig + '\n';
                    html += json.sentences[i].trans + '\n';
                }
                ele.innerText = html;
                ele.style.display = 'block';// 显示结果
            }, function (rst, ele) {
                ele.innerText = '谷歌翻译 无法连接!';
                ele.style.display = 'block';// 显示结果
            }, element);
        },
        // 百度翻译 引擎
        baidu_translator: function (text, element) {
            var data = new FormData();
            data.set('from', 'en');
            data.set('to', 'zh');
            data.set('query', text);
            this.ajax('http://fanyi.baidu.com/v2transapi', function (rst, ele) {
                    var json = JSON.parse(rst), html = '';
                    for (var i = 0; i < json.trans_result.data.length; i++) {
                        html += json.trans_result.data[i].src + '\n';
                        html += json.trans_result.data[i].dst + '\n';
                    }
                    ele.innerText = html;
                    ele.style.display = 'block';// 显示结果
                }, function (rst, ele) {
                    ele.innerText = '百度翻译 无法连接!';
                    ele.style.display = 'block';// 显示结果
                },
                element,
                'POST',
                data
            );
        },
        // ajax 跨域访问公共方法
        ajax: function (url, success, error, element, method, data, headers) {
            if (!!!method)
                method = 'GET';
            // >>>因为Tampermonkey跨域访问(a.com)时会自动携带对应域名(a.com)的对应cookie
            // 不会携带当前域名的cookie
            // 所以,GM_xmlhttpRequest【不存在】cookie跨域访问安全性问题
            // 以下设置默认headers不起作用<<<
            if (!!!headers)
                headers = {'cookie': ''};
            GM_xmlhttpRequest({
                method: method,
                url: url,
                headers: headers,
                data: data,
                onload: function (res) {
                    success(res.responseText, element);
                },
                onerror: function (res) {
                    error(res.responseText, element);
                }
            });
        },
        // 销毁已经生成的翻译内容面板
        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 div = document.createElement('div');
            div.setAttribute('style', '' +
                'display:none!important;' +
                'position:absolute!important;' +
                'font-size:13px!important;' +
                'overflow:auto!important;' +
                'background:#fefee6!important;' +
                'font-family:Arial,sans-serif!important;' +
                'font-weight:normal!important;' +
                'text-align:left!important;' +
                'color:#000!important;' +
                'padding:0.5em 1em!important;' +
                'line-height:1.5em!important;' +
                'border-radius:5px!important;' +
                'border:1px solid #ccc!important;' +
                'max-width:250px!important;' +
                'max-height:150px!important;' +
                'z-index:2147483647!important;' +
                '');
            return div;
        }
    };// 翻译server结束
})();