Advanced Telegram Web translator with Matrix-style UI, instant language switching & smart cache. Developed by Fer3on_Mod
// ==UserScript==
// @name 🌐 Telegram Translator Pro — Matrix Edition v4.5
// @namespace Fer3on_Mod
// @version 4.5
// @description Advanced Telegram Web translator with Matrix-style UI, instant language switching & smart cache. Developed by Fer3on_Mod
// @author Fer3on_Mod
// @match https://web.telegram.org/k/*
// @license MIT
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @connect translate.googleapis.com
// ==/UserScript==
(function () {
"use strict";
// 💠 Styles
GM_addStyle(`
#tg-translator-panel {
position: fixed;
right: 18px;
bottom: 18px;
z-index: 2147483647;
font-family: "Segoe UI", system-ui, sans-serif;
user-select: none;
color: #dfffe6;
}
#tg-panel-toggle {
width: 60px;
height: 60px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
background: radial-gradient(circle at 30% 30%, #00ff99 0%, #0066ff 100%);
color: white;
box-shadow: 0 0 25px rgba(0, 255, 136, 0.7);
cursor: pointer;
transition: all 0.2s ease;
}
#tg-panel-toggle:hover { transform: scale(1.1); filter: brightness(1.2); }
#tg-panel {
position: fixed;
right: 18px;
bottom: 18px;
width: 280px;
background: linear-gradient(180deg, #060a0d, #0a1418);
border-radius: 14px;
color: #dfffe6;
box-shadow: 0 0 25px rgba(0, 255, 136, 0.2);
padding: 16px;
display: none;
backdrop-filter: blur(8px);
border: 1px solid rgba(0, 255, 136, 0.08);
animation: slideIn 0.25s ease forwards;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
#tg-close-btn {
position: absolute;
top: -10px;
left: -10px;
width: 28px;
height: 28px;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, #00ff99, #0066ff);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #000;
cursor: pointer;
box-shadow: 0 0 15px rgba(0,255,136,0.6);
transition: transform 0.15s ease;
}
#tg-close-btn:hover { transform: scale(1.1); }
#tg-panel h3 {
margin-top: 0;
text-align: center;
color: #00ff88;
font-weight: 600;
letter-spacing: 0.5px;
margin-bottom: 10px;
}
.tg-row { display: flex; flex-direction: column; gap: 5px; margin: 10px 0; }
.tg-select, .tg-input {
width: 100%;
padding: 8px;
border-radius: 8px;
background: rgba(0,255,136,0.05);
border: 1px solid rgba(0,255,136,0.15);
color: #eaffea;
font-size: 13px;
outline: none;
}
.tg-select option { background: #071018; color: #eaffea; }
.tg-btn {
width: 100%;
padding: 8px;
margin-top: 8px;
border-radius: 10px;
background: linear-gradient(90deg,#0a1f1f,#002244);
border: 1px solid rgba(0,255,136,0.2);
cursor: pointer;
color: #dfffe6;
font-size: 13px;
transition: all 0.15s ease;
}
.tg-btn:hover { filter: brightness(1.3); }
.tg-btn.positive { background: linear-gradient(90deg,#00c853,#0091ea); box-shadow: 0 0 10px rgba(0,255,136,0.3); }
/* Switch style */
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 26px;
}
.switch input { opacity: 0; width: 0; height: 0; }
.slider {
position: absolute;
cursor: pointer;
top: 0; left: 0; right: 0; bottom: 0;
background-color: #555;
transition: .3s;
border-radius: 26px;
}
.slider:before {
position: absolute;
content: "";
height: 20px; width: 20px;
left: 3px; bottom: 3px;
background-color: white;
transition: .3s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #00ff88;
box-shadow: 0 0 10px rgba(0,255,136,0.4);
}
input:checked + .slider:before {
transform: translateX(24px);
}
.tg-footer {
margin-top: 12px;
text-align: center;
font-size: 12px;
opacity: 0.8;
}
.tg-footer a { color: #00ff88; text-decoration: none; font-weight: 600; }
`);
// 🌐 Panel HTML
const panelWrap = document.createElement("div");
panelWrap.id = "tg-translator-panel";
panelWrap.innerHTML = `
<div id="tg-panel-toggle" title="Open Translator Menu">🌐</div>
<div id="tg-panel" role="dialog" aria-label="Translator Pro Settings">
<div id="tg-close-btn">✕</div>
<h3>Translator Pro Settings</h3>
<div class="tg-row">
<label>Language:</label>
<select id="tg-lang-select" class="tg-select">
<option value="ar">Arabic</option>
<option value="en">English</option>
<option value="fr">French</option>
<option value="es">Spanish</option>
<option value="de">German</option>
<option value="ru">Russian</option>
<option value="zh-CN">Chinese (Simplified)</option>
<option value="ja">Japanese</option>
<option value="it">Italian</option>
<option value="pt">Portuguese</option>
<option value="tr">Turkish</option>
<option value="ko">Korean</option>
<option value="hi">Hindi</option>
<option value="nl">Dutch</option>
<option value="sv">Swedish</option>
<option value="pl">Polish</option>
<option value="uk">Ukrainian</option>
<option value="id">Indonesian</option>
<option value="th">Thai</option>
<option value="fa">Persian</option>
<option value="he">Hebrew</option>
<option value="vi">Vietnamese</option>
<option value="ro">Romanian</option>
<option value="cs">Czech</option>
<option value="fi">Finnish</option>
<option value="el">Greek</option>
</select>
</div>
<div class="tg-row">
<label><input type="checkbox" id="tg-auto-detect"> Auto-detect Source Language</label>
<label>Enable Translation:
<label class="switch">
<input type="checkbox" id="tg-enabled">
<span class="slider"></span>
</label>
</label>
</div>
<button id="tg-clear-btn" class="tg-btn">🧹 Clear Cache</button>
<div class="tg-footer">
<a href="https://t.me/Fer3on_Mod" target="_blank">Developer: Fer3on_Mod</a>
<div>v4.4 — Matrix Edition</div>
</div>
</div>
`;
document.body.appendChild(panelWrap);
// 🎛️ DOM refs
const toggleBtn = document.getElementById("tg-panel-toggle");
const panel = document.getElementById("tg-panel");
const closeBtn = document.getElementById("tg-close-btn");
const langSelect = document.getElementById("tg-lang-select");
const autoDetectInput = document.getElementById("tg-auto-detect");
const enableInput = document.getElementById("tg-enabled");
const clearBtn = document.getElementById("tg-clear-btn");
// ⚙️ Load Settings
let state = {
targetLang: localStorage.getItem("tg_target_lang") || "ar",
autoDetect: localStorage.getItem("tg_auto_detect") === "true",
enabled: localStorage.getItem("tg_enabled") !== "false"
};
langSelect.value = state.targetLang;
autoDetectInput.checked = state.autoDetect;
enableInput.checked = state.enabled;
// 🧩 Panel toggle behavior
toggleBtn.onclick = () => {
panel.style.display = "block";
toggleBtn.style.display = "none";
};
closeBtn.onclick = () => {
panel.style.display = "none";
toggleBtn.style.display = "flex";
};
// ⚡ Instant apply language change
langSelect.onchange = () => {
state.targetLang = langSelect.value;
localStorage.setItem("tg_target_lang", state.targetLang);
};
// ⚡ Instant toggle
enableInput.onchange = () => {
state.enabled = enableInput.checked;
localStorage.setItem("tg_enabled", state.enabled);
if (!state.enabled) removeAllTranslations();
};
autoDetectInput.onchange = () => {
state.autoDetect = autoDetectInput.checked;
localStorage.setItem("tg_auto_detect", state.autoDetect);
};
clearBtn.onclick = () => {
translateCache.clear();
alert("🧹 Cache cleared");
};
// 💾 Cache
const translateCache = new Map();
// 🧠 Translation Engine
function translateText(text) {
return new Promise((resolve) => {
if (!state.enabled) return resolve(null);
if (!text.trim() || text.length < 3) return resolve(null);
if (/^[0-9:\s]+$/.test(text)) return resolve(null);
if (translateCache.has(text)) return resolve(translateCache.get(text));
const sl = state.autoDetect ? "auto" : "en";
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${sl}&tl=${state.targetLang}&dt=t&q=${encodeURIComponent(text)}`;
GM_xmlhttpRequest({
method: "GET",
url,
onload: (res) => {
try {
const result = JSON.parse(res.responseText);
const translated = result[0].map(t => t[0]).join("");
translateCache.set(text, translated);
resolve(translated);
} catch {
resolve(null);
}
},
onerror: () => resolve(null)
});
});
}
// 🧩 Render translation
function renderTranslation(el, translated) {
if (!el || !translated) return;
if (el.querySelector(".tg-translated-text")) return;
const div = document.createElement("div");
div.className = "tg-translated-text";
div.textContent = translated;
div.style.marginTop = "6px";
div.style.color = "#00ff88";
div.style.fontSize = "0.88em";
el.appendChild(div);
}
// ❌ Remove all translations
function removeAllTranslations() {
document.querySelectorAll(".tg-translated-text").forEach(el => el.remove());
}
// 🔁 Observe messages
const observer = new MutationObserver((mutations) => {
if (!state.enabled) return;
mutations.forEach((m) => {
m.addedNodes.forEach(async (node) => {
if (node.nodeType === 1 && node.querySelector) {
const msg = node.querySelector(".text-content, .message, .message_text, .text-content-inner");
if (msg && !msg.querySelector(".tg-translated-text")) {
const text = msg.innerText.trim();
const translated = await translateText(text);
if (translated && translated !== text) renderTranslation(msg, translated);
}
}
});
});
});
const container = document.querySelector("#column-center, .messages-container, body");
if (container) observer.observe(container, { childList: true, subtree: true });
})();