refactor(i18n): add i18n context provider

This commit is contained in:
kunish 2023-09-23 01:38:36 +08:00
parent 48ca8d6dfa
commit e4a324625f
No known key found for this signature in database
GPG Key ID: 647A12B4F782C430
18 changed files with 54 additions and 43 deletions

View File

@ -19,6 +19,7 @@
"@felte/validator-zod": "^1.0.17",
"@fontsource/fira-sans": "^5.0.12",
"@solid-primitives/clipboard": "^1.5.7",
"@solid-primitives/context": "^0.2.1",
"@solid-primitives/event-listener": "^2.3.0",
"@solid-primitives/i18n": "^2.0.0",
"@solid-primitives/keyed": "^1.2.0",

11
pnpm-lock.yaml generated
View File

@ -20,6 +20,9 @@ dependencies:
'@solid-primitives/clipboard':
specifier: ^1.5.7
version: 1.5.7(solid-js@1.7.12)
'@solid-primitives/context':
specifier: ^0.2.1
version: 0.2.1(solid-js@1.7.12)
'@solid-primitives/event-listener':
specifier: ^2.3.0
version: 2.3.0(solid-js@1.7.12)
@ -2032,6 +2035,14 @@ packages:
solid-js: 1.7.12
dev: false
/@solid-primitives/context@0.2.1(solid-js@1.7.12):
resolution: {integrity: sha512-XIIwCOWpRKDersgkR9LNFXaJHIV8QlCFo/tq5bV0cAOZklcwOFcqi2bN+uWgEIQSWGjWXU2kc1H1/TzgYzVDlg==}
peerDependencies:
solid-js: ^1.6.12
dependencies:
solid-js: 1.7.12
dev: false
/@solid-primitives/event-listener@2.3.0(solid-js@1.7.12):
resolution: {integrity: sha512-0DS7DQZvCExWSpurVZC9/wjI8RmkhuOtWOy6Pp1Woq9ElMT9/bfjNpkwXsOwisLpcTqh9eUs17kp7jtpWcC20w==}
peerDependencies:

View File

