PageSourceSearch

https://gr2conserve.com/js/translate.js

js gr2conserve.com collected 2026-10-07 03:50:18 UTC 4,816 bytes, 181 lines download raw bytes

1document.addEventListener('DOMContentLoaded', async function () {
2    const userLang = getUserLangFromBrowser();
3    window.userLang = userLang;
4
5    const observedElements = new Set();
6
7    // 初始翻译
8    const fyelements = Array.from(document.querySelectorAll('p.title a,h2.page-title,div.video-tags-list ul li a,span.profile-name,ul.tags-list li a b'))
9    fyelements.forEach(element => {
10        if (!observedElements.has(element)) {
11            translateText(element);
12            observedElements.add(element);
13        }
14    });
15
16    const observer = new MutationObserver(() => {
17        const newElements = Array.from(document.querySelectorAll('p.title a,h2.page-title,div.video-tags-list ul li a,span.profile-name,ul.tags-list li a b'))
18        newElements.forEach(element => {
19            if (!observedElements.has(element)) {
20                translateText(element);
21                observedElements.add(element);
22            }
23        });
24    });
25
26    observer.observe(document.body, {
27        childList: true,
28        subtree: true
29    });
30});
31
32function getUserLangFromBrowser() {
33    const langRaw = (navigator.language || '').toLowerCase();
34    const langCode = langRaw.split('-')[0]; // 如 "en-US" → "en"
35
36    const langMap = {
37        zh: 'zh-cn',
38        en: 'en',
39        ja: 'ja',
40        ko: 'ko',
41        fr: 'fr',
42        de: 'de',
43        es: 'es',
44        pt: 'pt',
45        ru: 'ru',
46        hi: 'hi',
47        vi: 'vi',
48        th: 'th',
49        id: 'id',
50        it: 'it',
51        tr: 'tr',
52        ar: 'ar',
53        fa: 'fa',
54        ur: 'ur',
55        pl: 'pl',
56        nl: 'nl',
57        sv: 'sv',
58        fi: 'fi',
59        da: 'da',
60        no: 'no',
61        cs: 'cs',
62        ro: 'ro',
63        hu: 'hu',
64        el: 'el',
65        uk: 'uk',
66        he: 'he',
67        ms: 'ms',
68        bn: 'bn',
69        tl: 'tl',
70        sw: 'sw',
71        bg: 'bg',
72        sk: 'sk',
73        sr: 'sr',
74        hr: 'hr',
75        sl: 'sl',
76        lv: 'lv',
77        lt: 'lt',
78        et: 'et',
79        ka: 'ka',
80        az: 'az',
81        hy: 'hy',
82        kk: 'kk',
83        uz: 'uz',
84        mn: 'mn',
85        ne: 'ne',
86        si: 'si',
87        km: 'km',
88        lo: 'lo',
89        my: 'my',
90        am: 'am',
91        tg: 'tg',
92        ky: 'ky',
93        tk: 'tk',
94        dz: 'dz',
95        dv: 'dv',
96        sm: 'sm',
97        to: 'to',
98        bi: 'bi',
99        is: 'is'
100    };
101
102    return langMap[langCode] || 'zh-cn'; // 默认使用简体中文
103}
104
105
106
107function translateText(element) {
108    const textNodes = getTextNodes(element);
109    if (textNodes.length === 0) {
110        monitorElementForTextChanges(element);
111        return;
112    }
113
114    textNodes.forEach(textNode => {
115        const originalText = textNode.textContent.trim();
116        if (!originalText) return;
117
118        const cacheKey = `translation:${window.userLang}:${originalText}`;
119        const cachedTranslation = localStorage.getItem(cacheKey);
120        if (cachedTranslation) {
121            textNode.textContent = cachedTranslation;
122            return;
123        }
124
125        requestTranslation(originalText, window.userLang)
126            .then(translatedText => {
127                textNode.textContent = translatedText;
128                localStorage.setItem(cacheKey, translatedText);
129            })
130            .catch(err => console.error(err));
131    });
132}
133
134// 动态监听元素的内容变化
135function monitorElementForTextChanges(element) {
136    const observer = new MutationObserver(() => {
137        const textNodes = getTextNodes(element);
138        if (textNodes.length > 0) {
139            observer.disconnect();
140            translateText(element);
141        }
142    });
143
144    observer.observe(element, {
145        characterData: true,
146        subtree: true,
147        childList: true
148    });
149}
150
151async function requestTranslation(originalText, lang = 'zh-cn', retries = 3) {
152    const encodedText = encodeURIComponent(originalText);
153    try {
154        const response = await fetch(`https://fy.playergo.top/lang?lang=${lang}&text=${encodedText}`);
155        const data = await response.json();
156        if (data && data.translation) {
157            return data.translation;
158        } else if (retries > 0) {
159            return await requestTranslation(originalText, lang, retries - 1);
160        } else {
161            throw new Error(`Failed to translate: "${originalText}"`);
162        }
163    } catch (error) {
164        console.error(`Failed to translate: "${originalText}"`, error);
165        throw error;
166    }
167}
168
169function getTextNodes(element) {
170    let textNodes = [];
171    function walk(node) {
172        if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
173            textNodes.push(node);
174        } else if (node.nodeType === Node.ELEMENT_NODE) {
175            node.childNodes.forEach(walk);
176        }
177    }
178
179    walk(element);
180    return textNodes;
181}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.