From 1bceabe96783890bd64e26c68ec33ff06bb12023 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Sun, 3 May 2026 21:42:41 +0200 Subject: [PATCH] feat(errors): merge DE/EN into one page with client-side toggle Collapses /errors/.html and /errors/en/.html into a single prerendered page that shows both languages and reveals the right one via . Build script injects an inline bootstrap that sets data-lang from localStorage before paint and wires the lang + theme buttons (no Svelte hydration). --- package.json | 2 +- scripts/build-error-page.ts | 63 +++++++ .../errors/[status=httpStatus]/+page.svelte | 58 ++++-- .../en/[status=httpStatus]/+page.svelte | 171 ------------------ .../errors/en/[status=httpStatus]/+page.ts | 13 -- 5 files changed, 104 insertions(+), 203 deletions(-) delete mode 100644 src/routes/errors/en/[status=httpStatus]/+page.svelte delete mode 100644 src/routes/errors/en/[status=httpStatus]/+page.ts diff --git a/package.json b/package.json index 4fb1bd5c..597aa4e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "homepage", - "version": "1.64.1", + "version": "1.64.2", "private": true, "type": "module", "scripts": { diff --git a/scripts/build-error-page.ts b/scripts/build-error-page.ts index e9db0aba..e2c01744 100644 --- a/scripts/build-error-page.ts +++ b/scripts/build-error-page.ts @@ -26,6 +26,62 @@ const OUT_DIR = join(CLIENT, 'errors'); // the logo always lands on the real site. const CANONICAL_HOME = 'https://bocken.org/'; +// Marker for idempotent script injection (so re-runs don't stack copies). +const LANG_SCRIPT_MARKER = 'data-error-toggles'; +// Wires up language + theme toggles without Svelte hydration. Runs early +// so is set before paint (avoids flash of both langs). +// The icon inside the theme button is Svelte-reactive and stays at the +// SSR-rendered shape; the actual theme cycle + persistence still works. +const LANG_SCRIPT = ` +`; + if (!existsSync(PRERENDER_DIR)) { console.error(`[error-page] missing prerender dir: ${PRERENDER_DIR}`); console.error('[error-page] is /errors/[status=httpStatus]/+page.ts setting `prerender = true` with `entries()`?'); @@ -82,6 +138,13 @@ function inline(html: string, pagePath: string): string { html = html.replace(/]*\bclass="[^"]*\bhome-link\b[^"]*"[^>]*>/g, (tag) => tag.replace(/\bhref="[^"]*"/, `href="${CANONICAL_HOME}"`) ); + + // Inject the language-toggle bootstrap script just before so + // is set before the body paints (avoids flash of + // both languages). Idempotent — if the marker is already present, skip. + if (!html.includes(LANG_SCRIPT_MARKER)) { + html = html.replace('', `${LANG_SCRIPT}`); + } return html; } diff --git a/src/routes/errors/[status=httpStatus]/+page.svelte b/src/routes/errors/[status=httpStatus]/+page.svelte index bc30f3c2..f3764964 100644 --- a/src/routes/errors/[status=httpStatus]/+page.svelte +++ b/src/routes/errors/[status=httpStatus]/+page.svelte @@ -20,17 +20,17 @@ } })(); - const title = getErrorTitle(status, false); - const description = getErrorDescription(status, false); - const quote = getErrorBibleQuote(status, false); - const otherLangHref = `https://bocken.org/errors/en/${status}.html`; + const titleDe = getErrorTitle(status, false); + const titleEn = getErrorTitle(status, true); + const descDe = getErrorDescription(status, false); + const descEn = getErrorDescription(status, true); + const quoteDe = getErrorBibleQuote(status, false); + const quoteEn = getErrorBibleQuote(status, true); - {title} — Alexander's Website + {titleDe} — Alexander's Website - -
@@ -39,32 +39,52 @@ {/snippet} {#snippet language_selector_desktop()} - EN + {/snippet} -
+
-

{title}

-

{description}

+
+

{titleDe}

+

{descDe}

+ {#if quoteDe} +
+
„{quoteDe.text}“
+
{quoteDe.reference}
+
+ {/if} +
- {#if quote} -
-
„{quote.text}“
-
{quote.reference}
-
- {/if} +
+

{titleEn}

+

{descEn}

+ {#if quoteEn} +
+
“{quoteEn.text}”
+
{quoteEn.reference}
+
+ {/if} +
diff --git a/src/routes/errors/en/[status=httpStatus]/+page.ts b/src/routes/errors/en/[status=httpStatus]/+page.ts deleted file mode 100644 index bf33d92a..00000000 --- a/src/routes/errors/en/[status=httpStatus]/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HTTP_ERROR_STATUSES } from '../../../../params/httpStatus'; -import type { PageLoad, EntryGenerator } from './$types'; - -export const prerender = true; -export const ssr = true; -export const csr = false; - -export const entries: EntryGenerator = () => - HTTP_ERROR_STATUSES.map((status) => ({ status })); - -export const load: PageLoad = ({ params }) => ({ - status: parseInt(params.status, 10) -});