Files
wehub-resource-sync d68f003000
CI / Change detection (push) Has been cancelled
CI / Version drift (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Workflow RLM cache (push) Has been cancelled
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / npm wrapper smoke (push) Has been cancelled
CI / Mobile runtime smoke (push) Has been cancelled
CI / Workflow lint (push) Has been cancelled
CI / Documentation (push) Has been cancelled
Web Frontend / Lint & Type Check (push) Failing after 1s
Auto-close harvested PRs / close (push) Failing after 1s
cargo-deny / cargo-deny (bans licenses sources) (push) Failing after 1s
Security audit / cargo-audit (push) Failing after 1s
Sync to CNB / sync (push) Failing after 1s
cargo-deny / cargo-deny (advisories) (push) Failing after 3s
Web Frontend / Deploy to Cloudflare (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:08:23 +08:00

66 lines
2.0 KiB
TypeScript

"use client";
import { useRouter, usePathname } from "next/navigation";
import { ALL_LOCALES, locales } from "@/lib/i18n/config";
/** Labels for the dropdown. Keyed by locale code, displayed in native script. */
const LOCALE_LABELS: Record<string, string> = {};
for (const l of ALL_LOCALES) {
LOCALE_LABELS[l.code] = l.label;
}
/** Shipped locales that appear in the switcher. */
const SHIPPED = ALL_LOCALES.filter((l) => l.status === "shipped");
export function LocaleSwitcher({ current }: { current: string }) {
const router = useRouter();
const pathname = usePathname();
const switchLocale = (code: string) => {
if (code === current) return;
const segments = pathname.split("/");
if ((locales as readonly string[]).includes(segments[1])) {
segments[1] = code;
} else {
segments.splice(1, 0, code);
}
const newPath = segments.join("/") || `/${code}`;
document.cookie = `NEXT_LOCALE=${code};path=/;max-age=${60 * 60 * 24 * 365}`;
router.push(newPath);
};
// If only 1 shipped locale, no switcher needed.
if (SHIPPED.length <= 1) return null;
// If exactly 2 shipped locales, show a simple toggle.
if (SHIPPED.length === 2) {
const other = SHIPPED.find((l) => l.code !== current);
if (!other) return null;
return (
<button
onClick={() => switchLocale(other.code)}
className="font-mono text-[0.72rem] uppercase text-ink-mute hover:text-indigo transition-colors px-2 py-1"
aria-label={`Switch to ${other.label}`}
>
{other.label}
</button>
);
}
// 3+ shipped locales: show a dropdown.
return (
<select
value={current}
onChange={(e) => switchLocale(e.target.value)}
className="font-mono text-[0.72rem] uppercase text-ink-mute bg-transparent hairline-t hairline-b hairline-l hairline-r px-2 py-1 cursor-pointer hover:text-indigo transition-colors"
aria-label="Switch language"
>
{SHIPPED.map((l) => (
<option key={l.code} value={l.code}>
{l.label}
</option>
))}
</select>
);
}