mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-15 05:40:47 +08:00
refactor(frontend): remove unused modules
This commit is contained in:
@@ -21,15 +21,13 @@ src/locales/
|
||||
home.json
|
||||
shared.json
|
||||
...
|
||||
index.ts
|
||||
zh/
|
||||
...
|
||||
```
|
||||
|
||||
- JSON files map to namespaces (for example `home.json` → `home.*`). Keep keys scoped to the file they belong to.
|
||||
- `shared.json` stores reusable vocabulary (buttons, validations, etc.); feature-specific wording should live in the relevant namespace.
|
||||
- `index.ts` re-exports a `resources` object that aggregates the namespace JSON files. When adding or removing namespaces, mirror the pattern from `src/locales/en/index.ts`.
|
||||
- Frontend bundles are lazy-loaded by `src/services/i18n.ts`. Only languages listed in `supportedLanguages` are fetched at runtime, so append new codes there when you add a locale.
|
||||
- `src/services/i18n.ts` automatically discovers and lazy-loads each locale's JSON sections, so no aggregate module is required. Keep locales aligned with `src/locales/en/`, and add new codes to `supportedLanguages`.
|
||||
|
||||
Because backend translations now live in their own directory, you no longer need to run `pnpm prebuild` just to sync locales—the frontend folder is the sole source of truth for web bundles.
|
||||
|
||||
@@ -52,10 +50,9 @@ Native UI strings (tray menu, notifications, dialogs) use `rust-i18n` with YAML
|
||||
## Adding a new language
|
||||
|
||||
1. Duplicate `src/locales/en/` into `src/locales/<new-lang>/` and translate the JSON files while preserving key structure.
|
||||
2. Update the locale’s `index.ts` to import every namespace. Matching the English file is the easiest way to avoid missing exports.
|
||||
3. Append the language code to `supportedLanguages` in `src/services/i18n.ts`.
|
||||
4. If the backend should expose the language, create `crates/clash-verge-i18n/<new-lang>.yml` and translate the keys used in existing YAML files.
|
||||
5. Run `pnpm i18n:format`, `pnpm i18n:types`, and (optionally) `pnpm i18n:check` in dry-run mode to confirm structure.
|
||||
2. Append the language code to `supportedLanguages` in `src/services/i18n.ts`.
|
||||
3. If the backend should expose the language, create `crates/clash-verge-i18n/<new-lang>.yml` and translate the keys used in existing YAML files.
|
||||
4. Run `pnpm i18n:format`, `pnpm i18n:types`, and (optionally) `pnpm i18n:check` in dry-run mode to confirm structure.
|
||||
|
||||
## Authoring guidelines
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
@@ -1020,7 +1018,7 @@ function loadBackendLocales() {
|
||||
const localePath = path.join(BACKEND_LOCALES_DIR, entry.name)
|
||||
const name = entry.name.replace(/\.(ya?ml)$/i, '')
|
||||
const raw = fs.readFileSync(localePath, 'utf8')
|
||||
let data = {}
|
||||
let data
|
||||
try {
|
||||
const parsed = yaml.load(raw)
|
||||
data = isPlainObject(parsed) ? parsed : {}
|
||||
@@ -1055,6 +1053,7 @@ function ensureBackup(localePath) {
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to recycle existing backup for ${path.basename(localePath)}: ${error.message}`,
|
||||
{ cause: error },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1086,59 +1085,6 @@ function cleanupBackups(backups) {
|
||||
backups.clear()
|
||||
}
|
||||
|
||||
function toModuleIdentifier(namespace, seen) {
|
||||
const RESERVED = new Set([
|
||||
'default',
|
||||
'function',
|
||||
'var',
|
||||
'let',
|
||||
'const',
|
||||
'import',
|
||||
'export',
|
||||
'class',
|
||||
'enum',
|
||||
])
|
||||
|
||||
const base =
|
||||
namespace.replace(/[^a-zA-Z0-9_$]/g, '_').replace(/^[^a-zA-Z_$]+/, '') ||
|
||||
'ns'
|
||||
|
||||
let candidate = base
|
||||
let counter = 1
|
||||
while (RESERVED.has(candidate) || seen.has(candidate)) {
|
||||
candidate = `${base}_${counter}`
|
||||
counter += 1
|
||||
}
|
||||
seen.add(candidate)
|
||||
return candidate
|
||||
}
|
||||
|
||||
function regenerateLocaleIndex(localeDir, namespaces) {
|
||||
const seen = new Set()
|
||||
const imports = []
|
||||
const mappings = []
|
||||
|
||||
for (const namespace of namespaces) {
|
||||
const filePath = path.join(localeDir, `${namespace}.json`)
|
||||
if (!fs.existsSync(filePath)) continue
|
||||
const identifier = toModuleIdentifier(namespace, seen)
|
||||
const key = namespace === identifier ? namespace : `'${namespace}'`
|
||||
imports.push(`import ${identifier} from './${namespace}.json'`)
|
||||
mappings.push(` ${key}: ${identifier},`)
|
||||
}
|
||||
|
||||
const content = `${imports.join('\n')}
|
||||
|
||||
const resources = {
|
||||
${mappings.join('\n')}
|
||||
}
|
||||
|
||||
export default resources
|
||||
`
|
||||
|
||||
fs.writeFileSync(path.join(localeDir, 'index.ts'), content, 'utf8')
|
||||
}
|
||||
|
||||
function writeLocale(locale, data, options) {
|
||||
const backups = new Map()
|
||||
let success = false
|
||||
@@ -1163,7 +1109,6 @@ function writeLocale(locale, data, options) {
|
||||
}
|
||||
|
||||
const entries = Object.entries(data)
|
||||
const orderedNamespaces = entries.map(([namespace]) => namespace)
|
||||
const existingFiles = new Map(
|
||||
locale.files.map((file) => [file.namespace, file.path]),
|
||||
)
|
||||
@@ -1187,11 +1132,6 @@ function writeLocale(locale, data, options) {
|
||||
}
|
||||
}
|
||||
|
||||
regenerateLocaleIndex(locale.dir, orderedNamespaces)
|
||||
locale.files = orderedNamespaces.map((namespace) => ({
|
||||
namespace,
|
||||
path: path.join(locale.dir, `${namespace}.json`),
|
||||
}))
|
||||
success = true
|
||||
} finally {
|
||||
if (success) {
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import { CloseRounded } from '@mui/icons-material'
|
||||
import {
|
||||
styled,
|
||||
ListItem,
|
||||
IconButton,
|
||||
ListItemText,
|
||||
Box,
|
||||
alpha,
|
||||
} from '@mui/material'
|
||||
import { useLockFn } from 'ahooks'
|
||||
import dayjs from 'dayjs'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { closeConnection } from 'tauri-plugin-mihomo-api'
|
||||
|
||||
import parseTraffic from '@/utils/parse-traffic'
|
||||
|
||||
const Tag = styled('span')(({ theme }) => ({
|
||||
fontSize: '10px',
|
||||
padding: '0 4px',
|
||||
lineHeight: 1.375,
|
||||
border: '1px solid',
|
||||
borderRadius: 4,
|
||||
borderColor: alpha(theme.palette.text.secondary, 0.35),
|
||||
marginTop: '4px',
|
||||
marginRight: '4px',
|
||||
}))
|
||||
|
||||
interface Props {
|
||||
value: IConnectionsItem
|
||||
closed: boolean
|
||||
onShowDetail?: () => void
|
||||
}
|
||||
|
||||
export const ConnectionItem = (props: Props) => {
|
||||
const { value, closed, onShowDetail } = props
|
||||
|
||||
const { id, metadata, chains, start, curUpload, curDownload } = value
|
||||
const { t } = useTranslation()
|
||||
|
||||
const onDelete = useLockFn(async () => closeConnection(id))
|
||||
const showTraffic = curUpload! >= 100 || curDownload! >= 100
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
dense
|
||||
sx={{ borderBottom: '1px solid var(--divider-color)' }}
|
||||
secondaryAction={
|
||||
!closed && (
|
||||
<IconButton
|
||||
edge="end"
|
||||
color="inherit"
|
||||
onClick={onDelete}
|
||||
title={t('connections.components.actions.closeConnection')}
|
||||
aria-label={t('connections.components.actions.closeConnection')}
|
||||
>
|
||||
<CloseRounded />
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
>
|
||||
<ListItemText
|
||||
sx={{ userSelect: 'text', cursor: 'pointer' }}
|
||||
primary={metadata.host || metadata.destinationIP}
|
||||
onClick={onShowDetail}
|
||||
secondary={
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Tag sx={{ textTransform: 'uppercase', color: 'success' }}>
|
||||
{metadata.network}
|
||||
</Tag>
|
||||
|
||||
<Tag>{metadata.type}</Tag>
|
||||
|
||||
{!!metadata.process && <Tag>{metadata.process}</Tag>}
|
||||
|
||||
{chains?.length > 0 && (
|
||||
<Tag>{[...chains].reverse().join(' / ')}</Tag>
|
||||
)}
|
||||
|
||||
<Tag>{dayjs(start).fromNow()}</Tag>
|
||||
|
||||
{showTraffic && (
|
||||
<Tag>
|
||||
{parseTraffic(curUpload!)} / {parseTraffic(curDownload!)}
|
||||
</Tag>
|
||||
)}
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
TextField,
|
||||
} from '@mui/material'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface Props {
|
||||
onConfirm: (passwd: string) => Promise<void>
|
||||
}
|
||||
|
||||
export const PasswordInput = (props: Props) => {
|
||||
const { onConfirm } = props
|
||||
|
||||
const { t } = useTranslation()
|
||||
const [passwd, setPasswd] = useState('')
|
||||
|
||||
return (
|
||||
<Dialog open={true} maxWidth="xs" fullWidth>
|
||||
<DialogTitle>
|
||||
{t('settings.modals.password.prompts.enterRoot')}
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<TextField
|
||||
sx={{ mt: 1 }}
|
||||
autoFocus
|
||||
label={t('shared.labels.password')}
|
||||
fullWidth
|
||||
size="small"
|
||||
type="password"
|
||||
value={passwd}
|
||||
onKeyDown={(e) => e.key === 'Enter' && onConfirm(passwd)}
|
||||
onChange={(e) => setPasswd(e.target.value)}
|
||||
></TextField>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={async () => await onConfirm(passwd)}
|
||||
variant="contained"
|
||||
>
|
||||
{t('shared.actions.confirm')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import {
|
||||
useAppRefreshers,
|
||||
useClashConfigData,
|
||||
useProxiesData,
|
||||
} from '@/providers/app-data-context'
|
||||
|
||||
// 定义代理组类型
|
||||
interface ProxyGroup {
|
||||
name: string
|
||||
now: string
|
||||
}
|
||||
|
||||
// 获取当前代理节点信息的自定义Hook
|
||||
export const useCurrentProxy = () => {
|
||||
// 从AppDataProvider获取数据
|
||||
const { proxies } = useProxiesData()
|
||||
const { clashConfig } = useClashConfigData()
|
||||
const { refreshProxy } = useAppRefreshers()
|
||||
|
||||
// 获取当前模式
|
||||
const currentMode = clashConfig?.mode?.toLowerCase() || 'rule'
|
||||
|
||||
// 获取当前代理节点信息
|
||||
const currentProxyInfo = useMemo(() => {
|
||||
if (!proxies) return { currentProxy: null, primaryGroupName: null }
|
||||
|
||||
const { global, groups, records } = proxies
|
||||
|
||||
// 默认信息
|
||||
let primaryGroupName = 'GLOBAL'
|
||||
let currentName = global?.now
|
||||
|
||||
// 在规则模式下,寻找主要代理组(通常是第一个或者名字包含特定关键词的组)
|
||||
if (currentMode === 'rule' && groups.length > 0) {
|
||||
// 查找主要的代理组(优先级:包含关键词 > 第一个非GLOBAL组)
|
||||
const primaryKeywords = [
|
||||
'auto',
|
||||
'select',
|
||||
'proxy',
|
||||
'节点选择',
|
||||
'自动选择',
|
||||
]
|
||||
const primaryGroup =
|
||||
groups.find((group: ProxyGroup) =>
|
||||
primaryKeywords.some((keyword) =>
|
||||
group.name.toLowerCase().includes(keyword.toLowerCase()),
|
||||
),
|
||||
) || groups.filter((g: ProxyGroup) => g.name !== 'GLOBAL')[0]
|
||||
|
||||
if (primaryGroup) {
|
||||
primaryGroupName = primaryGroup.name
|
||||
currentName = primaryGroup.now
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到当前节点,返回null
|
||||
if (!currentName) return { currentProxy: null, primaryGroupName }
|
||||
|
||||
// 获取完整的节点信息
|
||||
const currentProxy = records[currentName] || {
|
||||
name: currentName,
|
||||
type: 'Unknown',
|
||||
udp: false,
|
||||
xudp: false,
|
||||
tfo: false,
|
||||
mptcp: false,
|
||||
smux: false,
|
||||
history: [],
|
||||
}
|
||||
|
||||
return { currentProxy, primaryGroupName }
|
||||
}, [proxies, currentMode])
|
||||
|
||||
return {
|
||||
currentProxy: currentProxyInfo.currentProxy,
|
||||
primaryGroupName: currentProxyInfo.primaryGroupName,
|
||||
mode: currentMode,
|
||||
refreshProxy,
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "إعادة تنشيط الملفات الشخصية"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "يرجى إدخال كلمة مرور الرووت"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "واجهة الشبكة",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "Abonnement erneut aktivieren"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "Bitte geben Sie Ihr Root-Passwort ein."
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "Netzwerkschnittstelle",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "Reactivate Profiles"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "Please enter your root password"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "Network Interface",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "Reactivar suscripciones"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "Ingrese su contraseña de root"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "Interfaz de red",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "فعالسازی مجدد پروفایلها"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "لطفاً رمز ریشه خود را وارد کنید"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "رابط شبکه",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "Reaktivasi Profil"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "Harap masukkan kata sandi root Anda"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "Antarmuka Jaringan",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "プロファイルを再アクティブ化"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "ルートパスワードを入力してください。"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "ネットワークインターフェース",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "프로필 재활성화"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "루트 암호를 입력하세요"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "네트워크 인터페이스",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "Перезапустить профиль"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "Пожалуйста, введите пароль root"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "Сетевой интерфейс",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "Profilleri Yeniden Etkinleştir"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "Lütfen root şifrenizi girin"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "Ağ Arayüzü",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "Профильләрне янәдән активлаштыру"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "root паролен языгыз"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "Челтәр интерфейсы",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "重新激活订阅"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "请输入您的 root 密码"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "网络接口",
|
||||
"fields": {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import connections from './connections.json'
|
||||
import home from './home.json'
|
||||
import layout from './layout.json'
|
||||
import logs from './logs.json'
|
||||
import profiles from './profiles.json'
|
||||
import proxies from './proxies.json'
|
||||
import rules from './rules.json'
|
||||
import settings from './settings.json'
|
||||
import shared from './shared.json'
|
||||
import tests from './tests.json'
|
||||
|
||||
const resources = {
|
||||
connections: connections,
|
||||
home: home,
|
||||
layout: layout,
|
||||
logs: logs,
|
||||
profiles: profiles,
|
||||
proxies: proxies,
|
||||
rules: rules,
|
||||
settings: settings,
|
||||
shared: shared,
|
||||
tests: tests,
|
||||
}
|
||||
|
||||
export default resources
|
||||
@@ -609,11 +609,6 @@
|
||||
"reactivateProfiles": "重新啟用訂閱"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"prompts": {
|
||||
"enterRoot": "請輸入您的 root 密碼"
|
||||
}
|
||||
},
|
||||
"networkInterface": {
|
||||
"title": "網路介面",
|
||||
"fields": {
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { createContext, use } from 'react'
|
||||
|
||||
export interface ChainProxyContextType {
|
||||
isChainMode: boolean
|
||||
setChainMode: (isChain: boolean) => void
|
||||
chainConfigData: string | null
|
||||
setChainConfigData: (data: string | null) => void
|
||||
}
|
||||
|
||||
export const ChainProxyContext = createContext<ChainProxyContextType | null>(
|
||||
null,
|
||||
)
|
||||
|
||||
export const useChainProxy = () => {
|
||||
const context = use(ChainProxyContext)
|
||||
if (!context) {
|
||||
throw new Error('useChainProxy must be used within a ChainProxyProvider')
|
||||
}
|
||||
return context
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
|
||||
import { ChainProxyContext } from './chain-proxy-context'
|
||||
|
||||
export const ChainProxyProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) => {
|
||||
const [isChainMode, setIsChainMode] = useState(false)
|
||||
const [chainConfigData, setChainConfigData] = useState<string | null>(null)
|
||||
|
||||
const setChainMode = useCallback((isChain: boolean) => {
|
||||
setIsChainMode(isChain)
|
||||
}, [])
|
||||
|
||||
const setChainConfigDataCallback = useCallback((data: string | null) => {
|
||||
setChainConfigData(data)
|
||||
}, [])
|
||||
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
isChainMode,
|
||||
setChainMode,
|
||||
chainConfigData,
|
||||
setChainConfigData: setChainConfigDataCallback,
|
||||
}),
|
||||
[isChainMode, setChainMode, chainConfigData, setChainConfigDataCallback],
|
||||
)
|
||||
|
||||
return <ChainProxyContext value={contextValue}>{children}</ChainProxyContext>
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
const SWR_NOT_SMART = {
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
revalidateIfStale: false,
|
||||
suspense: false,
|
||||
errorRetryCount: 2,
|
||||
dedupingInterval: 1500,
|
||||
errorRetryInterval: 3000,
|
||||
} as const
|
||||
|
||||
export const SWR_DEFAULTS = {
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
suspense: false,
|
||||
errorRetryCount: 2,
|
||||
dedupingInterval: 5000,
|
||||
} as const
|
||||
|
||||
export const SWR_SLOW_POLL = {
|
||||
...SWR_DEFAULTS,
|
||||
refreshInterval: 60000,
|
||||
} as const
|
||||
|
||||
export const SWR_MIHOMO = {
|
||||
...SWR_NOT_SMART,
|
||||
errorRetryInterval: 2000,
|
||||
errorRetryCount: 3,
|
||||
}
|
||||
|
||||
export const SWR_EXTERNAL_API = {
|
||||
...SWR_NOT_SMART,
|
||||
shouldRetryOnError: true,
|
||||
errorRetryCount: 1,
|
||||
errorRetryInterval: 30_000,
|
||||
} as const
|
||||
@@ -672,7 +672,6 @@ export const translationKeys = [
|
||||
'settings.modals.hotkey.functions.entryLightweightMode',
|
||||
'settings.modals.hotkey.functions.direct',
|
||||
'settings.modals.hotkey.functions.reactivateProfiles',
|
||||
'settings.modals.password.prompts.enterRoot',
|
||||
'settings.modals.networkInterface.title',
|
||||
'settings.modals.networkInterface.fields.ipAddress',
|
||||
'settings.modals.networkInterface.fields.macAddress',
|
||||
|
||||
@@ -981,11 +981,6 @@ export interface TranslationResources {
|
||||
}
|
||||
title: string
|
||||
}
|
||||
password: {
|
||||
prompts: {
|
||||
enterRoot: string
|
||||
}
|
||||
}
|
||||
sysproxy: {
|
||||
actions: {
|
||||
editPac: string
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// Deep copy and change all keys to lowercase
|
||||
type TData = Record<string, any>
|
||||
|
||||
export default function ignoreCase(data: TData): TData {
|
||||
if (!data) return {}
|
||||
|
||||
const newData = {} as TData
|
||||
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
newData[key.toLowerCase()] = JSON.parse(JSON.stringify(value))
|
||||
})
|
||||
|
||||
return newData
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export const truncateStr = (str?: string, prefixLen = 16, maxLen = 56) => {
|
||||
if (!str || str.length <= maxLen) return str
|
||||
return (
|
||||
str.slice(0, prefixLen) + ' ... ' + str.slice(-(maxLen - prefixLen - 5))
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user