mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-11-24 09:45:35 +08:00
feat(i18n): add more i18n resources
This commit is contained in:
parent
508e19a247
commit
b3172da302
@ -72,32 +72,32 @@ export const Header = () => {
|
|||||||
const navs = () => [
|
const navs = () => [
|
||||||
{
|
{
|
||||||
href: '/overview',
|
href: '/overview',
|
||||||
name: t('navs.overview'),
|
name: t('overview'),
|
||||||
icon: <IconHome />,
|
icon: <IconHome />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/proxies',
|
href: '/proxies',
|
||||||
name: t('navs.proxies'),
|
name: t('proxies'),
|
||||||
icon: <IconGlobe />,
|
icon: <IconGlobe />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/rules',
|
href: '/rules',
|
||||||
name: t('navs.rules'),
|
name: t('rules'),
|
||||||
icon: <IconRuler />,
|
icon: <IconRuler />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/conns',
|
href: '/conns',
|
||||||
name: t('navs.connections'),
|
name: t('connections'),
|
||||||
icon: <IconNetwork />,
|
icon: <IconNetwork />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/logs',
|
href: '/logs',
|
||||||
name: t('navs.logs'),
|
name: t('logs'),
|
||||||
icon: <IconFileStack />,
|
icon: <IconFileStack />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/config',
|
href: '/config',
|
||||||
name: t('navs.config'),
|
name: t('config'),
|
||||||
icon: <IconSettings />,
|
icon: <IconSettings />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -4,48 +4,70 @@ import { ParentComponent, createEffect, createSignal } from 'solid-js'
|
|||||||
|
|
||||||
const dict = {
|
const dict = {
|
||||||
'en-US': {
|
'en-US': {
|
||||||
navs: {
|
|
||||||
overview: 'Overview',
|
overview: 'Overview',
|
||||||
proxies: 'Proxies',
|
proxies: 'Proxies',
|
||||||
rules: 'Rules',
|
rules: 'Rules',
|
||||||
connections: 'Connections',
|
connections: 'Connections',
|
||||||
logs: 'Logs',
|
logs: 'Logs',
|
||||||
config: 'Config',
|
config: 'Config',
|
||||||
},
|
|
||||||
stats: {
|
|
||||||
upload: 'Upload',
|
upload: 'Upload',
|
||||||
download: 'Download',
|
download: 'Download',
|
||||||
uploadTotal: 'Upload Total',
|
uploadTotal: 'Upload Total',
|
||||||
downloadTotal: 'Download Total',
|
downloadTotal: 'Download Total',
|
||||||
activeConnections: 'Active Connections',
|
activeConnections: 'Active Connections',
|
||||||
memoryUsage: 'Memory Usage',
|
memoryUsage: 'Memory Usage',
|
||||||
},
|
traffic: 'Traffic',
|
||||||
proxies: {
|
memory: 'Memory',
|
||||||
proxies: 'Proxies',
|
down: 'Down',
|
||||||
proxyProvider: 'Proxy Provider',
|
up: 'Up',
|
||||||
},
|
proxyProviders: 'Proxy Providers',
|
||||||
|
ruleProviders: 'Rule Providers',
|
||||||
|
search: 'Search',
|
||||||
|
type: 'Type',
|
||||||
|
name: 'Name',
|
||||||
|
process: 'Process',
|
||||||
|
host: 'Host',
|
||||||
|
chains: 'Chains',
|
||||||
|
dlSpeed: 'DL Speed',
|
||||||
|
ulSpeed: 'UL Speed',
|
||||||
|
dl: 'DL',
|
||||||
|
ul: 'UL',
|
||||||
|
source: 'Source',
|
||||||
|
destination: 'Destination',
|
||||||
|
close: 'Close',
|
||||||
},
|
},
|
||||||
'zh-Hans': {
|
'zh-Hans': {
|
||||||
navs: {
|
|
||||||
overview: '概览',
|
overview: '概览',
|
||||||
proxies: '代理',
|
proxies: '代理',
|
||||||
rules: '规则',
|
rules: '规则',
|
||||||
connections: '连接',
|
connections: '连接',
|
||||||
logs: '日志',
|
logs: '日志',
|
||||||
config: '配置',
|
config: '配置',
|
||||||
},
|
|
||||||
stats: {
|
|
||||||
upload: '上传',
|
upload: '上传',
|
||||||
download: '下载',
|
download: '下载',
|
||||||
uploadTotal: '上传总量',
|
uploadTotal: '上传总量',
|
||||||
downloadTotal: '下载总量',
|
downloadTotal: '下载总量',
|
||||||
activeConnections: '活动连接',
|
activeConnections: '活动连接',
|
||||||
memoryUsage: '内存使用情况',
|
memoryUsage: '内存使用情况',
|
||||||
},
|
traffic: '流量',
|
||||||
proxies: {
|
memory: '内存',
|
||||||
proxies: '代理节点组',
|
down: '下载',
|
||||||
proxyProvider: '代理提供商',
|
up: '上传',
|
||||||
},
|
proxyProviders: '代理提供者',
|
||||||
|
ruleProviders: '规则提供者',
|
||||||
|
search: '搜索',
|
||||||
|
type: '类型',
|
||||||
|
name: '名字',
|
||||||
|
process: '进程',
|
||||||
|
host: '主机',
|
||||||
|
chains: '链路',
|
||||||
|
dlSpeed: '下载速度',
|
||||||
|
ulSpeed: '上传速度',
|
||||||
|
dl: '下载量',
|
||||||
|
ul: '上传量',
|
||||||
|
source: '源地址',
|
||||||
|
destination: '目标地址',
|
||||||
|
close: '关闭',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { createEventSignal } from '@solid-primitives/event-listener'
|
import { createEventSignal } from '@solid-primitives/event-listener'
|
||||||
|
import { useI18n } from '@solid-primitives/i18n'
|
||||||
import { makePersisted } from '@solid-primitives/storage'
|
import { makePersisted } from '@solid-primitives/storage'
|
||||||
import { createReconnectingWS } from '@solid-primitives/websocket'
|
import { createReconnectingWS } from '@solid-primitives/websocket'
|
||||||
import {
|
import {
|
||||||
@ -39,6 +40,7 @@ const initColumnVisibility = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
const [t] = useI18n()
|
||||||
const [columnVisibility, setColumnVisibility] = makePersisted(
|
const [columnVisibility, setColumnVisibility] = makePersisted(
|
||||||
createSignal<ColumnVisibility>(initColumnVisibility),
|
createSignal<ColumnVisibility>(initColumnVisibility),
|
||||||
{
|
{
|
||||||
@ -239,12 +241,14 @@ export default () => {
|
|||||||
<div class="flex w-full">
|
<div class="flex w-full">
|
||||||
<input
|
<input
|
||||||
class="input input-primary mr-4 w-40 flex-1"
|
class="input input-primary mr-4 w-40 flex-1"
|
||||||
placeholder="Search"
|
placeholder={t('search')}
|
||||||
onInput={(e) => setSearch(e.target.value)}
|
onInput={(e) => setSearch(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label for="connection-modal" class="btn btn-circle">
|
<label for="connection-modal" class="btn btn-circle">
|
||||||
<IconSettings />
|
<IconSettings />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<ConnectionsModal
|
<ConnectionsModal
|
||||||
order={columnOrder()}
|
order={columnOrder()}
|
||||||
visible={columnVisibility()}
|
visible={columnVisibility()}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { createEventSignal } from '@solid-primitives/event-listener'
|
import { createEventSignal } from '@solid-primitives/event-listener'
|
||||||
|
import { useI18n } from '@solid-primitives/i18n'
|
||||||
import { createReconnectingWS } from '@solid-primitives/websocket'
|
import { createReconnectingWS } from '@solid-primitives/websocket'
|
||||||
import {
|
import {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
@ -13,6 +14,7 @@ import { Log } from '~/types'
|
|||||||
type LogWithSeq = Log & { seq: number }
|
type LogWithSeq = Log & { seq: number }
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
const [t] = useI18n()
|
||||||
let seq = 0
|
let seq = 0
|
||||||
const [search, setSearch] = createSignal('')
|
const [search, setSearch] = createSignal('')
|
||||||
const [logs, setLogs] = createSignal<LogWithSeq[]>([])
|
const [logs, setLogs] = createSignal<LogWithSeq[]>([])
|
||||||
@ -68,7 +70,7 @@ export default () => {
|
|||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<input
|
<input
|
||||||
class="input input-primary"
|
class="input input-primary"
|
||||||
placeholder="Search"
|
placeholder={t('search')}
|
||||||
onInput={(e) => setSearch(e.target.value)}
|
onInput={(e) => setSearch(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -18,37 +18,6 @@ import type { Connection } from '~/types'
|
|||||||
|
|
||||||
const CHART_MAX_XAXIS = 10
|
const CHART_MAX_XAXIS = 10
|
||||||
|
|
||||||
const defaultChartOptions: ApexOptions = {
|
|
||||||
chart: {
|
|
||||||
toolbar: { show: false },
|
|
||||||
zoom: { enabled: false },
|
|
||||||
animations: { easing: 'linear' },
|
|
||||||
},
|
|
||||||
noData: { text: 'Loading...' },
|
|
||||||
legend: {
|
|
||||||
fontSize: '14px',
|
|
||||||
labels: { colors: 'gray' },
|
|
||||||
itemMargin: { horizontal: 64 },
|
|
||||||
},
|
|
||||||
dataLabels: { enabled: false },
|
|
||||||
grid: { yaxis: { lines: { show: false } } },
|
|
||||||
stroke: { curve: 'smooth' },
|
|
||||||
tooltip: { enabled: false },
|
|
||||||
xaxis: {
|
|
||||||
range: CHART_MAX_XAXIS,
|
|
||||||
labels: { show: false },
|
|
||||||
axisTicks: { show: false },
|
|
||||||
},
|
|
||||||
yaxis: {
|
|
||||||
labels: {
|
|
||||||
style: { colors: 'gray' },
|
|
||||||
formatter(val) {
|
|
||||||
return byteSize(val).toString()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
|
const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
|
||||||
<div class="stat flex-1">
|
<div class="stat flex-1">
|
||||||
<div class="stat-title text-secondary-content">{props.label}</div>
|
<div class="stat-title text-secondary-content">{props.label}</div>
|
||||||
@ -60,6 +29,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 }[]>(
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
@ -99,18 +69,53 @@ export default () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const defaultChartOptions: ApexOptions = {
|
||||||
|
chart: {
|
||||||
|
toolbar: { show: false },
|
||||||
|
zoom: { enabled: false },
|
||||||
|
animations: { easing: 'linear' },
|
||||||
|
},
|
||||||
|
noData: { text: 'Loading...' },
|
||||||
|
legend: {
|
||||||
|
fontSize: '14px',
|
||||||
|
labels: { colors: 'gray' },
|
||||||
|
itemMargin: { horizontal: 64 },
|
||||||
|
},
|
||||||
|
dataLabels: { enabled: false },
|
||||||
|
grid: { yaxis: { lines: { show: false } } },
|
||||||
|
stroke: { curve: 'smooth' },
|
||||||
|
tooltip: { enabled: false },
|
||||||
|
xaxis: {
|
||||||
|
range: CHART_MAX_XAXIS,
|
||||||
|
labels: { show: false },
|
||||||
|
axisTicks: { show: false },
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
labels: {
|
||||||
|
style: { colors: 'gray' },
|
||||||
|
formatter(val) {
|
||||||
|
return byteSize(val).toString()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const trafficChartOptions = createMemo<ApexOptions>(() => ({
|
const trafficChartOptions = createMemo<ApexOptions>(() => ({
|
||||||
title: { text: 'Traffic', align: 'center', style: { color: 'gray' } },
|
title: {
|
||||||
|
text: t('traffic'),
|
||||||
|
align: 'center',
|
||||||
|
style: { color: 'gray' },
|
||||||
|
},
|
||||||
...defaultChartOptions,
|
...defaultChartOptions,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const trafficChartSeries = createMemo(() => [
|
const trafficChartSeries = createMemo(() => [
|
||||||
{
|
{
|
||||||
name: 'Down',
|
name: t('down'),
|
||||||
data: traffics().map((t) => t.down),
|
data: traffics().map((t) => t.down),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Up',
|
name: t('up'),
|
||||||
data: traffics().map((t) => t.up),
|
data: traffics().map((t) => t.up),
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@ -138,16 +143,15 @@ export default () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const memoryChartOptions = createMemo<ApexOptions>(() => ({
|
const memoryChartOptions = createMemo<ApexOptions>(() => ({
|
||||||
title: { text: 'Memory', align: 'center', style: { color: 'gray' } },
|
title: {
|
||||||
|
text: t('memory'),
|
||||||
|
align: 'center',
|
||||||
|
style: { color: 'gray' },
|
||||||
|
},
|
||||||
...defaultChartOptions,
|
...defaultChartOptions,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const memoryChartSeries = createMemo(() => [
|
const memoryChartSeries = createMemo(() => [{ data: memories() }])
|
||||||
{
|
|
||||||
name: 'memory',
|
|
||||||
data: memories(),
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const connectionsWS = createReconnectingWS(
|
const connectionsWS = createReconnectingWS(
|
||||||
`${wsEndpointURL()}/connections?token=${secret()}`,
|
`${wsEndpointURL()}/connections?token=${secret()}`,
|
||||||
@ -172,27 +176,27 @@ export default () => {
|
|||||||
return (
|
return (
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="stats stats-vertical w-full bg-primary shadow lg:stats-horizontal lg:flex">
|
<div class="stats stats-vertical w-full bg-primary shadow lg:stats-horizontal lg:flex">
|
||||||
<TrafficWidget label={t('stats.upload')}>
|
<TrafficWidget label={t('upload')}>
|
||||||
{byteSize(traffic()?.up || 0).toString()}/s
|
{byteSize(traffic()?.up || 0).toString()}/s
|
||||||
</TrafficWidget>
|
</TrafficWidget>
|
||||||
|
|
||||||
<TrafficWidget label={t('stats.download')}>
|
<TrafficWidget label={t('download')}>
|
||||||
{byteSize(traffic()?.down || 0).toString()}/s
|
{byteSize(traffic()?.down || 0).toString()}/s
|
||||||
</TrafficWidget>
|
</TrafficWidget>
|
||||||
|
|
||||||
<TrafficWidget label={t('stats.uploadTotal')}>
|
<TrafficWidget label={t('uploadTotal')}>
|
||||||
{byteSize(connection()?.uploadTotal || 0).toString()}
|
{byteSize(connection()?.uploadTotal || 0).toString()}
|
||||||
</TrafficWidget>
|
</TrafficWidget>
|
||||||
|
|
||||||
<TrafficWidget label={t('stats.downloadTotal')}>
|
<TrafficWidget label={t('downloadTotal')}>
|
||||||
{byteSize(connection()?.downloadTotal || 0).toString()}
|
{byteSize(connection()?.downloadTotal || 0).toString()}
|
||||||
</TrafficWidget>
|
</TrafficWidget>
|
||||||
|
|
||||||
<TrafficWidget label={t('stats.activeConnections')}>
|
<TrafficWidget label={t('activeConnections')}>
|
||||||
{connection()?.connections.length || 0}
|
{connection()?.connections.length || 0}
|
||||||
</TrafficWidget>
|
</TrafficWidget>
|
||||||
|
|
||||||
<TrafficWidget label={t('stats.memoryUsage')}>
|
<TrafficWidget label={t('memoryUsage')}>
|
||||||
{byteSize(memory() || 0).toString()}
|
{byteSize(memory() || 0).toString()}
|
||||||
</TrafficWidget>
|
</TrafficWidget>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,9 +62,9 @@ export default () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-2">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="pb-4 text-lg font-semibold">{t('proxies.proxies')}</h1>
|
<h1 class="pb-4 text-lg font-semibold">{t('proxies')}</h1>
|
||||||
|
|
||||||
<ForTwoLine
|
<ForTwoLine
|
||||||
subChild={proxies().map((proxy) => {
|
subChild={proxies().map((proxy) => {
|
||||||
@ -119,7 +119,8 @@ export default () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show when={proxyProviders().length > 0}>
|
<Show when={proxyProviders().length > 0}>
|
||||||
<h1 class="pb-4 text-lg font-semibold">{t('proxies.proxyProvider')}</h1>
|
<div>
|
||||||
|
<h1 class="pb-4 text-lg font-semibold">{t('proxyProviders')}</h1>
|
||||||
|
|
||||||
<ForTwoLine
|
<ForTwoLine
|
||||||
subChild={proxyProviders().map((proxyProvider) => {
|
subChild={proxyProviders().map((proxyProvider) => {
|
||||||
@ -138,7 +139,9 @@ export default () => {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-circle btn-sm"
|
class="btn btn-circle btn-sm"
|
||||||
onClick={(e) => onHealthCheckClick(e, proxyProvider.name)}
|
onClick={(e) =>
|
||||||
|
onHealthCheckClick(e, proxyProvider.name)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<IconBrandSpeedtest />
|
<IconBrandSpeedtest />
|
||||||
</button>
|
</button>
|
||||||
@ -151,7 +154,9 @@ export default () => {
|
|||||||
{proxyProvider.vehicleType} :: Updated{' '}
|
{proxyProvider.vehicleType} :: Updated{' '}
|
||||||
{formatTimeFromNow(proxyProvider.updatedAt)}
|
{formatTimeFromNow(proxyProvider.updatedAt)}
|
||||||
</div>
|
</div>
|
||||||
<Show when={!collapsedMap()[`provider-${proxyProvider.name}`]}>
|
<Show
|
||||||
|
when={!collapsedMap()[`provider-${proxyProvider.name}`]}
|
||||||
|
>
|
||||||
<ProxyNodeDots
|
<ProxyNodeDots
|
||||||
proxyNameList={
|
proxyNameList={
|
||||||
proxyProvider.proxies.map((i) => i.name) ?? []
|
proxyProvider.proxies.map((i) => i.name) ?? []
|
||||||
@ -160,6 +165,7 @@ export default () => {
|
|||||||
</Show>
|
</Show>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<ProxyCardGroups
|
<ProxyCardGroups
|
||||||
proxies={proxyProvider.proxies.map((i) => i.name)}
|
proxies={proxyProvider.proxies.map((i) => i.name)}
|
||||||
@ -181,6 +187,7 @@ export default () => {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
import { useI18n } from '@solid-primitives/i18n'
|
||||||
import InfiniteScroll from 'solid-infinite-scroll'
|
import InfiniteScroll from 'solid-infinite-scroll'
|
||||||
import { For, createMemo, createSignal, onMount } from 'solid-js'
|
import { For, createMemo, createSignal, onMount } from 'solid-js'
|
||||||
import { useRequest } from '~/signals'
|
import { useRequest } from '~/signals'
|
||||||
import type { Rule, RuleProvider } from '~/types'
|
import type { Rule, RuleProvider } from '~/types'
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
const [t] = useI18n()
|
||||||
const request = useRequest()
|
const request = useRequest()
|
||||||
const [maxRuleRender, setMaxRuleRender] = createSignal(100)
|
const [maxRuleRender, setMaxRuleRender] = createSignal(100)
|
||||||
const [rules, setRules] = createSignal<Rule[]>([])
|
const [rules, setRules] = createSignal<Rule[]>([])
|
||||||
@ -27,7 +29,7 @@ export default () => {
|
|||||||
return (
|
return (
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="pb-4 text-lg font-semibold">Rules</h1>
|
<h1 class="pb-4 text-lg font-semibold">{t('rules')}</h1>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-2 sm:grid-cols-1">
|
<div class="grid grid-cols-1 gap-2 sm:grid-cols-1">
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
@ -48,7 +50,7 @@ export default () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1 class="pb-4 text-lg font-semibold">Rules Providers</h1>
|
<h1 class="pb-4 text-lg font-semibold">{t('ruleProviders')}</h1>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-2 sm:grid-cols-1">
|
<div class="grid grid-cols-1 gap-2 sm:grid-cols-1">
|
||||||
<For each={rulesProviders()}>
|
<For each={rulesProviders()}>
|
||||||
|
Loading…
Reference in New Issue
Block a user