// ==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')
}
})
})
}
})()