您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Disables Reddit's auto-translation feature and removes Google translation parameters
// ==UserScript== // @name Reddit Auto-Translation Disabler // @namespace http://tampermonkey.net/ // @version 1.2 // @description Disables Reddit's auto-translation feature and removes Google translation parameters // @author NagaYZ // @match *://www.reddit.com/* // @match *://reddit.com/* // @grant none // @run-at document-start // @license MIT // ==/UserScript== (function() { 'use strict'; // Remove Google translation parameter from URL function removeTranslationParam() { const url = new URL(window.location.href); if (url.searchParams.has('tl')) { url.searchParams.delete('tl'); window.location.replace(url.toString()); return true; } return false; } // Check and remove translation parameter immediately if (removeTranslationParam()) { // Exit early if we're reloading to avoid running the rest of the script return; } // Flag to prevent infinite recursion let settingCookie = false; // Function to set the translation cookie function setTranslationCookie() { if (settingCookie) return; settingCookie = true; const cookieValue = JSON.stringify({ shouldDisplayCoachmark: false, shouldDisplayFeedbackCoachmark: false, coachmarkDisplayCount: 999, showCommentTranslationModal: false, showPostTranslationModal: false, isTranslationActive: false, translationEnabled: false, autoTranslate: false }); document.cookie = `reddit_translation_status=${encodeURIComponent(cookieValue)}; path=/; domain=.reddit.com; max-age=31536000; SameSite=Lax`; settingCookie = false; } // Set cookie immediately setTranslationCookie(); // Intercept cookie modifications const originalCookieSetter = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie').set; const originalCookieGetter = Object.getOwnPropertyDescriptor(Document.prototype, 'cookie').get; Object.defineProperty(document, 'cookie', { set: function(value) { // Only intercept if we're not already setting the cookie and it's a translation cookie if (!settingCookie && value.includes('reddit_translation_status')) { // Check if it's trying to enable translation if (value.includes('isTranslationActive":true') || value.includes('translationEnabled":true') || value.includes('autoTranslate":true')) { // Set our disabled version instead setTranslationCookie(); return; } } return originalCookieSetter.call(document, value); }, get: function() { return originalCookieGetter.call(document); } }); // Intercept fetch requests to block translation-related API calls const originalFetch = window.fetch; window.fetch = function(...args) { const url = args[0]; // Block translation-related GraphQL requests if (typeof url === 'string' && url.includes('/svc/shreddit/graphql')) { try { const body = args[1]?.body; if (body && (body.includes('translate') || body.includes('translation'))) { // Return a fake successful response return Promise.resolve(new Response('{}', { status: 200, headers: { 'Content-Type': 'application/json' } })); } } catch (e) { // Continue with normal fetch if there's an error } } return originalFetch.apply(this, args); }; // Intercept XMLHttpRequest as well const originalXHRSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function(data) { if (this._url && this._url.includes('/svc/shreddit/graphql')) { try { if (data && (data.includes('translate') || data.includes('translation'))) { // Don't send the request this.abort(); return; } } catch (e) { // Continue normally if there's an error } } return originalXHRSend.apply(this, arguments); }; const originalXHROpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { this._url = url; return originalXHROpen.apply(this, arguments); }; // Override localStorage translation settings function overrideTranslationSettings() { try { const settings = { translationEnabled: false, autoTranslate: false, translationLanguage: null, isTranslationActive: false }; // Check for any translation-related keys and override them for (let key in localStorage) { if (key.toLowerCase().includes('translat')) { localStorage.setItem(key, JSON.stringify(settings)); } } } catch (e) { // Ignore errors } } // Run when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', overrideTranslationSettings); } else { overrideTranslationSettings(); } // Periodically check and disable translation setInterval(() => { setTranslationCookie(); overrideTranslationSettings(); // Also try to find and disable any translation toggles in the UI try { const translationToggles = document.querySelectorAll('[aria-label*="translat"], [data-testid*="translat"], button[class*="translat"]'); translationToggles.forEach(toggle => { if (toggle.getAttribute('aria-checked') === 'true' || toggle.classList.contains('active')) { toggle.click(); } }); } catch (e) { // Ignore errors } }, 5000); // Mutation observer to catch dynamically added translation elements const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // Element node try { // Check if it's a translation-related element if (node.matches && (node.matches('[aria-label*="translat"], [data-testid*="translat"], button[class*="translat"]'))) { if (node.getAttribute('aria-checked') === 'true' || node.classList.contains('active')) { setTimeout(() => node.click(), 100); } } } catch (e) { // Ignore errors } } }); }); }); // Start observing when body is available const startObserver = () => { if (document.body) { observer.observe(document.body, { childList: true, subtree: true }); } else { setTimeout(startObserver, 100); } }; startObserver(); // Additional check for URL changes (for single-page navigation) let lastUrl = window.location.href; setInterval(() => { if (window.location.href !== lastUrl) { lastUrl = window.location.href; removeTranslationParam(); } }, 1000); })();