// ==UserScript==
// @name Twitter External Translator
// @name:zh Twitter外部翻译器
// @name:zh-CN Twitter外部翻译器
// @name:zh-TW Twitter外部翻译器
// @name:nl Twitter Externe Vertaler
// @name:fr Traducteur externe Twitter
// @name:de Externer Twitter-Übersetzer
// @name:it Traduttore esterno di Twitter
// @name:ja ツイッター外部翻訳者
// @name:pl Zewnętrzny tłumacz Twittera
// @name:pt Tradutor externo do Twitter
// @name:ru-RU Twitter Внешний переводчик
// @name:ru Twitter Внешний переводчик
// @name:es Traductor externo de Twitter
// @description Adds 3rd party translators to Twitter
// @description:zh 将第三方翻译添加到推特
// @description:zh-CN 将第三方翻译添加到推特
// @description:zh-TW 將第三方翻譯添加到推特
// @description:nl Voegt vertalers van derden toe aan Twitter
// @description:fr Ajout de traducteurs tiers à Twitter
// @description:de Fügt Drittanbieter-Übersetzer zu Twitter hinzu
// @description:it Aggiunge traduttori di terze parti a Twitter
// @description:pl Dodaje tłumaczy innych firm do Twittera
// @description:pt Adiciona tradutores de terceiros ao Twitter
// @description:ja サードパーティの翻訳者をツイッターに追加
// @description:ru-RU Добавляет сторонних переводчиков в Twitter
// @description:ru Добавляет сторонних переводчиков в Twitter
// @description:es Añade traductores de terceros a Twitter
// @author Magic of Lolis
// @version 0.10
// @namespace https://github.com/magicoflolis/userscriptrepo/tree/master/ExternalTranslator
// @require https://code.jquery.com/jquery-3.6.0.slim.min.js
// @include https://twitter.com/*
// @grant none
// @run-at document-end
// @downloadURL none
// ==/UserScript==
( () => {
"use strict";
// CONFIGURE START
let cfg = {
/** @type {'en'|'zh'|'nl'|'fr'|'de'|'it'|'ja'|'pl'|'pt'|'ru'|'es'} */
lang: 'en', // Preferred language
/** @type {'deepl'|'yandex'|'bing'|'google'|'translate'} */
translator: 'deepl', // Preferred translator, lowercase only!
/** @type {'text'|'icon'|'text + icon'} */
display: 'text + icon', // Preferred display choice.
};
// CONFIGURE END
const iWidth = `width="10"`;
let icons = {
// Icons are retrieved from translators site and https://www.flaticon.com
deepl: `
`,
yandex: `
`,
bing: `
`,
google: `
`,
translate: `
`,
},
tw = {
en: `Translate with`,
zh: `翻译与`,
nl: `Vertaal met`,
fr: `Traduire avec`,
de: `Übersetzen mit`,
it: `Tradurre con`,
ja: `で翻訳する`,
pl: `Tłumaczenie za pomocą`,
pt: `Traduzir com`,
ru: `Перевод с`,
es: `Traducir con`,
};
function isHTML(str) {
let doc = new DOMParser().parseFromString(str, "text/html");
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
}
function injectTranslationButton(magicBtn, btContainer, btLang, content, site) {
content = ''; // prevent undefined
const translateTweet = $("div[lang]").eq(0).siblings().eq(0).children("span"),
translateBio = $('div[data-testid="UserDescription"]').eq(0).siblings().eq(0).children("span"),
trBtn = $('[dir="ltr"]').eq(0),
dlTweet = $("div[lang]").eq(0).siblings().eq(1),
dlBio = $('div[data-testid="UserDescription"]').eq(0).siblings().eq(1);
let name = (cfg.translator == 'yandex') ? `Yandex ${icons.yandex}` : (cfg.translator == 'bing') ? `Bing ${icons.bing}` : (cfg.translator == 'google') ? `Google ${icons.google}` : (cfg.translator == 'translate') ? `translate.com ${icons.translate}` : `DeepL ${icons.deepl}`,
settings = (cfg.display == 'text') ? icons = {
deepl: "",
yandex: "",
bing: "",
google: "",
translate: "",
} : (cfg.display == 'icon') ? name = (cfg.translator == 'yandex') ? icons.yandex : (cfg.translator == 'bing') ? icons.bing : (cfg.translator == 'google') ? icons.google : (cfg.translator == 'translate') ? icons.translate : icons.deepl : false,
tweetbtn = () => {
settings
btContainer = translateTweet.parent().siblings(),
btLang = btContainer.attr("lang");
magicBtn = translateTweet.parent().clone().appendTo(translateTweet.parent().parent());
btContainer.children("span").each((index,item) => {
let tweet = $(item).html().trim();
(tweet && tweet != '' && !isHTML(tweet)) ? content += ` ${tweet}` : false;
});
site = (cfg.translator == 'yandex') ? `https://translate.yandex.com/?lang=${btLang}-${cfg.lang}&text=${content}` : (cfg.translator == 'bing') ? `https://www.bing.com/translator/?text=${content}&from=${btLang}&to=${cfg.lang}` : (cfg.translator == 'google') ? `https://translate.google.com/?q=${content}&sl=${btLang}&tl=${cfg.lang}` : (cfg.translator == 'translate') ? `https://www.translate.com/#${btLang}/${cfg.lang}/${content}` : `https://www.deepl.com/translator#${btLang}/${cfg.lang}/${content}`;
let locate = (cfg.lang == 'zh') ? magicBtn.children("span").html(`${tw.zh} ${name}`) : (cfg.lang == 'nl') ? magicBtn.children("span").html(`${tw.nl} ${name}`) : (cfg.lang == 'fr') ? magicBtn.children("span").html(`${tw.fr} ${name}`) : (cfg.lang == 'de') ? magicBtn.children("span").html(`${tw.de} ${name}`) : (cfg.lang == 'it') ? magicBtn.children("span").html(`${tw.it} ${name}`) : (cfg.lang == 'ja') ? magicBtn.children("span").html(`${tw.ja} ${name}`) : (cfg.lang == 'pl') ? magicBtn.children("span").html(`${tw.pl} ${name}`) : (cfg.lang == 'pt') ? magicBtn.children("span").html(`${tw.pt} ${name}`) : (cfg.lang == 'ru') ? magicBtn.children("span").html(`${tw.ru} ${name}`) : (cfg.lang == 'es') ? magicBtn.children("span").html(`${tw.es} ${name}`) : (cfg.lang == 'en') ? magicBtn.children("span").html(`${tw.en} ${name}`) : magicBtn.children("span").html(`${tw.en} ${name}`);
locate
magicBtn.hover(function() {
$(this).css("text-decoration", "underline");
}, function() {
$(this).css("text-decoration", "none");
});
magicBtn.on("click", () => {
window.open(`${site}`,'_blank');
})
},
biobtn = () => {
settings
btContainer = translateBio.parent().siblings();
magicBtn = translateBio.parent().clone().appendTo(translateBio.parent().parent());
btContainer.children("span").each((index,item) => {
let bio = $(item).html().trim();
(bio && bio != '' && !isHTML(bio)) ? content += ` ${bio}` : false;
});
site = (cfg.translator == 'yandex') ? `https://translate.yandex.com/?lang=auto-${cfg.lang}&text=${content}` : (cfg.translator == 'bing') ? `https://www.bing.com/translator/?text=${content}&from=auto&to=${cfg.lang}` : (cfg.translator == 'google') ? `https://translate.google.com/?q=${content}&sl=auto&tl=${cfg.lang}` : (cfg.translator == 'translate') ? `https://www.translate.com/#auto/${cfg.lang}/${content}` : `https://www.deepl.com/translator#auto/${cfg.lang}/${content}`;
let locate = (cfg.lang == 'zh') ? magicBtn.children("span").html(`${tw.zh} ${name}`) : (cfg.lang == 'nl') ? magicBtn.children("span").html(`${tw.nl} ${name}`) : (cfg.lang == 'fr') ? magicBtn.children("span").html(`${tw.fr} ${name}`) : (cfg.lang == 'de') ? magicBtn.children("span").html(`${tw.de} ${name}`) : (cfg.lang == 'it') ? magicBtn.children("span").html(`${tw.it} ${name}`) : (cfg.lang == 'ja') ? magicBtn.children("span").html(`${tw.ja} ${name}`) : (cfg.lang == 'pl') ? magicBtn.children("span").html(`${tw.pl} ${name}`) : (cfg.lang == 'pt') ? magicBtn.children("span").html(`${tw.pt} ${name}`) : (cfg.lang == 'ru') ? magicBtn.children("span").html(`${tw.ru} ${name}`) : (cfg.lang == 'es') ? magicBtn.children("span").html(`${tw.es} ${name}`) : (cfg.lang == 'en') ? magicBtn.children("span").html(`${tw.en} ${name}`) : magicBtn.children("span").html(`${tw.en} ${name}`);
locate
magicBtn.hover(function() {
$(this).css("text-decoration", "underline");
}, function() {
$(this).css("text-decoration", "none");
});
magicBtn.on("click", () => {
window.open(`${site}`,'_blank');
})
};
return (translateBio.length && !dlBio.length) ? biobtn() : (trBtn.length && !dlTweet.length) ? tweetbtn() : false;
}
const init = { subtree: true, characterData: true, childList: true },
target = document.getElementById('react-root') ?? console.log(`[MoL] can't find ${target}`),
callback = (_mutations, observer) => {
observer.disconnect()
injectTranslationButton()
observer.observe(target, init)
};
new MutationObserver(callback).observe(target, init)
})();