feat: i18n — EN/MS/ZH translations with cookie-based locale switching, report form translated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FFDuBhMKvoWjrWT3ZnGmmr
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
'use client'
|
||||
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const LOCALES: Record<string, string> = {
|
||||
en: 'English',
|
||||
ms: 'Bahasa Malaysia',
|
||||
zh: '中文',
|
||||
}
|
||||
|
||||
export function LanguageSwitcher() {
|
||||
const router = useRouter()
|
||||
const [current, setCurrent] = useState('en')
|
||||
|
||||
useEffect(() => {
|
||||
const match = document.cookie
|
||||
.split('; ')
|
||||
.find(c => c.startsWith('locale='))
|
||||
?.split('=')[1]
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
if (match && match in LOCALES) setCurrent(match)
|
||||
}, [])
|
||||
|
||||
function handleChange(locale: string) {
|
||||
document.cookie = `locale=${locale}; path=/; max-age=31536000; SameSite=Lax`
|
||||
setCurrent(locale)
|
||||
router.refresh()
|
||||
}
|
||||
|
||||
return (
|
||||
<select
|
||||
value={current}
|
||||
onChange={e => handleChange(e.target.value)}
|
||||
aria-label="Select language"
|
||||
className="text-xs border border-gray-300 rounded px-2 py-1 bg-white text-gray-700 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
||||
>
|
||||
{Object.entries(LOCALES).map(([code, label]) => (
|
||||
<option key={code} value={code}>{label}</option>
|
||||
))}
|
||||
</select>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user