@ -45,7 +45,7 @@ const TagClientSourceIPWithNameForm: Component = () => {
sourceIP: z.string().nonempty(),
})
const { t } = useI18n()
const [t] = useI18n()
const { form, reset } = createForm<z.infer<typeof schema>>({
extend: validator({ schema }),
@ -113,7 +113,7 @@ export const ConnectionsSettingsModal = (props: {
onVisibleChange: (value: ConnectionsTableColumnVisibility) => void
}) => {
const modalID = MODAL.CONNECTIONS_SETTINGS
const { t } = useI18n()
const [t] = useI18n()
const [activeKey, setActiveKey] =
createSignal<CONNECTIONS_TABLE_ACCESSOR_KEY | null>(null)

View File

@ -13,7 +13,7 @@ import {
import { For, ParentComponent, Show, createSignal } from 'solid-js'
import { Button, LogoText } from '~/components'
import { LANG, ROUTES, themes } from '~/constants'
import { useI18n } from '~/i18n'
import { setLocale, useI18n } from '~/i18n'
import { setCurTheme } from '~/signals'
const Nav: ParentComponent<{ href: string; tooltip: string }> = ({
@ -62,7 +62,7 @@ const ThemeSwitcher = () => (
)
export const Header = () => {
const { t, locale } = useI18n()
const [t] = useI18n()
const navs = () => [
{
href: ROUTES.Overview,
@ -154,11 +154,9 @@ export const Header = () => {
<div class="flex items-center gap-2">
<Button
class="btn-circle btn-secondary btn-sm"
onClick={() => {
const curLocale = locale()
locale(curLocale === LANG.EN ? LANG.ZH : LANG.EN)
}}
onClick={() =>
setLocale((locale) => (locale === LANG.EN ? LANG.ZH : LANG.EN))
}
icon={<IconLanguage />}
/>

View File

@ -4,7 +4,7 @@ import { useI18n } from '~/i18n'
import { latencyQualityMap, useProxies } from '~/signals'
export const Latency = (props: { name?: string }) => {
const { t } = useI18n()
const [t] = useI18n()
const { latencyMap } = useProxies()
const [textClassName, setTextClassName] = createSignal('')
const latency = createMemo(() => {

View File

@ -19,7 +19,7 @@ import {
export const LogsSettingsModal = () => {
const modalID = MODAL.LOGS_SETTINGS
const { t } = useI18n()
const [t] = useI18n()
return (
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">

View File

@ -20,7 +20,7 @@ import {
export const ProxiesSettingsModal = () => {
const modalID = MODAL.PROXIES_SETTINGS
const { t } = useI18n()
const [t] = useI18n()
return (
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">

View File

@ -14,13 +14,13 @@ const getSubscriptionsInfo = (subscriptionInfo: ISubscriptionInfo) => {
const percentage = toFinite((((Download + Upload) / Total) * 100).toFixed(2))
const expirePrefix = () => {
const { t } = useI18n()
const [t] = useI18n()
return t('expire')
}
const expireStr = () => {
const { t } = useI18n()
const [t] = useI18n()
if (Expire === 0) {
return t('noExpire')

View File

@ -1,10 +1,11 @@
import { createContextProvider } from '@solid-primitives/context'
import * as i18n from '@solid-primitives/i18n'
import { makePersisted } from '@solid-primitives/storage'
import { createMemo, createSignal } from 'solid-js'
import { createSignal } from 'solid-js'
import { LANG } from '~/constants'
import dict from './dict'
import dict, { Dict } from './dict'
export const [curLocale, setCurLocale] = makePersisted(
export const [locale, setLocale] = makePersisted(
createSignal<LANG>(
Reflect.has(dict, navigator.language)
? (navigator.language as LANG)
@ -16,12 +17,9 @@ export const [curLocale, setCurLocale] = makePersisted(
},
)
const locale = (localeName?: LANG) =>
localeName ? setCurLocale(localeName) : curLocale()
export const [I18nProvider, useMaybeI18n] = createContextProvider<
[i18n.Translator<Dict>],
{ locale: LANG }
>((props) => [i18n.translator(() => i18n.flatten(dict[props.locale]))])
export const useI18n = () => {
const curDict = createMemo(() => i18n.flatten(dict[curLocale()]))!
const t = createMemo(() => i18n.translator(() => curDict()))
return { t: t(), locale }
}
export const useI18n = () => useMaybeI18n()!

View File

@ -7,14 +7,17 @@ import 'dayjs/locale/zh-cn'
import relativeTime from 'dayjs/plugin/relativeTime'
import { render } from 'solid-js/web'
import { App } from '~/App'
import { I18nProvider, locale } from '~/i18n'
dayjs.extend(relativeTime)
render(
() => (
<Router source={hashIntegration()}>
<App />
</Router>
<I18nProvider locale={locale()}>
<Router source={hashIntegration()}>
<App />
</Router>
</I18nProvider>
),
document.getElementById('root')!,
)

View File

@ -48,7 +48,7 @@ const dnsQueryFormSchema = z.object({
})
const DNSQueryForm = () => {
const { t } = useI18n()
const [t] = useI18n()
const request = useRequest()
const { form, isSubmitting } = createForm<z.infer<typeof dnsQueryFormSchema>>(
@ -111,7 +111,7 @@ const configFormSchema = z.object({
})
const ConfigForm = () => {
const { t } = useI18n()
const [t] = useI18n()
const navigate = useNavigate()
const portList = [
@ -352,7 +352,7 @@ const ConfigForm = () => {
}
const ConfigForXd = () => {
const { t } = useI18n()
const [t] = useI18n()
return (
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
@ -439,7 +439,7 @@ const Versions = () => {
}
export default () => {
const { t } = useI18n()
const [t] = useI18n()
return (
<div class="mx-auto flex max-w-screen-md flex-col gap-4">

View File

@ -78,7 +78,7 @@ const fuzzyFilter: FilterFn<Connection> = (row, columnId, value, addMeta) => {
}
export default () => {
const { t } = useI18n()
const [t] = useI18n()
const [activeTab, setActiveTab] = createSignal(ActiveTab.activeConnections)
const { activeConnections, closedConnections, paused, setPaused } =
@ -88,7 +88,7 @@ export default () => {
const [selectedConnectionID, setSelectedConnectionID] = createSignal<string>()
const columns = createMemo<ColumnDef<Connection>[]>(() => [
const columns: ColumnDef<Connection>[] = [
{
header: () => t('details'),
enableGrouping: false,
@ -243,7 +243,7 @@ export default () => {
original.metadata.destinationIP ||
original.metadata.host,
},
])
]
const [grouping, setGrouping] = createSignal<GroupingState>([])
const [sorting, setSorting] = makePersisted(
@ -281,7 +281,7 @@ export default () => {
},
sortDescFirst: true,
enableHiding: true,
columns: columns(),
columns,
onGlobalFilterChange: setGlobalFilter,
globalFilterFn: fuzzyFilter,
onGroupingChange: setGrouping,

View File

@ -40,7 +40,7 @@ const fuzzyFilter: FilterFn<LogWithSeq> = (row, columnId, value, addMeta) => {
}
export default () => {
const { t } = useI18n()
const [t] = useI18n()
let seq = 1
const [logs, setLogs] = createSignal<LogWithSeq[]>([])

View File

@ -26,7 +26,7 @@ const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
)
export default () => {
const { t } = useI18n()
const [t] = useI18n()
const [traffics, setTraffics] = createSignal<{ down: number; up: number }[]>(
[],

View File

@ -34,7 +34,7 @@ enum ActiveTab {
}
export default () => {
const { t } = useI18n()
const [t] = useI18n()
const {
proxies,
selectProxyInGroup,

View File

@ -12,7 +12,7 @@ enum ActiveTab {
}
export default () => {
const { t } = useI18n()
const [t] = useI18n()
const {
rules,
ruleProviders,

View File

@ -23,7 +23,7 @@ const schema = z.object({
})
export default () => {
const { t } = useI18n()
const [t] = useI18n()
const navigate = useNavigate()
const onSetupSuccess = (id: string) => {

View File

@ -1,5 +1,5 @@
import dayjs from 'dayjs'
import { curLocale } from '~/i18n'
import { locale } from '~/i18n'
export const formatTimeFromNow = (time: number | string) =>
dayjs(time).locale(curLocale()).fromNow()
dayjs(time).locale(locale()).fromNow()