🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

微软翻译组件

微软翻译组件 右下角点击翻译

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

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

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

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

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

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==UserScript==
// @name 微软翻译组件
// @description 微软翻译组件  右下角点击翻译
// @supportURL https://greasyfork.org/zh-CN/scripts/26027-%E5%BE%AE%E8%BD%AF%E7%BF%BB%E8%AF%91%E7%BB%84%E4%BB%B6/feedback
// @include     *
// @exclude     *.jpg
// @exclude     *.png
// @exclude     *.jpeg
// @exclude     *.gif
// @exclude     *.pdf
// @exclude     *115.com/*
// @require     https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.1.3/js.cookie.min.js
// @grant       GM_registerMenuCommand
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_getResourceText
// @grant       GM_getResourceUrl
// @grant       GM_xmlhttpRequest
// @resource httpJs http://www.microsofttranslator.com/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=False&ui=false&settings=Manual&from=
// @resource httpsJs https://ssl.microsofttranslator.com/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=False&ui=false&settings=Manual&from=
// @author      aogg
// @version 2.3.25
// @namespace https://greasyfork.org/users/25818
// ==/UserScript==


(function (){

  var width = '79',
      height = '23';
  var divId = 'MicrosoftTranslatorWidget',
      divMenu = null, // 菜单div
      divOne = null, // 一键翻译div
      selectNode = null, // 选择框
      divNode = null, // 主div
      translatorSwitch = function (){}, // 执行翻译函数
      localStorageLocalsKey = divId + 'localStorageLocals',
      localStorageAppCloseKey = divId + 'localStorageClose',
      localStorageAppOneKey = divId + 'localStorageOne',
      appOneFunc = { // 一键翻译处理函数
        get: function (){
          return GM_getValue(localStorageAppOneKey);
        },
        set: function (val){
          GM_setValue(localStorageAppOneKey, val);
          
          if (divOne){ // 修改文案
            divOne.innerText = divOne.oneTitleFunc();
          }
        }
      };
  
  
  GM_registerMenuCommand('切换微软一键翻译', function (){
    if (divOne){
      if (divNode){
          divNode.changeMenu('show'); // 显示菜单
        
          setTimeout(function (){
            divNode.changeMenu('hide');
          }, 500); // 关闭菜单
      }
      divOne.click();
    }
  });
  
  
  
  if (
    parent !== parent.parent || document.documentElement.clientWidth <= width * 2 || document.documentElement.clientHeight <= height * 2 || // iframe过多,或者屏幕过小
    checkOnlyItem() ||
    checkVideoFull() || // 检测视屏是否占满屏
    localStorage.getItem(localStorageAppCloseKey)
  ){ 
    // 控制层次,避免无限调用,如:http://www.w3school.com.cn/html/html_entities.asp
    // 控制宽高小的不显示
    return;
  }


  // 重置cookie
  try{
    Cookies.remove('mstto');
    console.log('remove cookie mstto');
  }catch(e){
    console.log(e);
  }

  var locals = ''; // zh-chs
  var source = null;
  var mainStatus = false; // 是否执行了main方法

  /**
  var noTranslator = ['wangpan'];
  if (self.frameElement && noTranslator.indexOf(self.frameElement.name) !== -1){
      return;
  }
  */

  
  if (navigator.userAgent.indexOf('Maxthon') > -1){ // 遨游浏览器
    var scriptNode = document.createElement('script');
    scriptNode.innerHTML = "setTimeout(function(){{var s=document.createElement('script');s.type='text/javascript';s.charset='UTF-8';s.src=((location && location.href && location.href.indexOf('https') == 0)?'https://ssl.microsofttranslator.com':'http://www.microsofttranslator.com')+'/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=False&ui=false&settings=Manual&from=';var p=document.head[0]||document.documentElement;p.insertBefore(s,p.firstChild); }},0);";

    document.head.appendChild(scriptNode);
    setTimeout(start,0);
    console.log('目前遨游浏览器因GM_xmlhttpRequest对于CSP的网站无法正确处理错误');
  }else{
    (function (){
        var url =((location && location.href && location.href.indexOf('https') == 0)?'https://ssl.microsofttranslator.com':'http://www.microsofttranslator.com')+
              '/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=False&ui=false&settings=Manual&from=';
        try{
          GM_xmlhttpRequest({
            method: "GET",
            url: url,
            onload: function(response) {
              try{
                if (response.responseText.length < 1000){
                  console.error('获取微软js失败,请ctrl+F5访问:' + url);
                }
                unsafeWindow.eval(response.responseText);

                start();
              }catch(e){
                console.error('无法执行eval,如github的CSP策略,可改用chrome自带的google翻译');
              }
            }
          });
        }catch(e){
          console.error('无法执行eval,如github的CSP策略,可改用chrome自带的google翻译');
          return;
        }
    })()
  }

  
  /**
  // 有缓存
  var code = location && location.href && location.href.indexOf('https') == 0?GM_getResourceText('httpsJs'):GM_getResourceText('httpJs');
  try{
    unsafeWindow.eval(code);
    setTimeout(start,0);
  }catch(e){
    console.log('无法执行eval,如github的CSP策略,可改用chrome自带的google翻译');
    return;
  }
  */
  

  
  
  divNode = document.createElement('div');

  divNode.id = divId;
  divNode.style.color = 'white';
  divNode.style.backgroundColor = '#555555';
  divNode.style.position = 'fixed';
  divNode.style.right = '0';
  divNode.style.bottom = '1px';
  divNode.style.zIndex = '9999999';
  divNode.style.fontSize = '13px';
  divNode.title = '翻译为,或双击隐藏';
  divNode.style.width= width + 'px';
  divNode.ondblclick = function(){ // 双击隐藏
    translatorHide();
  };
  divNode.changeMenu = function (action){
    var showArr = {'none':'block', 'block':'none'};
    if (divMenu){
      if (action === 'show'){ // 显示
        divMenu.style.display = 'block';
      }else if (action === 'hide'){ // 隐藏
        divMenu.style.display = 'none';
      }else {
        divMenu.style.display = showArr[divMenu.style.display] ? showArr[divMenu.style.display] : 'none';
      }
    }
  };
  divNode.oncontextmenu = function (event){ // 设置菜单
    event.preventDefault();
    this.changeMenu();
  }

  divMenu = menu(divNode);
  
  
  function start(){
      mutationStart();
      document.body.appendChild(divNode);
      document.onreadystatechange = main;
      setTimeout(main, 500); // 最少500ms内显示
  }
  
  // 隐藏全部
  var translatorHide = (function(div){
    return function (){
      div.style.display = 'none';
    }
  })(divNode)



  function main(){
    if (mainStatus || (document.readyState !== 'complete' && document.readyState !== 'interactive')){
      return;
    }
    mainStatus = true;

    // 多语言翻译
    var selectHtml = document.createElement('select'),
        selected = appOneFunc.get() || '',
        status = false, // 翻译状态,false为未翻译
        translateFunc = function (locals, setNodeNot){
          // var option = selectHtml.selectedOptions;
          source = selectHtml.getAttribute('data-source') || null;
          setLocals(locals, setNodeNot);
          translateStart();
        };
    selectHtml.style.backgroundColor = 'rgb(178, 178, 178)';
    selectHtml.ondblclick = function(){ // 双击隐藏
      this.parentNode.style.display = 'none';
    };
    selectHtml.style.margin = 0;
    selectHtml.style.padding = 0;
    selectHtml.style.fontSize = '13.3px';
    selectHtml.style.width= width + 'px';
    selectHtml.style.height= height + 'px';
    selectHtml.onclick = (function (){
      return function (event){ // 一键翻译
        var selected = appOneFunc.get(); // 每次重新获取
        if (selected){ // 需要一键翻译
          if (!status){ // 翻译
            event.preventDefault();
            translateFunc(selected)
          }else{ // 关闭
            closeTranslator();
          }
          status = !status;
        }
      }
    })();
    // Microsoft.Translator.Widget.GetLanguagesForTranslateLocalized()获取所有支持的翻译选项
    selectHtml.innerHTML = "\
      <option id='MicrosoftTranslatorWidget-option-select' value=''>翻译为</option>\
      <option value='zh-chs'>简体中文</option>\
      <option value='zh-cht'>繁体中文</option>\
      <option value='yue'>粤语</option>\
      <option value='ja'>日文</option>\
      <option id='MicrosoftTranslatorWidget-option-en' value='en'>英文</option>\
  ";
    
    if (selected){ // 修改默认值
      for (var i in selectHtml.options){
        if (selectHtml.options[i] && selectHtml.options[i].value == selected){
          selectHtml.options[i].selected = true;
        }
      }
      // selectHtml.value = selected; 此方法无效
    }
    
    selectHtml.onchange = function (){
      if (!this.value){ // 选择翻译为时,关闭翻译
        closeTranslator();
      }
      
      status = !!this.value;
      translateFunc(this.value, true);
    };
    
    
    var parentDiv = document.body.children.namedItem(divId);
    // parentDiv.style.display = 'block';
    parentDiv.appendChild(selectHtml);
    selectNode = selectHtml; // 放置到外部变量

    translateStart();

  }


  function translateStart(){
    if (mainStatus && locals && unsafeWindow['Microsoft']){
      // null, 'es', onProgress, onError, onComplete, onRestoreOriginal, 2000
      Microsoft.Translator.Widget.Translate(source, locals, null, null, onComplete);
    }
  }

  function onComplete(){
    var option = selectNode.options;
    option.namedItem('MicrosoftTranslatorWidget-option-en').innerText = '英文';
    option.namedItem('MicrosoftTranslatorWidget-option-select').innerText = '翻译为';

  }


  function addGlobalStyle(css) {
      var head, style;
      head = document.getElementsByTagName('head')[0];
      if (!head) { return; }
      style = document.createElement('style');
      style.type = 'text/css';
      style.innerHTML = css;
      head.appendChild(style);
  }


  console.log('完成');
  
  // 右击层
  function menu(parentDiv){
    var div = document.createElement('div');
    div.id= divId + "-menu";
    div.style.display = 'none';
    div.oncontextmenu = function (event){
      event.preventDefault();
      this.style.display = 'none';
    }
    
    // 当前网站永久隐藏
    var divHide = document.createElement('div');
    divHide.innerText = '当前网站隐藏';
    divHide.height = '20px';
    divHide.onclick = function (){
      if(window.confirm('确定要当前网站隐藏?')){
        localStorage.setItem(localStorageAppCloseKey, 1);
        translatorHide();
      }
    }
    div.appendChild(divHide);
    // 切换为一键翻译样式
    divOne = document.createElement('div');
    divOne.oneTitleFunc = function (){
          return (appOneFunc.get()?'取消':'') + '一键翻译'
        };
    divOne.innerText = divOne.oneTitleFunc();
    divOne.height = '20px';
    divOne.onclick = function (){
      var localValue = appOneFunc.get(),
          val = localValue ? '' : (locals || 'zh-chs');
      appOneFunc.set(val);
    }
    div.appendChild(divOne);
    
    
    parentDiv.appendChild(div);
    
    return div;
  }
  
  
  function setLocals(value, nodeNot){
    locals = value;
    localStorage.setItem(localStorageLocalsKey, value);
    !nodeNot && (selectNode.value = value);
  }
  
  
  // 取消翻译
  function closeTranslator(){
    unsafeWindow['Microsoft'] && Microsoft.Translator && Microsoft.Translator.FloaterOnClose();
    
    if (divOne){ // 恢复文案
      divOne.innerText = divOne.oneTitleFunc();
    }
  }
  
  
  
  function findVideo(){
      var names = ['object', 'embed', 'video'];
      var ele = [];
      for (var i in names){
        ele = document.getElementsByTagName(names[i]);
        if (ele.length){
          return ele;
        }
      }
      
      return ele;
  }
  
  
  
  function checkVideoFull(){ // 检测视频是否占满屏
    var ele = findVideo();

    if (ele.length){
      for (var i = 0; i < ele.length; ++i){
        if (ele.item(i).clientHeight == document.documentElement.clientHeight && ele.item(i).clientWidth == document.documentElement.clientWidth) {
          return true
        }
      }
    }
    
    return false;
  }
  
  
  
  
  function checkOnlyItem(){
  	if (document.body.childElementCount === 1){
  		var firstNodeName = document.body.firstElementChild.nodeName,
  			checkFirstNodeNameArr = ['SCRIPT', 'IMG'];
  		for (var i in checkFirstNodeNameArr){
  			if(checkFirstNodeNameArr[i] === firstNodeName){
  				return true;
  			}
  		}
  	}else if (document.body.childElementCount === 2){ // 只有img和script
  		if (
  			(document.body.childNodes.item(0).nodeName === 'IMG' && document.body.childNodes.item(1).nodeName === 'SCRIPT') ||
  			(document.body.childNodes.item(0).nodeName === 'SCRIPT' && document.body.childNodes.item(1).nodeName === 'IMG')
  		){
  			return true;
  		}
  	}


      
    return false;
  }
  
  
  
function mutationStart(){
  
  function mutationFunc(mutations){
        if (checkVideoFull() || checkOnlyItem()){
          observer.disconnect();
          translatorHide();
        }
  }
  
  
    // Firefox和Chrome早期版本中带有前缀
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver

    // 选择目标节点
    var target = document.body;
     
    // 创建观察者对象
    var observer = new MutationObserver(debounce(mutationFunc, 50));
     
    // 配置观察选项:
    var config = { childList: true, subtree: true }
     
    // 传入目标节点和观察选项
    observer.observe(target, config);
    
    // 先执行一次
    mutationFunc();
}
  
 
  
    
})()





 // 函数去抖
