Translate Discord Messages

Translate Discord messages and display them under the original text

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         Translate Discord Messages
// @namespace    http://tampermonkey.net/
// @version      0.3.0
// @description  Translate Discord messages and display them under the original text
// @author       CrankyBookworm
// @match        https://*.discord.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=discord.com
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @connect      translate.googleapis.com
// @esversion    11
// @run-at       document-end
// @license      MIT
// ==/UserScript==

/* jshint esversion: 11 */

const translateTo = "en";

let httpRequest;
if (typeof GM < "u" && GM.xmlHttpRequest) {
    httpRequest = GM.xmlHttpRequest;
}
else if (typeof GM < "u" && GM_xmlhttpRequest) {
    httpRequest = GM_xmlhttpRequest;
}
else if (typeof GM_xmlhttpRequest < "u") {
    httpRequest = GM_xmlhttpRequest;
}
else if (typeof GM < "u" && GM.xmlHttpRequest) {
    httpRequest = GM.xmlHttpRequest;
}
else {
    httpRequest = fetch;
    console.error("No HttpRequest Permission");
}

class TranslationResult {
    constructor() {
        /**
         * Translated Text.
         * @var {string?}
         */
        this.resultText = "";
        /**
         * Alternative translation results.
         * @var {string}
         */
        this.candidateText = "";
        /**
         * Translated from.
         * @var {string}
         */
        this.sourceLanguage = "";
        /**
         * Translation accuracy.
         * @var {float}
         */
        this.percentage = 0;
        /**
         * Is Error.
         * @var {bool}
         */
        this.isError = !1;
        /**
         * Error Message.
         * @var {string}
         */
        this.errorMessage = "";
    }
}

(function () {
    'use strict';

    const horizontalLine = document.createElement("hr");
    horizontalLine.style = "border: 0; padding-top: 1px; background: linear-gradient(to right, transparent, #d0d0d5, transparent);";

    const translateMsgElementTemplate = document.createElement("span");
    translateMsgElementTemplate.className = "myTranslateMsg";
    translateMsgElementTemplate.style = "color:#a4a9ab;";
    translateMsgElementTemplate.lang = translateTo;
    translateMsgElementTemplate.innerText = "Testing";


    /**
     * Translates a message
     * @param {string} textToTranslate Text that needs to be translated
     * @param {string?} fromLang Language to translate from
     * @param {string?} toLang Language to translate to
     * @returns {TranslationResult} Translation Result
     */
    async function translateText(textToTranslate, fromLang, toLang) {
        fromLang = fromLang ?? "auto";
        toLang = toLang ?? translateTo;
        const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${fromLang}&tl=${toLang}&dt=t&dt=bd&dj=1&q=${encodeURIComponent(textToTranslate)}`;

        var request = {
            "method": "GET",
            "timeout" : 6e4,
            "url": url,
            "synchronous" : !1,
        };

        /** @type {Response} */
        const response = await httpRequest(request).catch((e => e.response));
        const json_data = JSON.parse(await response.responseText);
        var result = new TranslationResult();

        // console.log(`response: Type: ${typeof response}. Value: ${response}`);
        if (response && 200 === (null == response ? void 0 : response.status)) {
            console.log(`json_data: Type: ${typeof json_data}. Value: ${json_data}`);
            result.sourceLanguage = json_data.src;
            result.percentage = json_data.ld_result.srclangs_confidences[0];
            result.resultText = json_data.sentences.map((e => e.trans)).join("");
            if(json_data.dict){
                result.candidateText = json_data.dict.map(
                    (e => `${e.pos}${"" != e.pos ? ": " : ""}${e.terms.join(", ")}\n`).join("")
                );
            }
        }
        else {
            result.isError = !0;
            if (response && 0 !== response.status) {
                if (429 === response.status || 503 === response.status) {
                    result.errorMessage = "Translation Service unavailable";
                }
                else {
                    result.errorMessage = `UnknownError occurred: [${null == response ? void 0 : response.status} ${null == response ? void 0 : response.statusText}]`;
                }
            }
            console.error("sendRequest()", result, response);
        }
        return result;
    }

    var observer = new MutationObserver(function (mutations) {
        /** @type {Array<Element>} */
        var messageElms = [];
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach((node) => {
                if (node instanceof HTMLElement) {
                    messageElms = messageElms.concat(
                        Array.from(node.querySelectorAll('[aria-roledescription="Message"]'))
                    );
                }
            });
        });

        // console.log(`node: Type: ${typeof node}. Value: ${node}`);
        messageElms.forEach(async (messageElm) => {
            const msgContentElm = messageElm.querySelector('[class^="contents_"] [id^="message-content-"]');
            if (!msgContentElm.querySelector(".myTranslateMsg")) {
                const translation = await translateText(msgContentElm.innerText);
                if(translation.sourceLanguage === translateTo ||
                   translation.resultText === msgContentElm.innerText){
                    return;
                }

                // Create translation element template
                var msgTranslationText = document.createTextNode(translation.isError ? translation.errorMessage : translation.resultText);
                const msgTranslationElm = translateMsgElementTemplate.cloneNode();
                msgTranslationElm.appendChild(msgTranslationText);

                // Add Translation to end of message
                msgContentElm.appendChild(horizontalLine.cloneNode());
                msgContentElm.appendChild(msgTranslationElm);
            }
        });
    });

    // Start observing the target node for configured mutations
    observer.observe(document, { attributes: true, childList: true, subtree: true });
})();