网页翻译-扩展版本

给非中文的网页右下角添加一个google翻译图标对网页进行翻译,该版本主要适配手机浏览器: X浏览器、via浏览器等不支持油猴扩展的浏览器

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         网页翻译-扩展版本
// @author       Kaiter-Plus
// @namespace    https://gitee.com/Kaiter-Plus/TampermonkeyScript/tree/master/Translate/Translate_ext.js
// @description  给非中文的网页右下角添加一个google翻译图标对网页进行翻译,该版本主要适配手机浏览器: X浏览器、via浏览器等不支持油猴扩展的浏览器
// @version      1.49
// @license      BSD-3-Clause
// @icon         https://www.google.cn/favicon.ico
// @include      *://*
// @run-at       document-end
// @noframes
// @note         2021/03/18 网页整页翻译功能,稍微调整了布局
// @note         2021/03/20 添加了排除网站的功能
// @note         2021/12/14 直接使用 https 获取谷歌翻译接口(防止有可能火狐浏览器无法用于翻译本地文件的bug)@古海沉舟
// @note         2022/10/05 由于谷歌关闭了国内的翻译接口,所以只能使用国际版的接口,现在使用脚本必须配合梯子
// ==/UserScript==

;(function () {
  'use strict'
  // 此处使用正则表达式排除不用进行翻译的网站
  const noTranslateDomain = [
    /^([0-9]+\.){3}[0-9]+/,
    /.*duyaoss\.com/,
    /.*lanzous\.com/,
    /.*w3school.*cn/,
    /.*iqiyi\.com/,
    /.*baidu.*/,
    /.*cnblogs\.com/,
    /.*csdn\.net/,
    /.*zhku\.edu\.cn/,
    /.*zhihuishu\.com/,
    /.*aliyuncs\.com/,
    /.*chaoxing\.com/,
    /.*youku\.com/,
    /.*examcoo\.com/,
    /.*mooc\.com/,
    /.*bilibili\.com/,
    /.*qq\.com/,
    /.*yy\.com/,
    /.*huya\.com/,
    /localhost/,
    /.*acfun\.cn/
  ]
  // 获取 head
  const head = document.head
  // 获取body
  const body = document.body
  // 获取当前页面的语言
  const lang = document.documentElement.lang.toLowerCase().substr(0, 2)
  // 获取网页使用的主要语言
  const mainLang = document.characterSet.toLowerCase().substr(0, 2)
  // 设置是否排除网站的标识
  let noTranslateDomainflag = false
  // 排除一些网站的翻译
  noTranslateDomain.every(reg => {
    if (reg.test(document.domain)) {
      noTranslateDomainflag = true
      return false
    } else {
      return true
    }
  })

  // 判断是不是中文,如果是则直接return,否则执行
  if (lang === 'zh' || mainLang === 'gb' || noTranslateDomainflag) {
    return
  } else {
    // 创建网页元素方法
    function createElement(html, nodeText, attr, parent) {
      const element = document.createElement(nodeText)
      if (attr) {
        element[attr] = html
      } else {
        element.innerHTML = html
      }
      parent.appendChild(element)
    }

    // 自定义样式,隐藏顶部栏
    createElement(
      `
      html,body{
        top: 0!important;
      }
      #google_translate_element {
        position: fixed;
        bottom: 60px;
        height: 21px;
        border-radius: 11px;
        left: 0px;
        transform: translateX(-75%);
        z-index: 10000000;
        overflow: hidden;
        box-shadow: 1px 1px 3px 0 #888;
        opacity: .5;
        transition: all .3s;
      }
      #google_translate_element .goog-te-gadget-simple {
        border: 0;
      }
      #google_translate_element .goog-te-gadget-simple span {
        margin-right: 0;
        border-radius: 11px;
      }
      #lb {
        display: inline-block;
      }
      .recoverPage {
        width: 4em;
        background-color: #fff;
        position: fixed;
        z-index: 10000000;
        bottom: 60px;
        right: 0px;
        transform: translateX(78%);
        user-select: none;
        text-align: center;
        font-size: small;
        line-height: 2em;
        border-radius: 1em;
        box-shadow: 1px 1px 3px 0 #888;
        opacity: .5;
        transition: all .3s;
      }
      #google_translate_element:hover, .recoverPage:hover {
        opacity: 1;
        transform: translateX(0);
      }
      .recoverPage:active {
        box-shadow: 1px 1px 3px 0 #888 inset;
      }
      #google_translate_element .goog-te-gadget-simple {
        width: 100%;
      }
      /* 隐藏移动端顶部栏 */
      [id=":1.container"].skiptranslate {
        display: none;
      }
      /* 隐藏 PC 端顶部栏 */
      [id=":2.container"].skiptranslate {
        display: none;
      }
      @media handheld, only screen and (max-width: 768px) {
        #google_translate_element {
          width: 104px;
        }
        #google_translate_element .goog-te-gadget>div:first-child {
          margin: 2px;
        }
        #google_translate_element .goog-te-combo {
          margin: 0;
          padding-top: 2px;
          border: none;
        }
        #goog-gt- {
          visibility: hidden!important;
          display: none!important;
        }
        .goog-text-highlight {
          background-color: inherit!important;
          box-shadow: 0 0 0 0 transparent!important;
        }
        .recoverPage {
          width: 2.8em;
          line-height: 2.8em;
          border-radius: 50%;
          opacity: .3;
          transform: translateX(0);
        }
        .recoverPage:hover {
          opacity: .3;
        }
      }
    `,
      'style',
      '',
      head
    )

    // 创建容器
    createElement('google_translate_element', 'div', 'id', body)

    // 初始化
    createElement(
      `function googleTranslateElementInit() {
        let google_translate_element = document.getElementById('google_translate_element')
        let timer = setInterval(function () {
          google_translate_element = document.getElementById('google_translate_element')
          if (google_translate_element) {
            clearInterval(timer)
            new google.translate.TranslateElement(
              {
                pageLanguage: 'auto',
                //包括的语言,中文简体,中文繁体,英语,日语,俄语
                includedLanguages: 'zh-CN,zh-TW,en,ja,ru',
                layout: /mobile/i.test(navigator.userAgent) ? 0 : 2,
              },
              'google_translate_element'
            )
            // 清除图片的请求,加快访问速度
            let img = [].slice.call(document.querySelectorAll('#goog-gt- img,#google_translate_element img'));
            img.forEach(function(v) {
              const a = v
              a.src = ''
              let b = a.outerHTML.replace(/<img(.*?)>/, () => {
                return '<span id="lb"' + RegExp.$1 +'></span>'
              })
              const c = document.createElement('div')
              c.innerHTML = b
              a.parentNode.insertBefore(c.children[0], a.parentNode.children[0])
              a.remove()
            });
            const recoverPage = document.createElement('div')
            recoverPage.setAttribute('class', 'notranslate recoverPage')
            recoverPage.innerText = '原'
            document.body.appendChild(recoverPage)
            // 点击恢复原网页
            recoverPage.onclick = () => {
              const phoneRecoverIframe = document.getElementById(':1.container') // 移动端
              const PCRecoverIframe = document.getElementById(':2.container') // PC端
              if (phoneRecoverIframe) {
                const recoverDocument = phoneRecoverIframe.contentWindow.document
                recoverDocument.getElementById(':1.restore').click()
              } else if (PCRecoverIframe) {
                const recoverDocument = PCRecoverIframe.contentWindow.document
                recoverDocument.getElementById(':2.restore').click()
              }
            }
          }
        }, 300)
      }`,
      'script',
      '',
      head
    )

    // 导入翻译接口
    createElement(
      'https://translate.google.com/translate_a/element.js?&cb=googleTranslateElementInit',
      'script',
      'src',
      head
    )

    // 排除一些代码的翻译
    const noTranslateArray = ['.bbCodeCode', 'tt', 'pre[translate="no"]']
    noTranslateArray.forEach(selectorName => {
      ;[...document.querySelectorAll(selectorName)].forEach(node => {
        if (node.className.indexOf('notranslate') === -1) {
          node.classList.add('notranslate')
        }
      })
    })
  }
})()