PageSourceSearch

https://neonyzer.de/wp-content/plugins/neonyzer-frontend-translate/nz-translate-frontend.js?ver=1.1.0

js neonyzer.de collected 2026-10-02 01:01:21 UTC 8,980 bytes, 271 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function () {
2    const cfg = window.NZ_TRANSLATE_CONFIG || {};
3    const debug = !!cfg.debug;
4
5    function log(...args) {
6        if (debug) console.log('[NZ_TRANSLATE]', ...args);
7    }
8    function warn(...args) {
9        if (debug) console.warn('[NZ_TRANSLATE]', ...args);
10    }
11
12    if (!cfg.restUrl) {
13        warn('Keine REST-URL konfiguriert – Plugin deaktiviert sich.');
14        return;
15    }
16
17    // ===================================================
18    // 1. Content-Container finden
19    // ===================================================
20    let contentEl = null;
21
22    if (cfg.contentSelector) {
23        contentEl = document.querySelector(cfg.contentSelector);
24        if (!contentEl) {
25            warn('Kein Element für Selector gefunden:', cfg.contentSelector, '→ versuche <main>');
26        }
27    }
28
29    if (!contentEl) {
30        contentEl = document.querySelector('main');
31        if (!contentEl) {
32            warn('Kein <main> gefunden → fallback auf <body>');
33            contentEl = document.body;
34        } else {
35            log('Nutze <main> als Content-Container.');
36        }
37    } else {
38        log('Nutze Content-Selector:', cfg.contentSelector, '→', contentEl);
39    }
40
41    // Originalzustand speichern (für "Original"-Button)
42    const originalHTML = contentEl.innerHTML;
43
44    // ===================================================
45    // 2. Floating Button + Panel
46    // ===================================================
47    const btn = document.createElement('div');
48    btn.id = 'nz-translate-float-btn';
49    btn.textContent = '🌐 Translate';
50    document.body.appendChild(btn);
51
52    const style = document.createElement('style');
53    style.textContent = `
54    #nz-translate-float-btn {
55        position: fixed;
56        left: 20px;
57        bottom: 20px;
58        background: #111;
59        color: #fff;
60        padding: 10px 14px;
61        border-radius: 999px;
62        font-size: 14px;
63        cursor: pointer;
64        z-index: 99999;
65        box-shadow: 0 4px 10px rgba(0,0,0,0.4);
66        font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
67    }
68    #nz-translate-panel {
69        position: fixed;
70        right: 20px;
71        bottom: 60px;
72        background: #1f1f1f;
73        color: #fff;
74        padding: 12px;
75        border-radius: 8px;
76        z-index: 99999;
77        box-shadow: 0 4px 10px rgba(0,0,0,0.4);
78        font-size: 14px;
79        font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
80    }
81    #nz-translate-panel select,
82    #nz-translate-panel button {
83        margin-top: 6px;
84        font-size: 13px;
85    }
86    #nz-translate-panel button {
87        cursor: pointer;
88    }
89    #nz-translate-overlay {
90        position: fixed;
91        inset: 0;
92        background: rgba(0,0,0,0.6);
93        color: #fff;
94        display: flex;
95        align-items: center;
96        justify-content: center;
97        z-index: 99998;
98        font-size: 18px;
99        text-align: center;
100        padding: 20px;
101        font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
102    }
103    `;
104    document.head.appendChild(style);
105
106    let panel = null;
107
108    function createOverlay() {
109        const overlay = document.createElement('div');
110        overlay.id = 'nz-translate-overlay';
111        overlay.textContent = cfg.loadingText || 'Ich übersetze diese Seite für dich …';
112        document.body.appendChild(overlay);
113        return overlay;
114    }
115
116    // ===================================================
117    // 3. Text-Elemente sammeln (ohne Header/Footer/Menu)
118    // ===================================================
119    function collectTextElements() {
120        const selector = 'h1,h2,h3,h4,h5,h6,p,li,blockquote';
121        const all = Array.from(contentEl.querySelectorAll(selector));
122
123        const elements = all.filter(el => {
124            const txt = el.innerText || el.textContent || '';
125            if (!txt.trim()) return false;
126
127            // Header/Nav/Footer & Menüs NICHT übersetzen
128            if (el.closest('header, nav, footer, .site-header, .site-footer, .menu, .cmplz-cookiebanner, .cookiebanner')) {
129                return false;
130            }
131            return true;
132        });
133
134        log('Gefundene Text-Elemente im Content-Bereich:', elements.length);
135        return elements;
136    }
137
138    // ===================================================
139    // 4. Übersetzung pro Element (Text bleibt, Design bleibt)
140    // ===================================================
141    async function translateAllElements(targetLang) {
142        const elements = collectTextElements();
143        if (!elements.length) {
144            alert('Keine Text-Elemente zum Übersetzen gefunden.');
145            return;
146        }
147
148        log('Starte Übersetzung für', elements.length, 'Elemente, Zielsprache:', targetLang);
149
150        const overlay = createOverlay();
151
152        let index = 0;
153        const baseText = cfg.loadingText || 'Ich übersetze diese Seite für dich …';
154
155        for (const el of elements) {
156            index++;
157            overlay.textContent = `${baseText} (${index}/${elements.length})`;
158
159            const text = (el.innerText || el.textContent || '').trim();
160            if (!text) {
161                continue;
162            }
163
164            log('Übersetze Element', index, 'Textlänge:', text.length);
165
166            try {
167                const res = await fetch(cfg.restUrl, {
168                    method: 'POST',
169                    headers: { 'Content-Type': 'application/json' },
170                    body: JSON.stringify({
171                        content: text,
172                        target_lang: targetLang
173                    })
174                });
175
176                const status = res.status;
177                let data = null;
178
179                try {
180                    data = await res.json();
181                } catch (e) {
182                    warn('Konnte REST-Response nicht als JSON lesen für Element', index, e);
183                    continue;
184                }
185
186                log('REST-Response Status Element', index, ':', status, data);
187
188                if (data && data.error) {
189                    warn('Fehler beim Übersetzen (Element ' + index + '):', data.error);
190                    continue;
191                }
192                if (data && data.translated_html) {
193                    // Wichtig: Nur TEXT austauschen, nicht die Struktur
194                    el.innerText = data.translated_html;
195                }
196            } catch (e) {
197                warn('Netzwerkfehler beim Übersetzen (Element ' + index + '):', e);
198                alert('Netzwerkfehler beim Übersetzen. Schau in die Konsole für Details.');
199                break;
200            }
201        }
202
203        overlay.remove();
204        log('Übersetzung abgeschlossen.');
205    }
206
207    // ===================================================
208    // 5. Button-Click → Panel mit Sprachwahl
209    // ===================================================
210    btn.addEventListener('click', () => {
211        log('Panel öffnen');
212
213        if (panel) {
214            panel.remove();
215            panel = null;
216            return;
217        }
218
219        panel = document.createElement('div');
220        panel.id = 'nz-translate-panel';
221
222        const label = document.createElement('div');
223        label.textContent = 'Zielsprache wählen:';
224
225        const select = document.createElement('select');
226        if (cfg.langs && cfg.langs.length > 0) {
227            cfg.langs.forEach(lang => {
228                const opt = document.createElement('option');
229                opt.value = lang;
230                opt.textContent = lang;
231                select.appendChild(opt);
232            });
233        } else {
234            const opt = document.createElement('option');
235            opt.value = 'de';
236            opt.textContent = 'de';
237            select.appendChild(opt);
238        }
239
240        const translateBtn = document.createElement('button');
241        translateBtn.textContent = 'Übersetzen';
242
243        const resetBtn = document.createElement('button');
244        resetBtn.textContent = 'Original';
245        resetBtn.style.marginLeft = '8px';
246
247        panel.appendChild(label);
248        panel.appendChild(select);
249        panel.appendChild(document.createElement('br'));
250        panel.appendChild(translateBtn);
251        panel.appendChild(resetBtn);
252
253        document.body.appendChild(panel);
254
255        // Klick "Übersetzen"
256        translateBtn.addEventListener('click', () => {
257            const targetLang = select.value || 'de';
258            log('Starte Übersetzung', {
259                targetLang,
260                restUrl: cfg.restUrl
261            });
262            translateAllElements(targetLang);
263        });
264
265        // Klick "Original"
266        resetBtn.addEventListener('click', () => {
267            log('Setze Content auf Original zurück.');
268            contentEl.innerHTML = originalHTML;
269        });
270    });
271});

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.