function debounce(func, wait, immediate) {
    var _ = {};
    _.now = Date.now || function() {
        return new Date().getTime();
    };
    var timeout, args, context, timestamp, result;

    var later = function() {
        // 定时器设置的回调 later 方法的触发时间,和连续事件触发的最后一次时间戳的间隔
        // 如果间隔为 wait(或者刚好大于 wait),则触发事件
        var last = _.now() - timestamp;

        // 时间间隔 last 在 [0, wait) 中
        // 还没到触发的点,则继续设置定时器
        // last 值应该不会小于 0 吧?
        if (last < wait && last >= 0) {
            timeout = setTimeout(later, wait - last);
        } else {
            // 到了可以触发的时间点
            timeout = null;
            // 可以触发了
            // 并且不是设置为立即触发的
            // 因为如果是立即触发(callNow),也会进入这个回调中
            // 主要是为了将 timeout 值置为空,使之不影响下次连续事件的触发
            // 如果不是立即执行,随即执行 func 方法
            if (!immediate) {
                // 执行 func 函数
                result = func.apply(context, args);
                // 这里的 timeout 一定是 null 了吧
                // 感觉这个判断多余了
                if (!timeout)
                    context = args = null;
            }
        }
    };

    // 嗯,闭包返回的函数,是可以传入参数的
    return function() {
        // 可以指定 this 指向
        context = this;
        args = arguments;

        // 每次触发函数,更新时间戳
        // later 方法中取 last 值时用到该变量
        // 判断距离上次触发事件是否已经过了 wait seconds 了
        // 即我们需要距离最后一次触发事件 wait seconds 后触发这个回调方法
        timestamp = _.now();

        // 立即触发需要满足两个条件
        // immediate 参数为 true,并且 timeout 还没设置
        // immediate 参数为 true 是显而易见的
        // 如果去掉 !timeout 的条件,就会一直触发,而不是触发一次
        // 因为第一次触发后已经设置了 timeout,所以根据 timeout 是否为空可以判断是否是首次触发
        var callNow = immediate && !timeout;

        // 设置 wait seconds 后触发 later 方法
        // 无论是否 callNow(如果是 callNow,也进入 later 方法,去 later 方法中判断是否执行相应回调函数)
        // 在某一段的连续触发中,只会在第一次触发时进入这个 if 分支中
        if (!timeout)
        // 设置了 timeout,所以以后不会进入这个 if 分支了
            timeout = setTimeout(later, wait);

        // 如果是立即触发
        if (callNow) {
            // func 可能是有返回值的
            result = func.apply(context, args);
            // 解除引用
            context = args = null;
        }

        return result;
    };
};