erinx

translator

Nov 28th, 2021
979
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * @name Translator
  3.  * @author DevilBro
  4.  * @authorId 278543574059057154
  5.  * @version 2.3.2
  6.  * @description Allows you to translate Messages and your outgoing Messages within Discord
  7.  * @invite Jx3TjNS
  8.  * @donate https://www.paypal.me/MircoWittrien
  9.  * @patreon https://www.patreon.com/MircoWittrien
  10.  * @website https://mwittrien.github.io/
  11.  * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/Translator/
  12.  * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/Translator/Translator.plugin.js
  13.  */
  14.  
  15. module.exports = (_ => {
  16.     const config = {
  17.         "info": {
  18.             "name": "Translator",
  19.             "author": "DevilBro",
  20.             "version": "2.3.2",
  21.             "description": "Allows you to translate Messages and your outgoing Messages within Discord"
  22.         },
  23.         "changeLog": {
  24.             "fixed": {
  25.                 "Yandex": "Fixed crashes with Yandex"
  26.             },
  27.             "added": {
  28.                 "Baidu": "Added",
  29.                 "Google": "Added zh-TW"
  30.             }
  31.         }
  32.     };
  33.    
  34.     return (window.Lightcord || window.LightCord) ? class {
  35.         getName () {return config.info.name;}
  36.         getAuthor () {return config.info.author;}
  37.         getVersion () {return config.info.version;}
  38.         getDescription () {return "Do not use LightCord!";}
  39.         load () {BdApi.alert("Attention!", "By using LightCord you are risking your Discord Account, due to using a 3rd Party Client. Switch to an official Discord Client (https://discord.com/) with the proper BD Injection (https://betterdiscord.app/)");}
  40.         start() {}
  41.         stop() {}
  42.     } : !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class {
  43.         getName () {return config.info.name;}
  44.         getAuthor () {return config.info.author;}
  45.         getVersion () {return config.info.version;}
  46.         getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;}
  47.        
  48.         downloadLibrary () {
  49.             require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => {
  50.                 if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"}));
  51.                 else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library");
  52.             });
  53.         }
  54.        
  55.         load () {
  56.             if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []});
  57.             if (!window.BDFDB_Global.downloadModal) {
  58.                 window.BDFDB_Global.downloadModal = true;
  59.                 BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, {
  60.                     confirmText: "Download Now",
  61.                     cancelText: "Cancel",
  62.                     onCancel: _ => {delete window.BDFDB_Global.downloadModal;},
  63.                     onConfirm: _ => {
  64.                         delete window.BDFDB_Global.downloadModal;
  65.                         this.downloadLibrary();
  66.                     }
  67.                 });
  68.             }
  69.             if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name);
  70.         }
  71.         start () {this.load();}
  72.         stop () {}
  73.         getSettingsPanel () {
  74.             let template = document.createElement("template");
  75.             template.innerHTML = `<div style="color: var(--header-primary); font-size: 16px; font-weight: 300; white-space: pre; line-height: 22px;">The Library Plugin needed for ${config.info.name} is missing.\nPlease click <a style="font-weight: 500;">Download Now</a> to install it.</div>`;
  76.             template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary);
  77.             return template.content.firstElementChild;
  78.         }
  79.     } : (([Plugin, BDFDB]) => {
  80.         var _this;
  81.        
  82.         const translateIconGeneral = `<svg name="Translate" width="24" height="24" viewBox="0 0 24 24"><mask/><path fill="currentColor" mask="url(#translateIconMask)" d="M 4 2 C 2.9005593 2 2 2.9005593 2 4 L 2 17 C 2 18.10035 2.9005593 19 4 19 L 11 19 L 12 22 L 20 22 C 21.10035 22 22 21.099441 22 20 L 22 7 C 22 5.9005592 21.099441 5 20 5 L 10.880859 5 L 10 2 L 4 2 z M 11.173828 6 L 20 6 C 20.550175 6 21 6.4498249 21 7 L 21 20 C 21 20.550175 20.550176 21 20 21 L 13 21 L 15 19 L 14.185547 16.236328 L 15.105469 15.314453 L 17.791016 18 L 18.521484 17.269531 L 15.814453 14.583984 C 16.714739 13.54911 17.414914 12.335023 17.730469 11.080078 L 19 11.080078 L 19 10.039062 L 15.365234 10.039062 L 15.365234 9 L 14.324219 9 L 14.324219 10.039062 L 12.365234 10.039062 L 11.173828 6 z M 7.1660156 6.4160156 C 8.2063466 6.4160156 9.1501519 6.7857022 9.9003906 7.4804688 L 9.9648438 7.5449219 L 8.7441406 8.7246094 L 8.6855469 8.6699219 C 8.4009108 8.3998362 7.9053417 8.0859375 7.1660156 8.0859375 C 5.8555986 8.0859375 4.7890625 9.1708897 4.7890625 10.505859 C 4.7890625 11.84083 5.8555986 12.925781 7.1660156 12.925781 C 8.5364516 12.925781 9.1309647 12.050485 9.2910156 11.464844 L 7.0800781 11.464844 L 7.0800781 9.9160156 L 11.03125 9.9160156 L 11.044922 9.984375 C 11.084932 10.194442 11.099609 10.379777 11.099609 10.589844 C 11.094109 12.945139 9.4803883 14.583984 7.1660156 14.583984 C 4.9107525 14.583984 3.0800781 12.749807 3.0800781 10.5 C 3.0800781 8.2501934 4.9162088 6.4160156 7.1660156 6.4160156 z M 12.675781 11.074219 L 16.669922 11.074219 C 16.669922 11.074219 16.330807 12.390095 15.111328 13.810547 C 14.576613 13.195806 14.206233 12.595386 13.970703 12.115234 L 12.980469 12.115234 L 12.675781 11.074219 z M 13.201172 12.884766 C 13.535824 13.484957 13.940482 14.059272 14.390625 14.583984 L 13.855469 15.115234 L 13.201172 12.884766 z"/><extra/></svg>`;
  83.         const translateIconMask = `<mask id="translateIconMask" fill="black"><path fill="white" d="M 0 0 H 24 V 24 H 0 Z"/><path fill="black" d="M24 12 H 12 V 24 H 24 Z"/></mask>`;
  84.         const translateIcon = translateIconGeneral.replace(`<extra/>`, ``).replace(`<mask/>`, ``).replace(` mask="url(#translateIconMask)"`, ``);
  85.         const translateIconUntranslate = translateIconGeneral.replace(`<extra/>`, `<path fill="none" stroke="#f04747" stroke-width="2" d="m 14.702359,14.702442 8.596228,8.596148 m 0,-8.597139 -8.59722,8.596147 z"/>`).replace(`<mask/>`, translateIconMask);
  86.        
  87.         const TranslateButtonComponent = class TranslateButton extends BdApi.React.Component {
  88.             render() {
  89.                 const enabled = _this.isTranslationEnabled(this.props.channelId);
  90.                 return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ChannelTextAreaButton, {
  91.                     className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN._translatortranslatebutton, _this.isTranslationEnabled(this.props.channelId) && BDFDB.disCN._translatortranslating, BDFDB.disCN.textareapickerbutton),
  92.                     isActive: this.props.isActive,
  93.                     iconSVG: translateIcon,
  94.                     nativeClass: true,
  95.                     tooltip: enabled && {
  96.                         text: (_ => `${BDFDB.LanguageUtils.getName(languages[_this.getLanguageChoice(languageTypes.INPUT, messageTypes.SENT, this.props.channelId)])} ➝ ${BDFDB.LanguageUtils.getName(languages[_this.getLanguageChoice(languageTypes.OUTPUT, messageTypes.SENT, this.props.channelId)])}`),
  97.                         tooltipConfig: {style: "max-width: 400px"}
  98.                     },
  99.                     onClick: _ => {
  100.                         this.props.isActive = true;
  101.                         BDFDB.ReactUtils.forceUpdate(this);
  102.                        
  103.                         BDFDB.ModalUtils.open(_this, {
  104.                             size: "LARGE",
  105.                             header: BDFDB.LanguageUtils.LanguageStrings.SETTINGS,
  106.                             subHeader: "",
  107.                             onClose: _ => {
  108.                                 this.props.isActive = false;
  109.                                 BDFDB.ReactUtils.forceUpdate(this);
  110.                             },
  111.                             children: BDFDB.ReactUtils.createElement(TranslateSettingsComponent, {
  112.                                 channelId: this.props.channelId
  113.                             })
  114.                         });
  115.                     },
  116.                     onContextMenu: _ => {
  117.                         _this.toggleTranslation(this.props.channelId);
  118.                         BDFDB.ReactUtils.forceUpdate(this);
  119.                     }
  120.                 });
  121.             }
  122.         };
  123.        
  124.         const TranslateSettingsComponent = class TranslateSettings extends BdApi.React.Component {
  125.             filterLanguages(direction, place) {
  126.                 let isOutput = direction == languageTypes.OUTPUT;
  127.                 return BDFDB.ObjectUtils.toArray(BDFDB.ObjectUtils.map(isOutput ? BDFDB.ObjectUtils.filter(languages, lang => !lang.auto) : languages, (lang, id) => ({
  128.                     value: id,
  129.                     label: BDFDB.LanguageUtils.getName(lang),
  130.                     backup: this.isOnlyBackup(lang)
  131.                 }))).filter(isOutput && this.isOnlyBackup(languages[_this.getLanguageChoice(languageTypes.INPUT, place, this.props.channelId)]) ? (n => n.backup) : (n => n));
  132.             }
  133.             isOnlyBackup(lang) {
  134.                 return lang && (lang.auto && !translationEngines[_this.settings.engines.translator].auto || !lang.auto && !lang.special && !translationEngines[_this.settings.engines.translator].languages.includes(lang.id));
  135.             }
  136.             render() {
  137.                 return [
  138.                     BDFDB.ArrayUtils.is(_this.settings.exceptions.wordStart) && _this.settings.exceptions.wordStart.length && [
  139.                         BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
  140.                             className: BDFDB.disCN.marginbottom8,
  141.                             children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsLabel, {
  142.                                 label: `Words starting with ${_this.settings.exceptions.wordStart.map(n => '"' + n + '"').join(", ")} will be ignored`
  143.                             })
  144.                         }),
  145.                         BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
  146.                             className: BDFDB.disCN.marginbottom8
  147.                         })
  148.                     ],
  149.                     Object.keys(_this.defaults.choices).map(place => {
  150.                         const isSpecific = channelLanguages[this.props.channelId] && channelLanguages[this.props.channelId][place];
  151.                         return Object.keys(_this.defaults.choices[place].value).map(direction => [
  152.                             BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
  153.                                 title: `${BDFDB.LibraryModules.StringUtils.upperCaseFirstChar(direction.toLowerCase())} Language in ${place.toLowerCase()} Messages: `,
  154.                                 titleChildren: direction == languageTypes.OUTPUT && [{
  155.                                     text: _ => isSpecific ? `${BDFDB.LibraryModules.StringUtils.upperCaseFirstChar(place)} Language Selection will be changed specifically for this Channel` : `${BDFDB.LibraryModules.StringUtils.upperCaseFirstChar(place)} Language Selection will be changed for all Channels`,
  156.                                     name: isSpecific ? BDFDB.LibraryComponents.SvgIcon.Names.LOCK_CLOSED : BDFDB.LibraryComponents.SvgIcon.Names.LOCK_OPEN,
  157.                                     color: isSpecific && "var(--bdfdb-red)",
  158.                                     onClick: _ => {
  159.                                         if (channelLanguages[this.props.channelId] && channelLanguages[this.props.channelId][place]) {
  160.                                             delete channelLanguages[this.props.channelId][place];
  161.                                             if (BDFDB.ObjectUtils.isEmpty(channelLanguages[this.props.channelId])) delete channelLanguages[this.props.channelId];
  162.                                         }
  163.                                         else {
  164.                                             if (!channelLanguages[this.props.channelId]) channelLanguages[this.props.channelId] = {};
  165.                                             channelLanguages[this.props.channelId][place] = {};
  166.                                             for (let l in languageTypes) channelLanguages[this.props.channelId][place][languageTypes[l]] = _this.getLanguageChoice(languageTypes[l], place, null);
  167.                                         }
  168.                                         BDFDB.DataUtils.save(channelLanguages, _this, "channelLanguages");
  169.                                        
  170.                                         BDFDB.ReactUtils.forceUpdate(this);
  171.                                     }
  172.                                 }, {
  173.                                     iconSVG: `<svg width="21" height="21" fill="currentColor"><path d="M 0, 10.515 c 0, 2.892, 1.183, 5.521, 3.155, 7.361 L 0, 21.031 h 7.887 V 13.144 l -2.892, 2.892 C 3.549, 14.722, 2.629, 12.75, 2.629, 10.515 c 0 -3.418, 2.235 -6.309, 5.258 -7.492 v -2.629 C 3.418, 1.577, 0, 5.652, 0, 10.515 z M 21.031, 0 H 13.144 v 7.887 l 2.892 -2.892 C 17.482, 6.309, 18.402, 8.281, 18.402, 10.515 c 0, 3.418 -2.235, 6.309 -5.258, 7.492 V 20.768 c 4.469 -1.183, 7.887 -5.258, 7.887 -10.121 c 0 -2.892 -1.183 -5.521 -3.155 -7.361 L 21.031, 0 z"/></svg>`,
  174.                                     onClick: _ => {
  175.                                         let input = _this.getLanguageChoice(languageTypes.INPUT, place, this.props.channelId);
  176.                                         let output = _this.getLanguageChoice(languageTypes.OUTPUT, place, this.props.channelId);
  177.                                         input = input == "auto" ? "en" : input;
  178.                                        
  179.                                         _this.saveLanguageChoice(output, languageTypes.INPUT, place, this.props.channelId);
  180.                                         _this.saveLanguageChoice(input, languageTypes.OUTPUT, place, this.props.channelId);
  181.                                        
  182.                                         _this.setLanguages();
  183.                                        
  184.                                         BDFDB.ReactUtils.forceUpdate(this);
  185.                                     }
  186.                                 }].map(data => {
  187.                                     const icon = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, {
  188.                                         className: BDFDB.disCN._translatorconfigbutton,
  189.                                         onClick: data.onClick,
  190.                                         children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, {
  191.                                             width: 24,
  192.                                             height: 24,
  193.                                             color: data.color || "currentColor",
  194.                                             name: data.name,
  195.                                             iconSVG: data.iconSVG
  196.                                         })
  197.                                     });
  198.                                     return data.text ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, {text: data.text, children: icon}) : icon;
  199.                                 }),
  200.                                 className: BDFDB.disCN.marginbottom8,
  201.                                 children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, {
  202.                                     value: _this.getLanguageChoice(direction, place, this.props.channelId),
  203.                                     options: this.filterLanguages(direction, place),
  204.                                     optionRenderer: lang => languages[lang.value] ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
  205.                                         align: BDFDB.LibraryComponents.Flex.Align.CENTER,
  206.                                         children: [
  207.                                             BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
  208.                                                 grow: 1,
  209.                                                 children: lang.label
  210.                                             }),
  211.                                             lang.backup && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, {
  212.                                                 text: "Will use Backup Translator",
  213.                                                 tooltipConfig: {
  214.                                                     color: "red"
  215.                                                 },
  216.                                                 children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, {
  217.                                                     nativeClass: true,
  218.                                                     width: 20,
  219.                                                     height: 20,
  220.                                                     color: "var(--bdfdb-red)",
  221.                                                     name: BDFDB.LibraryComponents.SvgIcon.Names.WARNING
  222.                                                 })
  223.                                             }),
  224.                                             BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FavButton, {
  225.                                                 isFavorite: languages[lang.value].fav == 0,
  226.                                                 onClick: value => {
  227.                                                     if (value) favorites.push(lang.value);
  228.                                                     else BDFDB.ArrayUtils.remove(favorites, lang.value, true);
  229.                                                     BDFDB.DataUtils.save(favorites.sort(), _this, "favorites");
  230.                                                     _this.setLanguages();
  231.                                                 }
  232.                                             })
  233.                                         ]
  234.                                     }) : null,
  235.                                     onChange: value => {
  236.                                         _this.saveLanguageChoice(value, direction, place, this.props.channelId);
  237.                                         BDFDB.ReactUtils.forceUpdate(this);
  238.                                     }
  239.                                 })
  240.                             }),
  241.                             direction == languageTypes.OUTPUT && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
  242.                                 className: BDFDB.disCN.marginbottom8
  243.                             })
  244.                         ]);
  245.                     }),
  246.                     Object.keys(_this.defaults.engines).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
  247.                         title: _this.defaults.engines[key].description,
  248.                         className: BDFDB.disCN.marginbottom8,
  249.                         children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, {
  250.                             value: _this.settings.engines[key],
  251.                             options: (key == "backup" ? ["----"] : []).concat(Object.keys(translationEngines)).filter(key == "backup" ? (n => n != _this.settings.engines.translator) : (n => n)).map(engineKey => ({value: engineKey, label: translationEngines[engineKey] ? translationEngines[engineKey].name : "----"})),
  252.                             maxVisibleItems: 3,
  253.                             onChange: value => {
  254.                                 _this.settings.engines[key] = value;
  255.                                 BDFDB.DataUtils.save(_this.settings.engines, _this, "engines");
  256.                                 _this.setLanguages();
  257.                                 BDFDB.ReactUtils.forceUpdate(this);
  258.                             }
  259.                         })
  260.                     })),
  261.                     Object.keys(_this.defaults.general).filter(key => _this.defaults.general[key].popout).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, {
  262.                         type: "Switch",
  263.                         plugin: _this,
  264.                         keys: ["general", key],
  265.                         label: _this.defaults.general[key].description,
  266.                         tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5,
  267.                         value: _this.settings.general[key]
  268.                     })),
  269.                     BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, {
  270.                         type: "Switch",
  271.                         label: "Translate your Messages before sending",
  272.                         tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5,
  273.                         value: _this.isTranslationEnabled(this.props.channelId),
  274.                         onChange: value => {
  275.                             _this.toggleTranslation(this.props.channelId);
  276.                             BDFDB.ReactUtils.forceUpdate(this);
  277.                         }
  278.                     })
  279.                 ].flat(10).filter(n => n);
  280.             }
  281.         };
  282.  
  283.         const brailleConverter = {
  284.             "0":"⠴", "1":"⠂", "2":"⠆", "3":"⠒", "4":"⠲", "5":"⠢", "6":"⠖", "7":"⠶", "8":"⠦", "9":"⠔", "!":"⠮", "\"":"⠐", "#":"⠼", "$":"⠫", "%":"⠩", "&":"⠯", "'":"⠄", "(":"⠷", ")":"⠾", "*":"⠡", "+":"⠬", ",":"⠠", "-":"⠤", ".":"⠨", "/":"⠌", ":":"⠱", ";":"⠰", "<":"⠣", "=":"⠿", ">":"⠜", "?":"⠹", "@":"⠈", "a":"⠁", "b":"⠃", "c":"⠉", "d":"⠙", "e":"⠑", "f":"⠋", "g":"⠛", "h":"⠓", "i":"⠊", "j":"⠚", "k":"⠅", "l":"⠇", "m":"⠍", "n":"⠝", "o":"⠕", "p":"⠏", "q":"⠟", "r":"⠗", "s":"⠎", "t":"⠞", "u":"⠥", "v":"⠧", "w":"⠺", "x":"⠭", "y":"⠽", "z":"⠵", "[":"⠪", "\\":"⠳", "]":"⠻", "^":"⠘", "⠁":"a", "⠂":"1", "⠃":"b", "⠄":"'", "⠅":"k", "⠆":"2", "⠇":"l", "⠈":"@", "⠉":"c", "⠊":"i", "⠋":"f", "⠌":"/", "⠍":"m", "⠎":"s", "⠏":"p", "⠐":"\"", "⠑":"e", "⠒":"3", "⠓":"h", "⠔":"9", "⠕":"o", "⠖":"6", "⠗":"r", "⠘":"^", "⠙":"d", "⠚":"j", "⠛":"g", "⠜":">", "⠝":"n", "⠞":"t", "⠟":"q", "⠠":", ", "⠡":"*", "⠢":"5", "⠣":"<", "⠤":"-", "⠥":"u", "⠦":"8", "⠧":"v", "⠨":".", "⠩":"%", "⠪":"[", "⠫":"$", "⠬":"+", "⠭":"x", "⠮":"!", "⠯":"&", "⠰":";", "⠱":":", "⠲":"4", "⠳":"\\", "⠴":"0", "⠵":"z", "⠶":"7", "⠷":"(", "⠸":"_", "⠹":"?", "⠺":"w", "⠻":"]", "⠼":"#", "⠽":"y", "⠾":")", "⠿":"=", "_":"⠸"
  285.         };
  286.  
  287.         const morseConverter = {
  288.             "0":"−−−−−", "1":"·−−−−", "2":"··−−−", "3":"···−−", "4":"····−", "5":"·····", "6":"−····", "7":"−−···", "8":"−−−··", "9":"−−−−·", "!":"−·−·−−", "\"":"·−··−·", "$":"···−··−", "&":"·−···", "'":"·−−−−·", "(":"−·−−·", ")":"−·−−·−", "+":"·−·−·", ",":"−−··−−", "-":"−····−", ".":"·−·−·−", "/":"−··−·", ":":"−−−···", ";":"−·−·−·", "=":"−···−", "?":"··−−··", "@":"·−−·−·", "a":"·−", "b":"−···", "c":"−·−·", "d":"−··", "e":"·", "f":"··−·", "g":"−−·", "h":"····", "i":"··", "j":"·−−−", "k":"−·−", "l":"·−··", "m":"−−", "n":"−·", "o":"−−−", "p":"·−−·", "q":"−−·−", "r":"·−·", "s":"···", "t":"−", "u":"··−", "v":"···−", "w":"·−−", "x":"−··−", "y":"−·−−", "z":"−−··", "·":"e", "··":"i", "···":"s", "····":"h", "·····":"5", "····−":"4", "···−":"v", "···−··−":"$", "···−−":"3", "··−":"u", "··−·":"f", "··−−··":"?", "··−−·−":"_", "··−−−":"2", "·−":"a", "·−·":"r", "·−··":"l", "·−···":"&", "·−··−·":"\"", "·−·−·":"+", "·−·−·−":".", "·−−":"w", "·−−·":"p", "·−−·−·":"@", "·−−−":"j", "·−−−−":"1", "·−−−−·":"'", "−":"t", "−·":"n", "−··":"d", "−···":"b", "−····":"6", "−····−":"-", "−···−":"=", "−··−":"x", "−··−·":"/", "−·−":"k", "−·−·":"c", "−·−·−·":";", "−·−·−−":"!", "−·−−":"y", "−·−−·":"(", "−·−−·−":")", "−−":"m", "−−·":"g", "−−··":"z", "−−···":"7", "−−··−−":",", "−−·−":"q", "−−−":"o", "−−−··":"8", "−−−···":":", "−−−−·":"9", "−−−−−":"0", "_":"··−−·−"
  289.         };
  290.        
  291.         const googleLanguages = ["af","am","ar","az","be","bg","bn","bs","ca","ceb","co","cs","cy","da","de","el","en","eo","es","et","eu","fa","fi","fr","fy","ga","gd","gl","gu","ha","haw","hi","hmn","hr","ht","hu","hy","id","ig","is","it","iw","ja","jw","ka","kk","km","kn","ko","ku","ky","la","lb","lo","lt","lv","mg","mi","mk","ml","mn","mr","ms","mt","my","ne","nl","no","ny","or","pa","pl","ps","pt","ro","ru","rw","sd","si","sk","sl","sm","sn","so","sq","sr","st","su","sv","sw","ta","te","tg","th","tk","tl","tr","tt","ug","uk","ur","uz","vi","xh","yi","yo","zh-CN","zh-TW","zu"];
  292.         const translationEngines = {
  293.             googleapi: {
  294.                 name: "Google",
  295.                 auto: true,
  296.                 funcName: "googleApiTranslate",
  297.                 languages: googleLanguages
  298.             },
  299.             deepl: {
  300.                 name: "DeepL",
  301.                 auto: true,
  302.                 funcName: "deepLTranslate",
  303.                 languages: ["bg","cs","da","de","en","el","es","et","fi","fr","hu","it","ja","lt","lv","nl","pl","pt","ro","ru","sk","sl","sv","zh"],
  304.                 key: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:fx"
  305.             },
  306.             itranslate: {
  307.                 name: "iTranslate",
  308.                 auto: true,
  309.                 funcName: "iTranslateTranslate",
  310.                 languages: [...new Set(["af","ar","az","be","bg","bn","bs","ca","ceb","cs","cy","da","de","el","en","eo","es","et","eu","fa","fi","fil","fr","ga","gl","gu","ha","he","hi","hmn","hr","ht","hu","hy","id","ig","is","it","ja","jw","ka","kk","km","kn","ko","la","lo","lt","lv","mg","mi","mk","ml","mn","mr","ms","mt","my","ne","nl","no","ny","pa","pl","pt-BR","pt-PT","ro","ru","si","sk","sl","so","sq","sr","st","su","sv","sw","ta","te","tg","th","tr","uk","ur","uz","vi","we","yi","yo","zh-CN","zh-TW","zu"].concat(googleLanguages))].sort(),
  311.                 key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  312.             },
  313.             yandex: {
  314.                 name: "Yandex",
  315.                 auto: true,
  316.                 funcName: "yandexTranslate",
  317.                 languages: ["af","am","ar","az","ba","be","bg","bn","bs","ca","ceb","cs","cy","da","de","el","en","eo","es","et","eu","fa","fi","fr","ga","gd","gl","gu","he","hi","hr","ht","hu","hy","id","is","it","ja","jv","ka","kk","km","kn","ko","ky","la","lb","lo","lt","lv","mg","mhr","mi","mk","ml","mn","mr","ms","mt","my","ne","nl","no","pa","pap","pl","pt","ro","ru","si","sk","sl","sq","sr","su","sv","sw","ta","te","tg","th","tl","tr","tt","udm","uk","ur","uz","vi","xh","yi","zh"],
  318.                 key: "trnsl.x.x.xxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  319.             },
  320.             papago: {
  321.                 name: "Papago",
  322.                 auto: false,
  323.                 funcName: "papagoTranslate",
  324.                 languages: ["en","es","fr","id","ja","ko","th","vi","zh-CN","zh-TW"],
  325.                 key: "xxxxxxxxxxxxxxxxxxxx xxxxxxxxxx"
  326.             },
  327.             baidu: {
  328.                 name: "Baidu",
  329.                 auto: true,
  330.                 funcName: "baiduTranslate",
  331.                 languages: ["ar","bg","cs","da","de","el","en","es","et","fi","fr","hu","it","jp","ko","nl","pl","pt","ro","ru","sl","sv","th","vi","zh","zh-CN","zh-TW"],
  332.                 parser: {
  333.                     "ar": "ara",
  334.                     "bg": "bul",
  335.                     "da": "dan",
  336.                     "es": "spa",
  337.                     "et": "est",
  338.                     "fi": "fin",
  339.                     "fr": "fra",
  340.                     "ko": "kor",
  341.                     "ro": "rom",
  342.                     "sl": "slo",
  343.                     "sv": "swe",
  344.                     "vi": "vie",
  345.                     "zh-CN": "wyw",
  346.                     "zh-TW": "cht"
  347.                 },
  348.                 key: "xxxxxxxxx xxxxxx xxxxxxxxxx"
  349.             }
  350.         };
  351.        
  352.         var languages = {};
  353.         var favorites = [];
  354.         var authKeys = {};
  355.         var channelLanguages = {};
  356.         var translationEnabledStates = [], isTranslating;
  357.         var translatedMessages = {}, oldMessages = {};
  358.        
  359.         const defaultLanguages = {
  360.             INPUT: "auto",
  361.             OUTPUT: "$discord"
  362.         };
  363.         const languageTypes = {
  364.             INPUT: "input",
  365.             OUTPUT: "output"
  366.         };
  367.         const messageTypes = {
  368.             RECEIVED: "received",
  369.             SENT: "sent",
  370.         };
  371.    
  372.         return class Translator extends Plugin {
  373.             onLoad () {
  374.                 _this = this;
  375.                
  376.                 this.defaults = {
  377.                     general: {
  378.                         addTranslateButton:     {value: true,   popout: false,  description: "Adds a Translate Button to the Channel Textarea"},
  379.                         usePerChatTranslation:  {value: true,   popout: false,  description: "Enables/Disables the Translator Button State per Channel and not globally"},
  380.                         sendOriginalMessage:    {value: false,  popout: true,   description: "Also sends the original Message when translating your own Message"},
  381.                         showOriginalMessage:    {value: false,  popout: true,   description: "Also shows the original Message when translating someones Message"}
  382.                     },
  383.                     choices: {},
  384.                     exceptions: {
  385.                         wordStart:              {value: ["!"],          max: 1,     description: "Words starting with any of these will be ignored"}
  386.                     },
  387.                     engines: {
  388.                         translator:             {value: "googleapi",    description: "Translation Engine"},
  389.                         backup:                 {value: "----",         description: "Backup Engine"}
  390.                     }
  391.                 };
  392.                 for (let m in messageTypes) this.defaults.choices[messageTypes[m]] = {value: Object.keys(languageTypes).reduce((newObj, l) => (newObj[languageTypes[l]] = defaultLanguages[l], newObj), {})};
  393.            
  394.                 this.patchedModules = {
  395.                     before: {
  396.                         ChannelTextAreaForm: "render",
  397.                         ChannelEditorContainer: "render",
  398.                         Embed: "render"
  399.                     },
  400.                     after: {
  401.                         ChannelTextAreaContainer: "render",
  402.                         Messages: "type",
  403.                         MessageContent: "type",
  404.                         Embed: "render"
  405.                     }
  406.                 };
  407.  
  408.                 this.css = `
  409.                     ${BDFDB.dotCN._translatortranslatebutton + BDFDB.dotCNS._translatortranslating + BDFDB.dotCN.textareaicon} {
  410.                         color: var(--bdfdb-red) !important;
  411.                     }
  412.                     ${BDFDB.dotCN._translatorconfigbutton} {
  413.                         margin: 2px 3px 0 6px;
  414.                     }
  415.                 `;
  416.             }
  417.            
  418.             onStart () {
  419.                 this.forceUpdateAll();
  420.             }
  421.            
  422.             onStop () {
  423.                 this.forceUpdateAll();
  424.             }
  425.  
  426.             getSettingsPanel (collapseStates = {}) {
  427.                 let settingsPanel;
  428.                 return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, {
  429.                     collapseStates: collapseStates,
  430.                     children: _ => {
  431.                         let settingsItems = [];
  432.                        
  433.                         for (let key in this.defaults.general) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, {
  434.                             type: "Switch",
  435.                             plugin: this,
  436.                             keys: ["general", key],
  437.                             label: this.defaults.general[key].description,
  438.                             value: this.settings.general[key]
  439.                         }));
  440.                        
  441.                         settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
  442.                             className: BDFDB.disCNS.dividerdefault + BDFDB.disCN.marginbottom8
  443.                         }));
  444.                        
  445.                         settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, {
  446.                             title: "Own Auth Keys:",
  447.                             children: Object.keys(translationEngines).filter(key => translationEngines[key].key).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, {
  448.                                 type: "TextInput",
  449.                                 basis: "75%",
  450.                                 label: translationEngines[key].name,
  451.                                 placeholder: translationEngines[key].key,
  452.                                 value: authKeys[key],
  453.                                 onChange: value => {
  454.                                     authKeys[key] = (value || "").trim();
  455.                                     if (!authKeys[key]) delete authKeys[key];
  456.                                     BDFDB.DataUtils.save(authKeys, this, "authKeys");
  457.                                 }
  458.                             }))
  459.                         }));
  460.                        
  461.                         settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
  462.                             className: BDFDB.disCNS.dividerdefault + BDFDB.disCN.marginbottom8
  463.                         }));
  464.                        
  465.                         for (let key in this.defaults.exceptions) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
  466.                             title: this.defaults.exceptions[key].description,
  467.                             className: BDFDB.disCN.marginbottom8,
  468.                             children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ListInput, {
  469.                                 placeholder: "New Exception",
  470.                                 maxLength: this.defaults.exceptions[key].max,
  471.                                 items: this.settings.exceptions[key],
  472.                                 onChange: value => {
  473.                                     this.SettingsUpdated = true;
  474.                                     BDFDB.DataUtils.save(value, this, "exceptions", key);
  475.                                 }
  476.                             })
  477.                         }));
  478.                        
  479.                         return settingsItems.flat(10);
  480.                     }
  481.                 });
  482.             }
  483.        
  484.             onSettingsClosed () {
  485.                 if (this.SettingsUpdated) {
  486.                     delete this.SettingsUpdated;
  487.                     this.forceUpdateAll();
  488.                 }
  489.             }
  490.        
  491.             forceUpdateAll () {
  492.                 favorites = BDFDB.DataUtils.load(this, "favorites");
  493.                 favorites = !BDFDB.ArrayUtils.is(favorites) ? [] : favorites;
  494.                
  495.                 authKeys = BDFDB.DataUtils.load(this, "authKeys");
  496.                 channelLanguages = BDFDB.DataUtils.load(this, "channelLanguages");
  497.                
  498.                 this.setLanguages();
  499.                 BDFDB.PatchUtils.forceAllUpdates(this);
  500.                 BDFDB.MessageUtils.rerenderAll();
  501.             }
  502.  
  503.             onMessageContextMenu (e) {
  504.                 if (e.instance.props.message && e.instance.props.channel) {
  505.                     let translated = translatedMessages[e.instance.props.message.id];
  506.                     let hint = BDFDB.BDUtils.isPluginEnabled("MessageUtilities") ? BDFDB.BDUtils.getPlugin("MessageUtilities").getActiveShortcutString("__Translate_Message") : null;
  507.                     let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: ["pin", "unpin"]});
  508.                     if (index == -1) [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: ["edit", "add-reaction", "quote"]});
  509.                     children.splice(index > -1 ? index + 1 : 0, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, {
  510.                         label: translated ? this.labels.context_messageuntranslateoption : this.labels.context_messagetranslateoption,
  511.                         id: BDFDB.ContextMenuUtils.createItemId(this.name, translated ? "untranslate-message" : "translate-message"),
  512.                         hint: hint && (_ => {
  513.                             return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.MenuItems.MenuHint, {
  514.                                 hint: hint
  515.                             });
  516.                         }),
  517.                         disabled: !translated && isTranslating,
  518.                         action: _ => this.translateMessage(e.instance.props.message, e.instance.props.channel)
  519.                     }));
  520.                     this.injectSearchItem(e);
  521.                 }
  522.             }
  523.            
  524.             onNativeContextMenu (e) {
  525.                 this.injectSearchItem(e);
  526.             }
  527.            
  528.             onSlateContextMenu (e) {
  529.                 this.injectSearchItem(e);
  530.             }
  531.            
  532.             injectSearchItem (e) {
  533.                 let text = document.getSelection().toString();
  534.                 if (text) {
  535.                     let translating, foundTranslation, foundInput, foundOutput;
  536.                     let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: ["devmode-copy-id", "search-google"], group: true});
  537.                     children.splice(index > -1 ? index + 1 : 0, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, {
  538.                         children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, {
  539.                             id: BDFDB.ContextMenuUtils.createItemId(this.name, "search-translation"),
  540.                             disabled: isTranslating,
  541.                             label: this.labels.context_translator,
  542.                             persisting: true,
  543.                             action: event => {
  544.                                 let item = BDFDB.DOMUtils.getParent(BDFDB.dotCN.menuitem, event.target);
  545.                                 if (item) {
  546.                                     let createTooltip = _ => {
  547.                                         BDFDB.TooltipUtils.create(item, [
  548.                                             `${BDFDB.LanguageUtils.LibraryStrings.from} ${foundInput.name}:`,
  549.                                             text,
  550.                                             `${BDFDB.LanguageUtils.LibraryStrings.to} ${foundOutput.name}:`,
  551.                                             foundTranslation
  552.                                         ].map(n => BDFDB.ReactUtils.createElement("div", {children: n})), {
  553.                                             type: "right",
  554.                                             color: "black",
  555.                                             className: "googletranslate-tooltip"
  556.                                         });
  557.                                     };
  558.                                     if (foundTranslation && foundInput && foundOutput) {
  559.                                         if (document.querySelector(".googletranslate-tooltip")) {
  560.                                             BDFDB.ContextMenuUtils.close(e.instance);
  561.                                             BDFDB.DiscordUtils.openLink(this.getGoogleTranslatePageURL(foundInput.id, foundOutput.id, text));
  562.                                         }
  563.                                         else createTooltip();
  564.                                     }
  565.                                     else if (!translating) {
  566.                                         translating = true;
  567.                                         this.translateText(text, messageTypes.RECEIVED, (translation, input, output) => {
  568.                                             if (translation) {
  569.                                                 foundTranslation = translation, foundInput = input, foundOutput = output;
  570.                                                 createTooltip();
  571.                                             }
  572.                                         });
  573.                                     }
  574.                                 }
  575.                             }
  576.                         })
  577.                     }));
  578.                 }
  579.             }
  580.            
  581.             onMessageOptionContextMenu (e) {
  582.                 if (e.instance.props.message && e.instance.props.channel) {
  583.                     let translated = !!translatedMessages[e.instance.props.message.id];
  584.                     let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: ["pin", "unpin"]});
  585.                     children.splice(index + 1, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, {
  586.                         label: translated ? this.labels.context_messageuntranslateoption : this.labels.context_messagetranslateoption,
  587.                         disabled: isTranslating,
  588.                         id: BDFDB.ContextMenuUtils.createItemId(this.name, translated ? "untranslate-message" : "translate-message"),
  589.                         icon: _ => {
  590.                             return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.MenuItems.MenuIcon, {
  591.                                 icon: translated ? translateIconUntranslate : translateIcon
  592.                             });
  593.                         },
  594.                         action: _ => this.translateMessage(e.instance.props.message, e.instance.props.channel)
  595.                     }));
  596.                 }
  597.             }
  598.        
  599.             onMessageOptionToolbar (e) {
  600.                 if (e.instance.props.expanded && e.instance.props.message && e.instance.props.channel) {
  601.                     let translated = !!translatedMessages[e.instance.props.message.id];
  602.                     e.returnvalue.props.children.unshift();
  603.                     e.returnvalue.props.children.unshift(BDFDB.ReactUtils.createElement(class extends BdApi.React.Component {
  604.                         render() {
  605.                             return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, {
  606.                                 key: translated ? "untranslate-message" : "translate-message",
  607.                                 text: _ => translated ? _this.labels.context_messageuntranslateoption : _this.labels.context_messagetranslateoption,
  608.                                 children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, {
  609.                                     className: BDFDB.disCN.messagetoolbarbutton,
  610.                                     onClick: _ => {
  611.                                         if (!isTranslating) _this.translateMessage(e.instance.props.message, e.instance.props.channel).then(_ => {
  612.                                             translated = !!translatedMessages[e.instance.props.message.id];
  613.                                             BDFDB.ReactUtils.forceUpdate(this);
  614.                                         });
  615.                                     },
  616.                                     children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, {
  617.                                         className: BDFDB.disCN.messagetoolbaricon,
  618.                                         iconSVG: translated ? translateIconUntranslate : translateIcon
  619.                                     })
  620.                                 })
  621.                             });
  622.                         }
  623.                     }));
  624.                 }
  625.             }
  626.            
  627.             processChannelTextAreaForm (e) {
  628.                 BDFDB.PatchUtils.patch(this, e.instance, "handleSendMessage", {instead: e2 => {
  629.                     if (this.isTranslationEnabled(e.instance.props.channel.id)) {
  630.                         e2.stopOriginalMethodCall();
  631.                         this.translateText(e2.methodArguments[0], messageTypes.SENT, (translation, input, output) => {
  632.                             translation = !translation ? e2.methodArguments[0] : (this.settings.general.sendOriginalMessage ? (e2.methodArguments[0] + "\n\n" + translation) : translation);
  633.                             e2.originalMethod(translation);
  634.                         });
  635.                         return Promise.resolve({
  636.                             shouldClear: true,
  637.                             shouldRefocus: true
  638.                         });
  639.                     }
  640.                     else return e2.callOriginalMethodAfterwards();
  641.                 }}, {force: true, noCache: true});
  642.             }
  643.  
  644.             processChannelEditorContainer (e) {
  645.                 if (this.isTranslationEnabled(e.instance.props.channel.id) && isTranslating) e.instance.props.disabled = true;
  646.             }
  647.            
  648.             processChannelTextAreaContainer (e) {
  649.                 if (this.settings.general.addTranslateButton) {
  650.                     let editor = BDFDB.ReactUtils.findChild(e.returnvalue, {name: "ChannelEditorContainer"});
  651.                     if (editor && (editor.props.type == BDFDB.DiscordConstants.TextareaTypes.NORMAL || editor.props.type == BDFDB.DiscordConstants.TextareaTypes.SIDEBAR) && !editor.props.disabled) {
  652.                         let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.textareapickerbuttons]]});
  653.                         if (index > -1 && children[index].props && children[index].props.children) children[index].props.children.unshift(BDFDB.ReactUtils.createElement(TranslateButtonComponent, {
  654.                             channelId: e.instance.props.channel.id
  655.                         }));
  656.                     }
  657.                 }
  658.             }
  659.  
  660.             processMessages (e) {
  661.                 e.returnvalue.props.children.props.channelStream = [].concat(e.returnvalue.props.children.props.channelStream);
  662.                 for (let i in e.returnvalue.props.children.props.channelStream) {
  663.                     let message = e.returnvalue.props.children.props.channelStream[i].content;
  664.                     if (message) {
  665.                         if (BDFDB.ArrayUtils.is(message.attachments)) this.checkMessage(e.returnvalue.props.children.props.channelStream[i], message);
  666.                         else if (BDFDB.ArrayUtils.is(message)) for (let j in message) {
  667.                             let childMessage = message[j].content;
  668.                             if (childMessage && BDFDB.ArrayUtils.is(childMessage.attachments)) this.checkMessage(message[j], childMessage);
  669.                         }
  670.                     }
  671.                 }
  672.             }
  673.            
  674.             checkMessage (stream, message) {
  675.                 let translation = translatedMessages[message.id];
  676.                 if (translation) stream.content.content = translation.content;
  677.                 else if (oldMessages[message.id] && Object.keys(message).some(key => !BDFDB.equals(oldMessages[message.id][key], message[key]))) {
  678.                     stream.content.content = oldMessages[message.id].content;
  679.                     delete oldMessages[message.id];
  680.                 }
  681.             }
  682.  
  683.             processMessageContent (e) {
  684.                 if (e.instance.props.message) {
  685.                     let translation = translatedMessages[e.instance.props.message.id];
  686.                     if (translation && translation.content) e.returnvalue.props.children.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, {
  687.                         text: `${BDFDB.LanguageUtils.getName(translation.input)} ➝ ${BDFDB.LanguageUtils.LibraryStrings.to} ${BDFDB.LanguageUtils.getName(translation.output)}`,
  688.                         tooltipConfig: {style: "max-width: 400px"},
  689.                         children: BDFDB.ReactUtils.createElement("span", {
  690.                             className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.messagetimestamp, BDFDB.disCN.messagetimestampinline, BDFDB.disCN._translatortranslated),
  691.                             children: BDFDB.ReactUtils.createElement("span", {
  692.                                 className: BDFDB.disCN.messageedited,
  693.                                 children: `(${this.labels.translated_watermark})`
  694.                             })
  695.                         })
  696.                     }));
  697.                 }
  698.             }
  699.  
  700.             processEmbed (e) {
  701.                 if (e.instance.props.embed && e.instance.props.embed.message_id) {
  702.                     let translation = translatedMessages[e.instance.props.embed.message_id];
  703.                     if (translation && Object.keys(translation.embeds).length) {
  704.                         if (!e.returnvalue) e.instance.props.embed = Object.assign({}, e.instance.props.embed, {
  705.                             rawDescription: translation.embeds[e.instance.props.embed.id],
  706.                             originalDescription: e.instance.props.embed.originalDescription || e.instance.props.embed.rawDescription
  707.                         });
  708.                         else {
  709.                             let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.embeddescription]]});
  710.                             if (index > -1) children[index].props.children.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, {
  711.                                 text: `${BDFDB.LanguageUtils.getName(translation.input)} ➝ ${BDFDB.LanguageUtils.getName(translation.output)}`,
  712.                                 tooltipConfig: {style: "max-width: 400px"},
  713.                                 children: BDFDB.ReactUtils.createElement("span", {
  714.                                     className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.messagetimestamp, BDFDB.disCN.messagetimestampinline, BDFDB.disCN._translatortranslated),
  715.                                     children: BDFDB.ReactUtils.createElement("span", {
  716.                                         className: BDFDB.disCN.messageedited,
  717.                                         children: `(${this.labels.translated_watermark})`
  718.                                     })
  719.                                 })
  720.                             }));
  721.                         }
  722.                     }
  723.                     else if (!e.returnvalue && e.instance.props.embed.originalDescription) {
  724.                         e.instance.props.embed = Object.assign({}, e.instance.props.embed, {rawDescription: e.instance.props.embed.originalDescription});
  725.                         delete e.instance.props.embed.originalDescription;
  726.                     }
  727.                 }
  728.             }
  729.            
  730.             toggleTranslation (channelId) {
  731.                 if (!this.isTranslationEnabled(channelId)) translationEnabledStates.push(this.settings.general.usePerChatTranslation ? channelId : "global");
  732.                 else BDFDB.ArrayUtils.remove(translationEnabledStates, this.settings.general.usePerChatTranslation ? channelId : "global", true);
  733.             }
  734.            
  735.             isTranslationEnabled (channelId) {
  736.                 return translationEnabledStates.includes(this.settings.general.usePerChatTranslation ? channelId : "global");
  737.             }
  738.  
  739.             setLanguages () {
  740.                 if (this.settings.engines.translator == this.settings.engines.backup) {
  741.                     this.settings.engines.backup = Object.keys(translationEngines).filter(n => n != this.settings.engines.translator)[0];
  742.                     BDFDB.DataUtils.save(this.settings.engines, this, "engines");
  743.                 }
  744.                 let engine = translationEngines[this.settings.engines.translator] || {};
  745.                 let backup = translationEngines[this.settings.engines.backup] || {};
  746.                 let languageIds = [].concat(engine.languages, backup.languages).flat(10).filter(n => n);
  747.                 languages = BDFDB.ObjectUtils.deepAssign(
  748.                     !engine.auto && !backup.auto ? {} : {
  749.                         auto: {
  750.                             auto: true,
  751.                             name: "Detect Language",
  752.                             id: "auto"
  753.                         }
  754.                     },
  755.                     BDFDB.ObjectUtils.filter(BDFDB.LanguageUtils.languages, lang => languageIds.includes(lang.id)),
  756.                     {
  757.                         binary: {
  758.                             special: true,
  759.                             name: "Binary",
  760.                             id: "binary"
  761.                         },
  762.                         braille: {
  763.                             special: true,
  764.                             name: "Braille 6-dot",
  765.                             id: "braille"
  766.                         },
  767.                         morse: {
  768.                             special: true,
  769.                             name: "Morse",
  770.                             id: "morse"
  771.                         }
  772.                     }
  773.                 );
  774.                 for (let id in languages) languages[id].fav = favorites.includes(id) ? 0 : 1;
  775.                 languages = BDFDB.ObjectUtils.sort(languages, "fav");
  776.             }
  777.  
  778.             getLanguageChoice (direction, place, channelId) {
  779.                 this.setLanguages();
  780.                 let choice;
  781.                 if (channelLanguages[channelId] && channelLanguages[channelId][place]) choice = channelLanguages[channelId][place][direction];
  782.                 else choice = this.settings.choices[place] && this.settings.choices[place][direction];
  783.                 choice = languages[choice] ? choice : Object.keys(languages)[0];
  784.                 choice = direction == languageTypes.OUTPUT && choice == "auto" ? "en" : choice;
  785.                 return choice;
  786.             }
  787.  
  788.             saveLanguageChoice (choice, direction, place, channelId) {
  789.                 if (channelLanguages[channelId] && channelLanguages[channelId][place]) {
  790.                     channelLanguages[channelId][place][direction] = choice;
  791.                     BDFDB.DataUtils.save(channelLanguages, this, "channelLanguages");
  792.                 }
  793.                 else {
  794.                     this.settings.choices[place][direction] = choice;
  795.                     BDFDB.DataUtils.save(this.settings.choices, this, "choices");
  796.                 }
  797.             }
  798.  
  799.             translateMessage (message, channel) {
  800.                 return new Promise(callback => {
  801.                     if (!message) return callback(null);
  802.                     if (translatedMessages[message.id]) {
  803.                         delete translatedMessages[message.id];
  804.                         BDFDB.MessageUtils.rerenderAll(true);
  805.                         callback(false);
  806.                     }
  807.                     else {
  808.                         let orignalContent = message.content || "";
  809.                         for (let embed of message.embeds) orignalContent += ("\n__________________ __________________ __________________\n" + embed.rawDescription);
  810.                         this.translateText(orignalContent, messageTypes.RECEIVED, (translation, input, output) => {
  811.                             if (translation) {
  812.                                 oldMessages[message.id] = new BDFDB.DiscordObjects.Message(message);
  813.                                 let oldStrings = orignalContent.split(/\n{0,1}__________________ __________________ __________________\n{0,1}/);
  814.                                 let strings = translation.split(/\n{0,1}__________________ __________________ __________________\n{0,1}/);
  815.                                 let oldContent = this.settings.general.showOriginalMessage && (oldStrings.shift() || "").trim();
  816.                                 let content = (strings.shift() || "").trim() + (oldContent ? `\n\n${oldContent}` : "");
  817.                                 let embeds = {};
  818.                                 for (let i in message.embeds) {
  819.                                     message.embeds[i].message_id = message.id;
  820.                                     let oldEmbedString = this.settings.general.showOriginalMessage && (oldStrings.shift() || "").trim();
  821.                                     embeds[message.embeds[i].id] = (strings.shift() || message.embeds[i].rawDescription).trim() + (oldEmbedString ? `\n\n${oldEmbedString}` : "");
  822.                                 }
  823.                                 translatedMessages[message.id] = {content, embeds, input, output};
  824.                                 BDFDB.MessageUtils.rerenderAll(true);
  825.                             }
  826.                             callback(true);
  827.                         });
  828.                     }
  829.                 });
  830.             }
  831.  
  832.             translateText (text, place, callback) {
  833.                 let toast = null, toastInterval, finished = false, finishTranslation = translation => {
  834.                     isTranslating = false;
  835.                     if (toast) toast.close();
  836.                     BDFDB.TimeUtils.clear(toastInterval);
  837.                    
  838.                     if (finished) return;
  839.                     finished = true;
  840.                     if (translation) translation = this.addExceptions(translation, excepts);
  841.                     callback(translation == text ? "" : translation, input, output);
  842.                 };
  843.                 let [newText, excepts, translate] = this.removeExceptions(text.trim(), place);
  844.                 let channelId = BDFDB.LibraryModules.LastChannelStore.getChannelId();
  845.                 let input = Object.assign({}, languages[this.getLanguageChoice(languageTypes.INPUT, place, channelId)]);
  846.                 let output = Object.assign({}, languages[this.getLanguageChoice(languageTypes.OUTPUT, place, channelId)]);
  847.                 if (translate && input.id != output.id) {
  848.                     let specialCase = this.checkForSpecialCase(newText, input);
  849.                     if (specialCase) {
  850.                         input.name = specialCase.name;
  851.                         switch (specialCase.id) {
  852.                             case "binary": newText = this.binary2string(newText); break;
  853.                             case "braille": newText = this.braille2string(newText); break;
  854.                             case "morse": newText = this.morse2string(newText); break;
  855.                         }
  856.                     }
  857.                     if (output.special) {
  858.                         switch (output.id) {
  859.                             case "binary": newText = this.string2binary(newText); break;
  860.                             case "braille": newText = this.string2braille(newText); break;
  861.                             case "morse": newText = this.string2morse(newText); break;
  862.                         }
  863.                         finishTranslation(newText);
  864.                     }
  865.                     else {
  866.                         const startTranslating = engine => {
  867.                             isTranslating = true;
  868.                             if (toast) toast.close();
  869.                             BDFDB.TimeUtils.clear(toastInterval);
  870.                            
  871.                             let loadingString = `${this.labels.toast_translating} (${translationEngines[engine].name}) - ${BDFDB.LanguageUtils.LibraryStrings.please_wait}`;
  872.                             let currentLoadingString = loadingString;
  873.                             toast = BDFDB.NotificationUtils.toast(loadingString, {
  874.                                 timeout: 0,
  875.                                 position: "center",
  876.                                 onClose: _ => BDFDB.TimeUtils.clear(toastInterval)
  877.                             });
  878.                             toastInterval = BDFDB.TimeUtils.interval((_, count) => {
  879.                                 if (count > 40) {
  880.                                     finishTranslation("");
  881.                                     BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed} (${translationEngines[engine].name}) - ${this.labels.toast_translating_tryanother}`, {
  882.                                         type: "danger",
  883.                                         position: "center"
  884.                                     });
  885.                                 }
  886.                                 else {
  887.                                     currentLoadingString = currentLoadingString.endsWith(".....") ? loadingString : currentLoadingString + ".";
  888.                                     toast.update(currentLoadingString);
  889.                                 }
  890.                             }, 500);
  891.                         };
  892.                         if (this.validTranslator(this.settings.engines.translator, input, output, specialCase)) {
  893.                             startTranslating(this.settings.engines.translator);
  894.                             this[translationEngines[this.settings.engines.translator].funcName].apply(this, [{input, output, text: newText, specialCase, engine: translationEngines[this.settings.engines.translator]}, translation => {
  895.                                 if (!translation && this.validTranslator(this.settings.engines.backup, input, output, specialCase)) {
  896.                                     startTranslating(this.settings.engines.backup);
  897.                                     this[translationEngines[this.settings.engines.backup].funcName].apply(this, [{input, output, text: newText, specialCase, engine: translationEngines[this.settings.engines.backup]}, finishTranslation]);
  898.                                 }
  899.                                 else finishTranslation(translation);
  900.                             }]);
  901.                         }
  902.                         else if (this.validTranslator(this.settings.engines.backup, input, output, specialCase)) {
  903.                             startTranslating(this.settings.engines.backup);
  904.                             this[translationEngines[this.settings.engines.backup].funcName].apply(this, [{input, output, text: newText, specialCase, engine: translationEngines[this.settings.engines.backup]}, finishTranslation]);
  905.                         }
  906.                         else finishTranslation();
  907.                     }
  908.                 }
  909.                 else finishTranslation();
  910.             }
  911.            
  912.             validTranslator (key, input, output, specialCase) {
  913.                 return translationEngines[key] && typeof this[translationEngines[key].funcName] == "function" && (specialCase || input.auto && translationEngines[key].auto || translationEngines[key].languages.includes(input.id) && translationEngines[key].languages.includes(output.id));
  914.             }
  915.            
  916.             googleApiTranslate (data, callback) {
  917.                 BDFDB.LibraryRequires.request(`https://translate.googleapis.com/translate_a/single?client=gtx&sl=${data.input.id}&tl=${data.output.id}&dt=t&dj=1&source=input&q=${encodeURIComponent(data.text)}`, (error, response, body) => {
  918.                     if (!error && body && response.statusCode == 200) {
  919.                         try {
  920.                             body = JSON.parse(body);
  921.                             if (!data.specialCase && body.src && body.src && languages[body.src]) {
  922.                                 data.input.name = languages[body.src].name;
  923.                                 data.input.ownlang = languages[body.src].ownlang;
  924.                             }
  925.                             callback(body.sentences.map(n => n && n.trans).filter(n => n).join(""));
  926.                         }
  927.                         catch (err) {callback("");}
  928.                     }
  929.                     else {
  930.                         if (response.statusCode == 429) BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Request Limit per Hour reached.`, {
  931.                             type: "danger",
  932.                             position: "center"
  933.                         });
  934.                         else BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Translation Server might be down.`, {
  935.                             type: "danger",
  936.                             position: "center"
  937.                         });
  938.                         callback("");
  939.                     }
  940.                 });
  941.             }
  942.            
  943.             deepLTranslate (data, callback) {
  944.                 BDFDB.LibraryRequires.request(`https://api-free.deepl.com/v2/translate?auth_key=${authKeys.deepl || "75cc2f40-fdae-14cd-7242-6a384e2abb9c:fx"}&text=${encodeURIComponent(data.text)}${data.input.auto ? "" : `&source_lang=${data.input.id}`}&target_lang=${data.output.id}`, (error, response, body) => {
  945.                     if (!error && body && response.statusCode == 200) {
  946.                         try {
  947.                             body = JSON.parse(body);
  948.                             if (!data.specialCase && body.translations[0] && body.translations[0].detected_source_language && languages[body.translations[0].detected_source_language.toLowerCase()]) {
  949.                                 data.input.name = languages[body.translations[0].detected_source_language.toLowerCase()].name;
  950.                                 data.input.ownlang = languages[body.translations[0].detected_source_language.toLowerCase()].ownlang;
  951.                             }
  952.                             callback(body.translations.map(n => n && n.text).filter(n => n).join(""));
  953.                         }
  954.                         catch (err) {callback("");}
  955.                     }
  956.                     else {
  957.                         if (response.statusCode == 429 || response.statusCode == 456) BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Request Limit reached.`, {
  958.                             type: "danger",
  959.                             position: "center"
  960.                         });
  961.                         else if (response.statusCode == 403) BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. API-Key outdated.`, {
  962.                             type: "danger",
  963.                             position: "center"
  964.                         });
  965.                         else BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Translation Server might be down.`, {
  966.                             type: "danger",
  967.                             position: "center"
  968.                         });
  969.                         callback("");
  970.                     }
  971.                 });
  972.             }
  973.            
  974.             iTranslateTranslate (data, callback) {
  975.                 let translate = _ => {
  976.                     BDFDB.LibraryRequires.request.post({
  977.                         url: "https://web-api.itranslateapp.com/v3/texts/translate",
  978.                         headers: {
  979.                             "API-KEY": authKeys.itranslate || data.engine.APIkey
  980.                         },
  981.                         body: JSON.stringify({
  982.                             source: {
  983.                                 dialect: data.input.id,
  984.                                 text: data.text
  985.                             },
  986.                             target: {
  987.                                 dialect: data.output.id
  988.                             }
  989.                         })
  990.                     }, (error, response, body) => {
  991.                         if (!error && response && response.statusCode == 200) {
  992.                             try {
  993.                                 body = JSON.parse(body);
  994.                                 if (!data.specialCase && body.source && body.source.dialect && languages[body.source.dialect]) {
  995.                                     data.input.name = languages[body.source.dialect].name;
  996.                                     data.input.ownlang = languages[body.source.dialect].ownlang;
  997.                                 }
  998.                                 callback(body.target.text);
  999.                             }
  1000.                             catch (err) {callback("");}
  1001.                         }
  1002.                         else {
  1003.                             if (response.statusCode == 429) BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Request Limit reached.`, {
  1004.                                 type: "danger",
  1005.                                 position: "center"
  1006.                             });
  1007.                             else if (response.statusCode == 403) BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. API-Key outdated.`, {
  1008.                                 type: "danger",
  1009.                                 position: "center"
  1010.                             });
  1011.                             else BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Translation Server might be down.`, {
  1012.                                 type: "danger",
  1013.                                 position: "center"
  1014.                             });
  1015.                             callback("");
  1016.                         }
  1017.                     });
  1018.                 };
  1019.                 if (authKeys.itranslate || data.engine.APIkey) translate();
  1020.                 else BDFDB.LibraryRequires.request("https://www.itranslate.com/js/webapp/main.js", {gzip: true}, (error, response, body) => {
  1021.                     if (!error && body) {
  1022.                         let APIkey = /var API_KEY = "(.+)"/.exec(body);
  1023.                         if (APIkey) {
  1024.                             data.engine.APIkey = APIkey[1];
  1025.                             translate();
  1026.                         }
  1027.                         else callback("");
  1028.                     }
  1029.                     else callback("");
  1030.                 });
  1031.             }
  1032.            
  1033.             yandexTranslate (data, callback) {
  1034.                 BDFDB.LibraryRequires.request(`https://translate.yandex.net/api/v1.5/tr/translate?key=${authKeys.yandex || "trnsl.1.1.20191206T223907Z.52bd512eca953a5b.1ec123ce4dcab3ae859f312d27cdc8609ab280de"}&text=${encodeURIComponent(data.text)}&lang=${data.specialCase || data.input.auto ? data.output.id : (data.input.id + "-" + data.output.id)}&options=1`, (error, response, body) => {
  1035.                     if (!error && body && response.statusCode == 200) {
  1036.                         try {
  1037.                             body = BDFDB.DOMUtils.create(body);
  1038.                             let translation = body.querySelector("text");
  1039.                             let detected = body.querySelector("detected");
  1040.                             if (translation && detected) {
  1041.                                 let detectedLang = detected.getAttribute("lang");
  1042.                                 if (!data.specialCase && detectedLang && languages[detectedLang]) {
  1043.                                     data.input.name = languages[detectedLang].name;
  1044.                                     data.input.ownlang = languages[detectedLang].ownlang;
  1045.                                 }
  1046.                                 callback(translation.innerText);
  1047.                             }
  1048.                             else callback("");
  1049.                         }
  1050.                         catch (err) {callback("");}
  1051.                     }
  1052.                     else if (body && body.indexOf('code="408"') > -1) {
  1053.                         BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Monthly Request Limit reached.`, {
  1054.                             type: "danger",
  1055.                             position: "center"
  1056.                         });
  1057.                         callback("");
  1058.                     }
  1059.                     else {
  1060.                         BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Translation Server down or API-Key outdated.`, {
  1061.                             type: "danger",
  1062.                             position: "center"
  1063.                         });
  1064.                         callback("");
  1065.                     }
  1066.                 });
  1067.             }
  1068.            
  1069.             papagoTranslate (data, callback) {
  1070.                 const credentials = (authKeys.papago || "kUNGxtAmTJQFbaFehdjk zC70k3VhpM").split(" ");
  1071.                 BDFDB.LibraryRequires.request.post({
  1072.                     url: "https://openapi.naver.com/v1/papago/n2mt",
  1073.                     form: {
  1074.                         source: data.input.id,
  1075.                         target: data.output.id,
  1076.                         text: data.text
  1077.                     },
  1078.                     headers: {
  1079.                         "X-Naver-Client-Id": credentials[0],
  1080.                         "X-Naver-Client-Secret": credentials[1]
  1081.                     }
  1082.                 }, (error, response, body) => {
  1083.                     if (!error && body && response.statusCode == 200) {
  1084.                         try {
  1085.                             let message = (JSON.parse(body) || {}).message;
  1086.                             let result = message && (message.body || message.result);
  1087.                             if (result && result.translatedText) callback(result.translatedText);
  1088.                             else callback("");
  1089.                         }
  1090.                         catch (err) {callback("");}
  1091.                     }
  1092.                     else {
  1093.                         if (response.statusCode == 429) BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Request Limit per Hour is reached.`, {
  1094.                             type: "danger",
  1095.                             position: "center"
  1096.                         });
  1097.                         else BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Translation Server is down or API-key outdated.`, {
  1098.                             type: "danger",
  1099.                             position: "center"
  1100.                         });
  1101.                         callback("");
  1102.                     }
  1103.                 });
  1104.             }
  1105.            
  1106.             baiduTranslate (data, callback) {
  1107.                 const credentials = (authKeys.baidu || "20210425000799880 e12h9h4rh39r8h12r8 D90usZcbznwthzKC1KOb").split(" ");
  1108.                 BDFDB.LibraryRequires.request.post({
  1109.                     url: "https://fanyi-api.baidu.com/api/trans/vip/translate",
  1110.                     form: {
  1111.                         from: translationEngines.baidu.parser[data.input.id] || data.input.id,
  1112.                         to: translationEngines.baidu.parser[data.output.id] || data.output.id,
  1113.                         q: data.text,
  1114.                         appid: credentials[0],
  1115.                         salt: credentials[1],
  1116.                         sign: this.MD5(credentials[0] + data.text + credentials[1] + credentials[2])
  1117.                     }
  1118.                 }, (error, response, result) => {
  1119.                     if (!error && result && response.statusCode == 200) {
  1120.                         try {
  1121.                             result = JSON.parse(result) || {};
  1122.                             if (!result.error_code) {
  1123.                                 let messages = result.trans_result;
  1124.                                 if (messages && messages.length > 0 && result.from != result.to) callback(messages.map(message => decodeURIComponent(message.dst)).join("\n"));
  1125.                                 else {callback("");}
  1126.                             }
  1127.                             else {
  1128.                                 BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. ${result.error_code} : ${result.error_msg}.`, {
  1129.                                     type: "danger",
  1130.                                     position: "center"
  1131.                                 });
  1132.                                 callback("");
  1133.                             }
  1134.                         }
  1135.                         catch (err) {callback("");}
  1136.                     }
  1137.                     else {
  1138.                         BDFDB.NotificationUtils.toast(`${this.labels.toast_translating_failed}. ${this.labels.toast_translating_tryanother}. Translation Server is down.`, {
  1139.                             type: "danger",
  1140.                             position: "center"
  1141.                         });
  1142.                         callback("");
  1143.                     }
  1144.                 });
  1145.             }
  1146.            
  1147.             MD5 (e) {
  1148.                 function h(a, b) {
  1149.                     var e = a & 2147483648, f = b & 2147483648, c = a & 1073741824, d = b & 1073741824, g = (a & 1073741823) + (b & 1073741823);
  1150.                     return c & d ? g ^ 2147483648 ^ e ^ f : c | d ? g & 1073741824 ? g ^ 3221225472 ^ e ^ f : g ^ 1073741824 ^ e ^ f : g ^ e ^ f
  1151.                 }
  1152.                 function k(a, b, c, d, e, f, g) {
  1153.                     a = h(a, h(h(b & c | ~b & d, e), g));
  1154.                     return h(a << f | a >>> 32 - f, b);
  1155.                 }
  1156.                 function l(a, b, c, d, e, f, g) {
  1157.                     a = h(a, h(h(b & d | c & ~d, e), g));
  1158.                     return h(a << f | a >>> 32 - f, b);
  1159.                 }
  1160.                 function m(a, b, d, c, e, f, g) {
  1161.                     a = h(a, h(h(b ^ d ^ c, e), g));
  1162.                     return h(a << f | a >>> 32 - f, b)
  1163.                 }
  1164.                 function n(a, b, d, c, e, f, g) {
  1165.                     a = h(a, h(h(d ^ (b | ~c), e), g));
  1166.                     return h(a << f | a >>> 32 - f, b);
  1167.                 }
  1168.                 function p(a) {
  1169.                     var b = "", d = "", c;
  1170.                     for (c = 0; 3 >= c; c++) d = a >>> 8 * c & 255, d = "0" + d.toString(16), b += d.substr(d.length - 2, 2);
  1171.                     return b;
  1172.                 }
  1173.                
  1174.                 var f = [], q, r, s, t, a, b, c, d;
  1175.                 e = function(a) {
  1176.                     a = a.replace(/\r\n/g, "\n");
  1177.                     for (var b = "", d = 0; d < a.length; d++) {
  1178.                         var c = a.charCodeAt(d);
  1179.                         128 > c ? b += String.fromCharCode(c) : (127 < c && 2048 > c ? b += String.fromCharCode(c >> 6 | 192) : (b += String.fromCharCode(c >> 12 | 224), b += String.fromCharCode(c >> 6 & 63 | 128)), b += String.fromCharCode(c & 63 | 128))
  1180.                     }
  1181.                     return b;
  1182.                 }(e);
  1183.                 f = function(b) {
  1184.                     var a, c = b.length;
  1185.                     a = c + 8;
  1186.                     for (var d = 16 * ((a - a % 64) / 64 + 1), e = Array(d - 1), f = 0, g = 0; g < c;) a = (g - g % 4) / 4, f = g % 4 * 8, e[a] |= b.charCodeAt(g) << f, g++;
  1187.                     a = (g - g % 4) / 4;
  1188.                     e[a] |= 128 << g % 4 * 8;
  1189.                     e[d - 2] = c << 3;
  1190.                     e[d - 1] = c >>> 29;
  1191.                     return e
  1192.                 }(e);
  1193.                 a = 1732584193, b = 4023233417, c = 2562383102, d = 271733878;
  1194.                 for (e = 0; e < f.length; e += 16) q = a, r = b, s = c, t = d, a = k(a, b, c, d, f[e + 0], 7, 3614090360), d = k(d, a, b, c, f[e + 1], 12, 3905402710), c = k(c, d, a, b, f[e + 2], 17, 606105819), b = k(b, c, d, a, f[e + 3], 22, 3250441966), a = k(a, b, c, d, f[e + 4], 7, 4118548399), d = k(d, a, b, c, f[e + 5], 12, 1200080426), c = k(c, d, a, b, f[e + 6], 17, 2821735955), b = k(b, c, d, a, f[e + 7], 22, 4249261313), a = k(a, b, c, d, f[e + 8], 7, 1770035416), d = k(d, a, b, c, f[e + 9], 12, 2336552879), c = k(c, d, a, b, f[e + 10], 17, 4294925233), b = k(b, c, d, a, f[e + 11], 22, 2304563134), a = k(a, b, c, d, f[e + 12], 7, 1804603682), d = k(d, a, b, c, f[e + 13], 12, 4254626195), c = k(c, d, a, b, f[e + 14], 17, 2792965006), b = k(b, c, d, a, f[e + 15], 22, 1236535329), a = l(a, b, c, d, f[e + 1], 5, 4129170786), d = l(d, a, b, c, f[e + 6], 9, 3225465664), c = l(c, d, a, b, f[e + 11], 14, 643717713), b = l(b, c, d, a, f[e + 0], 20, 3921069994), a = l(a, b, c, d, f[e + 5], 5, 3593408605), d = l(d, a, b, c, f[e + 10], 9, 38016083), c = l(c, d, a, b, f[e + 15], 14, 3634488961), b = l(b, c, d, a, f[e + 4], 20, 3889429448), a = l(a, b, c, d, f[e + 9], 5, 568446438), d = l(d, a, b, c, f[e + 14], 9, 3275163606), c = l(c, d, a, b, f[e + 3], 14, 4107603335), b = l(b, c, d, a, f[e + 8], 20, 1163531501), a = l(a, b, c, d, f[e + 13], 5, 2850285829), d = l(d, a, b, c, f[e + 2], 9, 4243563512), c = l(c, d, a, b, f[e + 7], 14, 1735328473), b = l(b, c, d, a, f[e + 12], 20, 2368359562), a = m(a, b, c, d, f[e + 5], 4, 4294588738), d = m(d, a, b, c, f[e + 8], 11, 2272392833), c = m(c, d, a, b, f[e + 11], 16, 1839030562), b = m(b, c, d, a, f[e + 14], 23, 4259657740), a = m(a, b, c, d, f[e + 1], 4, 2763975236), d = m(d, a, b, c, f[e + 4], 11, 1272893353), c = m(c, d, a, b, f[e + 7], 16, 4139469664), b = m(b, c, d, a, f[e + 10], 23, 3200236656), a = m(a, b, c, d, f[e + 13], 4, 681279174), d = m(d, a, b, c, f[e + 0], 11, 3936430074), c = m(c, d, a, b, f[e + 3], 16, 3572445317), b = m(b, c, d, a, f[e + 6], 23, 76029189), a = m(a, b, c, d, f[e + 9], 4, 3654602809), d = m(d, a, b, c, f[e + 12], 11, 3873151461), c = m(c, d, a, b, f[e + 15], 16, 530742520), b = m(b, c, d, a, f[e + 2], 23, 3299628645), a = n(a, b, c, d, f[e + 0], 6, 4096336452), d = n(d, a, b, c, f[e + 7], 10, 1126891415), c = n(c, d, a, b, f[e + 14], 15, 2878612391), b = n(b, c, d, a, f[e + 5], 21, 4237533241), a = n(a, b, c, d, f[e + 12], 6, 1700485571), d = n(d, a, b, c, f[e + 3], 10, 2399980690), c = n(c, d, a, b, f[e + 10], 15, 4293915773), b = n(b, c, d, a, f[e + 1], 21, 2240044497), a = n(a, b, c, d, f[e + 8], 6, 1873313359), d = n(d, a, b, c, f[e + 15], 10, 4264355552), c = n(c, d, a, b, f[e + 6], 15, 2734768916), b = n(b, c, d, a, f[e + 13], 21, 1309151649), a = n(a, b, c, d, f[e + 4], 6, 4149444226), d = n(d, a, b, c, f[e + 11], 10, 3174756917), c = n(c, d, a, b, f[e + 2], 15, 718787259), b = n(b, c, d, a, f[e + 9], 21, 3951481745), a = h(a, q), b = h(b, r), c = h(c, s), d = h(d, t);
  1195.                 return (p(a) + p(b) + p(c) + p(d)).toLowerCase();
  1196.             }
  1197.  
  1198.             checkForSpecialCase (text, input) {
  1199.                 if (input.special) return input;
  1200.                 else if (input.auto) {
  1201.                     if (/^[0-1]*$/.test(text.replace(/\s/g, ""))) {
  1202.                         return {id: "binary", name: "Binary"};
  1203.                     }
  1204.                     else if (/^[⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿]*$/.test(text.replace(/\s/g, ""))) {
  1205.                         return {id: "braille", name: "Braille 6-dot"};
  1206.                     }
  1207.                     else if (/^[/|·−._-]*$/.test(text.replace(/\s/g, ""))) {
  1208.                         return {id: "morse", name: "Morse"};
  1209.                     }
  1210.                 }
  1211.                 return null;
  1212.             }
  1213.  
  1214.             string2binary (string) {
  1215.                 let binary = "";
  1216.                 for (let character of string) binary += parseInt(character.charCodeAt(0).toString(2)).toPrecision(8).split(".").reverse().join("").toString() + " ";
  1217.                 return binary;
  1218.             }
  1219.  
  1220.             string2braille (string) {
  1221.                 let braille = "";
  1222.                 for (let character of string) braille += brailleConverter[character.toLowerCase()] ? brailleConverter[character.toLowerCase()] : character;
  1223.                 return braille;
  1224.             }
  1225.  
  1226.             string2morse (string) {
  1227.                 string = string.replace(/ /g, "%%%%%%%%%%");
  1228.                 let morse = "";
  1229.                 for (let character of string) morse += (morseConverter[character.toLowerCase()] ? morseConverter[character.toLowerCase()] : character) + " ";
  1230.                 morse = morse.split("\n");
  1231.                 for (let i in morse) morse[i] = morse[i].trim();
  1232.                 return morse.join("\n").replace(/% % % % % % % % % % /g, "/ ");
  1233.             }
  1234.  
  1235.             binary2string (binary) {
  1236.                 let string = "";
  1237.                 binary = binary.replace(/\n/g, "00001010").replace(/\r/g, "00001101").replace(/\t/g, "00001001").replace(/\s/g, "");
  1238.                 if (/^[0-1]*$/.test(binary)) {
  1239.                     let eightDigits = "";
  1240.                     let counter = 0;
  1241.                     for (let digit of binary) {
  1242.                         eightDigits += digit;
  1243.                         counter++;
  1244.                         if (counter > 7) {
  1245.                             string += String.fromCharCode(parseInt(eightDigits, 2).toString(10));
  1246.                             eightDigits = "";
  1247.                             counter = 0;
  1248.                         }
  1249.                     }
  1250.                 }
  1251.                 else BDFDB.NotificationUtils.toast("Invalid binary format. Only use 0s and 1s.", {
  1252.                     type: "danger",
  1253.                     position: "center"
  1254.                 });
  1255.                 return string;
  1256.             }
  1257.  
  1258.             braille2string (braille) {
  1259.                 let string = "";
  1260.                 for (let character of braille) string += brailleConverter[character.toLowerCase()] ? brailleConverter[character.toLowerCase()] : character;
  1261.                 return string;
  1262.             }
  1263.  
  1264.             morse2string (morse) {
  1265.                 let string = "";
  1266.                 for (let word of morse.replace(/[_-]/g, "").replace(/\./g, "·").replace(/\r|\t/g, "").split(/\/|\||\n/g)) {
  1267.                     for (let characterstr of word.trim().split(" ")) string += morseConverter[characterstr] ? morseConverter[characterstr] : characterstr;
  1268.                     string += " ";
  1269.                 }
  1270.                 return string.trim();
  1271.             }
  1272.  
  1273.             addExceptions (string, excepts) {
  1274.                 for (let count in excepts) {
  1275.                     let exception = BDFDB.ArrayUtils.is(this.settings.exceptions.wordStart) && this.settings.exceptions.wordStart.some(n => excepts[count].indexOf(n) == 0) ? excepts[count].slice(1) : excepts[count];
  1276.                     let newString = string.replace(new RegExp(BDFDB.StringUtils.regEscape(`{{${count}}}`)), exception);
  1277.                     if (newString == string) string = newString + " " + exception;
  1278.                     else string = newString;
  1279.                 }
  1280.                 return string;
  1281.             }
  1282.  
  1283.             removeExceptions (string, place) {
  1284.                 let excepts = {}, newString = [], count = 0;
  1285.                 if (place == messageTypes.RECEIVED) {
  1286.                     let text = [], i = 0;
  1287.                     string.split("").forEach(chara => {
  1288.                         if (chara == "<" && text[i]) i++;
  1289.                         text[i] = text[i] ? text[i] + chara : chara;
  1290.                         if (chara == ">") i++;
  1291.                     });
  1292.                     for (let j in text) {
  1293.                         if (text[j].indexOf("<") == 0) {
  1294.                             newString.push(`{{${count}}}`);
  1295.                             excepts[count] = text[j];
  1296.                             count++;
  1297.                         }
  1298.                         else newString.push(text[j]);
  1299.                     }
  1300.                 }
  1301.                 else {
  1302.                     let usedExceptions = BDFDB.ArrayUtils.is(this.settings.exceptions.wordStart) ? this.settings.exceptions.wordStart : [];
  1303.                     string.split(" ").forEach(word => {
  1304.                         if (word.indexOf("<@!") == 0 || word.indexOf("<#") == 0 || word.indexOf(":") == 0 || word.indexOf("<:") == 0 || word.indexOf("<a:") == 0 || word.indexOf("@") == 0 || word.indexOf("#") == 0 || usedExceptions.some(n => word.indexOf(n) == 0 && word.length > 1)) {
  1305.                             newString.push(`{{${count}}}`);
  1306.                             excepts[count] = word;
  1307.                             count++;
  1308.                         }
  1309.                         else newString.push(word);
  1310.                     });
  1311.                 }
  1312.                 return [newString.join(" "), excepts, newString.length-count != 0];
  1313.             }
  1314.  
  1315.             getGoogleTranslatePageURL (input, output, text) {
  1316.                 return `https://translate.google.com/#${BDFDB.LanguageUtils.languages[input] ? input : "auto"}/${output}/${encodeURIComponent(text)}`;
  1317.             }
  1318.  
  1319.             setLabelsByLanguage () {
  1320.                 switch (BDFDB.LanguageUtils.getLanguage().id) {
  1321.                     case "bg":      // Bulgarian
  1322.                         return {
  1323.                             context_translator:                 "Търсене превод",
  1324.                             context_messagetranslateoption:     "Превод на съобщението",
  1325.                             context_messageuntranslateoption:   "Превод на съобщението",
  1326.                             popout_translateoption:             "Превод",
  1327.                             popout_untranslateoption:           "Непревод",
  1328.                             toast_translating:                  "Превод",
  1329.                             toast_translating_failed:           "Преводът не бе успешен",
  1330.                             toast_translating_tryanother:       "Опитайте друг преводач",
  1331.                             translated_watermark:               "преведено"
  1332.                         };
  1333.                     case "da":      // Danish
  1334.                         return {
  1335.                             context_translator:                 "Søg oversættelse",
  1336.                             context_messagetranslateoption:     "Oversæt besked",
  1337.                             context_messageuntranslateoption:   "Ikke-oversat besked",
  1338.                             popout_translateoption:             "Oversætte",
  1339.                             popout_untranslateoption:           "Untranslate",
  1340.                             toast_translating:                  "Oversætter",
  1341.                             toast_translating_failed:           "Kunne ikke oversætte",
  1342.                             toast_translating_tryanother:       "Prøv en anden oversætter",
  1343.                             translated_watermark:               "oversat"
  1344.                         };
  1345.                     case "de":      // German
  1346.                         return {
  1347.                             context_translator:                 "Übersetzung suchen",
  1348.                             context_messagetranslateoption:     "Nachricht übersetzen",
  1349.                             context_messageuntranslateoption:   "Nachricht unübersetzen",
  1350.                             popout_translateoption:             "Übersetzen",
  1351.                             popout_untranslateoption:           "Unübersetzen",
  1352.                             toast_translating:                  "Übersetzen",
  1353.                             toast_translating_failed:           "Übersetzung fehlgeschlagen",
  1354.                             toast_translating_tryanother:       "Versuch einen anderen Übersetzer",
  1355.                             translated_watermark:               "übersetzt"
  1356.                         };
  1357.                     case "el":      // Greek
  1358.                         return {
  1359.                             context_translator:                 "Αναζήτηση μετάφρασης",
  1360.                             context_messagetranslateoption:     "Μετάφραση μηνύματος",
  1361.                             context_messageuntranslateoption:   "Μη μετάφραση μηνύματος",
  1362.                             popout_translateoption:             "Μεταφράζω",
  1363.                             popout_untranslateoption:           "Μη μετάφραση",
  1364.                             toast_translating:                  "Μετάφραση",
  1365.                             toast_translating_failed:           "Αποτυχία μετάφρασης",
  1366.                             toast_translating_tryanother:       "Δοκιμάστε έναν άλλο Μεταφραστή",
  1367.                             translated_watermark:               "μεταφρασμένο"
  1368.                         };
  1369.                     case "es":      // Spanish
  1370.                         return {
  1371.                             context_translator:                 "Buscar traducción",
  1372.                             context_messagetranslateoption:     "Traducir mensaje",
  1373.                             context_messageuntranslateoption:   "Mensaje sin traducir",
  1374.                             popout_translateoption:             "Traducir",
  1375.                             popout_untranslateoption:           "No traducir",
  1376.                             toast_translating:                  "Traductorio",
  1377.                             toast_translating_failed:           "No se pudo traducir",
  1378.                             toast_translating_tryanother:       "Prueba con otro traductor",
  1379.                             translated_watermark:               "traducido"
  1380.                         };
  1381.                     case "fi":      // Finnish
  1382.                         return {
  1383.                             context_translator:                 "Hae käännöstä",
  1384.                             context_messagetranslateoption:     "Käännä viesti",
  1385.                             context_messageuntranslateoption:   "Käännä viesti",
  1386.                             popout_translateoption:             "Kääntää",
  1387.                             popout_untranslateoption:           "Käännä",
  1388.                             toast_translating:                  "Kääntäminen",
  1389.                             toast_translating_failed:           "Käännös epäonnistui",
  1390.                             toast_translating_tryanother:       "Kokeile toista kääntäjää",
  1391.                             translated_watermark:               "käännetty"
  1392.                         };
  1393.                     case "fr":      // French
  1394.                         return {
  1395.                             context_translator:                 "Recherche de traduction",
  1396.                             context_messagetranslateoption:     "Traduire le message",
  1397.                             context_messageuntranslateoption:   "Message non traduit",
  1398.                             popout_translateoption:             "Traduire",
  1399.                             popout_untranslateoption:           "Non traduit",
  1400.                             toast_translating:                  "Traduction en cours",
  1401.                             toast_translating_failed:           "Échec de la traduction",
  1402.                             toast_translating_tryanother:       "Essayez un autre traducteur",
  1403.                             translated_watermark:               "traduit"
  1404.                         };
  1405.                     case "hr":      // Croatian
  1406.                         return {
  1407.                             context_translator:                 "Pretraži prijevod",
  1408.                             context_messagetranslateoption:     "Prevedi poruku",
  1409.                             context_messageuntranslateoption:   "Prevedi poruku",
  1410.                             popout_translateoption:             "Prevedi",
  1411.                             popout_untranslateoption:           "Neprevedi",
  1412.                             toast_translating:                  "Prevođenje",
  1413.                             toast_translating_failed:           "Prijevod nije uspio",
  1414.                             toast_translating_tryanother:       "Pokušajte s drugim prevoditeljem",
  1415.                             translated_watermark:               "prevedeno"
  1416.                         };
  1417.                     case "hu":      // Hungarian
  1418.                         return {
  1419.                             context_translator:                 "Keresés a fordításban",
  1420.                             context_messagetranslateoption:     "Üzenet lefordítása",
  1421.                             context_messageuntranslateoption:   "Az üzenet lefordítása",
  1422.                             popout_translateoption:             "fordít",
  1423.                             popout_untranslateoption:           "Fordítás le",
  1424.                             toast_translating:                  "Fordítás",
  1425.                             toast_translating_failed:           "Nem sikerült lefordítani",
  1426.                             toast_translating_tryanother:       "Próbálkozzon másik fordítóval",
  1427.                             translated_watermark:               "lefordított"
  1428.                         };
  1429.                     case "it":      // Italian
  1430.                         return {
  1431.                             context_translator:                 "Cerca traduzione",
  1432.                             context_messagetranslateoption:     "Traduci messaggio",
  1433.                             context_messageuntranslateoption:   "Annulla traduzione messaggio",
  1434.                             popout_translateoption:             "Tradurre",
  1435.                             popout_untranslateoption:           "Non tradurre",
  1436.                             toast_translating:                  "Tradurre",
  1437.                             toast_translating_failed:           "Impossibile tradurre",
  1438.                             toast_translating_tryanother:       "Prova un altro traduttore",
  1439.                             translated_watermark:               "tradotto"
  1440.                         };
  1441.                     case "ja":      // Japanese
  1442.                         return {
  1443.                             context_translator:                 "翻訳を検索",
  1444.                             context_messagetranslateoption:     "メッセージの翻訳",
  1445.                             context_messageuntranslateoption:   "メッセージの翻訳解除",
  1446.                             popout_translateoption:             "翻訳する",
  1447.                             popout_untranslateoption:           "翻訳しない",
  1448.                             toast_translating:                  "翻訳",
  1449.                             toast_translating_failed:           "翻訳に失敗しました",
  1450.                             toast_translating_tryanother:       "別の翻訳者を試す",
  1451.                             translated_watermark:               "翻訳済み"
  1452.                         };
  1453.                     case "ko":      // Korean
  1454.                         return {
  1455.                             context_translator:                 "번역 검색",
  1456.                             context_messagetranslateoption:     "메시지 번역",
  1457.                             context_messageuntranslateoption:   "메시지 번역 취소",
  1458.                             popout_translateoption:             "옮기다",
  1459.                             popout_untranslateoption:           "번역 취소",
  1460.                             toast_translating:                  "번역 중",
  1461.                             toast_translating_failed:           "번역하지 못했습니다.",
  1462.                             toast_translating_tryanother:       "다른 번역기 시도",
  1463.                             translated_watermark:               "번역"
  1464.                         };
  1465.                     case "lt":      // Lithuanian
  1466.                         return {
  1467.                             context_translator:                 "Paieškos vertimas",
  1468.                             context_messagetranslateoption:     "Versti pranešimą",
  1469.                             context_messageuntranslateoption:   "Išversti pranešimą",
  1470.                             popout_translateoption:             "Išversti",
  1471.                             popout_untranslateoption:           "Neišversti",
  1472.                             toast_translating:                  "Vertimas",
  1473.                             toast_translating_failed:           "Nepavyko išversti",
  1474.                             toast_translating_tryanother:       "Išbandykite kitą vertėją",
  1475.                             translated_watermark:               "išverstas"
  1476.                         };
  1477.                     case "nl":      // Dutch
  1478.                         return {
  1479.                             context_translator:                 "Zoek vertaling",
  1480.                             context_messagetranslateoption:     "Bericht vertalen",
  1481.                             context_messageuntranslateoption:   "Bericht onvertalen",
  1482.                             popout_translateoption:             "Vertalen",
  1483.                             popout_untranslateoption:           "Onvertalen",
  1484.                             toast_translating:                  "Vertalen",
  1485.                             toast_translating_failed:           "Kan niet vertalen",
  1486.                             toast_translating_tryanother:       "Probeer een andere vertaler",
  1487.                             translated_watermark:               "vertaald"
  1488.                         };
  1489.                     case "no":      // Norwegian
  1490.                         return {
  1491.                             context_translator:                 "Søk i oversettelse",
  1492.                             context_messagetranslateoption:     "Oversett melding",
  1493.                             context_messageuntranslateoption:   "Ikke oversett melding",
  1494.                             popout_translateoption:             "Oversette",
  1495.                             popout_untranslateoption:           "Ikke oversett",
  1496.                             toast_translating:                  "Oversetter",
  1497.                             toast_translating_failed:           "Kunne ikke oversette",
  1498.                             toast_translating_tryanother:       "Prøv en annen oversetter",
  1499.                             translated_watermark:               "oversatt"
  1500.                         };
  1501.                     case "pl":      // Polish
  1502.                         return {
  1503.                             context_translator:                 "Wyszukaj tłumaczenie",
  1504.                             context_messagetranslateoption:     "Przetłumacz wiadomość",
  1505.                             context_messageuntranslateoption:   "Nieprzetłumacz wiadomość",
  1506.                             popout_translateoption:             "Tłumaczyć",
  1507.                             popout_untranslateoption:           "Nie przetłumacz",
  1508.                             toast_translating:                  "Tłumaczenie",
  1509.                             toast_translating_failed:           "Nie udało się przetłumaczyć",
  1510.                             toast_translating_tryanother:       "Wypróbuj innego tłumacza",
  1511.                             translated_watermark:               "przetłumaczony"
  1512.                         };
  1513.                     case "pt-BR":   // Portuguese (Brazil)
  1514.                         return {
  1515.                             context_translator:                 "Tradução de pesquisa",
  1516.                             context_messagetranslateoption:     "Traduzir mensagem",
  1517.                             context_messageuntranslateoption:   "Mensagem não traduzida",
  1518.                             popout_translateoption:             "Traduzir",
  1519.                             popout_untranslateoption:           "Não traduzido",
  1520.                             toast_translating:                  "Traduzindo",
  1521.                             toast_translating_failed:           "Falha ao traduzir",
  1522.                             toast_translating_tryanother:       "Tente outro tradutor",
  1523.                             translated_watermark:               "traduzido"
  1524.                         };
  1525.                     case "ro":      // Romanian
  1526.                         return {
  1527.                             context_translator:                 "Căutare traducere",
  1528.                             context_messagetranslateoption:     "Traduceți mesajul",
  1529.                             context_messageuntranslateoption:   "Untraduceți mesajul",
  1530.                             popout_translateoption:             "Traduceți",
  1531.                             popout_untranslateoption:           "Netradus",
  1532.                             toast_translating:                  "Traducere",
  1533.                             toast_translating_failed:           "Nu s-a putut traduce",
  1534.                             toast_translating_tryanother:       "Încercați un alt traducător",
  1535.                             translated_watermark:               "tradus"
  1536.                         };
  1537.                     case "ru":      // Russian
  1538.                         return {
  1539.                             context_translator:                 "Искать перевод",
  1540.                             context_messagetranslateoption:     "Перевести сообщение",
  1541.                             context_messageuntranslateoption:   "Непереведенное сообщение",
  1542.                             popout_translateoption:             "Переведите",
  1543.                             popout_untranslateoption:           "Неперевести",
  1544.                             toast_translating:                  "Идет перевод",
  1545.                             toast_translating_failed:           "Не удалось перевести",
  1546.                             toast_translating_tryanother:       "Попробуйте другой переводчик",
  1547.                             translated_watermark:               "переведено"
  1548.                         };
  1549.                     case "sv":      // Swedish
  1550.                         return {
  1551.                             context_translator:                 "Sök översättning",
  1552.                             context_messagetranslateoption:     "Översätt meddelande",
  1553.                             context_messageuntranslateoption:   "Untranslate meddelande",
  1554.                             popout_translateoption:             "Översätt",
  1555.                             popout_untranslateoption:           "Untranslate",
  1556.                             toast_translating:                  "Översätter",
  1557.                             toast_translating_failed:           "Det gick inte att översätta",
  1558.                             toast_translating_tryanother:       "Prova en annan översättare",
  1559.                             translated_watermark:               "översatt"
  1560.                         };
  1561.                     case "th":      // Thai
  1562.                         return {
  1563.                             context_translator:                 "ค้นหาคำแปล",
  1564.                             context_messagetranslateoption:     "แปลข้อความ",
  1565.                             context_messageuntranslateoption:   "ยกเลิกการแปลข้อความ",
  1566.                             popout_translateoption:             "แปลภาษา",
  1567.                             popout_untranslateoption:           "ไม่แปล",
  1568.                             toast_translating:                  "กำลังแปล",
  1569.                             toast_translating_failed:           "แปลไม่สำเร็จ",
  1570.                             toast_translating_tryanother:       "ลองใช้นักแปลคนอื่น",
  1571.                             translated_watermark:               "แปล"
  1572.                         };
  1573.                     case "tr":      // Turkish
  1574.                         return {
  1575.                             context_translator:                 "Çeviri ara",
  1576.                             context_messagetranslateoption:     "Mesajı Çevir",
  1577.                             context_messageuntranslateoption:   "Çeviriyi Kaldır Mesajı",
  1578.                             popout_translateoption:             "Çevirmek",
  1579.                             popout_untranslateoption:           "Çevirmeyi kaldır",
  1580.                             toast_translating:                  "Çeviri",
  1581.                             toast_translating_failed:           "Tercüme edilemedi",
  1582.                             toast_translating_tryanother:       "Başka bir Çevirmen deneyin",
  1583.                             translated_watermark:               "tercüme"
  1584.                         };
  1585.                     case "uk":      // Ukrainian
  1586.                         return {
  1587.                             context_translator:                 "Пошук перекладу",
  1588.                             context_messagetranslateoption:     "Перекласти повідомлення",
  1589.                             context_messageuntranslateoption:   "Неперекладене повідомлення",
  1590.                             popout_translateoption:             "Перекласти",
  1591.                             popout_untranslateoption:           "Неперекласти",
  1592.                             toast_translating:                  "Переклад",
  1593.                             toast_translating_failed:           "Не вдалося перекласти",
  1594.                             toast_translating_tryanother:       "Спробуйте іншого перекладача",
  1595.                             translated_watermark:               "переклав"
  1596.                         };
  1597.                     case "vi":      // Vietnamese
  1598.                         return {
  1599.                             context_translator:                 "Tìm kiếm bản dịch",
  1600.                             context_messagetranslateoption:     "Dịch tin nhắn",
  1601.                             context_messageuntranslateoption:   "Thư chưa dịch",
  1602.                             popout_translateoption:             "Phiên dịch",
  1603.                             popout_untranslateoption:           "Chưa dịch",
  1604.                             toast_translating:                  "Phiên dịch",
  1605.                             toast_translating_failed:           "Không dịch được",
  1606.                             toast_translating_tryanother:       "Thử một Trình dịch khác",
  1607.                             translated_watermark:               "đã dịch"
  1608.                         };
  1609.                     case "zh-CN":   // Chinese (China)
  1610.                         return {
  1611.                             context_translator:                 "搜索翻译",
  1612.                             context_messagetranslateoption:     "翻译消息",
  1613.                             context_messageuntranslateoption:   "取消翻译消息",
  1614.                             popout_translateoption:             "翻译",
  1615.                             popout_untranslateoption:           "取消翻译",
  1616.                             toast_translating:                  "正在翻译",
  1617.                             toast_translating_failed:           "翻译失败",
  1618.                             toast_translating_tryanother:       "尝试其他翻译器",
  1619.                             translated_watermark:               "已翻译"
  1620.                         };
  1621.                     case "zh-TW":   // Chinese (Taiwan)
  1622.                         return {
  1623.                             context_translator:                 "搜索翻譯",
  1624.                             context_messagetranslateoption:     "翻譯訊息",
  1625.                             context_messageuntranslateoption:   "取消翻譯訊息",
  1626.                             popout_translateoption:             "翻譯",
  1627.                             popout_untranslateoption:           "取消翻譯",
  1628.                             toast_translating:                  "正在翻譯",
  1629.                             toast_translating_failed:           "翻譯失敗",
  1630.                             toast_translating_tryanother:       "嘗試其他翻譯器",
  1631.                             translated_watermark:               "已翻譯"
  1632.                         };
  1633.                     default:        // English
  1634.                         return {
  1635.                             context_translator:                 "Search Translation",
  1636.                             context_messagetranslateoption:     "Translate Message",
  1637.                             context_messageuntranslateoption:   "Untranslate Message",
  1638.                             popout_translateoption:             "Translate",
  1639.                             popout_untranslateoption:           "Untranslate",
  1640.                             toast_translating:                  "Translating",
  1641.                             toast_translating_failed:           "Failed to translate",
  1642.                             toast_translating_tryanother:       "Try another Translator",
  1643.                             translated_watermark:               "translated"
  1644.                         };
  1645.                 }
  1646.             }
  1647.         };
  1648.     })(window.BDFDB_Global.PluginUtils.buildPlugin(config));
  1649. })();
  1650.  
RAW Paste Data