From 6f1dbce1a643a13b931b82575be73055c5f1aa09 Mon Sep 17 00:00:00 2001 From: MisakaAkio Date: Fri, 25 Sep 2026 06:33:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20SPA=20=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/layout/site-footer.tsx | 19 +++++++++++------ src/components/layout/site-header.tsx | 24 ++++++++++++++-------- src/components/status/http-status-page.tsx | 4 +++- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/components/layout/site-footer.tsx b/src/components/layout/site-footer.tsx index ed6b5d1..e1292dd 100644 --- a/src/components/layout/site-footer.tsx +++ b/src/components/layout/site-footer.tsx @@ -3,6 +3,7 @@ import { useRouteLocale } from "@/components/layout/locale-context"; import Image from "next/image"; +import Link from "next/link"; import { useEffect, useState, useSyncExternalStore } from "react"; import { applyLocale, getInitialLocale, withLocale, getLocaleMessages, type Locale } from "@/lib/i18n"; import { ThemeToggle } from "@/components/layout/theme-toggle"; @@ -81,9 +82,12 @@ export function SiteFooter() {

{group.title}

))} @@ -104,9 +108,12 @@ export function SiteFooter() {
- {messages.footer.legal.map((item, itemIndex) => ( - {item} - ))} + {messages.footer.legal.map((item, itemIndex) => { + const href = withLocale(footerLegalHrefs[itemIndex], locale); + return href.startsWith("/") + ? {item} + : {item}; + })}

{messages.footer.description}

diff --git a/src/components/layout/site-header.tsx b/src/components/layout/site-header.tsx index c9efce0..f7630cb 100644 --- a/src/components/layout/site-header.tsx +++ b/src/components/layout/site-header.tsx @@ -4,12 +4,23 @@ import { useRouteLocale } from "@/components/layout/locale-context"; import Link from "next/link"; import Image from "next/image"; +import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { applyLocale, getInitialLocale, withLocale, withoutLocale, getLocaleMessages, localeLabels, locales, localeShortLabels, type Locale } from "@/lib/i18n"; export function SiteHeader() { - const [locale, setLocale] = useState(useRouteLocale()); + const locale = useRouteLocale(); const [menuOpen, setMenuOpen] = useState(false); + const router = useRouter(); + + const changeLocale = (nextLocale: Locale) => { + try { + window.localStorage.setItem("kr-locale", nextLocale); + } catch { /* The URL remains the source of truth when storage is unavailable. */ } + + const href = `${window.location.pathname}${window.location.search}${window.location.hash}`; + router.replace(withLocale(href, nextLocale)); + }; useEffect(() => { const updateDocumentTitle = (nextLocale: Locale) => { @@ -25,10 +36,7 @@ export function SiteHeader() { document.title = pageLabel ? `${pageLabel} | ${messages.common.siteTitle}` : messages.common.siteTitle; }; - const syncLocale = (nextLocale: Locale) => { - setLocale(nextLocale); - updateDocumentTitle(nextLocale); - }; + const syncLocale = (nextLocale: Locale) => updateDocumentTitle(nextLocale); const handleLocaleChange = (event: Event) => { const nextLocale = (event as CustomEvent<{ locale?: Locale }>).detail?.locale ?? getInitialLocale(); @@ -83,8 +91,7 @@ export function SiteHeader() { className={item === locale ? "active" : ""} aria-pressed={item === locale} onClick={() => { - setLocale(item); - applyLocale(item); + changeLocale(item); }} aria-label={localeLabels[item]} title={localeLabels[item]} @@ -103,8 +110,7 @@ export function SiteHeader() { className={item === locale ? "active" : ""} aria-pressed={item === locale} onClick={() => { - setLocale(item); - applyLocale(item); + changeLocale(item); }} aria-label={localeLabels[item]} title={localeLabels[item]} diff --git a/src/components/status/http-status-page.tsx b/src/components/status/http-status-page.tsx index dab4fde..29b3783 100644 --- a/src/components/status/http-status-page.tsx +++ b/src/components/status/http-status-page.tsx @@ -3,6 +3,7 @@ import { useRouteLocale } from "@/components/layout/locale-context"; import Image from "next/image"; +import { useRouter } from "next/navigation"; import { useEffect, useMemo, useState } from "react"; import { getInitialLocale, withLocale, type Locale } from "@/lib/i18n"; @@ -72,6 +73,7 @@ function parseLocalizedMessages(source: string): Partial(useRouteLocale()); const [randomMessages, setRandomMessages] = useState>>({}); + const router = useRouter(); useEffect(() => { const syncLocale = () => setLocale(getInitialLocale()); @@ -105,7 +107,7 @@ export function HttpStatusPage({ code }: { code: HttpStatusCode }) { window.history.back(); return; } - window.location.assign(withLocale("/", locale)); + router.replace(withLocale("/", locale)); }; return (