Files
beh-rde-brief/tools/sprachseiten/build.js
T
JUSNandClaude Opus 5 7d0692150c Website: 28 Sprachen statt 7 — per Generator statt Handarbeit
tools/sprachseiten/ enthaelt jetzt vorlage.html + texte.js + build.js.
'node tools/sprachseiten/build.js' erzeugt alle 27 Sprachseiten und pflegt
hreflang + Sprachwaehler auch in der handgemachten index.html nach.

Warum ein Generator: 28 Seiten von Hand zu pflegen heisst, jede kuenftige
Aenderung 28-mal zu machen. So ist es eine Aenderung an einer Stelle.

Neue Sprachen u. a. Rumaenisch, Kurdisch (Kurmanci), Bulgarisch, Kroatisch,
Serbisch, Bosnisch, Albanisch, Italienisch, Griechisch, Vietnamesisch, Hindi,
Urdu, Paschtu, Tigrinya, Somali, Chinesisch.

Sprachleiste ist jetzt ein Aufklappmenue — 28 Links nebeneinander waeren
unbenutzbar, besonders auf dem Handy. Google findet die Seiten weiter ueber
hreflang (28 + x-default, auf jeder Seite identisch) und die Sitemap (38 URLs).

Ausserdem: Hinweis in beiden Kauf-Boxen, warum sich die E-Mail-Angabe lohnt
(Zugangs-Link -> Guthaben auf jedem Geraet nutzbar).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 15:56:49 +02:00

130 lines
5.3 KiB
JavaScript

/**
* 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) => ` <link rel="alternate" hreflang="${s.code}" href="${BASIS}${s.pfad}">`).join('\n') +
`\n <link rel="alternate" hreflang="x-default" href="${BASIS}/">`
);
}
/**
* 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) =>
` <option value="${s.datei}" lang="${s.code}"${s.code === aktiv ? ' selected' : ''}>${s.eigenname}</option>`
).join('\n');
return ` <nav class="sprachen" aria-label="${label}">
🌐
<select class="sprachwahl" onchange="if(this.value)location.href=this.value">
${optionen}
</select>
</nav>`;
}
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(
/( <link rel="alternate" hreflang="[\s\S]*?hreflang="x-default"[^>]*>)/,
hreflangBlock()
);
idx = idx.replace(
/ <nav class="sprachen"[\s\S]*?<\/nav>/,
waehlerBlock('de', 'Sprache wählen')
);
if (!idx.includes('.sprachwahl {')) {
idx = idx.replace(' </style>', WAEHLER_CSS + '\n </style>');
}
fs.writeFileSync(idxPfad, idx, 'utf8');
console.log(`${n} Sprachseiten erzeugt + index.html aktualisiert (${ALLE.length} Sprachen gesamt)`);