useAppI18n.ts
2.21 KB
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import en from '~/locales/en'
import zhCN from '~/locales/zh-CN'
type Locale = 'en' | 'zh-CN'
type MessageValue = string | Record<string, unknown> | unknown[]
const DEFAULT_LOCALE: Locale = 'zh-CN'
const messages = {
en,
'zh-CN': zhCN
} as const
function resolveLocale(input?: string | null): Locale {
if (input === 'zh' || input === 'zh-CN') {
return 'zh-CN'
}
if (input === 'en') {
return 'en'
}
return DEFAULT_LOCALE
}
function getValueByPath(source: Record<string, unknown>, path: string): MessageValue | undefined {
return path.split('.').reduce<MessageValue | undefined>((acc, segment) => {
if (!acc || typeof acc !== 'object' || Array.isArray(acc)) {
return undefined
}
return (acc as Record<string, unknown>)[segment] as MessageValue | undefined
}, source)
}
function interpolate(template: string, params?: Record<string, string | number>): string {
if (!params) {
return template
}
return template.replace(/\{(\w+)\}/g, (_, key: string) => {
return params[key] === undefined ? `{${key}}` : String(params[key])
})
}
export function useAppI18n() {
const localeCookie = useCookie<Locale>('locale', {
default: () => DEFAULT_LOCALE
})
const locale = useState<Locale>('app-locale', () => resolveLocale(localeCookie.value))
watch(locale, (value) => {
localeCookie.value = value
}, { immediate: true })
const setLocale = (value: Locale) => {
locale.value = value
}
const t = (path: string, params?: Record<string, string | number>): string => {
const current = getValueByPath(messages[locale.value] as unknown as Record<string, unknown>, path)
const fallback = getValueByPath(messages.en as unknown as Record<string, unknown>, path)
const value = current ?? fallback
if (typeof value !== 'string') {
return path
}
return interpolate(value, params)
}
const tm = <T = unknown>(path: string): T => {
const current = getValueByPath(messages[locale.value] as unknown as Record<string, unknown>, path)
const fallback = getValueByPath(messages.en as unknown as Record<string, unknown>, path)
return (current ?? fallback) as T
}
return {
locale,
setLocale,
t,
tm
}
}
export type { Locale }