// ==UserScript==
// @name 一键去除在线翻译网站的换行符
// @namespace https://greasyfork.org/zh-CN/scripts/390059-%E7%BF%BB%E8%AF%91%E6%8F%92%E4%BB%B6-%E5%8E%BB%E9%99%A4%E6%8D%A2%E8%A1%8C
// @version 2.4.2
// @description 在各大在线翻译网站的页面上增加了一个“格式化”按钮,用来移除从PDF等复制过来的文本中包含的回车符、换行符、"\n"等,支持DeepL翻译、谷歌翻译、百度翻译、网易有道翻译
// @author Kevin Chen
// @match https://fanyi.baidu.com/*
// @match https://fanyi.youdao.com/*
// @match https://translate.google.cn/*
// @match https://translate.google.com/*
// @match https://translate.google.com.hk/*
// @match https://www.deepl.com/translator
// @match https://fanyi.qq.com/*
// @match https://dict.cnki.net/*
// @icon https://translate.google.cn/favicon.ico
// @grant GM_addStyle
// @run-at document-end
// @license MIT
// @downloadURL none
// ==/UserScript==
const FORMAT_CN = '格式化'
const LOADING_WAIT_TIME = 500
// DeepL翻译CONFIG配置文件
const DEEPL_TRANSLATE_CONFIG = {
host: 'www.deepl.com',
inputAreaSelector: '#panelTranslateText > div.lmt__sides_container > div.lmt__sides_wrapper > section.lmt__side_container.lmt__side_container--source > div.lmt__textarea_container > div.lmt__inner_textarea_container > d-textarea > div',
containerSelector: '#gatsby-focus-wrapper div.contents',
translateButtonSelector: null,
buttonClass: 'myCustomDeepLButtonClass',
createButtonHtml: ``,
}
// 谷歌翻译(香港)CONFIG配置文件
const GOOGLE_FANYI_CONFIG = {
host: 'translate.google.com.hk',
inputAreaSelector: 'textarea',
containerSelector: '#yDmH0d > c-wiz > div > div.WFnNle > c-wiz > div.hgbeOc.EjH7wc > nav',
translateButtonSelector: null,
buttonClass: 'myCustomGoogleButtonClass',
createButtonHtml: ``,
}
// 谷歌翻译(国际)CONFIG配置文件
const GOOGLE_TRANSLATE_CONFIG = {
host: 'translate.google.com',
inputAreaSelector: 'textarea',
containerSelector: '#yDmH0d > c-wiz nav',
translateButtonSelector: null,
buttonClass: 'myCustomGoogleButtonClass',
createButtonHtml: ``,
}
// 百度翻译CONFIG配置文件
const BAIDU_FANYI_CONFIG = {
host: 'fanyi.baidu.com',
inputAreaSelector: '#baidu_translate_input',
containerSelector: '#main-outer div.trans-operation.clearfix',
translateButtonSelector: '#translate-button',
buttonClass: 'myCustomBaiduButtonClass',
createButtonHtml: `${FORMAT_CN}`,
}
// 有道翻译CONFIG配置文件
const YOUDAO_FANYI_CONFIG = {
host: 'fanyi.youdao.com',
inputAreaSelector: '#js_fanyi_input',
containerSelector: '#app > div.index.os_Windows > div.translate-tab-container > div.tab-header > div.tab-left',
translateButtonSelector: '#TextTranslate > div.fixedBottomActionBar-border-box > div > div.sourceActionContainer > div > div > div.opt-right.yd-form-container > a',
buttonClass: null,
createButtonHtml: `
${FORMAT_CN}
`,
}
// 腾讯翻译CONFIG配置文件
const TENCENT_FANYI_CONFIG = {
host: 'fanyi.qq.com',
inputAreaSelector: 'body > div.layout-container > div.textpanel > div.textpanel-container.clearfix > div.textpanel-source.active > div.textpanel-source-textarea > textarea',
containerSelector: '#language-button-group-translate',
translateButtonSelector: '#language-button-group-translate > div',
buttonClass: null,
createButtonHtml: `${FORMAT_CN}
`
}
// CNKI翻译CONFIG配置文件
const CNKI_FANYI_CONFIG = {
host: 'dict.cnki.net',
inputTextSelector: '#app > div > section > div > div:nth-child(2) > div.translate > div.trans-left > div.trans-left-con > p > span > pre',
inputAreaSelector: '#translateLeft',
containerSelector: '#app > div > section > div > div.hanlder > div.hanlder-left > div.hanlder-left-right',
translateButtonSelector: '#app > div > section > div > div.hanlder > div.hanlder-left > div.hanlder-left-right > button',
buttonClass: null,
createButtonHtml: ``
}
// button class styles
GM_addStyle(`
.myCustomGoogleButtonClass {
color: #1967d2;
background: transparent;
border-width: 1px;
border-radius: 4px;
border-style: solid;
padding: 0 15px 0 15px;
height: 36px;
font-size: .875rem;
border-color: #dadce0;
cursor:pointer
}
.myCustomGoogleButtonClass:hover {
background-color: #f1f5f9;
color: #174ea6
}
`)
GM_addStyle(`
.myCustomBaiduButtonClass {
text-align: center;
margin-left: 14px;
width: 106px;
height: 30px;
line-height: 30px;
font-size: 14px;
color: #4395ff;
letter-spacing: 2px;
background-color: #f9f9f9;
border: 1px solid #4395ff;
border-radius: 3px
}
`)
GM_addStyle(`
.myCustomDeepLButtonClass {
background-color: #fff;
border: 1px solid #e3e3e3;
border-radius: 8px;
cursor: pointer;
height: 66px;
min-width: 160px;
box-shadow: 0px 4px 16px rgb(0 0 0 / 8%);
font-weight: 400;
font-size: 20px;
}
`)
// convert string to web element
function parseDom(html) {
const e = document.createElement('div')
e.innerHTML = html
return e.firstChild
}
// get text context of node
function getTextContent(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent;
}
let text = ' ';
for (let i = 0, len = node.childNodes.length; i < len; i++) {
text += getTextContent(node.childNodes[i]);
}
return text;
}
// simulate textArea input
function simulateInput(inputBox, value) {
const properties = {
value: value,
writable: true,
configurable: true
};
// 为input输入元素添加一个值属性
Object.defineProperty(inputBox, 'value', properties);
// 创建并分配一个新的input事件
let inputEvent = new Event("input", { bubbles: true });
inputBox.dispatchEvent(inputEvent);
}
// format code
function formatByConfig(config) {
const inputArea = document.querySelector(config.inputAreaSelector)
if (config.host == DEEPL_TRANSLATE_CONFIG.host) {
let content = format(getTextContent(inputArea)).trim();
inputArea.innerHTML = content;
return
}
let txt = inputArea.value != null ? inputArea.value : inputArea.innerHTML
if (inputArea.value != null) {
inputArea.value = format(txt)
} else {
inputArea.innerHTML = format(txt)
}
// click translate button
if (config.translateButtonSelector != null) {
const translateButton = document.querySelector(config.translateButtonSelector)
translateButton.click()
}
}
function format (txt) {
for (var i = 0; i < txt.length; i++) {
if (txt.indexOf('\n')) txt = txt.replace('\n', ' ')
}
// merge space in txt
return txt.replace(/\s+/g, ' ');
}
// create new button by config
function createButtonByConfig(config) {
const newButton = parseDom(config.createButtonHtml)
if (newButton == null) {
console.info('创建的新按钮为空')
return
}
newButton.onclick = () => {
if (config.host == CNKI_FANYI_CONFIG.host) {
let inputText = document.querySelector(config.inputTextSelector);
let txt = inputText.innerHTML;
txt = format(txt);
simulateInput(document.querySelector(config.inputAreaSelector), txt);
}
formatByConfig(config)
}
const container = document.querySelector(config.containerSelector)
if (container != null) {
container.appendChild(newButton)
} else {
console.info('无法找到container,请检查CSS规则是否有效:' + config.containerSelector)
}
}
function findConfigByHost(host) {
console.info('当前网页host:', host)
if (host == GOOGLE_FANYI_CONFIG.host) {
} else if (host == GOOGLE_TRANSLATE_CONFIG.host) {
return GOOGLE_TRANSLATE_CONFIG
} else if (host == BAIDU_FANYI_CONFIG.host) {
return BAIDU_FANYI_CONFIG
} else if (host == YOUDAO_FANYI_CONFIG.host) {
return YOUDAO_FANYI_CONFIG
} else if (host == DEEPL_TRANSLATE_CONFIG.host) {
return DEEPL_TRANSLATE_CONFIG
} else if (host == TENCENT_FANYI_CONFIG.host) {
return TENCENT_FANYI_CONFIG
} else if (host == CNKI_FANYI_CONFIG.host) {
return CNKI_FANYI_CONFIG
}
}
;(function () {
//'use strict';
console.log('%s毫秒后加载格式化按钮', LOADING_WAIT_TIME)
window.setTimeout(function () {
const config = findConfigByHost(window.location.host)
createButtonByConfig(config)
console.log('加载格式化按钮完成')
}, LOADING_WAIT_TIME)
})()