From 3d1c4f85f218a7c83946ab35d812547d40f4a2e2 Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Fri, 26 Dec 2025 22:45:12 +0100 Subject: [PATCH] make main landing page bilingual and eliminate language switcher flicker Replace window.location.reload() with custom event dispatching to avoid flicker when switching languages on main page. Add bilingual labels for all content including welcome message and link grid. --- src/lib/components/UserHeader.svelte | 14 ++++- src/routes/(main)/+layout.svelte | 10 ++-- src/routes/(main)/+page.svelte | 85 +++++++++++++++++++--------- 3 files changed, 74 insertions(+), 35 deletions(-) diff --git a/src/lib/components/UserHeader.svelte b/src/lib/components/UserHeader.svelte index 1cdd4398..46d7df81 100644 --- a/src/lib/components/UserHeader.svelte +++ b/src/lib/components/UserHeader.svelte @@ -18,6 +18,10 @@ currentLang = 'en'; } else if (path.startsWith('/rezepte')) { currentLang = 'de'; + } else if (path === '/') { + // On main page, read from localStorage + const preferredLanguage = localStorage.getItem('preferredLanguage'); + currentLang = preferredLanguage === 'en' ? 'en' : 'de'; } } }); @@ -44,6 +48,12 @@ // Get the current path directly from window const path = typeof window !== 'undefined' ? window.location.pathname : currentPath; + // If on main page, dispatch event instead of reloading + if (path === '/') { + window.dispatchEvent(new CustomEvent('languagechange', { detail: { lang } })); + return; + } + // If we have recipe translation data from store, use the correct short names const recipeData = $recipeTranslationStore; if (recipeData) { @@ -62,8 +72,8 @@ newPath = path.replace('/rezepte', '/recipes'); } else if (lang === 'de' && path.startsWith('/recipes')) { newPath = path.replace('/recipes', '/rezepte'); - } else if (path === '/' || (!path.startsWith('/rezepte') && !path.startsWith('/recipes'))) { - // On main page or other pages, go to recipe home + } else if (!path.startsWith('/rezepte') && !path.startsWith('/recipes')) { + // On other pages (glaube, cospend, etc), go to recipe home newPath = lang === 'en' ? '/recipes' : '/rezepte'; } diff --git a/src/routes/(main)/+layout.svelte b/src/routes/(main)/+layout.svelte index 31b36e93..55c5c9f8 100644 --- a/src/routes/(main)/+layout.svelte +++ b/src/routes/(main)/+layout.svelte @@ -1,16 +1,14 @@
- +
diff --git a/src/routes/(main)/+page.svelte b/src/routes/(main)/+page.svelte index f81a8c99..bd429b6b 100644 --- a/src/routes/(main)/+page.svelte +++ b/src/routes/(main)/+page.svelte @@ -4,16 +4,55 @@ import { onMount } from 'svelte'; let { data } = $props(); + let lang = $state<'de' | 'en'>('de'); let recipesUrl = $state('/rezepte'); onMount(() => { // Check localStorage for preferred language const preferredLanguage = localStorage.getItem('preferredLanguage'); if (preferredLanguage === 'en') { + lang = 'en'; recipesUrl = '/recipes'; } else { + lang = 'de'; recipesUrl = '/rezepte'; } + + // Listen for language changes from UserHeader + const handleLanguageChange = (e: CustomEvent) => { + lang = e.detail.lang; + recipesUrl = lang === 'en' ? '/recipes' : '/rezepte'; + }; + window.addEventListener('languagechange', handleLanguageChange as EventListener); + + return () => { + window.removeEventListener('languagechange', handleLanguageChange as EventListener); + }; + }); + + const isEnglish = $derived(lang === 'en'); + const labels = $derived({ + welcome: isEnglish ? 'Welcome to bocken.org' : 'Willkommen auf bocken.org', + intro1: isEnglish + ? 'Hello, I\'m Alexander Bocken. On this website you\'ll find some software projects for friends, family, and myself. Everything is self-hosted at my home on a small mini-server (Arch, btw).' + : 'Hallo, ich bin Alexander Bocken. Auf dieser Seite findest du einige Softwareprojekte für Freunde, Familie und mich. Alles ist selbst gehostet bei mir daheim auf einem kleinen Mini-Server (Arch, btw).', + intro2: isEnglish + ? 'I recommend my continuously growing recipe collection. There you\'ll find many delicious recipes that I\'ve tried myself and constantly refine. You\'re also welcome to use my search engine or Jitsi instance for video conferences. Some things are hidden behind a login, others are publicly accessible. If you know a bit about programming, feel free to browse my Git repositories.' + : 'Zu empfehlen ist meine stetig wachsende Rezeptsammlung. Dort findest du viele leckere Rezepte, die ich selbst ausprobiert habe und ständig weiterfeilsche. Zudem kannst du gerne meine Suchmaschine oder auch Jitsi-instanz für Videokonferenzen nutzen. Einiges ist hinter einem Login versteckt, anderes ist öffentlich zugänglich. Wer sich ein bisschen mit Programmieren auskennt, kann auch gerne in meinen Git-Repositories stöbern.', + pages: isEnglish ? 'Pages' : 'Seiten', + recipes: isEnglish ? 'Recipes' : 'Rezepte', + git: 'Git', + streaming: 'Streaming', + familyPhotos: isEnglish ? 'Family Photos' : 'Familienbilder', + cloud: 'Cloud', + videoConferences: isEnglish ? 'Video Conferences' : 'Videokonferenzen', + searchEngine: isEnglish ? 'Search Engine' : 'Suchmaschine', + shopping: isEnglish ? 'Shopping' : 'Einkauf', + familyTree: isEnglish ? 'Family Tree' : 'Stammbaum', + faith: isEnglish ? 'Faith' : 'Glaube', + transmission: 'Transmission', + documents: isEnglish ? 'Documents' : 'Dokumente', + audiobooksPodcasts: isEnglish ? 'Audiobooks & Podcasts' : 'Hörbücher & Podcasts' });