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)