Files
ds2api/webui/src/i18n.jsx

63 lines
1.9 KiB
JavaScript

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)