Переводит сообщения на выбранный язык и отображает их в каналах Discord / by LZT users
当前为
// ==UserScript==
// @name DiscordAutoTranslator
// @namespace http://tampermonkey.net/
// @version 1.11
// @description Переводит сообщения на выбранный язык и отображает их в каналах Discord / by LZT users
// @match *://discord.com/*
// @author Timka251 & eretly
// @grant GM_xmlhttpRequest
// @icon https://i.pinimg.com/236x/68/95/31/689531dc04ba222ab7af0fa34dc63644.jpg
// @run-at document-end
// @license BSD-3-Clause
// ==/UserScript==
/*
* Copyright 2024 eretly
* Licensed under the BSD 3-Clause License.
*/
(function () {
'use strict';
const languageSelector = document.createElement('div');
languageSelector.style.position = 'fixed';
languageSelector.style.bottom = '10px';
languageSelector.style.right = '10px';
languageSelector.style.backgroundColor = '#2f3136';
languageSelector.style.padding = '10px';
languageSelector.style.zIndex = '1000';
languageSelector.style.border = '1px solid #ccc';
languageSelector.style.borderRadius = '5px';
languageSelector.style.display = 'none';
const sourceLangSelect = document.createElement('select');
const targetLangSelect = document.createElement('select');
const toggleButton = document.createElement('button');
toggleButton.style.backgroundColor = '#7289da';
toggleButton.style.color = 'white';
toggleButton.style.border = 'none';
toggleButton.style.borderRadius = '5px';
toggleButton.style.cursor = 'pointer';
toggleButton.style.marginTop = '5px';
toggleButton.style.padding = '5px';
toggleButton.style.display = 'block';
toggleButton.textContent = 'Enable Translator';
const languages = {
'af': 'Afrikaans',
'sq': 'Albanian',
'ar': 'Arabic',
'hy': 'Armenian',
'az': 'Azerbaijani',
'eu': 'Basque',
'bn': 'Bengali',
'bs': 'Bosnian',
'ca': 'Catalan',
'hr': 'Croatian',
'cs': 'Czech',
'da': 'Danish',
'nl': 'Dutch',
'en': 'English',
'eo': 'Esperanto',
'et': 'Estonian',
'tl': 'Filipino',
'fi': 'Finnish',
'fr': 'French',
'gl': 'Galician',
'ka': 'Georgian',
'de': 'German',
'el': 'Greek',
'gu': 'Gujarati',
'ht': 'Haitian Creole',
'ha': 'Hausa',
'he': 'Hebrew',
'hi': 'Hindi',
'hmn': 'Hmong',
'hu': 'Hungarian',
'is': 'Icelandic',
'ig': 'Igbo',
'id': 'Indonesian',
'it': 'Italian',
'ja': 'Japanese',
'jw': 'Javanese',
'kn': 'Kannada',
'km': 'Khmer',
'ko': 'Korean',
'la': 'Latin',
'lv': 'Latvian',
'lt': 'Lithuanian',
'lb': 'Luxembourgish',
'mk': 'Macedonian',
'ml': 'Malayalam',
'mt': 'Maltese',
'mi': 'Maori',
'mr': 'Marathi',
'my': 'Myanmar (Burmese)',
'ne': 'Nepali',
'no': 'Norwegian',
'ny': 'Nyanja',
'or': 'Odia',
'ps': 'Pashto',
'fa': 'Persian',
'pl': 'Polish',
'pt': 'Portuguese',
'pa': 'Punjabi',
'ro': 'Romanian',
'ru': 'Russian',
'sr': 'Serbian',
'si': 'Sinhala',
'sk': 'Slovak',
'sl': 'Slovenian',
'es': 'Spanish',
'su': 'Sundanese',
'sw': 'Swahili',
'sv': 'Swedish',
'tg': 'Tajik',
'ta': 'Tamil',
'te': 'Telugu',
'th': 'Thai',
'tr': 'Turkish',
'uk': 'Ukrainian',
'ur': 'Urdu',
'vi': 'Vietnamese',
'cy': 'Welsh',
'xh': 'Xhosa',
'yi': 'Yiddish',
'yo': 'Yoruba',
'zu': 'Zulu',
'zh-CN': 'Chinese (Simplified)',
'zh-TW': 'Chinese (Traditional)',
};
const sortedLanguages = Object.entries(languages).sort((a, b) => a[1].localeCompare(b[1]));
sortedLanguages.forEach(([code, name]) => {
const option1 = document.createElement('option');
option1.value = code;
option1.textContent = name;
sourceLangSelect.appendChild(option1);
const option2 = document.createElement('option');
option2.value = code;
option2.textContent = name;
targetLangSelect.appendChild(option2);
});
const style = document.createElement('style');
style.textContent = `
select {
color: white;
background-color: #2f3136;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
margin: 5px 0;
}
.source-lang-label {
color: white;
margin-left: 5px;
}
.target-lang-label {
color: white;
margin-left: 5px;
}
`;
document.head.appendChild(style);
const sourceLangLabel = document.createElement('span');
sourceLangLabel.classList.add('source-lang-label');
sourceLangLabel.textContent = 'Source Language';
const targetLangLabel = document.createElement('span');
targetLangLabel.classList.add('target-lang-label');
targetLangLabel.textContent = 'Target Language';
const sourceLangDiv = document.createElement('div');
sourceLangDiv.appendChild(sourceLangSelect);
sourceLangDiv.appendChild(sourceLangLabel);
const targetLangDiv = document.createElement('div');
targetLangDiv.appendChild(targetLangSelect);
targetLangDiv.appendChild(targetLangLabel);
languageSelector.appendChild(sourceLangDiv);
languageSelector.appendChild(targetLangDiv);
languageSelector.appendChild(toggleButton);
document.body.appendChild(languageSelector);
const savedSourceLang = localStorage.getItem('sourceLang') || 'en';
const savedTargetLang = localStorage.getItem('targetLang') || 'ru';
let isTranslatorActive = localStorage.getItem('isTranslatorActive') === 'true';
sourceLangSelect.value = savedSourceLang;
targetLangSelect.value = savedTargetLang;
let sourceLang = savedSourceLang;
let targetLang = savedTargetLang;
if (isTranslatorActive) {
toggleButton.textContent = 'Disable Translator';
translateAllMessages();
}
function updateLanguages() {
sourceLang = sourceLangSelect.value;
targetLang = targetLangSelect.value;
localStorage.setItem('sourceLang', sourceLang);
localStorage.setItem('targetLang', targetLang);
if (isTranslatorActive) {
translateAllMessages();
}
}
sourceLangSelect.addEventListener('change', updateLanguages);
targetLangSelect.addEventListener('change', updateLanguages);
function updateTranslatorState() {
isTranslatorActive = !isTranslatorActive;
localStorage.setItem('isTranslatorActive', isTranslatorActive);
toggleButton.textContent = isTranslatorActive ? 'Disable Translator' : 'Enable Translator';
if (isTranslatorActive) {
translateAllMessages();
} else {
resetTranslations();
}
}
toggleButton.addEventListener('click', updateTranslatorState);
function translateText(text, callback) {
const url = `https://translate.google.com/m?hl=${targetLang}&sl=${sourceLang}&tl=${targetLang}&ie=UTF-8&prev=_m&q=${encodeURIComponent(text)}`;
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function (response) {
if (response.status === 200) {
const parser = new DOMParser();
const doc = parser.parseFromString(response.responseText, "text/html");
const translatedTextElement = doc.querySelector('.result-container');
if (translatedTextElement) {
callback(translatedTextElement.textContent.trim());
} else {
console.error("Перевод не удался");
}
} else {
console.error("Ошибка при получении перевода, статус: " + response.status);
}
},
onerror: function () {
console.error("Ошибка сети во время запроса перевода");
}
});
}
function annotateMessage(div) {
const originalText = div.textContent.trim();
const container = document.createElement('div');
container.style.position = 'relative';
const translatedDiv = document.createElement('div');
translatedDiv.classList.add('translated-message');
translatedDiv.style.color = 'rgb(135, 155, 164)';
translatedDiv.style.marginTop = '0px';
translatedDiv.style.paddingLeft = '8px';
translateText(originalText, function (translatedText) {
translatedDiv.textContent = translatedText;
container.appendChild(translatedDiv);
div.parentNode.insertBefore(container, div.nextSibling);
});
}
function checkNewDiv() {
const divs = document.querySelectorAll('div[id^="message-content-"]');
divs.forEach(div => {
if (!div.dataset.processed) {
const text = div.textContent;
const lang = detectLanguage(text);
if (lang === sourceLang && isTranslatorActive) {
annotateMessage(div);
}
div.dataset.processed = 'true';
}
});
}
function detectLanguage(text) {
return text.match(/[a-zA-Z]/) ? 'en' : 'ru';
}
function resetTranslations() {
const translatedMessages = document.querySelectorAll('.translated-message');
translatedMessages.forEach(msg => msg.remove());
}
function translateAllMessages() {
resetTranslations();
const divs = document.querySelectorAll('div[id^="message-content-"]');
divs.forEach(div => {
const text = div.textContent;
const lang = detectLanguage(text);
if (lang === sourceLang && isTranslatorActive) {
annotateMessage(div);
}
});
}
document.addEventListener('keydown', (event) => {
if (event.altKey && (event.key === 't' || event.key === 'е')) { // Alt + T or Alt + Е
event.preventDefault();
languageSelector.style.display = languageSelector.style.display === 'none' ? 'block' : 'none';
}
});
setInterval(checkNewDiv, 1000);
})();