From 4e247c409485b24e4482bf94ad0d87658fa40000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20R=C3=BChe?= <471338+Marv51@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:55:38 +0200 Subject: [PATCH] Keep language switcher on the same page when switching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nav language links pointed unconditionally at / and /de, so switching language on the imprint page dumped you back on the homepage instead of the equivalent /de/impressum or /en/imprint. Extract a shared LangSwitcher component that reads the current location and links each language to the equivalent page in the other tree. The en/de page pairs are derived from the existing PAGES record in seo-links.ts, so it stays a single source of truth alongside the canonical/hreflang links and the sitemap — a new bilingual page added there now flows into the switcher too. Co-Authored-By: Claude Opus 4.8 --- src/app/lang-switcher/lang-switcher.tsx | 41 +++++++++++++++++++++++++ src/app/routes/layout-de.tsx | 8 ++--- src/app/routes/layout.tsx | 8 ++--- 3 files changed, 47 insertions(+), 10 deletions(-) create mode 100644 src/app/lang-switcher/lang-switcher.tsx diff --git a/src/app/lang-switcher/lang-switcher.tsx b/src/app/lang-switcher/lang-switcher.tsx new file mode 100644 index 0000000..e1bd60a --- /dev/null +++ b/src/app/lang-switcher/lang-switcher.tsx @@ -0,0 +1,41 @@ +import { NavLink, useLocation } from "react-router"; +import { PAGES, type PagePair } from "../seo-links"; + +// Equivalent EN ↔ DE page pairs come from the single source of truth in +// seo-links.ts, so a page added there automatically works in the switcher too. +const pagePairs = Object.values(PAGES) as PagePair[]; + +function equivalentPaths(pathname: string): PagePair { + return ( + pagePairs.find((p) => p.en === pathname || p.de === pathname) ?? + PAGES.home + ); +} + +export function LangSwitcher() { + const { pathname } = useLocation(); + const { en, de } = equivalentPaths(pathname); + + return ( +
+ + isActive ? "lang-left" : "not-active lang-left" + } + to={en} + end + > + en + + + isActive ? "lang-right" : "not-active lang-right" + } + to={de} + end + > + de + +
+ ); +} diff --git a/src/app/routes/layout-de.tsx b/src/app/routes/layout-de.tsx index fd15d7e..e63469b 100644 --- a/src/app/routes/layout-de.tsx +++ b/src/app/routes/layout-de.tsx @@ -1,7 +1,8 @@ import type { Route } from "./+types/layout"; import { Imprint } from "../imprint/imprint"; -import { NavLink, Outlet } from "react-router"; +import { Outlet } from "react-router"; import { Footer } from "../footer/footer"; +import { LangSwitcher } from "../lang-switcher/lang-switcher"; export function meta({}: Route.MetaArgs) { return [ @@ -11,10 +12,7 @@ export function meta({}: Route.MetaArgs) { export default function Layout() { return (<>
-
- isActive ? "lang-left" : "not-active lang-left"} to="/">en - isActive ? "lang-right" : "not-active lang-right"} to="/de">de -
+
diff --git a/src/app/routes/layout.tsx b/src/app/routes/layout.tsx index 152a5ce..b7e5273 100644 --- a/src/app/routes/layout.tsx +++ b/src/app/routes/layout.tsx @@ -1,7 +1,8 @@ import type { Route } from "./+types/layout"; import { Imprint } from "../imprint/imprint"; -import { NavLink, Outlet } from "react-router"; +import { Outlet } from "react-router"; import { Footer } from "../footer/footer"; +import { LangSwitcher } from "../lang-switcher/lang-switcher"; export function meta({}: Route.MetaArgs) { return [ @@ -11,10 +12,7 @@ export function meta({}: Route.MetaArgs) { export default function Layout() { return (<>
-
- isActive ? "lang-left" : "not-active lang-left"} to="/">en - isActive ? "lang-right" : "not-active lang-right"} to="/de">de -
+