mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-11-24 09:45:35 +08:00
refactor(i18n): add i18n context provider
This commit is contained in:
parent
48ca8d6dfa
commit
e4a324625f
@ -19,6 +19,7 @@
|
|||||||
"@felte/validator-zod": "^1.0.17",
|
"@felte/validator-zod": "^1.0.17",
|
||||||
"@fontsource/fira-sans": "^5.0.12",
|
"@fontsource/fira-sans": "^5.0.12",
|
||||||
"@solid-primitives/clipboard": "^1.5.7",
|
"@solid-primitives/clipboard": "^1.5.7",
|
||||||
|
"@solid-primitives/context": "^0.2.1",
|
||||||
"@solid-primitives/event-listener": "^2.3.0",
|
"@solid-primitives/event-listener": "^2.3.0",
|
||||||
"@solid-primitives/i18n": "^2.0.0",
|
"@solid-primitives/i18n": "^2.0.0",
|
||||||
"@solid-primitives/keyed": "^1.2.0",
|
"@solid-primitives/keyed": "^1.2.0",
|
||||||
|
@ -20,6 +20,9 @@ dependencies:
|
|||||||
'@solid-primitives/clipboard':
|
'@solid-primitives/clipboard':
|
||||||
specifier: ^1.5.7
|
specifier: ^1.5.7
|
||||||
version: 1.5.7(solid-js@1.7.12)
|
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':
|
'@solid-primitives/event-listener':
|
||||||
specifier: ^2.3.0
|
specifier: ^2.3.0
|
||||||
version: 2.3.0(solid-js@1.7.12)
|
version: 2.3.0(solid-js@1.7.12)
|
||||||
@ -2032,6 +2035,14 @@ packages:
|
|||||||
solid-js: 1.7.12
|
solid-js: 1.7.12
|
||||||
dev: false
|
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):
|
/@solid-primitives/event-listener@2.3.0(solid-js@1.7.12):
|
||||||
resolution: {integrity: sha512-0DS7DQZvCExWSpurVZC9/wjI8RmkhuOtWOy6Pp1Woq9ElMT9/bfjNpkwXsOwisLpcTqh9eUs17kp7jtpWcC20w==}
|
resolution: {integrity: sha512-0DS7DQZvCExWSpurVZC9/wjI8RmkhuOtWOy6Pp1Woq9ElMT9/bfjNpkwXsOwisLpcTqh9eUs17kp7jtpWcC20w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -45,7 +45,7 @@ const TagClientSourceIPWithNameForm: Component = () => {
|
|||||||
sourceIP: z.string().nonempty(),
|
sourceIP: z.string().nonempty(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
const { form, reset } = createForm<z.infer<typeof schema>>({
|
const { form, reset } = createForm<z.infer<typeof schema>>({
|
||||||
extend: validator({ schema }),
|
extend: validator({ schema }),
|
||||||
@ -113,7 +113,7 @@ export const ConnectionsSettingsModal = (props: {
|
|||||||
onVisibleChange: (value: ConnectionsTableColumnVisibility) => void
|
onVisibleChange: (value: ConnectionsTableColumnVisibility) => void
|
||||||
}) => {
|
}) => {
|
||||||
const modalID = MODAL.CONNECTIONS_SETTINGS
|
const modalID = MODAL.CONNECTIONS_SETTINGS
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
const [activeKey, setActiveKey] =
|
const [activeKey, setActiveKey] =
|
||||||
createSignal<CONNECTIONS_TABLE_ACCESSOR_KEY | null>(null)
|
createSignal<CONNECTIONS_TABLE_ACCESSOR_KEY | null>(null)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
import { For, ParentComponent, Show, createSignal } from 'solid-js'
|
import { For, ParentComponent, Show, createSignal } from 'solid-js'
|
||||||
import { Button, LogoText } from '~/components'
|
import { Button, LogoText } from '~/components'
|
||||||
import { LANG, ROUTES, themes } from '~/constants'
|
import { LANG, ROUTES, themes } from '~/constants'
|
||||||
import { useI18n } from '~/i18n'
|
import { setLocale, useI18n } from '~/i18n'
|
||||||
import { setCurTheme } from '~/signals'
|
import { setCurTheme } from '~/signals'
|
||||||
|
|
||||||
const Nav: ParentComponent<{ href: string; tooltip: string }> = ({
|
const Nav: ParentComponent<{ href: string; tooltip: string }> = ({
|
||||||
@ -62,7 +62,7 @@ const ThemeSwitcher = () => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const { t, locale } = useI18n()
|
const [t] = useI18n()
|
||||||
const navs = () => [
|
const navs = () => [
|
||||||
{
|
{
|
||||||
href: ROUTES.Overview,
|
href: ROUTES.Overview,
|
||||||
@ -154,11 +154,9 @@ export const Header = () => {
|
|||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
class="btn-circle btn-secondary btn-sm"
|
class="btn-circle btn-secondary btn-sm"
|
||||||
onClick={() => {
|
onClick={() =>
|
||||||
const curLocale = locale()
|
setLocale((locale) => (locale === LANG.EN ? LANG.ZH : LANG.EN))
|
||||||
|
}
|
||||||
locale(curLocale === LANG.EN ? LANG.ZH : LANG.EN)
|
|
||||||
}}
|
|
||||||
icon={<IconLanguage />}
|
icon={<IconLanguage />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { useI18n } from '~/i18n'
|
|||||||
import { latencyQualityMap, useProxies } from '~/signals'
|
import { latencyQualityMap, useProxies } from '~/signals'
|
||||||
|
|
||||||
export const Latency = (props: { name?: string }) => {
|
export const Latency = (props: { name?: string }) => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
const { latencyMap } = useProxies()
|
const { latencyMap } = useProxies()
|
||||||
const [textClassName, setTextClassName] = createSignal('')
|
const [textClassName, setTextClassName] = createSignal('')
|
||||||
const latency = createMemo(() => {
|
const latency = createMemo(() => {
|
||||||
|
@ -19,7 +19,7 @@ import {
|
|||||||
|
|
||||||
export const LogsSettingsModal = () => {
|
export const LogsSettingsModal = () => {
|
||||||
const modalID = MODAL.LOGS_SETTINGS
|
const modalID = MODAL.LOGS_SETTINGS
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
|
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
|
||||||
|
@ -20,7 +20,7 @@ import {
|
|||||||
|
|
||||||
export const ProxiesSettingsModal = () => {
|
export const ProxiesSettingsModal = () => {
|
||||||
const modalID = MODAL.PROXIES_SETTINGS
|
const modalID = MODAL.PROXIES_SETTINGS
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
|
<dialog id={modalID} class="modal modal-bottom sm:modal-middle">
|
||||||
|
@ -14,13 +14,13 @@ const getSubscriptionsInfo = (subscriptionInfo: ISubscriptionInfo) => {
|
|||||||
const percentage = toFinite((((Download + Upload) / Total) * 100).toFixed(2))
|
const percentage = toFinite((((Download + Upload) / Total) * 100).toFixed(2))
|
||||||
|
|
||||||
const expirePrefix = () => {
|
const expirePrefix = () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
return t('expire')
|
return t('expire')
|
||||||
}
|
}
|
||||||
|
|
||||||
const expireStr = () => {
|
const expireStr = () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
if (Expire === 0) {
|
if (Expire === 0) {
|
||||||
return t('noExpire')
|
return t('noExpire')
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
import { createContextProvider } from '@solid-primitives/context'
|
||||||
import * as i18n from '@solid-primitives/i18n'
|
import * as i18n from '@solid-primitives/i18n'
|
||||||
import { makePersisted } from '@solid-primitives/storage'
|
import { makePersisted } from '@solid-primitives/storage'
|
||||||
import { createMemo, createSignal } from 'solid-js'
|
import { createSignal } from 'solid-js'
|
||||||
import { LANG } from '~/constants'
|
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>(
|
createSignal<LANG>(
|
||||||
Reflect.has(dict, navigator.language)
|
Reflect.has(dict, navigator.language)
|
||||||
? (navigator.language as LANG)
|
? (navigator.language as LANG)
|
||||||
@ -16,12 +17,9 @@ export const [curLocale, setCurLocale] = makePersisted(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const locale = (localeName?: LANG) =>
|
export const [I18nProvider, useMaybeI18n] = createContextProvider<
|
||||||
localeName ? setCurLocale(localeName) : curLocale()
|
[i18n.Translator<Dict>],
|
||||||
|
{ locale: LANG }
|
||||||
|
>((props) => [i18n.translator(() => i18n.flatten(dict[props.locale]))])
|
||||||
|
|
||||||
export const useI18n = () => {
|
export const useI18n = () => useMaybeI18n()!
|
||||||
const curDict = createMemo(() => i18n.flatten(dict[curLocale()]))!
|
|
||||||
const t = createMemo(() => i18n.translator(() => curDict()))
|
|
||||||
|
|
||||||
return { t: t(), locale }
|
|
||||||
}
|
|
||||||
|
@ -7,14 +7,17 @@ import 'dayjs/locale/zh-cn'
|
|||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import { render } from 'solid-js/web'
|
import { render } from 'solid-js/web'
|
||||||
import { App } from '~/App'
|
import { App } from '~/App'
|
||||||
|
import { I18nProvider, locale } from '~/i18n'
|
||||||
|
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
render(
|
render(
|
||||||
() => (
|
() => (
|
||||||
<Router source={hashIntegration()}>
|
<I18nProvider locale={locale()}>
|
||||||
<App />
|
<Router source={hashIntegration()}>
|
||||||
</Router>
|
<App />
|
||||||
|
</Router>
|
||||||
|
</I18nProvider>
|
||||||
),
|
),
|
||||||
document.getElementById('root')!,
|
document.getElementById('root')!,
|
||||||
)
|
)
|
||||||
|
@ -48,7 +48,7 @@ const dnsQueryFormSchema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const DNSQueryForm = () => {
|
const DNSQueryForm = () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
const request = useRequest()
|
const request = useRequest()
|
||||||
|
|
||||||
const { form, isSubmitting } = createForm<z.infer<typeof dnsQueryFormSchema>>(
|
const { form, isSubmitting } = createForm<z.infer<typeof dnsQueryFormSchema>>(
|
||||||
@ -111,7 +111,7 @@ const configFormSchema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const ConfigForm = () => {
|
const ConfigForm = () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const portList = [
|
const portList = [
|
||||||
@ -352,7 +352,7 @@ const ConfigForm = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ConfigForXd = () => {
|
const ConfigForXd = () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||||
@ -439,7 +439,7 @@ const Versions = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="mx-auto flex max-w-screen-md flex-col gap-4">
|
<div class="mx-auto flex max-w-screen-md flex-col gap-4">
|
||||||
|
@ -78,7 +78,7 @@ const fuzzyFilter: FilterFn<Connection> = (row, columnId, value, addMeta) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = createSignal(ActiveTab.activeConnections)
|
const [activeTab, setActiveTab] = createSignal(ActiveTab.activeConnections)
|
||||||
const { activeConnections, closedConnections, paused, setPaused } =
|
const { activeConnections, closedConnections, paused, setPaused } =
|
||||||
@ -88,7 +88,7 @@ export default () => {
|
|||||||
|
|
||||||
const [selectedConnectionID, setSelectedConnectionID] = createSignal<string>()
|
const [selectedConnectionID, setSelectedConnectionID] = createSignal<string>()
|
||||||
|
|
||||||
const columns = createMemo<ColumnDef<Connection>[]>(() => [
|
const columns: ColumnDef<Connection>[] = [
|
||||||
{
|
{
|
||||||
header: () => t('details'),
|
header: () => t('details'),
|
||||||
enableGrouping: false,
|
enableGrouping: false,
|
||||||
@ -243,7 +243,7 @@ export default () => {
|
|||||||
original.metadata.destinationIP ||
|
original.metadata.destinationIP ||
|
||||||
original.metadata.host,
|
original.metadata.host,
|
||||||
},
|
},
|
||||||
])
|
]
|
||||||
|
|
||||||
const [grouping, setGrouping] = createSignal<GroupingState>([])
|
const [grouping, setGrouping] = createSignal<GroupingState>([])
|
||||||
const [sorting, setSorting] = makePersisted(
|
const [sorting, setSorting] = makePersisted(
|
||||||
@ -281,7 +281,7 @@ export default () => {
|
|||||||
},
|
},
|
||||||
sortDescFirst: true,
|
sortDescFirst: true,
|
||||||
enableHiding: true,
|
enableHiding: true,
|
||||||
columns: columns(),
|
columns,
|
||||||
onGlobalFilterChange: setGlobalFilter,
|
onGlobalFilterChange: setGlobalFilter,
|
||||||
globalFilterFn: fuzzyFilter,
|
globalFilterFn: fuzzyFilter,
|
||||||
onGroupingChange: setGrouping,
|
onGroupingChange: setGrouping,
|
||||||
|
@ -40,7 +40,7 @@ const fuzzyFilter: FilterFn<LogWithSeq> = (row, columnId, value, addMeta) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
let seq = 1
|
let seq = 1
|
||||||
const [logs, setLogs] = createSignal<LogWithSeq[]>([])
|
const [logs, setLogs] = createSignal<LogWithSeq[]>([])
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
|
|
||||||
const [traffics, setTraffics] = createSignal<{ down: number; up: number }[]>(
|
const [traffics, setTraffics] = createSignal<{ down: number; up: number }[]>(
|
||||||
[],
|
[],
|
||||||
|
@ -34,7 +34,7 @@ enum ActiveTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
const {
|
const {
|
||||||
proxies,
|
proxies,
|
||||||
selectProxyInGroup,
|
selectProxyInGroup,
|
||||||
|
@ -12,7 +12,7 @@ enum ActiveTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
const {
|
const {
|
||||||
rules,
|
rules,
|
||||||
ruleProviders,
|
ruleProviders,
|
||||||
|
@ -23,7 +23,7 @@ const schema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const { t } = useI18n()
|
const [t] = useI18n()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const onSetupSuccess = (id: string) => {
|
const onSetupSuccess = (id: string) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { curLocale } from '~/i18n'
|
import { locale } from '~/i18n'
|
||||||
|
|
||||||
export const formatTimeFromNow = (time: number | string) =>
|
export const formatTimeFromNow = (time: number | string) =>
|
||||||
dayjs(time).locale(curLocale()).fromNow()
|
dayjs(time).locale(locale()).fromNow()
|
||||||
|
Loading…
Reference in New Issue
Block a user