feat(web): add language switcher to site footer
TR/EN toggle in the footer bottom bar, wired to the i18n store's setLocale (persists to localStorage, updates <html lang>). Buttons use aria-pressed within a labelled group; active locale is highlighted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,37 @@
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { type Locale, useTranslation } from "@/lib/i18n";
|
||||
import { Separator } from "@sase/ui";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { Globe } from "lucide-react";
|
||||
|
||||
const LOCALES: { code: Locale; label: string }[] = [
|
||||
{ code: "tr", label: "TR" },
|
||||
{ code: "en", label: "EN" },
|
||||
];
|
||||
|
||||
export function SiteFooter({ variant = "full" }: { variant?: "full" | "compact" }) {
|
||||
const { t } = useTranslation();
|
||||
const { t, locale, setLocale } = useTranslation();
|
||||
|
||||
const languageSwitcher = (
|
||||
// biome-ignore lint/a11y/useSemanticElements: a button group, not a form fieldset; role="group" is the correct ARIA here
|
||||
<div className="flex items-center gap-1 text-sm" role="group" aria-label={t("footer.language")}>
|
||||
<Globe className="mr-1 size-4 text-muted-foreground" aria-hidden="true" />
|
||||
{LOCALES.map(({ code, label }) => (
|
||||
<button
|
||||
key={code}
|
||||
type="button"
|
||||
onClick={() => setLocale(code)}
|
||||
aria-pressed={locale === code}
|
||||
className={`rounded-md px-2 py-1 transition-colors ${
|
||||
locale === code
|
||||
? "font-semibold text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
// Compact variant — single line for app/dashboard layouts.
|
||||
if (variant === "compact") {
|
||||
@@ -123,10 +151,11 @@ export function SiteFooter({ variant = "full" }: { variant?: "full" | "compact"
|
||||
|
||||
<Separator className="bg-border" />
|
||||
|
||||
<div className="py-6">
|
||||
<p className="text-center text-sm text-muted-foreground sm:text-left">
|
||||
<div className="flex flex-col items-center justify-between gap-4 py-6 sm:flex-row">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
© {new Date().getFullYear()} Sase.tr. {t("footer.rights")}
|
||||
</p>
|
||||
{languageSwitcher}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -78,7 +78,8 @@
|
||||
"privacy": "Privacy Policy",
|
||||
"terms": "Terms of Use",
|
||||
"kvkk": "KVKK",
|
||||
"rights": "All rights reserved."
|
||||
"rights": "All rights reserved.",
|
||||
"language": "Language"
|
||||
},
|
||||
"catalog": {
|
||||
"title": "Parts Catalog",
|
||||
|
||||
@@ -78,7 +78,8 @@
|
||||
"privacy": "Gizlilik Politikası",
|
||||
"terms": "Kullanım Koşulları",
|
||||
"kvkk": "KVKK",
|
||||
"rights": "Tüm hakları saklıdır."
|
||||
"rights": "Tüm hakları saklıdır.",
|
||||
"language": "Dil"
|
||||
},
|
||||
"catalog": {
|
||||
"title": "Parça Kataloğu",
|
||||
|
||||
Reference in New Issue
Block a user