74 lines
1.7 KiB
TypeScript
74 lines
1.7 KiB
TypeScript
import { createContext, memo, useContext, useEffect, useMemo, useState } from "react"
|
|
import texts from "./texts.yml"
|
|
|
|
type Keys = keyof typeof texts
|
|
|
|
const ALLOWED = new Set(["en", "fr"])
|
|
const LOCALSTORAGE_KEY = "preferred-locale"
|
|
|
|
function getLocaleFromStorage() {
|
|
try {
|
|
const key = localStorage.getItem(LOCALSTORAGE_KEY)
|
|
if (key && ALLOWED.has(key)) {
|
|
return key
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
function getNavigatorLocale() {
|
|
if (typeof navigator !== "undefined") {
|
|
for (const lang of navigator.languages) {
|
|
if (ALLOWED.has(lang)) {
|
|
return lang
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function getEnvLocale() {
|
|
return getLocaleFromStorage() ?? getNavigatorLocale() ?? "en"
|
|
}
|
|
|
|
const LocaleContext = createContext<{
|
|
locale: string
|
|
setLocale(locale: string): void
|
|
}>(undefined!)
|
|
|
|
export const useLocaleContext = () => useContext(LocaleContext)
|
|
|
|
export function useTranslate() {
|
|
const { locale } = useContext(LocaleContext)
|
|
const t = useMemo(
|
|
() =>
|
|
new Proxy(
|
|
{},
|
|
{
|
|
get(_, p: string) {
|
|
if (
|
|
process.env.NODE_ENV === "development" &&
|
|
!Object.prototype.hasOwnProperty.call(texts, p)
|
|
) {
|
|
throw new Error(`t.${p} does not exist.`)
|
|
}
|
|
return (texts as any)[p][locale]
|
|
},
|
|
}
|
|
) as {
|
|
[key in Keys]: string
|
|
},
|
|
[locale]
|
|
)
|
|
return t
|
|
}
|
|
|
|
export const LocaleContextProvider = memo(({ children }) => {
|
|
const [locale, setLocale] = useState(getEnvLocale)
|
|
useEffect(() => {
|
|
try {
|
|
localStorage.setItem(LOCALSTORAGE_KEY, locale)
|
|
} catch {}
|
|
}, [locale])
|
|
const value = useMemo(() => ({ locale, setLocale }), [locale])
|
|
return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
|
|
})
|