85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
'use client'
|
||
|
||
import i18nConfig from '@/i18nConfig'
|
||
import { usePathname, useRouter } from 'next/navigation'
|
||
import { useEffect, useTransition } from 'react'
|
||
import { Globe } from 'lucide-react'
|
||
|
||
export function LanguageSwitcher() {
|
||
const router = useRouter()
|
||
const pathname = usePathname()
|
||
const [isPending, startTransition] = useTransition()
|
||
|
||
const currentLocale = pathname.split('/')[1] || i18nConfig.defaultLocale
|
||
|
||
useEffect(() => {
|
||
if (typeof window !== 'undefined') {
|
||
const saved = localStorage.getItem('preferred-language')
|
||
const isLocaleInPath = i18nConfig.locales.includes(currentLocale as any)
|
||
|
||
// 只有在 URL 中没有 locale 前缀时才写入 cookie 和 localStorage,避免错误覆盖
|
||
if (!isLocaleInPath && saved !== currentLocale) {
|
||
localStorage.setItem('preferred-language', currentLocale)
|
||
document.cookie = `preferred-language=${currentLocale}; path=/; max-age=31536000`
|
||
|
||
console.log('[LanguageSwitcher] set preferred-language to:', currentLocale)
|
||
|
||
// 确保 cookie 写入
|
||
const cookieValue = document.cookie
|
||
console.log('[LanguageSwitcher] Cookie after setting:', cookieValue)
|
||
}
|
||
}
|
||
}, [currentLocale])
|
||
|
||
const handleChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||
const newLocale = e.target.value
|
||
|
||
// 写入 cookie
|
||
document.cookie = `preferred-language=${newLocale}; path=/; max-age=31536000`
|
||
|
||
// 检查 cookie 是否正确写入
|
||
const cookieValue = document.cookie
|
||
console.log('[LanguageSwitcher] Cookie set to:', cookieValue)
|
||
|
||
let segments = pathname === '/' ? [] : pathname.split('/').filter(Boolean)
|
||
const isLocaleInPath = i18nConfig.locales.includes(segments[0] as any)
|
||
|
||
if (isLocaleInPath) {
|
||
segments[0] = newLocale
|
||
} else {
|
||
segments.unshift(newLocale)
|
||
}
|
||
|
||
const newPath = '/' + segments.join('/')
|
||
|
||
// 延迟跳转,确保 cookie 写入完成
|
||
setTimeout(() => {
|
||
startTransition(() => {
|
||
if (pathname !== newPath) {
|
||
router.push(newPath)
|
||
} else {
|
||
router.refresh()
|
||
}
|
||
})
|
||
}, 0)
|
||
}
|
||
|
||
return (
|
||
<div className="absolute top-4 right-4 z-50 flex items-center gap-2">
|
||
<Globe size={18} className="text-muted-foreground" />
|
||
<select
|
||
className="rounded-md border px-2 py-1 text-sm bg-background text-foreground"
|
||
value={currentLocale}
|
||
onChange={handleChange}
|
||
disabled={isPending}
|
||
>
|
||
{i18nConfig.locales.map(locale => (
|
||
<option key={locale} value={locale}>
|
||
{i18nConfig.languageNames[locale] || locale.toUpperCase()}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
)
|
||
}
|