From 9cd990f1b9a058467c287957da68496970166251 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 1cdd439..46d7df8 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 31b36e9..55c5c9f 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 f81a8c9..bd429b6 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' });