diff --git a/tools/sprachseiten/build.js b/tools/sprachseiten/build.js new file mode 100644 index 0000000..39b93be --- /dev/null +++ b/tools/sprachseiten/build.js @@ -0,0 +1,129 @@ +/** + * Erzeugt alle Sprach-Landingpages aus EINER Vorlage + texte.js. + * + * node tools/sprachseiten/build.js + * + * Warum ein Generator: Bei 28 Sprachen müsste sonst jede Änderung (neuer + * Abschnitt, neuer Link, neues Brevo-Formular) 28-mal von Hand gemacht werden. + * So ist es eine Änderung an einer Stelle. + * + * Deutsch (index.html) wird NICHT erzeugt — die Startseite ist handgemacht + * und deutlich umfangreicher. Sie bekommt nur hreflang + Sprachwähler gepflegt + * (siehe hreflangBlock() / waehlerBlock(), die auch index.html aktualisieren). + */ +const fs = require('fs'); +const path = require('path'); + +const { SPRACHEN, TEXTE } = require('./texte.js'); +const AUS = path.join(__dirname, '..', '..', 'webseite'); +const BASIS = 'https://behoerdenklar.de'; +const BREVO = 'https://86550585.sibforms.com/serve/MUIFAAvOQCpFg148k-xD2Ze2PDVKKaFEIaLECCCMe9fGKd_uIurPljyn_IhTrkR0EkM_pQp_8VBzcHZ6N9sKDX5GBZi9elYKN6isXGPUUxcAgO37OKhTFZyMlJiC9ikRmPI8Q2tU2GvqP6esJ5ReGfv1htZV_OfXRIgW59P6pkeUsYKxqdXA7nWOaWxNTYz4MzzoGg7czJMJ2fxuEg=='; + +/** Alle Sprachen inkl. Deutsch, in der Reihenfolge aus texte.js. */ +const ALLE = [{ code: 'de', eigenname: 'Deutsch', datei: 'index.html', pfad: '/' }].concat( + SPRACHEN.map((s) => ({ ...s, datei: `${s.code}.html`, pfad: `/${s.code}` })) +); + +/** hreflang-Satz — identisch auf JEDER Seite, sonst wertet Google ihn ab. */ +function hreflangBlock() { + return ( + ALLE.map((s) => ` `).join('\n') + + `\n ` + ); +} + +/** + * Sprachwähler als Auswahlliste. Bei 28 Sprachen wäre eine Linkleiste + * unbenutzbar — ein Aufklappmenü bleibt auch auf dem Handy bedienbar. + * Google findet die Seiten trotzdem: über hreflang und die Sitemap. + */ +function waehlerBlock(aktiv, label) { + const optionen = ALLE.map( + (s) => + ` ` + ).join('\n'); + return ` `; +} + +const WAEHLER_CSS = ` + .sprachwahl { + font-family: inherit; font-size: 15px; color: var(--tinte); + background: #fff; border: 1.5px solid var(--tinte); padding: 6px 10px; + max-width: 220px; cursor: pointer; + }`; + +function seite(s) { + const t = TEXTE[s.code]; + if (!t) throw new Error('Keine Texte für ' + s.code); + const rtl = s.rtl ? ' dir="rtl"' : ''; + const vorlage = fs.readFileSync(path.join(__dirname, 'vorlage.html'), 'utf8'); + + return vorlage + .replace(/\{\{LANG\}\}/g, s.code) + .replace(/\{\{DIR\}\}/g, rtl) + .replace(/\{\{LOCALE\}\}/g, t.locale || s.code) + .replace(/\{\{TITEL\}\}/g, t.titel) + .replace(/\{\{BESCHREIBUNG\}\}/g, t.beschreibung) + .replace(/\{\{OG_TITEL\}\}/g, t.ogTitel) + .replace(/\{\{OG_BESCHREIBUNG\}\}/g, t.ogBeschreibung) + .replace(/\{\{URL\}\}/g, `${BASIS}/${s.code}`) + .replace(/\{\{HREFLANG\}\}/g, hreflangBlock()) + .replace(/\{\{WAEHLER_CSS\}\}/g, WAEHLER_CSS) + .replace(/\{\{WAEHLER\}\}/g, waehlerBlock(s.code, t.navLabel)) + .replace(/\{\{H1_A\}\}/g, t.h1a) + .replace(/\{\{H1_B\}\}/g, t.h1b) + .replace(/\{\{INTRO\}\}/g, t.intro) + .replace(/\{\{CTA_HERO\}\}/g, t.ctaHero) + .replace(/\{\{STEMPEL\}\}/g, t.stempel) + .replace(/\{\{S1_TITEL\}\}/g, t.s1Titel) + .replace(/\{\{VORHER_LABEL\}\}/g, t.vorherLabel) + .replace(/\{\{PFEIL\}\}/g, t.pfeil) + .replace(/\{\{NACHHER_LABEL\}\}/g, t.nachherLabel) + .replace(/\{\{NACHHER_TEXT\}\}/g, t.nachherText) + .replace(/\{\{HINWEIS\}\}/g, t.hinweis) + .replace(/\{\{S2_TITEL\}\}/g, t.s2Titel) + .replace(/\{\{SCHRITT1_T\}\}/g, t.schritt1T).replace(/\{\{SCHRITT1_B\}\}/g, t.schritt1B) + .replace(/\{\{SCHRITT2_T\}\}/g, t.schritt2T).replace(/\{\{SCHRITT2_B\}\}/g, t.schritt2B) + .replace(/\{\{SCHRITT3_T\}\}/g, t.schritt3T).replace(/\{\{SCHRITT3_B\}\}/g, t.schritt3B) + .replace(/\{\{S3_TITEL\}\}/g, t.s3Titel) + .replace(/\{\{FORMULAR_KOPF\}\}/g, t.formularKopf) + .replace(/\{\{FORM_H3\}\}/g, t.formH3) + .replace(/\{\{FORM_TEXT\}\}/g, t.formText) + .replace(/\{\{BONUS\}\}/g, t.bonus) + .replace(/\{\{BREVO\}\}/g, BREVO) + .replace(/\{\{EMAIL_PLATZHALTER\}\}/g, t.emailPlatzhalter) + .replace(/\{\{CTA_FORM\}\}/g, t.ctaForm) + .replace(/\{\{KLEIN\}\}/g, t.klein) + .replace(/\{\{DATENSCHUTZ\}\}/g, t.datenschutz) + .replace(/\{\{IMPRESSUM\}\}/g, t.impressum) + .replace(/\{\{FUSS_FRAGE\}\}/g, t.fussFrage); +} + +let n = 0; +for (const s of SPRACHEN) { + fs.writeFileSync(path.join(AUS, `${s.code}.html`), seite(s), 'utf8'); + n++; +} + +// index.html (Deutsch, handgemacht) mitpflegen: hreflang + Sprachwähler +const idxPfad = path.join(AUS, 'index.html'); +let idx = fs.readFileSync(idxPfad, 'utf8'); +idx = idx.replace( + /( ]*>)/, + hreflangBlock() +); +idx = idx.replace( + /