Press Alt+X to toggle between original and Google-translated page.
// ==UserScript==
// @name Translate Website (Alt+X)
// @namespace https://github.com/zyrocossol11/Translate-Websites-Userscript
// @version 2.1.0
// @description Press Alt+X to toggle between original and Google-translated page.
// @match http://*/*
// @match https://*/*
// @run-at document-start
// @grant GM_registerMenuCommand
// @grant GM_getValue
// @grant GM_setValue
// @noframes
// ==/UserScript==
(() => {
'use strict';
const STORAGE_KEY = 'translate_toggle_target_lang';
const DEFAULT_LANG = 'en';
const TRANSLATE_BASE = 'https://translate.google.com/translate';
const PRESET_LANGS = [
{ label: 'English (en)', code: 'en' },
{ label: 'Español (es)', code: 'es' },
{ label: 'Français (fr)', code: 'fr' },
{ label: 'Deutsch (de)', code: 'de' },
{ label: 'Português (pt)', code: 'pt' },
{ label: 'Русский (ru)', code: 'ru' },
{ label: '日本語 (ja)', code: 'ja' },
{ label: '한국어 (ko)', code: 'ko' },
{ label: '简体中文 (zh-CN)', code: 'zh-CN' },
{ label: '繁體中文 (zh-TW)', code: 'zh-TW' },
{ label: 'العربية (ar)', code: 'ar' },
];
let targetLang = DEFAULT_LANG;
const setLang = (code) => {
targetLang = code;
try {
const r = typeof GM_setValue === 'function' ? GM_setValue(STORAGE_KEY, code) : null;
if (r && typeof r.then === 'function') r.catch(() => {});
console.info(`[Translate Toggle] Language set to ${code}`);
} catch {}
};
const loadLang = () => {
try {
const v = typeof GM_getValue === 'function' ? GM_getValue(STORAGE_KEY, DEFAULT_LANG) : DEFAULT_LANG;
if (v && typeof v.then === 'function') {
v.then((val) => (targetLang = val || DEFAULT_LANG)).catch(() => {});
} else {
targetLang = v || DEFAULT_LANG;
}
} catch {
targetLang = DEFAULT_LANG;
}
};
loadLang();
const isEditable = (el) => {
if (!el) return false;
if (el.isContentEditable) return true;
const tag = (el.tagName || '').toUpperCase();
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;
if (tag === 'DIV' && el.getAttribute('role') === 'textbox') return true;
return false;
};
const isOnGoogleTranslate = (urlObj) => {
const host = urlObj.hostname;
return (
/^translate\.google\./i.test(host) ||
/(^|\.)translate\.goog$/i.test(host) ||
/translate\.googleusercontent\.com$/i.test(host)
);
};
const extractOriginalFromTranslateURL = (urlObj) => {
const params = urlObj.searchParams;
for (const name of ['u', 'url', 'q']) {
const val = params.get(name);
if (val) return val;
}
return '';
};
const buildTranslateUrl = (originalUrl, lang) =>
`${TRANSLATE_BASE}?sl=auto&tl=${encodeURIComponent(lang)}&hl=${encodeURIComponent(lang)}&u=${encodeURIComponent(originalUrl)}`;
const toggleTranslate = () => {
const here = new URL(location.href);
if (isOnGoogleTranslate(here)) {
const original = extractOriginalFromTranslateURL(here);
if (original) {
location.assign(original);
return;
}
const canonical = document.querySelector('link[rel="canonical"]')?.href;
if (canonical) {
try {
const ch = new URL(canonical).hostname;
if (!/translate\./i.test(ch)) {
location.assign(canonical);
return;
}
} catch {}
}
if (history.length > 1) {
history.back();
} else {
console.warn('[Translate Toggle] Could not find original URL.');
}
} else {
const to = buildTranslateUrl(location.href, targetLang);
location.assign(to);
}
};
const chooseLanguage = () => {
const list = PRESET_LANGS.map((o, i) => `${i + 1}. ${o.label}`).join('\n');
const input = prompt(
`Choose target language (type number or code)\nCurrent: ${targetLang}\n\n${list}\n\nOr enter any language code (e.g., en, es, fr, de, ja, zh-CN):`,
targetLang
);
if (!input) return;
const trimmed = input.trim();
const idx = Number(trimmed);
if (Number.isInteger(idx) && idx >= 1 && idx <= PRESET_LANGS.length) {
setLang(PRESET_LANGS[idx - 1].code);
} else {
setLang(trimmed);
}
};
window.addEventListener(
'keydown',
(e) => {
if (
e.altKey &&
!e.ctrlKey &&
!e.metaKey &&
!e.shiftKey &&
!e.repeat &&
String(e.key).toLowerCase() === 'x' &&
!isEditable(e.target)
) {
e.preventDefault();
toggleTranslate();
}
},
true
);
if (typeof GM_registerMenuCommand === 'function') {
GM_registerMenuCommand('Toggle translate (Alt+X)', toggleTranslate);
GM_registerMenuCommand('Set language…', chooseLanguage);
}
})();