translator

划词翻译

目前為 2018-04-19 提交的版本,檢視 最新版本

'use strict';

var css = "._panel_nvbn4_1 {\n  position: fixed;\n  max-width: 300px;\n  z-index: 10000;\n}\n  ._panel_nvbn4_1 * {\n    margin: 0;\n    padding: 0;\n    box-sizing: border-box;\n  }\n._body_nvbn4_11 {\n  position: relative;\n  padding: 8px;\n  border-radius: 4px;\n  border: 1px solid #eaeaea;\n  line-height: 24px;\n  color: #555;\n  background-color: #fff;\n  font-family: monospace, consolas;\n  font-size: 14px;\n  text-align: left;\n  word-break: break-all;\n}\n._header_nvbn4_24 {\n  padding: 0 0 8px;\n  border-bottom: 1px dashed #aaa;\n  color: #333;\n}\n._header_nvbn4_24 > a {\n    margin-left: 8px;\n    color: #7cbef0;\n    cursor: pointer;\n    font-size: 13px;\n  }\n._detail_nvbn4_35 {\n  margin: 8px 0 0;\n  line-height: 22px;\n  list-style: none;\n  font-size: 13px;\n}\n._detail_nvbn4_35 > li {\n    font-size: 13px;\n    line-height: 26px;\n  }\n";
var classMap = {
  "panel": "_panel_nvbn4_1",
  "body": "_body_nvbn4_11",
  "header": "_header_nvbn4_24",
  "detail": "_detail_nvbn4_35"
};

// ==UserScript==
// @name translator
// @namespace https://lufei.so
// @supportURL https://github.com/intellilab/translator.user.js
// @description 划词翻译
// @version 1.5.11
// @run-at document-start
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @include *
// ==/UserScript==
GM_addStyle(css);
var translator = initialize();

function createElement(tagName, props, attrs) {
  var el = document.createElement(tagName);

  if (props) {
    Object.keys(props).forEach(function (key) {
      el[key] = props[key];
    });
  }

  if (attrs) {
    Object.keys(attrs).forEach(function (key) {
      el.setAttribute(key, attrs[key]);
    });
  }

  return el;
}

function render(data) {
  var body = translator.body,
      audio = translator.audio;
  body.innerHTML = '';
  var basic = data.basic,
      query = data.query,
      translation = data.translation;

  if (basic) {
    var explains = basic.explains,
        us = basic['us-phonetic'],
        uk = basic['uk-phonetic'];
    var noPhonetic = '♥';
    var header = createElement('div', {
      className: classMap.header
    });
    header.appendChild(createElement('span', {
      textContent: query
    }));
    header.appendChild(createElement('a', {
      innerHTML: `uk: [${uk || noPhonetic}]`
    }, {
      'data-type': 1
    }));
    header.appendChild(createElement('a', {
      innerHTML: `us: [${us || noPhonetic}]`
    }, {
      'data-type': 2
    }));
    header.appendChild(createElement('a', {
      textContent: '详情'
    }, {
      target: '_blank',
      href: `http://dict.youdao.com/search?q=${encodeURIComponent(query)}`
    }));
    body.appendChild(header);
    header.addEventListener('click', function (e) {
      var type = e.target.dataset.type;

      if (type) {
        audio.src = `http://dict.youdao.com/dictvoice?audio=${encodeURIComponent(query)}&type=${type}`;
      }
    });

    if (explains) {
      var ul = createElement('ul', {
        className: classMap.detail
      });

      for (var i = 0; i < explains.length; i += 1) {
        var li = createElement('li', {
          innerHTML: explains[i]
        });
        ul.appendChild(li);
      }

      body.appendChild(ul);
    }
  } else if (translation) {
    var div = createElement('div', {
      innerHTML: translation[0]
    });
    body.appendChild(div);
  }
}

function translate(e) {
  var sel = window.getSelection();
  var text = sel.toString();
  if (/^\s*$/.test(text)) return;
  var _document = document,
      activeElement = _document.activeElement;
  if (['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) < 0 && !activeElement.contains(sel.getRangeAt(0).startContainer)) return;
  var query = {
    type: 'data',
    doctype: 'json',
    version: '1.1',
    relatedUrl: 'http://fanyi.youdao.com/',
    keyfrom: 'fanyiweb',
    key: null,
    translate: 'on',
    q: text,
    ts: Date.now()
  };
  var qs = Object.keys(query).map(function (key) {
    return `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`;
  }).join('&');
  GM_xmlhttpRequest({
    method: 'GET',
    url: `https://fanyi.youdao.com/openapi.do?${qs}`,

    onload(res) {
      var data = JSON.parse(res.responseText);

      if (!data.errorCode) {
        render(data);
        var panel = translator.panel;
        var _window = window,
            innerWidth = _window.innerWidth,
            innerHeight = _window.innerHeight;

        if (e.clientY > innerHeight * 0.5) {
          panel.style.top = 'auto';
          panel.style.bottom = `${innerHeight - e.clientY + 10}px`;
        } else {
          panel.style.top = `${e.clientY + 10}px`;
          panel.style.bottom = 'auto';
        }

        if (e.clientX > innerWidth * 0.5) {
          panel.style.left = 'auto';
          panel.style.right = `${innerWidth - e.clientX}px`;
        } else {
          panel.style.left = `${e.clientX}px`;
          panel.style.right = 'auto';
        }

        document.body.appendChild(panel);
      }
    }

  });
}

function debounce(func, delay) {
  var timer;

  function exec() {
    timer = null;
    func.apply(void 0, arguments);
  }

  return function () {
    if (timer) clearTimeout(timer);

    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    timer = setTimeout.apply(void 0, [exec, delay].concat(args));
  };
}

function initialize() {
  var audio = createElement('audio', {
    autoplay: true
  });
  var panel = createElement('div', {
    className: classMap.panel
  });
  var panelBody = createElement('div', {
    className: classMap.body
  });
  panel.appendChild(panelBody);
  var debouncedTranslate = debounce(translate);
  var isSelecting;
  document.addEventListener('mousedown', function (e) {
    isSelecting = false;
    if (panel.contains(e.target)) return;
    if (panel.parentNode) panel.parentNode.removeChild(panel);
    panelBody.innerHTML = '';
  }, true);
  document.addEventListener('mousemove', function () {
    isSelecting = true;
  }, true);
  document.addEventListener('mouseup', function (e) {
    if (panel.contains(e.target) || !isSelecting) return;
    debouncedTranslate(e);
  }, true);
  document.addEventListener('dblclick', function (e) {
    if (panel.contains(e.target)) return;
    debouncedTranslate(e);
  }, true);
  return {
    audio,
    panel,
    body: panelBody
  };
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址