File size: 1,934 Bytes
8d3471e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | import { createContext, useContext, useEffect, useMemo, useState } from 'react'
import en from './locales/en.json'
import zh from './locales/zh.json'
const STORAGE_KEY = 'ds2api_lang'
const translations = { en, zh }
const I18nContext = createContext({
lang: 'zh',
setLang: () => {},
t: (key) => key,
})
const getBrowserLang = () => {
if (typeof navigator === 'undefined') return 'zh'
return navigator.language?.toLowerCase().startsWith('zh') ? 'zh' : 'en'
}
const getValue = (obj, key) => {
if (!obj) return undefined
return key.split('.').reduce((acc, part) => (acc ? acc[part] : undefined), obj)
}
const formatMessage = (message, vars) => {
if (!vars) return message
return message.replace(/\{(\w+)\}/g, (match, key) => {
if (Object.prototype.hasOwnProperty.call(vars, key)) {
return vars[key]
}
return match
})
}
export const I18nProvider = ({ children }) => {
const [lang, setLang] = useState(() => {
if (typeof localStorage === 'undefined') return getBrowserLang()
return localStorage.getItem(STORAGE_KEY) || getBrowserLang()
})
useEffect(() => {
if (typeof localStorage !== 'undefined') {
localStorage.setItem(STORAGE_KEY, lang)
}
if (typeof document !== 'undefined') {
document.documentElement.lang = lang === 'zh' ? 'zh-CN' : 'en'
}
}, [lang])
const t = useMemo(() => {
return (key, vars) => {
const value = getValue(translations[lang], key) ?? getValue(translations.en, key) ?? key
if (typeof value !== 'string') return value
return formatMessage(value, vars)
}
}, [lang])
const contextValue = useMemo(() => ({ lang, setLang, t }), [lang, t])
return <I18nContext.Provider value={contextValue}>{children}</I18nContext.Provider>
}
export const useI18n = () => useContext(I18nContext)
|