Translator | 2026

Chat Translation Assistant

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name             Translator | 2026
// @namespace        https://github.com/GameSketchers
// @version          0.1
// @description      Chat Translation Assistant
// @description:tr   Sohbet Çeviri Yardımcısı
// @description:pt   Assistente de Tradução de Chat
// @description:ru   Помощник перевода чата
// @description:es   Asistente de Traducción de Chat
// @description:fr   Assistant de Traduction de Chat
// @description:de   Chat-Übersetzungsassistent
// @description:ja   チャット翻訳アシスタント
// @description:ko   채팅 번역 도우미
// @description:zh   聊天翻译助手
// @description:ar   مساعد ترجمة الدردشة
// @author           Qwyua
// @match            *://gartic.io/*
// @run-at           document-end
// @grant            unsafeWindow
// @grant            GM_xmlhttpRequest
// @connect          translate.googleapis.com
// @license          MIT
// ==/UserScript==
// obsolescencethysen istegi uzerine
/gartic\.io$/.test(location.host)&&(()=>{
    const onElementAdded4=(s,c,m=1)=>{let o,d=0,p=e=>(d||c(e),m||(d=1,o?.disconnect())),t=()=>{o?.disconnect(),d=0,o=new MutationObserver(r=>{for(let i=0;i<r.length;i++)for(let n of r[i].addedNodes)n.nodeType===1&&(n.matches?.(s)?p(n):(n.querySelector?.(s)&&p(n.querySelector(s))))}),o.observe(document.documentElement,{childList:1,subtree:1});document.querySelector(s)&&p(document.querySelector(s))};t();return{stop:()=>(o?.disconnect(),d=1),start:()=>(o?.disconnect(),t()),get active(){return!d}}};
    ;(o=>o[Object.keys(o).find(k=>location.href.includes(k))]?.())({
        gartic:()=>{
            new class{
                constructor(){
                    const w=unsafeWindow
                    this._translator=w._translator||(w._translator={})
                    Object.defineProperty(this._translator,"self",{value:this,enumerable:0,configurable:1,writable:1})
                    onElementAdded4("div#screenRoom",e=>{let g,c,k,f=n=>n&&!g&&(n.tag==1&&(c=n.stateNode?.props?.children?.[0]?._owner?.stateNode)&&(g=this._translator._game=c._game)&&(g._chat=c._chatElem,this.joinedRoom(g)),!g&&f(n.child));for(k in e)/^__r/.test(k)&&f(e[k])},1)
                    this.langs={
                        "none": "Off",
                        "en": "English",
                        "tr": "Türkçe",
                        "pt": "Português",
                        "ru": "Русский",
                        "es": "Español",
                        "fr": "Français",
                        "de": "Deutsch",
                        "it": "Italiano",
                        "zh": "中文",
                        "hi": "हिन्दी",
                        "ar": "العربية",
                        "bn": "বাংলা",
                        "ja": "日本語",
                        "ko": "한국어"
                    }
                    this.readLanguage=localStorage.getItem("readLanguage")||"auto"
                    this.seenLanguage=localStorage.getItem("seenLanguage")||(navigator.language||navigator.userLanguage)
                    this.sendLanguage=localStorage.getItem("sendLanguage")||"none"
                    this.translateActive=!1
                    this.smartMode=1
                    this.spamDejected=0
                    this.messageQueue = [];
                }
                isOnlySymbols = (msg) => !/[\p{L}\p{N}]/u.test(msg);
                async translate(MMq,tLang,rLang) {
                    const isArray = Array.isArray(MMq);
                    const query = isArray?MMq.map(m=>encodeURIComponent(m)).join('&q='):encodeURIComponent(MMq);
                    const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${rLang||"auto"}&tl=${tLang}&dt=t&q=${query}`;
                    return new Promise(resolve=>{
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: url,
                            onload:(x)=>{
                                const data=JSON.parse(x.responseText);
                                isArray&&(resolve(data[0].map(item=>item[0])),0);
                                !isArray&&(()=>{
                                    const result=data[2]==this.readLanguage?MMq:data[0][0][0];
                                    const fail=!result&&this.translateActive;
                                    this.spamDejected=fail?this.spamDejected+1:0;
                                    (fail&&this.spamDejected>=5)&&(document.querySelector("#Translation button").click(),this.spamDejected=0);
                                    resolve(result||MMq);
                                })();
                            },
                            onerror:()=>resolve(MMq)
                        });
                    });
                }
                async joinedRoom(){
                    onElementAdded4("#chat h5",h5=>{document.getElementById('TranslationTrigger')||(this.h5=h5,this.injectHTML())},0);
                    this.timeoutId = null;
                    this.addCHATMessage = this._translator._game._socket._callbacks["$11"][0].bind(this._translator._game._socket._callbacks["$11"][0]);
                    this._translator._game._socket._callbacks["$11"][0]=async(playerID,message)=>{
                        this.isOnlySymbols(message)||message.length<5||this._translator._game._id==playerID||!this.translateActive||this.sendLanguage=="auto"||this.seenLanguage=='none'?this.addCHATMessage(playerID,message):(
                            this.messageQueue.push({playerID,message}),
                            this.timeoutId && clearTimeout(this.timeoutId),
                            this.timeoutId=setTimeout(async()=>{
                                const translated = await this.translate(this.messageQueue.map(m=>m.message),this.seenLanguage);
                                this.messageQueue.forEach((q,w)=>this.addCHATMessage(q.playerID,translated[w]||q.message));
                                this.messageQueue=[];
                                this.timeoutId=null;
                            },600)
                        );
                    };
                    this.sendMessageCHAT=this._translator._game.message.bind(this._translator._game);
                    this._translator._game.message=async(t)=>{
                        this.isOnlySymbols(t)||!this.translateActive||this.sendLanguage=="auto"||this.sendLanguage=='none'?this.sendMessageCHAT(t):(async()=>{
                            const Mq=await this.translate(t,this.sendLanguage);
                            this.sendMessageCHAT(this.smartMode?this.simplifyText(Mq):Mq);
                        })()
                    }
                }
                syncPos=()=>{const{bottom:b,right:r}=this.h5.getBoundingClientRect();Object.assign(this.control.style,{top:`${b+8}px`,left:`${r-190}px`})};
                setLanguage=(q,w)=>{this[q+"Language"]=w;localStorage.setItem(q+"Language",w)};
                startStopTranslation(q){this.translateActive=q.classList.toggle('active');q.textContent=this.translateActive?'ON':'OFF'}
                switchSmartMode(q){this.smartMode=q.classList.toggle('active');q.textContent=this.smartMode?'ON':'OFF'}
                simplifyText(m){
                    let t=m.toLowerCase().replace(/[!?.,;:()\[\]{}"']/g,'');
                    const s={you:'u',are:'re',your:'ur',"you're":'ur',because:'cuz',please:'pls',thanks:'thx',language:'lang',okay:'ok'};
                    Object.entries(s).forEach(([k,v])=>t=t.replace(new RegExp(`\\b${k}\\b`,'g'),v));
                    return t;
                }
                injectHTML() {
                    this.trigger = Object.assign(document.createElement('span'),{
                        id: 'TranslationTrigger',
                        textContent: '\uE941',
                        onclick:e=>{e.stopPropagation();this.control.style.display=this.control.style.display==='block'?'none':(this.syncPos(),'block')},
                        style: 'font-family:ico;color:#3080cb;cursor:pointer;margin-left:8px;font-size:15px;vertical-align:middle;display:inline-block;transform:rotate(20deg)'
                    });
                    this.h5.appendChild(this.trigger);
                    this.control = Object.assign(document.createElement('div'),{
                        id:'Translation',
                        onchange:(q)=>{this._translator?.self.setLanguage(q.target.id,q.target.value)},
                        innerHTML: `<style>#Translation{position:fixed;display:none;background:#11223e;border:2px solid #234476;border-radius:6px;padding:12px;width:190px;z-index:9e6;box-shadow:0 6px 20px #000;box-sizing:border-box;font-family:sans-serif}#Translation div{display:flex;align-items:center;margin-bottom:5px;gap:8px}#Translation label{font-size:12px;font-weight:700;color:#8bb4e7;width:45px;flex-shrink:0}#Translation div div{display:flex;flex:1;gap:4px}#Translation select{background:#1b335a;border:1px solid #2d558d;color:#fff;border-radius:4px;font-size:12px;padding:4px;width:100%;cursor:pointer;outline:none}#Translation button{width:100%;padding:7px;border:none;border-radius:4px;font-weight:900;font-size:12px;cursor:pointer;color:#fff;transition:transform .1s;background:#ef4444;box-shadow:0 2px 0 #dc2626}#Translation button.active{background:#22c55e;box-shadow:0 2px 0 #16a34a}#Translation button:first-of-type:not(.active)~div{opacity:.5}#Translation button:active{transform:scale(.97)}</style><button onclick="_translator.self.startStopTranslation(this)" style="margin-bottom:8px">OFF</button><div><label>RECV</label><div><select id="read" style="display:none"></select><select id="seen"></select></div></div><div><label>SEND</label><div><select id="send"></select></div></div><div><label>SMART MODE</label><button onclick="_translator.self.switchSmartMode(this)" class="active" style="width:unset">ON</button></div>`
                        });
                    document.body.appendChild(this.control);
                    this.control.querySelectorAll('select').forEach(q=>{q.innerHTML=Object.entries(this.langs).map(([k,v])=>`<option ${k===this[`${q.id}Language`]?'selected':''} value=${k}>${v}</option>`).join('')});
                    document.addEventListener('mousedown',e=>{!this.control.contains(e.target)&&e.target!==this.trigger&&(this.control.style.display='none')});
                    window.addEventListener('resize',()=>this.control.style.display=='block'&&this.syncPos());
                }
            }
        }
    });
})();