This commit is contained in:
Your Name committed 2026-06-18 18:42:39 -04:00
1 parent 6f67ee6077
commit 62db477dbd
13 files changed
+660 -98

No files matched your search

+23 -10
View File
@@ -1,21 +1,34 @@
import { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import i18n from '../lib/i18n'
/**
* Returns the current i18n language code (2-char) in a hydration-safe way.
* Returns a hydration-safe 2-char language code.
*
* On the server and during initial client render the value is always 'th'
* (matching the SSR output). After hydration it updates to the user's saved
* language so all components re-render with the correct locale without
* triggering a hydration mismatch.
* WHY this pattern is necessary:
* - i18n.ts reads localStorage synchronously at module-load time (before React hydrates)
* - So i18n.language may already be 'ja', 'ko', etc. when client components first render
* - useTranslation() subscribes to this and causes components to render the user's language
* DURING hydration, but the server rendered 'th' — causing a mismatch error
*
* SOLUTION:
* - Always return 'th' until the component has mounted (matching the server)
* - After mount, sync to the real language and subscribe to future changes
* - Components using this hook NEVER cause a hydration mismatch
*/
export function useLang(): string {
const { i18n } = useTranslation()
const [lang, setLang] = useState('th') // must match server default
// Always 'th' on first render (matches SSR) — updated post-hydration
const [lang, setLang] = useState('th')
useEffect(() => {
setLang(i18n.language ? i18n.language.substring(0, 2) : 'th')
}, [i18n.language])
// Sync immediately after hydration
const current = i18n.language ? i18n.language.substring(0, 2) : 'th'
setLang(current)
// Subscribe to future language changes (user clicks language button)
const handler = (lng: string) => setLang(lng.substring(0, 2))
i18n.on('languageChanged', handler)
return () => { i18n.off('languageChanged', handler) }
}, [])
return lang
}