This commit is contained in:
Nông Đức Huy
2026-08-13 23:20:22 +07:00
parent 3e5d38ec18
commit 3d6b0e0d4e
145 changed files with 7817 additions and 801 deletions
@@ -0,0 +1,69 @@
'use client';
import { useLocale, useTranslations } from 'next-intl';
import { useTransition } from 'react';
import { LOCALE_LABELS, LOCALES, type Locale } from '@sport/types';
import { cn } from '@sport/ui';
import { usePathname, useRouter } from '@/i18n/navigation';
/**
* Switches locale while staying on the current page.
*
* `usePathname` from `@/i18n/navigation` returns the path *without* the locale
* prefix, so re-pushing it under a different locale lands on the same page in
* the other language — rather than dumping the user on the homepage, which is
* what a plain `<a href="/en">` does and is the usual way this is got wrong.
*
* Product pages are the interesting case: slugs are localised, so switching on
* `/products/ao-chay-bo-aero` produces `/en/products/ao-chay-bo-aero`. That is
* intentional — the API resolves a slug in any locale, and the PDP then
* redirects to the canonical `/en/products/aero-run-tee`. One redirect keeps
* this component simple and keeps every cross-locale link working.
*/
export function LanguageSwitcher({ className }: { className?: string }) {
const t = useTranslations('nav');
const activeLocale = useLocale() as Locale;
const router = useRouter();
const pathname = usePathname();
const [isPending, startTransition] = useTransition();
function switchTo(locale: Locale) {
if (locale === activeLocale) return;
// `replace`, not `push`: a language switch is a correction, not a
// navigation step. Leaving it in history makes the back button toggle
// languages instead of going back.
startTransition(() => {
router.replace(pathname, { locale });
});
}
return (
<div
className={cn('flex items-center gap-1', isPending && 'opacity-60', className)}
role="group"
aria-label={t('changeLanguage')}
>
{LOCALES.map((locale) => (
<button
key={locale}
type="button"
onClick={() => switchTo(locale)}
aria-current={locale === activeLocale ? 'true' : undefined}
lang={locale}
title={LOCALE_LABELS[locale]}
className={cn(
'px-1.5 py-1 text-xs font-semibold uppercase tracking-widest transition-colors',
locale === activeLocale
? 'text-ink-950 underline underline-offset-4'
: 'text-ink-400 hover:text-ink-950',
)}
>
{locale}
</button>
))}
</div>
);
}