Greasy Fork

Greasy Fork is available in English.

Reddit Auto-Translation Disabler

Disable Reddit Auto-Translation and Partially Restore Translated Titles in Google Search Results

当前为 2025-10-22 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Reddit Auto-Translation Disabler
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Disable Reddit Auto-Translation and Partially Restore Translated Titles in Google Search Results 
// @author       NagaYZ
// @match        *://www.google.com/search*
// @match        *://www.google.fr/search*
// @match        *://www.google.*/search*
// @match        *://www.reddit.com/*
// @match        *://reddit.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const isGoogleSearch = window.location.hostname.includes('google');
    const isReddit = window.location.hostname.includes('reddit.com');

    // ===== GOOGLE SEARCH: REDDIT TITLE RESTORER =====
    if (isGoogleSearch) {
        // Wait for document-end equivalent
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', initGoogleScript);
        } else {
            initGoogleScript();
        }

        function initGoogleScript() {
            // Function to extract title from Reddit URL
            function extractTitleFromUrl(url) {
                try {
                    const cleanUrl = url.split('?')[0];
                    const match = cleanUrl.match(/\/r\/[^\/]+\/comments\/[^\/]+\/([^\/]+)/);

                    if (match && match[1]) {
                        let title = match[1];

                        // Decode URL encoding to handle special characters and accents
                        title = decodeURIComponent(title);

                        // Replace underscores and hyphens with spaces
                        title = title.replace(/[_-]/g, ' ');

                        const smallWords = ['a', 'an', 'and', 'as', 'at', 'but', 'by', 'for', 'from', 'in', 'into', 'is', 'it', 'of', 'on', 'or', 'the', 'to', 'with',
                                           'de', 'la', 'el', 'en', 'un', 'una', 'y', 'o', 'con', 'por', 'para'];

                        title = title.split(' ')
                            .map((word, index) => {
                                // Always capitalize first word
                                if (index === 0) {
                                    return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
                                }

                                // Keep small words lowercase unless they start a sentence
                                if (smallWords.includes(word.toLowerCase())) {
                                    return word.toLowerCase();
                                }

                                // Capitalize other words (handles accented characters properly)
                                return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
                            })
                            .join(' ');

                        return title;
                    }
                } catch (e) {
                    // Silently fail
                }
                return null;
            }

            // Function to clean Reddit URLs
            function cleanRedditUrl(url) {
                if (!url || !url.includes('reddit.com')) {
                    return url;
                }

                let cleanUrl = url;
                cleanUrl = cleanUrl.replace(/[?&]tl=[^&]*/g, '');
                cleanUrl = cleanUrl.replace(/[?&]translate=[^&]*/g, '');
                cleanUrl = cleanUrl.replace(/[?&]translation=[^&]*/g, '');
                cleanUrl = cleanUrl.replace(/[?&]$/, '');
                cleanUrl = cleanUrl.replace(/&&+/g, '&');
                cleanUrl = cleanUrl.replace(/\?&/, '?');

                return cleanUrl;
            }

            // Function to restore Reddit titles
            function restoreRedditTitles() {
                const redditLinks = document.querySelectorAll('a[href*="reddit.com/r/"][href*="/comments/"]');
                let restoredCount = 0;

                redditLinks.forEach(link => {
                    const originalHref = link.href;
                    const cleanedHref = cleanRedditUrl(originalHref);

                    if (originalHref !== cleanedHref) {
                        link.href = cleanedHref;
                    }

                    const titleElement = link.querySelector('h3');

                    if (titleElement && !titleElement.dataset.restored) {
                        const originalTitle = extractTitleFromUrl(link.href);

                        if (originalTitle) {
                            titleElement.dataset.translatedTitle = titleElement.textContent;
                            titleElement.dataset.restored = 'true';
                            titleElement.textContent = originalTitle;
                            titleElement.style.fontStyle = 'normal';
                            restoredCount++;
                        }
                    }

                    if (link.dataset.url) {
                        link.dataset.url = cleanRedditUrl(link.dataset.url);
                    }
                });

                // Clean citation URLs
                const citeElements = document.querySelectorAll('cite');
                citeElements.forEach(cite => {
                    if (cite.textContent.includes('reddit.com') && cite.textContent.includes('tl=')) {
                        cite.textContent = cleanRedditUrl(cite.textContent);
                    }
                });


            }

            // Add CSS
            const style = document.createElement('style');
            style.textContent = `
                a[href*="reddit.com"] h3[data-restored="true"] {
                    font-style: normal !important;
                }
            `;
            document.head.appendChild(style);

            // Run immediately
            restoreRedditTitles();

            // Intercept link clicks
            document.addEventListener('click', (e) => {
                const link = e.target.closest('a[href*="reddit.com"]');
                if (link && link.href) {
                    const cleanedHref = cleanRedditUrl(link.href);
                    if (link.href !== cleanedHref) {
                        link.href = cleanedHref;
                    }
                }
            }, true);

            // MutationObserver for dynamic content
            const observer = new MutationObserver((mutations) => {
                let shouldProcess = false;

                mutations.forEach((mutation) => {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === 1) {
                            if (node.matches && node.matches('a[href*="reddit.com"]')) {
                                shouldProcess = true;
                            } else if (node.querySelectorAll) {
                                const redditLinks = node.querySelectorAll('a[href*="reddit.com"]');
                                if (redditLinks.length > 0) {
                                    shouldProcess = true;
                                }
                            }
                        }
                    });
                });

                if (shouldProcess) {
                    setTimeout(restoreRedditTitles, 100);
                }
            });

            const startObserver = () => {
                if (document.body) {
                    observer.observe(document.body, {
                        childList: true,
                        subtree: true
                    });
                } else {
                    setTimeout(startObserver, 100);
                }
            };

            startObserver();

            // Periodic check
            setInterval(restoreRedditTitles, 2000);

            // Handle navigation
            window.addEventListener('popstate', () => {
                setTimeout(restoreRedditTitles, 200);
            });

            // Handle Google's dynamic navigation
            const originalPushState = history.pushState;
            const originalReplaceState = history.replaceState;

            history.pushState = function() {
                const result = originalPushState.apply(this, arguments);
                setTimeout(restoreRedditTitles, 200);
                return result;
            };

            history.replaceState = function() {
                const result = originalReplaceState.apply(this, arguments);
                setTimeout(restoreRedditTitles, 200);
                return result;
            };


        }
    }

    // ===== REDDIT: AUTO-TRANSLATION DISABLER =====
    if (isReddit) {
        // Remove translation parameter from URL
        const currentUrl = window.location.href;
        const hasLanguageParam = currentUrl.includes('/?tl=');

        if (hasLanguageParam) {
            const cleanUrl = currentUrl.replace(/\/\?tl=[^&?]*(&|$)/, '/');
            if (cleanUrl !== currentUrl) {
                window.location.replace(cleanUrl);
            }
        }

        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;
        }

        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) {
                if (!settingCookie && value.includes('reddit_translation_status')) {
                    if (value.includes('isTranslationActive":true') ||
                        value.includes('translationEnabled":true') ||
                        value.includes('autoTranslate":true')) {
                        setTranslationCookie();
                        return;
                    }
                }
                return originalCookieSetter.call(document, value);
            },
            get: function() {
                return originalCookieGetter.call(document);
            }
        });

        // Intercept fetch requests
        const originalFetch = window.fetch;
        window.fetch = function(...args) {
            const url = args[0];

            if (typeof url === 'string' && url.includes('/svc/shreddit/graphql')) {
                try {
                    const body = args[1]?.body;
                    if (body && (body.includes('translate') || body.includes('translation'))) {
                        return Promise.resolve(new Response('{}', {
                            status: 200,
                            headers: { 'Content-Type': 'application/json' }
                        }));
                    }
                } catch (e) {
                    // Continue with normal fetch
                }
            }

            return originalFetch.apply(this, args);
        };

        // Intercept XMLHttpRequest
        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'))) {
                        this.abort();
                        return;
                    }
                } catch (e) {
                    // Continue normally
                }
            }
            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
                };

                for (let key in localStorage) {
                    if (key.toLowerCase().includes('translat')) {
                        localStorage.setItem(key, JSON.stringify(settings));
                    }
                }
            } catch (e) {
                // Ignore errors
            }
        }

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', overrideTranslationSettings);
        } else {
            overrideTranslationSettings();
        }

        // Periodic check and disable translation
        setInterval(() => {
            setTranslationCookie();
            overrideTranslationSettings();

            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
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === 1) {
                        try {
                            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
                        }
                    }
                });
            });
        });

        const startObserver = () => {
            if (document.body) {
                observer.observe(document.body, {
                    childList: true,
                    subtree: true
                });
            } else {
                setTimeout(startObserver, 100);
            }
        };

        startObserver();

        // Check for URL changes
        let lastUrl = window.location.href;
        setInterval(() => {
            if (window.location.href !== lastUrl) {
                lastUrl = window.location.href;
                const currentUrl = window.location.href;
                if (currentUrl.includes('/?tl=')) {
                    const cleanUrl = currentUrl.replace(/\/\?tl=[^&?]*(&|$)/, '/');
                    if (cleanUrl !== currentUrl) {
                        window.location.replace(cleanUrl);
                    }
                }
            }
        }, 1000);


    }
})();