/* ===================================================================== Prueft die Rechtstexte in fuenf Sprachen. Der wichtigste Test hier ist NICHT "ist alles uebersetzt", sondern: Steht unter jedem Schluessel auch der Text, der im HTML an dieser Stelle steht? Beim Bauen waren die Schluessel ab einer Stelle um eins verschoben, weil zwei Bloecke uebersprungen worden waren. Im Musterformular haette dadurch ueber jedem Feld die falsche Beschriftung gestanden -- "Datum" wo "Name" hingehoert. In fuenf Sprachen waere das niemandem aufgefallen, denn jede Sprache war ja vollstaendig gefuellt. Gegen diese Art Fehler ist eine Vollstaendigkeitspruefung wehrlos. Deshalb wird hier der deutsche Text im Woerterbuch mit dem im HTML verglichen -- Zeichen fuer Zeichen. ===================================================================== */ import { chromium } from "playwright"; import http from "http"; import fs from "fs"; import path from "path"; const TYP = { ".html": "text/html", ".css": "text/css", ".js": "text/javascript", ".png": "image/png", ".svg": "image/svg+xml", ".webp": "image/webp", ".json": "application/json", ".ico": "image/x-icon", ".jpg": "image/jpeg", }; const srv = http.createServer((q, r) => { const p = path.join(process.cwd(), decodeURIComponent(q.url.split("?")[0])); if (fs.existsSync(p) && !p.endsWith("/")) { r.writeHead(200, { "content-type": TYP[path.extname(p)] || "text/plain" }); return r.end(fs.readFileSync(p)); } r.writeHead(404); r.end(""); }); let ok = 0, fehl = 0; const pruefe = (name, gut, info) => { if (gut) { ok++; console.log(" ok " + name + (info ? " -> " + info : "")); } else { fehl++; console.log(" FEHL " + name + (info ? " -> " + info : "")); } }; const SPRACHEN = ["de", "de-CH", "en", "fr", "pt"]; srv.listen(4406, async () => { const browser = await chromium.launch(); const seite = await browser.newPage({ viewport: { width: 1440, height: 900 } }); const skriptfehler = []; seite.on("pageerror", (e) => skriptfehler.push(String(e).slice(0, 140))); await seite.goto("http://127.0.0.1:4406/webdesign/rechtliches.html"); await seite.waitForTimeout(1600); console.log("1. LIEGT UNTER JEDEM SCHLUESSEL DER RICHTIGE TEXT?"); const versatz = await seite.evaluate(() => { const W = window.I18N_WD || {}; /* HTML-Entitaeten aufloesen, bevor verglichen wird. Im Woerterbuch steht "&", im Browser liest textContent daraus ein "&". Ohne dieses Aufloesen meldet der Test eine Abweichung, wo in Wahrheit derselbe Text steht -- genau bei der Ueberschrift "Impressum, AGB & Datenschutz". */ const entschluesseln = (t) => { const hilf = document.createElement("textarea"); hilf.innerHTML = t; return hilf.value; }; const sauber = (t) => entschluesseln(t).replace(/\s+/g, " ").trim(); const raus = []; for (const el of document.querySelectorAll("[data-i18n^='rl_']")) { const k = el.getAttribute("data-i18n"); if (!W[k]) { raus.push({ k, grund: "kein Eintrag", html: sauber(el.textContent).slice(0, 50) }); continue; } const imBuch = sauber(W[k].de.replace(/<[^>]*>/g, " ")); const imHtml = sauber(el.textContent); if (imBuch.slice(0, 45) !== imHtml.slice(0, 45)) { raus.push({ k, grund: "Text weicht ab", html: imHtml.slice(0, 45), buch: imBuch.slice(0, 45) }); } } return raus; }); pruefe("jeder Schluessel traegt seinen eigenen Text", versatz.length === 0, versatz.length ? versatz.slice(0, 3).map((v) => v.k + " (" + v.grund + ")").join(", ") : "alle 95 stimmen"); console.log("\n2. GREIFT DIE UEBERSETZUNG IN JEDER SPRACHE?"); const proben = { rl_001: "Titel", rl_003: "Sprachhinweis", rl_047: "Widerrufsrecht" }; const gesehen = {}; for (const spr of SPRACHEN) { const r = await seite.evaluate((p) => { window.WD.setSprache(p); const hole = (k) => document.querySelector(`[data-i18n="${k}"]`)?.textContent.trim() || ""; return { lang: document.documentElement.lang, rl_001: hole("rl_001"), rl_003: hole("rl_003"), rl_047: hole("rl_047"), leer: [...document.querySelectorAll("[data-i18n^='rl_']")] .filter((el) => !el.textContent.trim()).length, }; }, spr); gesehen[spr] = r; pruefe(` ${spr}: lang-Attribut folgt`, r.lang === spr, r.lang); pruefe(` ${spr}: kein Textblock ist leer`, r.leer === 0, r.leer + " leer"); } /* Gegenprobe: Der Test darf nicht gruen sein, weil die Umschaltung gar nichts tut. Die drei Fremdsprachen MUESSEN sich vom Deutschen unterscheiden. */ for (const spr of ["en", "fr", "pt"]) { pruefe(` ${spr} unterscheidet sich wirklich vom Deutschen`, gesehen[spr].rl_003 !== gesehen.de.rl_003, gesehen[spr].rl_003.slice(0, 38)); } /* de-CH ist bei Rechtstexten ABSICHTLICH kein Dialekt, sondern Hochdeutsch in Schweizer Rechtschreibung -- also identisch bis auf das Eszett. Eine Widerrufsbelehrung auf Mundart waere unserioes. */ console.log("\n3. SCHWEIZ: HOCHDEUTSCH OHNE ESZETT, KEIN DIALEKT"); const ch = await seite.evaluate(() => { window.WD.setSprache("de-CH"); const W = window.I18N_WD; let mitEszett = 0, abweichend = 0; for (const v of Object.values(W)) { if (/ß/.test(v["de-CH"])) mitEszett++; if (v["de-CH"] !== v.de.replace(/ß/g, "ss")) abweichend++; } return { mitEszett, abweichend }; }); pruefe("kein Eszett in der Schweizer Fassung", ch.mitEszett === 0, ch.mitEszett + " Stellen"); pruefe("sonst wortgleich mit dem Deutschen", ch.abweichend === 0, ch.abweichend + " Abweichungen"); console.log("\n4. DIE MASSGEBLICHKEITSKLAUSEL STEHT IN JEDER SPRACHE"); /* Ohne diesen Hinweis waere die Uebersetzung ein Risiko: Ein Kunde koennte sich auf die franzoesische Fassung berufen. */ const klausel = await seite.evaluate(() => { const W = window.I18N_WD; const muster = { de: /deutsch/i, "de-CH": /deutsch/i, en: /german/i, fr: /allemand/i, pt: /alem/i, }; const raus = {}; for (const [spr, m] of Object.entries(muster)) { raus[spr] = m.test(W.rl_003[spr]) && m.test(W.rl_004[spr]); } return raus; }); for (const [spr, gut] of Object.entries(klausel)) { pruefe(` ${spr}: nennt die deutsche Fassung als verbindlich`, gut); } pruefe("kein Skriptfehler", skriptfehler.length === 0, skriptfehler[0] || ""); console.log(`\n===== ${ok} bestanden, ${fehl} fehlgeschlagen =====`); await browser.close(); srv.close(); process.exit(fehl ? 1 : 0); });