refactor(i18n): flatten locales and move theme/validation strings
This commit is contained in:
@@ -66,19 +66,19 @@ The locale files now follow a two-namespace layout designed to mirror the React/
|
||||
|
||||
- **`shared.*`** — cross-cutting vocabulary (buttons, statuses, validation hints, window chrome, etc.).
|
||||
- Buckets to prefer: `actions`, `labels`, `statuses`, `messages`, `placeholders`, `units`, `validation`, `window`, `editorModes`.
|
||||
- Add to `shared` only when the copy is used (or is expected to be reused) by two or more features. Otherwise keep it in the owning feature under `entities`.
|
||||
- **`entities.<feature>.*`** — route-level or domain-level strings scoped to a single feature.
|
||||
- Top-level nodes generally match folders under `src/pages`, `src/components`, or service domains (`settings`, `proxy`, `profile`, `home`, `validation`, `unlock`, …).
|
||||
- Within a feature namespace, prefer consistent buckets like `view`, `page`, `sections`, `forms`, `fields`, `actions`, `tooltips`, `notifications`, `errors`, `dialogs`, `tables`, `components`. Choose the minimum depth needed to describe the UI.
|
||||
- Add to `shared` only when the copy is used (or is expected to be reused) by two or more features. Otherwise keep it in the owning feature namespace.
|
||||
- **`<feature>.*`** — route-level or domain-level strings scoped to a single feature.
|
||||
- Top-level keys mirror folders under `src/pages`, `src/components`, or service domains (`settings`, `proxies`, `profiles`, `home`, `unlock`, `layout`, …).
|
||||
- Within a feature namespace, prefer consistent buckets like `page`, `sections`, `forms`, `fields`, `actions`, `tooltips`, `notifications`, `errors`, `dialogs`, `tables`, `components`. Choose the minimum depth needed to describe the UI.
|
||||
|
||||
### Authoring guidelines
|
||||
|
||||
1. **Follow the shared/feature split** — before inventing a new key, check whether an equivalent exists under `shared.*`.
|
||||
2. **Use camelCase leaf keys** — keep names semantic (`systemProxy`, `updateInterval`) and avoid positional names (`item1`, `btn_ok`).
|
||||
3. **Group by UI responsibility** — for example:
|
||||
- `entities.settings.dns.fields.listen`
|
||||
- `entities.settings.dns.dialog.title`
|
||||
- `entities.settings.dns.sections.general`
|
||||
- `settings.dns.fields.listen`
|
||||
- `settings.dns.dialog.title`
|
||||
- `settings.dns.sections.general`
|
||||
4. **Component-specific copy** — nest under `components.<ComponentName>` or `dialogs.<DialogName>` to keep implementation-specific strings organized but still discoverable.
|
||||
5. **Dynamic placeholders** — continue using `{{placeholder}}` syntax and document required params in code when possible.
|
||||
|
||||
@@ -92,23 +92,21 @@ The locale files now follow a two-namespace layout designed to mirror the React/
|
||||
"cancel": "Cancel"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"profile": {
|
||||
"view": {
|
||||
"title": "Profiles",
|
||||
"actions": {
|
||||
"import": "Import",
|
||||
"updateAll": "Update All Profiles"
|
||||
},
|
||||
"notifications": {
|
||||
"importSuccess": "Profile imported successfully"
|
||||
}
|
||||
"profiles": {
|
||||
"page": {
|
||||
"title": "Profiles",
|
||||
"actions": {
|
||||
"import": "Import",
|
||||
"updateAll": "Update All Profiles"
|
||||
},
|
||||
"components": {
|
||||
"batchDialog": {
|
||||
"title": "Batch Operations",
|
||||
"items": "items"
|
||||
}
|
||||
"notifications": {
|
||||
"importSuccess": "Profile imported successfully"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"batchDialog": {
|
||||
"title": "Batch Operations",
|
||||
"items": "items"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,7 @@
|
||||
"lint:fix": "eslint -c eslint.config.ts --max-warnings=0 --cache --cache-location .eslintcache --fix src",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"format:i18n": "node scripts/cleanup-unused-i18n.mjs --align --apply && pnpm i18n:validate",
|
||||
"i18n:validate": "node scripts/validate-i18n-structure.mjs",
|
||||
"format:i18n": "node scripts/cleanup-unused-i18n.mjs --align --apply",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run"
|
||||
},
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readFileSync, readdirSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import process from "node:process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { glob } from "glob";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const repoRoot = path.resolve(__dirname, "..");
|
||||
const localesDir = path.join(repoRoot, "src", "locales");
|
||||
const baselineFile = path.join(localesDir, "en.json");
|
||||
|
||||
const bannedNamespaces = [
|
||||
"common",
|
||||
"profiles",
|
||||
"settings",
|
||||
"proxies",
|
||||
"rules",
|
||||
"home",
|
||||
"connections",
|
||||
"logs",
|
||||
"theme",
|
||||
"unlock",
|
||||
"validation",
|
||||
];
|
||||
|
||||
function isRecord(value) {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function compareStructure(base, target, segments = []) {
|
||||
const errors = [];
|
||||
const baseKeys = Object.keys(base ?? {}).sort();
|
||||
const targetKeys = Object.keys(target ?? {}).sort();
|
||||
|
||||
const missing = baseKeys.filter((key) => !targetKeys.includes(key));
|
||||
const extra = targetKeys.filter((key) => !baseKeys.includes(key));
|
||||
|
||||
if (missing.length > 0) {
|
||||
errors.push(
|
||||
`Missing keys at ${segments.join(".") || "<root>"}: ${missing.join(", ")}`,
|
||||
);
|
||||
}
|
||||
if (extra.length > 0) {
|
||||
errors.push(
|
||||
`Unexpected keys at ${segments.join(".") || "<root>"}: ${extra.join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
for (const key of baseKeys) {
|
||||
if (!targetKeys.includes(key)) continue;
|
||||
const nextSegments = [...segments, key];
|
||||
const baseValue = base[key];
|
||||
const targetValue = target[key];
|
||||
|
||||
if (isRecord(baseValue) !== isRecord(targetValue)) {
|
||||
errors.push(
|
||||
`Type mismatch at ${nextSegments.join(".")}: expected ${
|
||||
isRecord(baseValue) ? "object" : "string"
|
||||
}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isRecord(baseValue) && isRecord(targetValue)) {
|
||||
errors.push(...compareStructure(baseValue, targetValue, nextSegments));
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
function readJson(file) {
|
||||
return JSON.parse(readFileSync(file, "utf8"));
|
||||
}
|
||||
|
||||
function validateLocaleParity() {
|
||||
const baseline = readJson(baselineFile);
|
||||
const localeFiles = readdirSync(localesDir)
|
||||
.filter((file) => file.endsWith(".json"))
|
||||
.map((file) => path.join(localesDir, file));
|
||||
|
||||
const issues = [];
|
||||
|
||||
for (const localeFile of localeFiles) {
|
||||
if (localeFile === baselineFile) continue;
|
||||
const localeData = readJson(localeFile);
|
||||
const diff = compareStructure(baseline, localeData);
|
||||
if (diff.length) {
|
||||
issues.push(
|
||||
`Locale ${path.basename(localeFile)}:\n ${diff.join("\n ")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
async function validateCodePrefixes() {
|
||||
const files = await glob("src/**/*.{ts,tsx,js,jsx,mts,cts}", {
|
||||
cwd: repoRoot,
|
||||
nodir: true,
|
||||
ignore: ["src/locales/**"],
|
||||
});
|
||||
|
||||
const violations = [];
|
||||
|
||||
for (const relativePath of files) {
|
||||
const absolutePath = path.join(repoRoot, relativePath);
|
||||
const content = readFileSync(absolutePath, "utf8");
|
||||
|
||||
for (const ns of bannedNamespaces) {
|
||||
const pattern = new RegExp(`["'\`]${ns}\\.`, "g");
|
||||
if (pattern.test(content)) {
|
||||
violations.push(
|
||||
`${relativePath}: forbidden namespace "${ns}." detected`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const issues = validateLocaleParity();
|
||||
const prefixViolations = await validateCodePrefixes();
|
||||
const allProblems = [...issues, ...prefixViolations];
|
||||
|
||||
if (allProblems.length > 0) {
|
||||
console.error("i18n structure validation failed:\n");
|
||||
for (const problem of allProblems) {
|
||||
console.error(`- ${problem}`);
|
||||
}
|
||||
console.error(
|
||||
"\nRun `pnpm format:i18n` or update locale files to match the baseline.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("i18n structure validation passed.");
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error("Unexpected error while validating i18n structure:");
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -68,50 +68,50 @@ const InnerConnectionDetail = ({ data, onClose }: InnerProps) => {
|
||||
: metadata.remoteDestination;
|
||||
|
||||
const information = [
|
||||
{ label: t("entities.connection.fields.host"), value: host },
|
||||
{ label: t("connections.fields.host"), value: host },
|
||||
{
|
||||
label: t("entities.connection.fields.downloaded"),
|
||||
label: t("connections.fields.downloaded"),
|
||||
value: parseTraffic(data.download).join(" "),
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.uploaded"),
|
||||
label: t("connections.fields.uploaded"),
|
||||
value: parseTraffic(data.upload).join(" "),
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.dlSpeed"),
|
||||
label: t("connections.fields.dlSpeed"),
|
||||
value: parseTraffic(data.curDownload ?? -1).join(" ") + "/s",
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.ulSpeed"),
|
||||
label: t("connections.fields.ulSpeed"),
|
||||
value: parseTraffic(data.curUpload ?? -1).join(" ") + "/s",
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.chains"),
|
||||
label: t("connections.fields.chains"),
|
||||
value: chains,
|
||||
},
|
||||
{ label: t("entities.connection.fields.rule"), value: rule },
|
||||
{ label: t("connections.fields.rule"), value: rule },
|
||||
{
|
||||
label: t("entities.connection.fields.process"),
|
||||
label: t("connections.fields.process"),
|
||||
value: `${metadata.process}${metadata.processPath ? `(${metadata.processPath})` : ""}`,
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.time"),
|
||||
label: t("connections.fields.time"),
|
||||
value: dayjs(data.start).fromNow(),
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.source"),
|
||||
label: t("connections.fields.source"),
|
||||
value: `${metadata.sourceIP}:${metadata.sourcePort}`,
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.destination"),
|
||||
label: t("connections.fields.destination"),
|
||||
value: Destination,
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.destinationPort"),
|
||||
label: t("connections.fields.destinationPort"),
|
||||
value: `${metadata.destinationPort}`,
|
||||
},
|
||||
{
|
||||
label: t("entities.connection.fields.type"),
|
||||
label: t("connections.fields.type"),
|
||||
value: `${metadata.type}(${metadata.network})`,
|
||||
},
|
||||
];
|
||||
@@ -137,13 +137,13 @@ const InnerConnectionDetail = ({ data, onClose }: InnerProps) => {
|
||||
<Box sx={{ textAlign: "right" }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
title={t("entities.connection.actions.closeConnection")}
|
||||
title={t("connections.actions.closeConnection")}
|
||||
onClick={() => {
|
||||
onDelete();
|
||||
onClose?.();
|
||||
}}
|
||||
>
|
||||
{t("entities.connection.actions.closeConnection")}
|
||||
{t("connections.actions.closeConnection")}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -48,8 +48,8 @@ export const ConnectionItem = (props: Props) => {
|
||||
edge="end"
|
||||
color="inherit"
|
||||
onClick={onDelete}
|
||||
title={t("entities.connection.actions.closeConnection")}
|
||||
aria-label={t("entities.connection.actions.closeConnection")}
|
||||
title={t("connections.actions.closeConnection")}
|
||||
aria-label={t("connections.actions.closeConnection")}
|
||||
>
|
||||
<CloseRounded />
|
||||
</IconButton>
|
||||
|
||||
@@ -162,13 +162,13 @@ export const ConnectionTable = (props: Props) => {
|
||||
return [
|
||||
{
|
||||
field: "host",
|
||||
headerName: t("entities.connection.fields.host"),
|
||||
headerName: t("connections.fields.host"),
|
||||
width: columnWidths["host"] || 220,
|
||||
minWidth: 180,
|
||||
},
|
||||
{
|
||||
field: "download",
|
||||
headerName: t("entities.connection.fields.downloaded"),
|
||||
headerName: t("connections.fields.downloaded"),
|
||||
width: columnWidths["download"] || 88,
|
||||
align: "right",
|
||||
headerAlign: "right",
|
||||
@@ -176,7 +176,7 @@ export const ConnectionTable = (props: Props) => {
|
||||
},
|
||||
{
|
||||
field: "upload",
|
||||
headerName: t("entities.connection.fields.uploaded"),
|
||||
headerName: t("connections.fields.uploaded"),
|
||||
width: columnWidths["upload"] || 88,
|
||||
align: "right",
|
||||
headerAlign: "right",
|
||||
@@ -184,7 +184,7 @@ export const ConnectionTable = (props: Props) => {
|
||||
},
|
||||
{
|
||||
field: "dlSpeed",
|
||||
headerName: t("entities.connection.fields.dlSpeed"),
|
||||
headerName: t("connections.fields.dlSpeed"),
|
||||
width: columnWidths["dlSpeed"] || 88,
|
||||
align: "right",
|
||||
headerAlign: "right",
|
||||
@@ -192,7 +192,7 @@ export const ConnectionTable = (props: Props) => {
|
||||
},
|
||||
{
|
||||
field: "ulSpeed",
|
||||
headerName: t("entities.connection.fields.ulSpeed"),
|
||||
headerName: t("connections.fields.ulSpeed"),
|
||||
width: columnWidths["ulSpeed"] || 88,
|
||||
align: "right",
|
||||
headerAlign: "right",
|
||||
@@ -200,25 +200,25 @@ export const ConnectionTable = (props: Props) => {
|
||||
},
|
||||
{
|
||||
field: "chains",
|
||||
headerName: t("entities.connection.fields.chains"),
|
||||
headerName: t("connections.fields.chains"),
|
||||
width: columnWidths["chains"] || 340,
|
||||
minWidth: 180,
|
||||
},
|
||||
{
|
||||
field: "rule",
|
||||
headerName: t("entities.connection.fields.rule"),
|
||||
headerName: t("connections.fields.rule"),
|
||||
width: columnWidths["rule"] || 280,
|
||||
minWidth: 180,
|
||||
},
|
||||
{
|
||||
field: "process",
|
||||
headerName: t("entities.connection.fields.process"),
|
||||
headerName: t("connections.fields.process"),
|
||||
width: columnWidths["process"] || 220,
|
||||
minWidth: 180,
|
||||
},
|
||||
{
|
||||
field: "time",
|
||||
headerName: t("entities.connection.fields.time"),
|
||||
headerName: t("connections.fields.time"),
|
||||
width: columnWidths["time"] || 120,
|
||||
minWidth: 100,
|
||||
align: "right",
|
||||
@@ -229,19 +229,19 @@ export const ConnectionTable = (props: Props) => {
|
||||
},
|
||||
{
|
||||
field: "source",
|
||||
headerName: t("entities.connection.fields.source"),
|
||||
headerName: t("connections.fields.source"),
|
||||
width: columnWidths["source"] || 200,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
field: "remoteDestination",
|
||||
headerName: t("entities.connection.fields.destination"),
|
||||
headerName: t("connections.fields.destination"),
|
||||
width: columnWidths["remoteDestination"] || 200,
|
||||
minWidth: 130,
|
||||
},
|
||||
{
|
||||
field: "type",
|
||||
headerName: t("entities.connection.fields.type"),
|
||||
headerName: t("connections.fields.type"),
|
||||
width: columnWidths["type"] || 160,
|
||||
minWidth: 100,
|
||||
},
|
||||
|
||||
@@ -32,7 +32,7 @@ export const ClashInfoCard = () => {
|
||||
<Stack spacing={1.5}>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.clashInfo.fields.coreVersion")}
|
||||
{t("home.cards.clashInfo.fields.coreVersion")}
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
{clashVersion || "-"}
|
||||
@@ -41,7 +41,7 @@ export const ClashInfoCard = () => {
|
||||
<Divider />
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.clashInfo.fields.systemProxyAddress")}
|
||||
{t("home.cards.clashInfo.fields.systemProxyAddress")}
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
{systemProxyAddress}
|
||||
@@ -50,7 +50,7 @@ export const ClashInfoCard = () => {
|
||||
<Divider />
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.clashInfo.fields.mixedPort")}
|
||||
{t("home.cards.clashInfo.fields.mixedPort")}
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
{clashConfig.mixedPort || "-"}
|
||||
@@ -59,7 +59,7 @@ export const ClashInfoCard = () => {
|
||||
<Divider />
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.clashInfo.fields.uptime")}
|
||||
{t("home.cards.clashInfo.fields.uptime")}
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
{formattedUptime}
|
||||
@@ -68,7 +68,7 @@ export const ClashInfoCard = () => {
|
||||
<Divider />
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.clashInfo.fields.rulesCount")}
|
||||
{t("home.cards.clashInfo.fields.rulesCount")}
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
{rules.length}
|
||||
@@ -87,7 +87,7 @@ export const ClashInfoCard = () => {
|
||||
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.cards.clashInfo.title")}
|
||||
title={t("home.cards.clashInfo.title")}
|
||||
icon={<DeveloperBoardOutlined />}
|
||||
iconColor="warning"
|
||||
action={null}
|
||||
|
||||
@@ -21,16 +21,16 @@ const isClashMode = (mode: string): mode is ClashMode =>
|
||||
|
||||
const MODE_META: Record<ClashMode, { label: string; description: string }> = {
|
||||
rule: {
|
||||
label: "entities.home.cards.clashMode.labels.rule",
|
||||
description: "entities.home.cards.clashMode.descriptions.rule",
|
||||
label: "home.cards.clashMode.labels.rule",
|
||||
description: "home.cards.clashMode.descriptions.rule",
|
||||
},
|
||||
global: {
|
||||
label: "entities.home.cards.clashMode.labels.global",
|
||||
description: "entities.home.cards.clashMode.descriptions.global",
|
||||
label: "home.cards.clashMode.labels.global",
|
||||
description: "home.cards.clashMode.descriptions.global",
|
||||
},
|
||||
direct: {
|
||||
label: "entities.home.cards.clashMode.labels.direct",
|
||||
description: "entities.home.cards.clashMode.descriptions.direct",
|
||||
label: "home.cards.clashMode.labels.direct",
|
||||
description: "home.cards.clashMode.descriptions.direct",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -53,7 +53,7 @@ export const ClashModeCard = () => {
|
||||
if (currentModeKey) {
|
||||
return t(MODE_META[currentModeKey].description);
|
||||
}
|
||||
return t("entities.home.cards.clashMode.errors.communication");
|
||||
return t("home.cards.clashMode.errors.communication");
|
||||
}, [currentModeKey, t]);
|
||||
|
||||
// 模式图标映射
|
||||
|
||||
@@ -811,11 +811,11 @@ export const CurrentProxyCard = () => {
|
||||
const getSortTooltip = (): string => {
|
||||
switch (sortType) {
|
||||
case 0:
|
||||
return t("entities.proxy.page.tooltips.sortDefault");
|
||||
return t("proxies.page.tooltips.sortDefault");
|
||||
case 1:
|
||||
return t("entities.proxy.page.tooltips.sortDelay");
|
||||
return t("proxies.page.tooltips.sortDelay");
|
||||
case 2:
|
||||
return t("entities.proxy.page.tooltips.sortName");
|
||||
return t("proxies.page.tooltips.sortName");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@@ -823,7 +823,7 @@ export const CurrentProxyCard = () => {
|
||||
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.cards.currentProxy.title")}
|
||||
title={t("home.cards.currentProxy.title")}
|
||||
icon={
|
||||
<Tooltip
|
||||
title={
|
||||
@@ -840,9 +840,7 @@ export const CurrentProxyCard = () => {
|
||||
iconColor={currentProxy ? "primary" : undefined}
|
||||
action={
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<Tooltip
|
||||
title={t("entities.home.cards.currentProxy.actions.refreshDelay")}
|
||||
>
|
||||
<Tooltip title={t("home.cards.currentProxy.actions.refreshDelay")}>
|
||||
<span>
|
||||
<IconButton
|
||||
size="small"
|
||||
@@ -870,7 +868,7 @@ export const CurrentProxyCard = () => {
|
||||
sx={{ borderRadius: 1.5 }}
|
||||
endIcon={<ChevronRight fontSize="small" />}
|
||||
>
|
||||
{t("entities.navigation.tabs.proxies")}
|
||||
{t("layout.navigation.tabs.proxies")}
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
@@ -908,9 +906,7 @@ export const CurrentProxyCard = () => {
|
||||
{isGlobalMode && (
|
||||
<Chip
|
||||
size="small"
|
||||
label={t(
|
||||
"entities.home.cards.currentProxy.labels.globalMode",
|
||||
)}
|
||||
label={t("home.cards.currentProxy.labels.globalMode")}
|
||||
color="primary"
|
||||
sx={{ mr: 0.5 }}
|
||||
/>
|
||||
@@ -918,9 +914,7 @@ export const CurrentProxyCard = () => {
|
||||
{isDirectMode && (
|
||||
<Chip
|
||||
size="small"
|
||||
label={t(
|
||||
"entities.home.cards.currentProxy.labels.directMode",
|
||||
)}
|
||||
label={t("home.cards.currentProxy.labels.directMode")}
|
||||
color="success"
|
||||
sx={{ mr: 0.5 }}
|
||||
/>
|
||||
@@ -961,13 +955,13 @@ export const CurrentProxyCard = () => {
|
||||
sx={{ mb: 1.5 }}
|
||||
>
|
||||
<InputLabel id="proxy-group-select-label">
|
||||
{t("entities.home.cards.currentProxy.labels.group")}
|
||||
{t("home.cards.currentProxy.labels.group")}
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="proxy-group-select-label"
|
||||
value={state.selection.group}
|
||||
onChange={handleGroupChange}
|
||||
label={t("entities.home.cards.currentProxy.labels.group")}
|
||||
label={t("home.cards.currentProxy.labels.group")}
|
||||
disabled={isGlobalMode || isDirectMode}
|
||||
>
|
||||
{state.proxyData.groups.map((group) => (
|
||||
@@ -981,13 +975,13 @@ export const CurrentProxyCard = () => {
|
||||
{/* 代理节点选择器 */}
|
||||
<FormControl fullWidth variant="outlined" size="small" sx={{ mb: 0 }}>
|
||||
<InputLabel id="proxy-select-label">
|
||||
{t("entities.home.cards.currentProxy.labels.proxy")}
|
||||
{t("home.cards.currentProxy.labels.proxy")}
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="proxy-select-label"
|
||||
value={state.selection.proxy}
|
||||
onChange={handleProxyChange}
|
||||
label={t("entities.home.cards.currentProxy.labels.proxy")}
|
||||
label={t("home.cards.currentProxy.labels.proxy")}
|
||||
disabled={isDirectMode}
|
||||
renderValue={renderProxyValue}
|
||||
MenuProps={{
|
||||
@@ -1043,7 +1037,7 @@ export const CurrentProxyCard = () => {
|
||||
) : (
|
||||
<Box sx={{ textAlign: "center", py: 4 }}>
|
||||
<Typography variant="body1" color="text.secondary">
|
||||
{t("entities.home.cards.currentProxy.labels.noActiveNode")}
|
||||
{t("home.cards.currentProxy.labels.noActiveNode")}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -851,7 +851,7 @@ export const EnhancedCanvasTrafficGraph = memo(
|
||||
|
||||
// 获取时间范围文本
|
||||
const getTimeRangeText = useCallback(() => {
|
||||
return t("entities.home.cards.traffic.patterns.minutes", {
|
||||
return t("home.cards.traffic.patterns.minutes", {
|
||||
time: timeRange,
|
||||
});
|
||||
}, [timeRange, t]);
|
||||
@@ -936,7 +936,7 @@ export const EnhancedCanvasTrafficGraph = memo(
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
{t("entities.home.cards.traffic.legends.upload")}
|
||||
{t("home.cards.traffic.legends.upload")}
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
@@ -946,7 +946,7 @@ export const EnhancedCanvasTrafficGraph = memo(
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
{t("entities.home.cards.traffic.legends.download")}
|
||||
{t("home.cards.traffic.legends.download")}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -219,42 +219,42 @@ export const EnhancedTrafficStats = () => {
|
||||
() => [
|
||||
{
|
||||
icon: <ArrowUpwardRounded fontSize="small" />,
|
||||
title: t("entities.home.cards.traffic.metrics.uploadSpeed"),
|
||||
title: t("home.cards.traffic.metrics.uploadSpeed"),
|
||||
value: parsedData.up,
|
||||
unit: `${parsedData.upUnit}/s`,
|
||||
color: "secondary" as const,
|
||||
},
|
||||
{
|
||||
icon: <ArrowDownwardRounded fontSize="small" />,
|
||||
title: t("entities.home.cards.traffic.metrics.downloadSpeed"),
|
||||
title: t("home.cards.traffic.metrics.downloadSpeed"),
|
||||
value: parsedData.down,
|
||||
unit: `${parsedData.downUnit}/s`,
|
||||
color: "primary" as const,
|
||||
},
|
||||
{
|
||||
icon: <LinkRounded fontSize="small" />,
|
||||
title: t("entities.home.cards.traffic.metrics.activeConnections"),
|
||||
title: t("home.cards.traffic.metrics.activeConnections"),
|
||||
value: parsedData.connectionsCount,
|
||||
unit: "",
|
||||
color: "success" as const,
|
||||
},
|
||||
{
|
||||
icon: <CloudUploadRounded fontSize="small" />,
|
||||
title: t("entities.home.cards.traffic.metrics.uploaded"),
|
||||
title: t("home.cards.traffic.metrics.uploaded"),
|
||||
value: parsedData.uploadTotal,
|
||||
unit: parsedData.uploadTotalUnit,
|
||||
color: "secondary" as const,
|
||||
},
|
||||
{
|
||||
icon: <CloudDownloadRounded fontSize="small" />,
|
||||
title: t("entities.home.cards.traffic.metrics.downloaded"),
|
||||
title: t("home.cards.traffic.metrics.downloaded"),
|
||||
value: parsedData.downloadTotal,
|
||||
unit: parsedData.downloadTotalUnit,
|
||||
color: "primary" as const,
|
||||
},
|
||||
{
|
||||
icon: <MemoryRounded fontSize="small" />,
|
||||
title: t("entities.home.cards.traffic.metrics.memoryUsage"),
|
||||
title: t("home.cards.traffic.metrics.memoryUsage"),
|
||||
value: parsedData.inuse,
|
||||
unit: parsedData.inuseUnit,
|
||||
color: "error" as const,
|
||||
|
||||
@@ -112,7 +112,7 @@ const ProfileDetails = ({
|
||||
sx={{ display: "flex", alignItems: "center" }}
|
||||
>
|
||||
<span style={{ flexShrink: 0 }}>
|
||||
{t("entities.profile.card.labels.from")}:{" "}
|
||||
{t("profiles.card.labels.from")}:{" "}
|
||||
</span>
|
||||
{current.home ? (
|
||||
<Link
|
||||
@@ -188,7 +188,7 @@ const ProfileDetails = ({
|
||||
sx={{ cursor: "pointer" }}
|
||||
onClick={onUpdateProfile}
|
||||
>
|
||||
{t("entities.profile.card.labels.updateTime")}:{" "}
|
||||
{t("profiles.card.labels.updateTime")}:{" "}
|
||||
<Box component="span" fontWeight="medium">
|
||||
{dayjs(current.updated * 1000).format("YYYY-MM-DD HH:mm")}
|
||||
</Box>
|
||||
@@ -201,7 +201,7 @@ const ProfileDetails = ({
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<SpeedOutlined fontSize="small" color="action" />
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.profile.card.labels.usedTotal")}:{" "}
|
||||
{t("profiles.card.labels.usedTotal")}:{" "}
|
||||
<Box component="span" fontWeight="medium">
|
||||
{parseTraffic(usedTraffic)} /{" "}
|
||||
{parseTraffic(current.extra.total)}
|
||||
@@ -213,7 +213,7 @@ const ProfileDetails = ({
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<EventOutlined fontSize="small" color="action" />
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.profile.card.labels.expireTime")}:{" "}
|
||||
{t("profiles.card.labels.expireTime")}:{" "}
|
||||
<Box component="span" fontWeight="medium">
|
||||
{parseExpire(current.extra.expire)}
|
||||
</Box>
|
||||
@@ -268,11 +268,10 @@ const EmptyProfile = ({ onClick }: { onClick: () => void }) => {
|
||||
sx={{ fontSize: 60, color: "primary.main", mb: 2 }}
|
||||
/>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{t("entities.profile.page.actions.import")}{" "}
|
||||
{t("entities.profile.page.title")}
|
||||
{t("profiles.page.actions.import")} {t("profiles.page.title")}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.profile.card.labels.clickToImport")}
|
||||
{t("profiles.card.labels.clickToImport")}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
@@ -313,7 +312,7 @@ export const HomeProfileCard = ({
|
||||
|
||||
// 卡片标题
|
||||
const cardTitle = useMemo(() => {
|
||||
if (!current) return t("entities.profile.page.title");
|
||||
if (!current) return t("profiles.page.title");
|
||||
|
||||
if (!current.home) return current.name;
|
||||
|
||||
@@ -366,7 +365,7 @@ export const HomeProfileCard = ({
|
||||
endIcon={<StorageOutlined fontSize="small" />}
|
||||
sx={{ borderRadius: 1.5 }}
|
||||
>
|
||||
{t("entities.navigation.tabs.proxies")}
|
||||
{t("layout.navigation.tabs.proxies")}
|
||||
</Button>
|
||||
);
|
||||
}, [current, goToProfiles, t]);
|
||||
|
||||
@@ -70,9 +70,7 @@ export const IpInfoCard = () => {
|
||||
setCountdown(IP_REFRESH_SECONDS);
|
||||
} catch (err) {
|
||||
setError(
|
||||
err instanceof Error
|
||||
? err.message
|
||||
: t("entities.home.cards.ipInfo.errors.load"),
|
||||
err instanceof Error ? err.message : t("home.cards.ipInfo.errors.load"),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -118,7 +116,7 @@ export const IpInfoCard = () => {
|
||||
if (loading) {
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.cards.ipInfo.title")}
|
||||
title={t("home.cards.ipInfo.title")}
|
||||
icon={<LocationOnOutlined />}
|
||||
iconColor="info"
|
||||
action={
|
||||
@@ -141,7 +139,7 @@ export const IpInfoCard = () => {
|
||||
if (error) {
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.cards.ipInfo.title")}
|
||||
title={t("home.cards.ipInfo.title")}
|
||||
icon={<LocationOnOutlined />}
|
||||
iconColor="info"
|
||||
action={
|
||||
@@ -174,7 +172,7 @@ export const IpInfoCard = () => {
|
||||
// 渲染正常数据
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.cards.ipInfo.title")}
|
||||
title={t("home.cards.ipInfo.title")}
|
||||
icon={<LocationOnOutlined />}
|
||||
iconColor="info"
|
||||
action={
|
||||
@@ -226,8 +224,7 @@ export const IpInfoCard = () => {
|
||||
maxWidth: "100%",
|
||||
}}
|
||||
>
|
||||
{ipInfo?.country ||
|
||||
t("entities.home.cards.ipInfo.labels.unknown")}
|
||||
{ipInfo?.country || t("home.cards.ipInfo.labels.unknown")}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
@@ -237,7 +234,7 @@ export const IpInfoCard = () => {
|
||||
color="text.secondary"
|
||||
sx={{ flexShrink: 0 }}
|
||||
>
|
||||
{t("entities.home.cards.ipInfo.labels.ip")}:
|
||||
{t("home.cards.ipInfo.labels.ip")}:
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
@@ -271,7 +268,7 @@ export const IpInfoCard = () => {
|
||||
</Box>
|
||||
|
||||
<InfoItem
|
||||
label={t("entities.home.cards.ipInfo.labels.asn")}
|
||||
label={t("home.cards.ipInfo.labels.asn")}
|
||||
value={ipInfo?.asn ? `AS${ipInfo.asn}` : "N/A"}
|
||||
/>
|
||||
</Box>
|
||||
@@ -279,19 +276,19 @@ export const IpInfoCard = () => {
|
||||
{/* 右侧:组织、ISP和位置信息 */}
|
||||
<Box sx={{ width: "60%", overflow: "auto" }}>
|
||||
<InfoItem
|
||||
label={t("entities.home.cards.ipInfo.labels.isp")}
|
||||
label={t("home.cards.ipInfo.labels.isp")}
|
||||
value={ipInfo?.isp}
|
||||
/>
|
||||
<InfoItem
|
||||
label={t("entities.home.cards.ipInfo.labels.org")}
|
||||
label={t("home.cards.ipInfo.labels.org")}
|
||||
value={ipInfo?.asn_organization}
|
||||
/>
|
||||
<InfoItem
|
||||
label={t("entities.home.cards.ipInfo.labels.location")}
|
||||
label={t("home.cards.ipInfo.labels.location")}
|
||||
value={[ipInfo?.city, ipInfo?.region].filter(Boolean).join(", ")}
|
||||
/>
|
||||
<InfoItem
|
||||
label={t("entities.home.cards.ipInfo.labels.timezone")}
|
||||
label={t("home.cards.ipInfo.labels.timezone")}
|
||||
value={ipInfo?.timezone}
|
||||
/>
|
||||
</Box>
|
||||
@@ -311,7 +308,7 @@ export const IpInfoCard = () => {
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption">
|
||||
{t("entities.home.cards.ipInfo.labels.autoRefresh")}: {countdown}s
|
||||
{t("home.cards.ipInfo.labels.autoRefresh")}: {countdown}s
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="caption"
|
||||
|
||||
@@ -160,18 +160,18 @@ export const ProxyTunCard: FC = () => {
|
||||
if (activeTab === "system") {
|
||||
return {
|
||||
text: systemProxyActualState
|
||||
? t("entities.home.cards.proxyTun.status.systemProxyEnabled")
|
||||
: t("entities.home.cards.proxyTun.status.systemProxyDisabled"),
|
||||
tooltip: t("entities.home.cards.proxyTun.tooltips.systemProxy"),
|
||||
? t("home.cards.proxyTun.status.systemProxyEnabled")
|
||||
: t("home.cards.proxyTun.status.systemProxyDisabled"),
|
||||
tooltip: t("home.cards.proxyTun.tooltips.systemProxy"),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
text: !isTunModeAvailable
|
||||
? t("entities.home.cards.proxyTun.status.tunModeServiceRequired")
|
||||
? t("home.cards.proxyTun.status.tunModeServiceRequired")
|
||||
: enable_tun_mode
|
||||
? t("entities.home.cards.proxyTun.status.tunModeEnabled")
|
||||
: t("entities.home.cards.proxyTun.status.tunModeDisabled"),
|
||||
tooltip: t("entities.home.cards.proxyTun.tooltips.tunMode"),
|
||||
? t("home.cards.proxyTun.status.tunModeEnabled")
|
||||
: t("home.cards.proxyTun.status.tunModeDisabled"),
|
||||
tooltip: t("home.cards.proxyTun.tooltips.tunMode"),
|
||||
};
|
||||
}
|
||||
}, [
|
||||
@@ -198,14 +198,14 @@ export const ProxyTunCard: FC = () => {
|
||||
isActive={activeTab === "system"}
|
||||
onClick={() => handleTabChange("system")}
|
||||
icon={ComputerRounded}
|
||||
label={t("entities.settings.system.toggles.systemProxy")}
|
||||
label={t("settings.system.toggles.systemProxy")}
|
||||
hasIndicator={systemProxyActualState}
|
||||
/>
|
||||
<TabButton
|
||||
isActive={activeTab === "tun"}
|
||||
onClick={() => handleTabChange("tun")}
|
||||
icon={TroubleshootRounded}
|
||||
label={t("entities.settings.system.toggles.tunMode")}
|
||||
label={t("settings.system.toggles.tunMode")}
|
||||
hasIndicator={enable_tun_mode && isTunModeAvailable}
|
||||
/>
|
||||
</Stack>
|
||||
@@ -238,8 +238,8 @@ export const ProxyTunCard: FC = () => {
|
||||
onError={handleError}
|
||||
label={
|
||||
activeTab === "system"
|
||||
? t("entities.settings.system.toggles.systemProxy")
|
||||
: t("entities.settings.system.toggles.tunMode")
|
||||
? t("settings.system.toggles.systemProxy")
|
||||
: t("settings.system.toggles.tunMode")
|
||||
}
|
||||
noRightPadding={true}
|
||||
/>
|
||||
|
||||
@@ -175,7 +175,7 @@ export const SystemInfoCard = () => {
|
||||
const info = await checkUpdate();
|
||||
if (!info?.available) {
|
||||
showNotice.success(
|
||||
t("entities.settings.verge.advanced.notifications.latestVersion"),
|
||||
t("settings.verge.advanced.notifications.latestVersion"),
|
||||
);
|
||||
} else {
|
||||
showNotice.info("Update Available", 2000);
|
||||
@@ -219,13 +219,11 @@ export const SystemInfoCard = () => {
|
||||
<>
|
||||
<AdminPanelSettingsOutlined
|
||||
sx={{ color: "primary.main", fontSize: 16 }}
|
||||
titleAccess={t("entities.home.cards.systemInfo.badges.adminMode")}
|
||||
titleAccess={t("home.cards.systemInfo.badges.adminMode")}
|
||||
/>
|
||||
<DnsOutlined
|
||||
sx={{ color: "success.main", fontSize: 16, ml: 0.5 }}
|
||||
titleAccess={t(
|
||||
"entities.home.cards.systemInfo.badges.serviceMode",
|
||||
)}
|
||||
titleAccess={t("home.cards.systemInfo.badges.serviceMode")}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -233,21 +231,21 @@ export const SystemInfoCard = () => {
|
||||
return (
|
||||
<AdminPanelSettingsOutlined
|
||||
sx={{ color: "primary.main", fontSize: 16 }}
|
||||
titleAccess={t("entities.home.cards.systemInfo.badges.adminMode")}
|
||||
titleAccess={t("home.cards.systemInfo.badges.adminMode")}
|
||||
/>
|
||||
);
|
||||
} else if (isSidecarMode) {
|
||||
return (
|
||||
<ExtensionOutlined
|
||||
sx={{ color: "info.main", fontSize: 16 }}
|
||||
titleAccess={t("entities.home.cards.systemInfo.badges.sidecarMode")}
|
||||
titleAccess={t("home.cards.systemInfo.badges.sidecarMode")}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<DnsOutlined
|
||||
sx={{ color: "success.main", fontSize: 16 }}
|
||||
titleAccess={t("entities.home.cards.systemInfo.badges.serviceMode")}
|
||||
titleAccess={t("home.cards.systemInfo.badges.serviceMode")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -258,13 +256,13 @@ export const SystemInfoCard = () => {
|
||||
if (isAdminMode) {
|
||||
// 判断是否同时处于服务模式
|
||||
if (!isSidecarMode) {
|
||||
return t("entities.home.cards.systemInfo.badges.adminServiceMode");
|
||||
return t("home.cards.systemInfo.badges.adminServiceMode");
|
||||
}
|
||||
return t("entities.home.cards.systemInfo.badges.adminMode");
|
||||
return t("home.cards.systemInfo.badges.adminMode");
|
||||
} else if (isSidecarMode) {
|
||||
return t("entities.home.cards.systemInfo.badges.sidecarMode");
|
||||
return t("home.cards.systemInfo.badges.sidecarMode");
|
||||
} else {
|
||||
return t("entities.home.cards.systemInfo.badges.serviceMode");
|
||||
return t("home.cards.systemInfo.badges.serviceMode");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -273,14 +271,14 @@ export const SystemInfoCard = () => {
|
||||
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.cards.systemInfo.title")}
|
||||
title={t("home.cards.systemInfo.title")}
|
||||
icon={<InfoOutlined />}
|
||||
iconColor="error"
|
||||
action={
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={goToSettings}
|
||||
title={t("entities.home.cards.systemInfo.actions.settings")}
|
||||
title={t("home.cards.systemInfo.actions.settings")}
|
||||
>
|
||||
<SettingsOutlined fontSize="small" />
|
||||
</IconButton>
|
||||
@@ -289,7 +287,7 @@ export const SystemInfoCard = () => {
|
||||
<Stack spacing={1.5}>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.systemInfo.fields.osInfo")}
|
||||
{t("home.cards.systemInfo.fields.osInfo")}
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
{systemState.osInfo}
|
||||
@@ -302,14 +300,12 @@ export const SystemInfoCard = () => {
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.systemInfo.fields.autoLaunch")}
|
||||
{t("home.cards.systemInfo.fields.autoLaunch")}
|
||||
</Typography>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
{isAdminMode && (
|
||||
<Tooltip
|
||||
title={t(
|
||||
"entities.home.cards.systemInfo.tooltips.autoLaunchAdmin",
|
||||
)}
|
||||
title={t("home.cards.systemInfo.tooltips.autoLaunchAdmin")}
|
||||
>
|
||||
<WarningOutlined sx={{ color: "warning.main", fontSize: 20 }} />
|
||||
</Tooltip>
|
||||
@@ -335,7 +331,7 @@ export const SystemInfoCard = () => {
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.systemInfo.fields.runningMode")}
|
||||
{t("home.cards.systemInfo.fields.runningMode")}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
@@ -350,7 +346,7 @@ export const SystemInfoCard = () => {
|
||||
<Divider />
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.systemInfo.fields.lastCheckUpdate")}
|
||||
{t("home.cards.systemInfo.fields.lastCheckUpdate")}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
@@ -368,7 +364,7 @@ export const SystemInfoCard = () => {
|
||||
<Divider />
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.home.cards.systemInfo.fields.vergeVersion")}
|
||||
{t("home.cards.systemInfo.fields.vergeVersion")}
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="medium">
|
||||
v{appVersion}
|
||||
|
||||
@@ -173,16 +173,16 @@ export const TestCard = () => {
|
||||
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.cards.tests.title")}
|
||||
title={t("home.cards.tests.title")}
|
||||
icon={<NetworkCheck />}
|
||||
action={
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
<Tooltip title={t("entities.test.page.actions.testAll")} arrow>
|
||||
<Tooltip title={t("tests.page.actions.testAll")} arrow>
|
||||
<IconButton size="small" onClick={handleTestAll}>
|
||||
<NetworkCheck fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={t("entities.test.viewer.title.create")} arrow>
|
||||
<Tooltip title={t("tests.viewer.title.create")} arrow>
|
||||
<IconButton size="small" onClick={handleCreateTest}>
|
||||
<Add fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
@@ -87,7 +87,7 @@ export const LayoutTraffic = () => {
|
||||
|
||||
<Box display="flex" flexDirection="column" gap={0.75}>
|
||||
<Box
|
||||
title={`${t("entities.home.cards.traffic.metrics.uploadSpeed")}`}
|
||||
title={`${t("home.cards.traffic.metrics.uploadSpeed")}`}
|
||||
{...boxStyle}
|
||||
sx={{
|
||||
...boxStyle.sx,
|
||||
@@ -105,7 +105,7 @@ export const LayoutTraffic = () => {
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
title={`${t("entities.home.cards.traffic.metrics.downloadSpeed")}`}
|
||||
title={`${t("home.cards.traffic.metrics.downloadSpeed")}`}
|
||||
{...boxStyle}
|
||||
sx={{
|
||||
...boxStyle.sx,
|
||||
@@ -124,7 +124,7 @@ export const LayoutTraffic = () => {
|
||||
|
||||
{displayMemory && (
|
||||
<Box
|
||||
title={`${t("entities.home.cards.traffic.metrics.memoryUsage")} `}
|
||||
title={`${t("home.cards.traffic.metrics.memoryUsage")} `}
|
||||
{...boxStyle}
|
||||
sx={{
|
||||
cursor: "auto",
|
||||
|
||||
@@ -97,7 +97,7 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
|
||||
onClose,
|
||||
} = props;
|
||||
|
||||
const resolvedTitle = title ?? t("entities.profile.menu.editFile");
|
||||
const resolvedTitle = title ?? t("profiles.menu.editFile");
|
||||
const resolvedInitialData = useMemo(
|
||||
() => initialData ?? Promise.resolve(""),
|
||||
[initialData],
|
||||
@@ -203,7 +203,7 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
|
||||
mouseWheelZoom: true, // 按住Ctrl滚轮调节缩放比例
|
||||
readOnly: readOnly, // 只读模式
|
||||
readOnlyMessage: {
|
||||
value: t("entities.profile.editor.readOnlyMessage"),
|
||||
value: t("profiles.editor.readOnlyMessage"),
|
||||
}, // 只读模式尝试编辑时的提示信息
|
||||
renderValidationDecorations: "on", // 只读模式下显示校验信息
|
||||
quickSuggestions: {
|
||||
@@ -233,7 +233,7 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
|
||||
size="medium"
|
||||
color="inherit"
|
||||
sx={{ display: readOnly ? "none" : "" }}
|
||||
title={t("entities.profile.editor.format")}
|
||||
title={t("profiles.editor.format")}
|
||||
onClick={() =>
|
||||
editorRef.current
|
||||
?.getAction("editor.action.formatDocument")
|
||||
|
||||
@@ -42,7 +42,7 @@ export const FileInput = (props: Props) => {
|
||||
sx={{ flex: "none" }}
|
||||
onClick={() => inputRef.current?.click()}
|
||||
>
|
||||
{t("entities.profile.fileInput.chooseFile")}
|
||||
{t("profiles.fileInput.chooseFile")}
|
||||
</Button>
|
||||
|
||||
<input
|
||||
|
||||
@@ -74,17 +74,17 @@ interface Props {
|
||||
const builtinProxyPolicies = ["DIRECT", "REJECT", "REJECT-DROP", "PASS"];
|
||||
|
||||
const PROXY_STRATEGY_LABEL_KEYS: Record<string, string> = {
|
||||
select: "entities.proxy.enums.strategies.select",
|
||||
"url-test": "entities.proxy.enums.strategies.url-test",
|
||||
fallback: "entities.proxy.enums.strategies.fallback",
|
||||
"load-balance": "entities.proxy.enums.strategies.load-balance",
|
||||
relay: "entities.proxy.enums.strategies.relay",
|
||||
select: "proxies.enums.strategies.select",
|
||||
"url-test": "proxies.enums.strategies.url-test",
|
||||
fallback: "proxies.enums.strategies.fallback",
|
||||
"load-balance": "proxies.enums.strategies.load-balance",
|
||||
relay: "proxies.enums.strategies.relay",
|
||||
};
|
||||
|
||||
const PROXY_POLICY_LABEL_KEYS: Record<string, string> =
|
||||
builtinProxyPolicies.reduce(
|
||||
(acc, policy) => {
|
||||
acc[policy] = `entities.proxy.enums.policies.${policy}`;
|
||||
acc[policy] = `proxies.enums.policies.${policy}`;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, string>,
|
||||
@@ -400,7 +400,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
const validateGroup = () => {
|
||||
const group = formIns.getValues();
|
||||
if (group.name === "") {
|
||||
throw new Error(t("entities.profile.groupsEditor.errors.nameRequired"));
|
||||
throw new Error(t("profiles.groupsEditor.errors.nameRequired"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -415,7 +415,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
}
|
||||
|
||||
await saveProfileFile(property, nextData);
|
||||
showNotice.success("entities.profile.notifications.saved");
|
||||
showNotice.success("profiles.notifications.saved");
|
||||
setPrevData(nextData);
|
||||
onSave?.(prevData, nextData);
|
||||
onClose();
|
||||
@@ -429,7 +429,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<DialogTitle>
|
||||
{
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("entities.profile.groupsEditor.title")}
|
||||
{t("profiles.groupsEditor.title")}
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -470,7 +470,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.profile.groupsEditor.fields.type")}
|
||||
primary={t("profiles.groupsEditor.fields.type")}
|
||||
/>
|
||||
<Autocomplete
|
||||
size="small"
|
||||
@@ -501,7 +501,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.profile.groupsEditor.fields.name")}
|
||||
primary={t("profiles.groupsEditor.fields.name")}
|
||||
/>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -520,7 +520,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.profile.groupsEditor.fields.icon")}
|
||||
primary={t("profiles.groupsEditor.fields.icon")}
|
||||
/>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -537,9 +537,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.proxies",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.proxies")}
|
||||
/>
|
||||
<Autocomplete
|
||||
size="small"
|
||||
@@ -567,9 +565,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.provider",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.provider")}
|
||||
/>
|
||||
<Autocomplete
|
||||
size="small"
|
||||
@@ -590,7 +586,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.healthCheckUrl",
|
||||
"profiles.groupsEditor.fields.healthCheckUrl",
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
@@ -610,7 +606,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.expectedStatus",
|
||||
"profiles.groupsEditor.fields.expectedStatus",
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
@@ -631,9 +627,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.interval",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.interval")}
|
||||
/>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -663,9 +657,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.timeout",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.timeout")}
|
||||
/>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -696,7 +688,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.maxFailedTimes",
|
||||
"profiles.groupsEditor.fields.maxFailedTimes",
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
@@ -719,7 +711,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.interfaceName",
|
||||
"profiles.groupsEditor.fields.interfaceName",
|
||||
)}
|
||||
/>
|
||||
<Autocomplete
|
||||
@@ -739,9 +731,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.routingMark",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.routingMark")}
|
||||
/>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -761,9 +751,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.filter",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.filter")}
|
||||
/>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
@@ -781,7 +769,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.excludeFilter",
|
||||
"profiles.groupsEditor.fields.excludeFilter",
|
||||
)}
|
||||
/>
|
||||
<TextField
|
||||
@@ -799,9 +787,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.excludeType",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.excludeType")}
|
||||
/>
|
||||
<Autocomplete
|
||||
multiple
|
||||
@@ -849,9 +835,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.includeAll",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.fields.includeAll")}
|
||||
/>
|
||||
<Switch checked={field.value} {...field} />
|
||||
</Item>
|
||||
@@ -864,7 +848,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.includeAllProxies",
|
||||
"profiles.groupsEditor.fields.includeAllProxies",
|
||||
)}
|
||||
/>
|
||||
<Switch checked={field.value} {...field} />
|
||||
@@ -878,7 +862,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.fields.includeAllProviders",
|
||||
"profiles.groupsEditor.fields.includeAllProviders",
|
||||
)}
|
||||
/>
|
||||
<Switch checked={field.value} {...field} />
|
||||
@@ -891,9 +875,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.toggles.lazy",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.toggles.lazy")}
|
||||
/>
|
||||
<Switch checked={field.value} {...field} />
|
||||
</Item>
|
||||
@@ -905,9 +887,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.toggles.disableUdp",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.toggles.disableUdp")}
|
||||
/>
|
||||
<Switch checked={field.value} {...field} />
|
||||
</Item>
|
||||
@@ -919,9 +899,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.profile.groupsEditor.toggles.hidden",
|
||||
)}
|
||||
primary={t("profiles.groupsEditor.toggles.hidden")}
|
||||
/>
|
||||
<Switch checked={field.value} {...field} />
|
||||
</Item>
|
||||
@@ -939,9 +917,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
for (const item of [...prependSeq, ...groupList]) {
|
||||
if (item.name === formIns.getValues().name) {
|
||||
throw new Error(
|
||||
t(
|
||||
"entities.profile.groupsEditor.errors.nameExists",
|
||||
),
|
||||
t("profiles.groupsEditor.errors.nameExists"),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -951,7 +927,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("entities.profile.groupsEditor.actions.prepend")}
|
||||
{t("profiles.groupsEditor.actions.prepend")}
|
||||
</Button>
|
||||
</Item>
|
||||
<Item>
|
||||
@@ -965,9 +941,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
for (const item of [...appendSeq, ...groupList]) {
|
||||
if (item.name === formIns.getValues().name) {
|
||||
throw new Error(
|
||||
t(
|
||||
"entities.profile.groupsEditor.errors.nameExists",
|
||||
),
|
||||
t("profiles.groupsEditor.errors.nameExists"),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -977,7 +951,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("entities.profile.groupsEditor.actions.append")}
|
||||
{t("profiles.groupsEditor.actions.append")}
|
||||
</Button>
|
||||
</Item>
|
||||
</List>
|
||||
|
||||
@@ -26,7 +26,7 @@ export const LogViewer = (props: Props) => {
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose}>
|
||||
<DialogTitle>{t("entities.profile.logViewer.title")}</DialogTitle>
|
||||
<DialogTitle>{t("profiles.logViewer.title")}</DialogTitle>
|
||||
|
||||
<DialogContent
|
||||
sx={{
|
||||
|
||||
@@ -120,42 +120,38 @@ export const ProfileItem = (props: Props) => {
|
||||
|
||||
// 如果已经过期,显示"更新失败"
|
||||
if (nextUpdateDate.isBefore(now)) {
|
||||
setNextUpdateTime(
|
||||
t("entities.profile.item.status.lastUpdateFailed"),
|
||||
);
|
||||
setNextUpdateTime(t("profiles.item.status.lastUpdateFailed"));
|
||||
} else {
|
||||
// 否则显示剩余时间
|
||||
const diffMinutes = nextUpdateDate.diff(now, "minute");
|
||||
|
||||
if (diffMinutes < 60) {
|
||||
if (diffMinutes <= 0) {
|
||||
setNextUpdateTime(
|
||||
`${t("entities.profile.item.status.nextUp")} <1m`,
|
||||
);
|
||||
setNextUpdateTime(`${t("profiles.item.status.nextUp")} <1m`);
|
||||
} else {
|
||||
setNextUpdateTime(
|
||||
`${t("entities.profile.item.status.nextUp")} ${diffMinutes}m`,
|
||||
`${t("profiles.item.status.nextUp")} ${diffMinutes}m`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const hours = Math.floor(diffMinutes / 60);
|
||||
const mins = diffMinutes % 60;
|
||||
setNextUpdateTime(
|
||||
`${t("entities.profile.item.status.nextUp")} ${hours}h ${mins}m`,
|
||||
`${t("profiles.item.status.nextUp")} ${hours}h ${mins}m`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(`返回的下次更新时间为空`);
|
||||
setNextUpdateTime(t("entities.profile.item.status.noSchedule"));
|
||||
setNextUpdateTime(t("profiles.item.status.noSchedule"));
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`获取下次更新时间出错:`, err);
|
||||
setNextUpdateTime(t("entities.profile.item.status.unknown"));
|
||||
setNextUpdateTime(t("profiles.item.status.unknown"));
|
||||
}
|
||||
} else {
|
||||
console.log(`该配置未设置更新间隔或间隔为0`);
|
||||
setNextUpdateTime(t("entities.profile.item.status.autoUpdateDisabled"));
|
||||
setNextUpdateTime(t("profiles.item.status.autoUpdateDisabled"));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -369,18 +365,18 @@ export const ProfileItem = (props: Props) => {
|
||||
};
|
||||
|
||||
const menuLabels = {
|
||||
home: "entities.profile.menu.home",
|
||||
select: "entities.profile.menu.select",
|
||||
editInfo: "entities.profile.menu.editInfo",
|
||||
editFile: "entities.profile.menu.editFile",
|
||||
editRules: "entities.profile.menu.editRules",
|
||||
editProxies: "entities.profile.menu.editProxies",
|
||||
editGroups: "entities.profile.menu.editGroups",
|
||||
extendConfig: "entities.profile.menu.extendConfig",
|
||||
extendScript: "entities.profile.menu.extendScript",
|
||||
openFile: "entities.profile.menu.openFile",
|
||||
update: "entities.profile.menu.update",
|
||||
updateViaProxy: "entities.profile.menu.updateViaProxy",
|
||||
home: "profiles.menu.home",
|
||||
select: "profiles.menu.select",
|
||||
editInfo: "profiles.menu.editInfo",
|
||||
editFile: "profiles.menu.editFile",
|
||||
editRules: "profiles.menu.editRules",
|
||||
editProxies: "profiles.menu.editProxies",
|
||||
editGroups: "profiles.menu.editGroups",
|
||||
extendConfig: "profiles.menu.extendConfig",
|
||||
extendScript: "profiles.menu.extendScript",
|
||||
openFile: "profiles.menu.openFile",
|
||||
update: "profiles.menu.update",
|
||||
updateViaProxy: "profiles.menu.updateViaProxy",
|
||||
delete: "shared.actions.delete",
|
||||
} as const;
|
||||
|
||||
@@ -737,8 +733,8 @@ export const ProfileItem = (props: Props) => {
|
||||
textAlign="right"
|
||||
title={
|
||||
showNextUpdate
|
||||
? t("entities.profile.item.tooltips.showLast")
|
||||
: `${t("shared.labels.updateTime")}: ${parseExpire(updated)}\n${t("entities.profile.item.tooltips.showNext")}`
|
||||
? t("profiles.item.tooltips.showLast")
|
||||
: `${t("shared.labels.updateTime")}: ${parseExpire(updated)}\n${t("profiles.item.tooltips.showNext")}`
|
||||
}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
@@ -895,8 +891,8 @@ export const ProfileItem = (props: Props) => {
|
||||
)}
|
||||
|
||||
<ConfirmViewer
|
||||
title={t("entities.profile.confirm.delete.title")}
|
||||
message={t("entities.profile.confirm.delete.message")}
|
||||
title={t("profiles.confirm.delete.title")}
|
||||
message={t("profiles.confirm.delete.message")}
|
||||
open={confirmOpen}
|
||||
onClose={() => setConfirmOpen(false)}
|
||||
onConfirm={() => {
|
||||
|
||||
@@ -55,18 +55,18 @@ export const ProfileMore = (props: Props) => {
|
||||
const hasError = entries.some(([level]) => level === "exception");
|
||||
|
||||
const globalTitles: Record<Props["id"], string> = {
|
||||
Merge: "entities.profile.more.global.merge",
|
||||
Script: "entities.profile.more.global.script",
|
||||
Merge: "profiles.more.global.merge",
|
||||
Script: "profiles.more.global.script",
|
||||
};
|
||||
|
||||
const chipLabels: Record<Props["id"], string> = {
|
||||
Merge: "entities.profile.more.chips.merge",
|
||||
Script: "entities.profile.more.chips.script",
|
||||
Merge: "profiles.more.chips.merge",
|
||||
Script: "profiles.more.chips.script",
|
||||
};
|
||||
|
||||
const itemMenu = [
|
||||
{ label: "entities.profile.menu.editFile", handler: onEditFile },
|
||||
{ label: "entities.profile.menu.openFile", handler: onOpenFile },
|
||||
{ label: "profiles.menu.editFile", handler: onEditFile },
|
||||
{ label: "profiles.menu.openFile", handler: onOpenFile },
|
||||
];
|
||||
|
||||
const boxStyle = {
|
||||
@@ -121,7 +121,7 @@ export const ProfileMore = (props: Props) => {
|
||||
size="small"
|
||||
edge="start"
|
||||
color="error"
|
||||
title={t("entities.profile.logViewer.title")}
|
||||
title={t("profiles.logViewer.title")}
|
||||
onClick={() => setLogOpen(true)}
|
||||
>
|
||||
<FeaturedPlayListRounded fontSize="inherit" />
|
||||
@@ -132,7 +132,7 @@ export const ProfileMore = (props: Props) => {
|
||||
size="small"
|
||||
edge="start"
|
||||
color="inherit"
|
||||
title={t("entities.profile.logViewer.title")}
|
||||
title={t("profiles.logViewer.title")}
|
||||
onClick={() => setLogOpen(true)}
|
||||
>
|
||||
<FeaturedPlayListRounded fontSize="inherit" />
|
||||
|
||||
@@ -144,9 +144,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
}
|
||||
} catch {
|
||||
// 首次创建/更新失败,尝试使用自身代理
|
||||
showNotice.info(
|
||||
"entities.profile.viewer.notifications.creationRetry",
|
||||
);
|
||||
showNotice.info("profiles.viewer.notifications.creationRetry");
|
||||
|
||||
// 使用自身代理的配置
|
||||
const retryItem = {
|
||||
@@ -169,9 +167,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
await patchProfile(form.uid, { option: originalOptions });
|
||||
}
|
||||
|
||||
showNotice.success(
|
||||
"entities.profile.viewer.notifications.creationSuccess",
|
||||
);
|
||||
showNotice.success("profiles.viewer.notifications.creationSuccess");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,8 +216,8 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
open={open}
|
||||
title={
|
||||
openType === "new"
|
||||
? t("entities.profile.viewer.title.create")
|
||||
: t("entities.profile.viewer.title.edit")
|
||||
? t("profiles.viewer.title.create")
|
||||
: t("profiles.viewer.title.edit")
|
||||
}
|
||||
contentSx={{ width: 375, pb: 0, maxHeight: "80%" }}
|
||||
okBtn={t("shared.actions.save")}
|
||||
@@ -236,11 +232,11 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormControl size="small" fullWidth sx={{ mt: 1, mb: 1 }}>
|
||||
<InputLabel>{t("entities.profile.viewer.fields.type")}</InputLabel>
|
||||
<InputLabel>{t("profiles.viewer.fields.type")}</InputLabel>
|
||||
<Select
|
||||
{...field}
|
||||
autoFocus
|
||||
label={t("entities.profile.viewer.fields.type")}
|
||||
label={t("profiles.viewer.fields.type")}
|
||||
>
|
||||
<MenuItem value="remote">Remote</MenuItem>
|
||||
<MenuItem value="local">Local</MenuItem>
|
||||
@@ -256,7 +252,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
<TextField
|
||||
{...text}
|
||||
{...field}
|
||||
label={t("entities.profile.viewer.fields.name")}
|
||||
label={t("profiles.viewer.fields.name")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -268,7 +264,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
<TextField
|
||||
{...text}
|
||||
{...field}
|
||||
label={t("entities.profile.viewer.fields.description")}
|
||||
label={t("profiles.viewer.fields.description")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -283,7 +279,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
{...text}
|
||||
{...field}
|
||||
multiline
|
||||
label={t("entities.profile.viewer.fields.subscriptionUrl")}
|
||||
label={t("profiles.viewer.fields.subscriptionUrl")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -310,7 +306,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
{...field}
|
||||
type="number"
|
||||
placeholder="60"
|
||||
label={t("entities.profile.viewer.fields.httpTimeout")}
|
||||
label={t("profiles.viewer.fields.httpTimeout")}
|
||||
slotProps={{
|
||||
input: {
|
||||
endAdornment: (
|
||||
@@ -335,7 +331,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
{...text}
|
||||
{...field}
|
||||
type="number"
|
||||
label={t("entities.profile.viewer.fields.updateInterval")}
|
||||
label={t("profiles.viewer.fields.updateInterval")}
|
||||
slotProps={{
|
||||
input: {
|
||||
endAdornment: (
|
||||
@@ -367,7 +363,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
render={({ field }) => (
|
||||
<StyledBox>
|
||||
<InputLabel>
|
||||
{t("entities.profile.viewer.fields.useSystemProxy")}
|
||||
{t("profiles.viewer.fields.useSystemProxy")}
|
||||
</InputLabel>
|
||||
<Switch checked={field.value} {...field} color="primary" />
|
||||
</StyledBox>
|
||||
@@ -380,7 +376,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
render={({ field }) => (
|
||||
<StyledBox>
|
||||
<InputLabel>
|
||||
{t("entities.profile.viewer.fields.useClashProxy")}
|
||||
{t("profiles.viewer.fields.useClashProxy")}
|
||||
</InputLabel>
|
||||
<Switch checked={field.value} {...field} color="primary" />
|
||||
</StyledBox>
|
||||
@@ -393,7 +389,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
render={({ field }) => (
|
||||
<StyledBox>
|
||||
<InputLabel>
|
||||
{t("entities.profile.viewer.fields.acceptInvalidCerts")}
|
||||
{t("profiles.viewer.fields.acceptInvalidCerts")}
|
||||
</InputLabel>
|
||||
<Switch checked={field.value} {...field} color="primary" />
|
||||
</StyledBox>
|
||||
@@ -406,7 +402,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) {
|
||||
render={({ field }) => (
|
||||
<StyledBox>
|
||||
<InputLabel>
|
||||
{t("entities.profile.viewer.fields.allowAutoUpdate")}
|
||||
{t("profiles.viewer.fields.allowAutoUpdate")}
|
||||
</InputLabel>
|
||||
<Switch checked={field.value} {...field} color="primary" />
|
||||
</StyledBox>
|
||||
|
||||
@@ -263,7 +263,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
const handleSave = useLockFn(async () => {
|
||||
try {
|
||||
await saveProfileFile(property, currData);
|
||||
showNotice.success("entities.profile.notifications.saved");
|
||||
showNotice.success("profiles.notifications.saved");
|
||||
onSave?.(prevData, currData);
|
||||
onClose();
|
||||
} catch (err) {
|
||||
@@ -276,7 +276,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
<DialogTitle>
|
||||
{
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("entities.profile.proxiesEditor.title")}
|
||||
{t("profiles.proxiesEditor.title")}
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -315,7 +315,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
placeholder={t(
|
||||
"entities.profile.proxiesEditor.placeholders.multiUri",
|
||||
"profiles.proxiesEditor.placeholders.multiUri",
|
||||
)}
|
||||
fullWidth
|
||||
rows={9}
|
||||
@@ -336,7 +336,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("entities.profile.proxiesEditor.actions.prepend")}
|
||||
{t("profiles.proxiesEditor.actions.prepend")}
|
||||
</Button>
|
||||
</Item>
|
||||
<Item>
|
||||
@@ -350,7 +350,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("entities.profile.proxiesEditor.actions.append")}
|
||||
{t("profiles.proxiesEditor.actions.append")}
|
||||
</Button>
|
||||
</Item>
|
||||
</List>
|
||||
|
||||
@@ -241,10 +241,7 @@ const rules: {
|
||||
];
|
||||
|
||||
const RULE_TYPE_LABEL_KEYS: Record<string, string> = Object.fromEntries(
|
||||
rules.map((rule) => [
|
||||
rule.name,
|
||||
`entities.rule.editor.ruleTypes.${rule.name}`,
|
||||
]),
|
||||
rules.map((rule) => [rule.name, `rules.editor.ruleTypes.${rule.name}`]),
|
||||
);
|
||||
|
||||
const builtinProxyPolicies = ["DIRECT", "REJECT", "REJECT-DROP", "PASS"];
|
||||
@@ -478,12 +475,10 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
|
||||
const validateRule = () => {
|
||||
if ((ruleType.required ?? true) && !ruleContent) {
|
||||
throw new Error(
|
||||
t("entities.rule.editor.form.validation.conditionRequired"),
|
||||
);
|
||||
throw new Error(t("rules.editor.form.validation.conditionRequired"));
|
||||
}
|
||||
if (ruleType.validator && !ruleType.validator(ruleContent)) {
|
||||
throw new Error(t("entities.rule.editor.form.validation.invalidRule"));
|
||||
throw new Error(t("rules.editor.form.validation.invalidRule"));
|
||||
}
|
||||
|
||||
const condition = (ruleType.required ?? true) ? ruleContent : "";
|
||||
@@ -495,7 +490,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
const handleSave = useLockFn(async () => {
|
||||
try {
|
||||
await saveProfileFile(property, currData);
|
||||
showNotice.success("entities.profile.notifications.saved");
|
||||
showNotice.success("profiles.notifications.saved");
|
||||
onSave?.(prevData, currData);
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
@@ -508,7 +503,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
<DialogTitle>
|
||||
{
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("entities.rule.editor.title")}
|
||||
{t("rules.editor.title")}
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -538,9 +533,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
}}
|
||||
>
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.rule.editor.form.labels.type")}
|
||||
/>
|
||||
<ListItemText primary={t("rules.editor.form.labels.type")} />
|
||||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ minWidth: "240px" }}
|
||||
@@ -566,9 +559,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
<Item
|
||||
sx={{ display: !(ruleType.required ?? true) ? "none" : "" }}
|
||||
>
|
||||
<ListItemText
|
||||
primary={t("entities.rule.editor.form.labels.content")}
|
||||
/>
|
||||
<ListItemText primary={t("rules.editor.form.labels.content")} />
|
||||
|
||||
{ruleType.name === "RULE-SET" && (
|
||||
<Autocomplete
|
||||
@@ -606,7 +597,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
</Item>
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.rule.editor.form.labels.proxyPolicy")}
|
||||
primary={t("rules.editor.form.labels.proxyPolicy")}
|
||||
/>
|
||||
<Autocomplete
|
||||
size="small"
|
||||
@@ -631,7 +622,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
{ruleType.noResolve && (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.rule.editor.form.toggles.noResolve")}
|
||||
primary={t("rules.editor.form.toggles.noResolve")}
|
||||
/>
|
||||
<Switch
|
||||
checked={noResolve}
|
||||
@@ -654,7 +645,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("entities.rule.editor.form.actions.prependRule")}
|
||||
{t("rules.editor.form.actions.prependRule")}
|
||||
</Button>
|
||||
</Item>
|
||||
<Item>
|
||||
@@ -672,7 +663,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("entities.rule.editor.form.actions.appendRule")}
|
||||
{t("rules.editor.form.actions.appendRule")}
|
||||
</Button>
|
||||
</Item>
|
||||
</List>
|
||||
|
||||
@@ -66,11 +66,11 @@ export const ProviderButton = () => {
|
||||
await refreshProxy();
|
||||
await refreshProxyProviders();
|
||||
|
||||
showNotice.success("entities.proxy.page.provider.notices.updateSuccess", {
|
||||
showNotice.success("proxies.page.provider.notices.updateSuccess", {
|
||||
name,
|
||||
});
|
||||
} catch (err) {
|
||||
showNotice.error("entities.proxy.page.provider.notices.updateFailed", {
|
||||
showNotice.error("proxies.page.provider.notices.updateFailed", {
|
||||
name,
|
||||
message: String(err),
|
||||
});
|
||||
@@ -86,7 +86,7 @@ export const ProviderButton = () => {
|
||||
// 获取所有provider的名称
|
||||
const allProviders = Object.keys(proxyProviders || {});
|
||||
if (allProviders.length === 0) {
|
||||
showNotice.info("entities.proxy.page.provider.notices.none");
|
||||
showNotice.info("proxies.page.provider.notices.none");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,9 +116,9 @@ export const ProviderButton = () => {
|
||||
await refreshProxy();
|
||||
await refreshProxyProviders();
|
||||
|
||||
showNotice.success("entities.proxy.page.provider.notices.allUpdated");
|
||||
showNotice.success("proxies.page.provider.notices.allUpdated");
|
||||
} catch (err) {
|
||||
showNotice.error("entities.proxy.page.provider.notices.genericError", {
|
||||
showNotice.error("proxies.page.provider.notices.genericError", {
|
||||
message: String(err),
|
||||
});
|
||||
} finally {
|
||||
@@ -142,7 +142,7 @@ export const ProviderButton = () => {
|
||||
onClick={() => setOpen(true)}
|
||||
sx={{ mr: 1 }}
|
||||
>
|
||||
{t("entities.proxy.page.provider.title")}
|
||||
{t("proxies.page.provider.title")}
|
||||
</Button>
|
||||
|
||||
<Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
|
||||
@@ -153,16 +153,16 @@ export const ProviderButton = () => {
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography variant="h6">
|
||||
{t("entities.proxy.page.provider.title")}
|
||||
{t("proxies.page.provider.title")}
|
||||
</Typography>
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={updateAllProviders}
|
||||
aria-label={t("entities.proxy.page.provider.actions.updateAll")}
|
||||
aria-label={t("proxies.page.provider.actions.updateAll")}
|
||||
>
|
||||
{t("entities.proxy.page.provider.actions.updateAll")}
|
||||
{t("proxies.page.provider.actions.updateAll")}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -326,10 +326,8 @@ export const ProviderButton = () => {
|
||||
"100%": { transform: "rotate(360deg)" },
|
||||
},
|
||||
}}
|
||||
title={t("entities.proxy.page.provider.actions.update")}
|
||||
aria-label={t(
|
||||
"entities.proxy.page.provider.actions.update",
|
||||
)}
|
||||
title={t("proxies.page.provider.actions.update")}
|
||||
aria-label={t("proxies.page.provider.actions.update")}
|
||||
>
|
||||
<RefreshRounded />
|
||||
</IconButton>
|
||||
|
||||
@@ -303,9 +303,7 @@ export const ProxyChain = ({
|
||||
// onUpdateChain([]);
|
||||
} catch (error) {
|
||||
console.error("Failed to disconnect from proxy chain:", error);
|
||||
alert(
|
||||
t("entities.proxy.page.chain.disconnectFailed") || "断开链式代理失败",
|
||||
);
|
||||
alert(t("proxies.page.chain.disconnectFailed") || "断开链式代理失败");
|
||||
} finally {
|
||||
setIsConnecting(false);
|
||||
}
|
||||
@@ -313,10 +311,7 @@ export const ProxyChain = ({
|
||||
}
|
||||
|
||||
if (proxyChain.length < 2) {
|
||||
alert(
|
||||
t("entities.proxy.page.chain.minimumNodes") ||
|
||||
"链式代理至少需要2个节点",
|
||||
);
|
||||
alert(t("proxies.page.chain.minimumNodes") || "链式代理至少需要2个节点");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -348,7 +343,7 @@ export const ProxyChain = ({
|
||||
console.log("Successfully connected to proxy chain");
|
||||
} catch (error) {
|
||||
console.error("Failed to connect to proxy chain:", error);
|
||||
alert(t("entities.proxy.page.chain.connectFailed") || "连接链式代理失败");
|
||||
alert(t("proxies.page.chain.connectFailed") || "连接链式代理失败");
|
||||
} finally {
|
||||
setIsConnecting(false);
|
||||
}
|
||||
@@ -478,9 +473,7 @@ export const ProxyChain = ({
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6">
|
||||
{t("entities.proxy.page.chain.header")}
|
||||
</Typography>
|
||||
<Typography variant="h6">{t("proxies.page.chain.header")}</Typography>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
{proxyChain.length > 0 && (
|
||||
<IconButton
|
||||
@@ -496,8 +489,7 @@ export const ProxyChain = ({
|
||||
},
|
||||
}}
|
||||
title={
|
||||
t("entities.proxy.page.actions.clearChainConfig") ||
|
||||
"删除链式配置"
|
||||
t("proxies.page.actions.clearChainConfig") || "删除链式配置"
|
||||
}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
@@ -519,16 +511,16 @@ export const ProxyChain = ({
|
||||
}}
|
||||
title={
|
||||
proxyChain.length < 2
|
||||
? t("entities.proxy.page.chain.minimumNodes") ||
|
||||
? t("proxies.page.chain.minimumNodes") ||
|
||||
"链式代理至少需要2个节点"
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{isConnecting
|
||||
? t("entities.proxy.page.actions.connecting") || "连接中..."
|
||||
? t("proxies.page.actions.connecting") || "连接中..."
|
||||
: isConnected
|
||||
? t("entities.proxy.page.actions.disconnect") || "断开"
|
||||
: t("entities.proxy.page.actions.connect") || "连接"}
|
||||
? t("proxies.page.actions.disconnect") || "断开"
|
||||
: t("proxies.page.actions.connect") || "连接"}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -538,9 +530,9 @@ export const ProxyChain = ({
|
||||
sx={{ mb: 2 }}
|
||||
>
|
||||
{proxyChain.length === 1
|
||||
? t("entities.proxy.page.chain.minimumNodesHint") ||
|
||||
? t("proxies.page.chain.minimumNodesHint") ||
|
||||
"链式代理至少需要2个节点,请再添加一个节点。"
|
||||
: t("entities.proxy.page.chain.instruction") ||
|
||||
: t("proxies.page.chain.instruction") ||
|
||||
"按顺序点击节点添加到代理链中"}
|
||||
</Alert>
|
||||
|
||||
@@ -555,7 +547,7 @@ export const ProxyChain = ({
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
<Typography>{t("entities.proxy.page.chain.empty")}</Typography>
|
||||
<Typography>{t("proxies.page.chain.empty")}</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
<DndContext
|
||||
|
||||
@@ -239,7 +239,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
setProxyChain((prev) => {
|
||||
// 检查是否已经存在相同名称的代理,防止重复添加
|
||||
if (prev.some((item) => item.name === proxy.name)) {
|
||||
const warningMessage = t("entities.proxy.page.chain.duplicateNode");
|
||||
const warningMessage = t("proxies.page.chain.duplicateNode");
|
||||
setDuplicateWarning({
|
||||
open: true,
|
||||
message: warningMessage,
|
||||
@@ -372,7 +372,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
}, [renderList]);
|
||||
|
||||
if (mode === "direct") {
|
||||
return <BaseEmpty textKey="entities.proxy.page.messages.directMode" />;
|
||||
return <BaseEmpty textKey="proxies.page.messages.directMode" />;
|
||||
}
|
||||
|
||||
if (isChainMode) {
|
||||
@@ -403,7 +403,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
variant="h6"
|
||||
sx={{ fontWeight: 600, fontSize: "16px" }}
|
||||
>
|
||||
{t("entities.proxy.page.rules.title")}
|
||||
{t("proxies.page.rules.title")}
|
||||
</Typography>
|
||||
{currentGroup && (
|
||||
<Box
|
||||
@@ -442,7 +442,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
variant="body2"
|
||||
sx={{ mr: 0.5, fontSize: "12px" }}
|
||||
>
|
||||
{t("entities.proxy.page.rules.select")}
|
||||
{t("proxies.page.rules.select")}
|
||||
</Typography>
|
||||
<ExpandMoreRounded fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
@@ -67,7 +67,7 @@ export const ProxyHead = ({
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={t("entities.proxy.page.tooltips.locate")}
|
||||
title={t("proxies.page.tooltips.locate")}
|
||||
onClick={onLocation}
|
||||
>
|
||||
<MyLocationRounded />
|
||||
@@ -76,7 +76,7 @@ export const ProxyHead = ({
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={t("entities.proxy.page.tooltips.delayCheck")}
|
||||
title={t("proxies.page.tooltips.delayCheck")}
|
||||
onClick={() => {
|
||||
console.log(`[ProxyHead] 点击延迟测试按钮,组: ${groupName}`);
|
||||
// Remind the user that it is custom test url
|
||||
@@ -95,9 +95,9 @@ export const ProxyHead = ({
|
||||
color="inherit"
|
||||
title={
|
||||
[
|
||||
t("entities.proxy.page.tooltips.sortDefault"),
|
||||
t("entities.proxy.page.tooltips.sortDelay"),
|
||||
t("entities.proxy.page.tooltips.sortName"),
|
||||
t("proxies.page.tooltips.sortDefault"),
|
||||
t("proxies.page.tooltips.sortDelay"),
|
||||
t("proxies.page.tooltips.sortName"),
|
||||
][sortType]
|
||||
}
|
||||
onClick={() =>
|
||||
@@ -112,7 +112,7 @@ export const ProxyHead = ({
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={t("entities.proxy.page.tooltips.delayCheckUrl")}
|
||||
title={t("proxies.page.tooltips.delayCheckUrl")}
|
||||
onClick={() =>
|
||||
onHeadState({ textState: textState === "url" ? null : "url" })
|
||||
}
|
||||
@@ -129,8 +129,8 @@ export const ProxyHead = ({
|
||||
color="inherit"
|
||||
title={
|
||||
showType
|
||||
? t("entities.proxy.page.tooltips.showBasic")
|
||||
: t("entities.proxy.page.tooltips.showDetail")
|
||||
? t("proxies.page.tooltips.showBasic")
|
||||
: t("proxies.page.tooltips.showDetail")
|
||||
}
|
||||
onClick={() => onHeadState({ showType: !showType })}
|
||||
>
|
||||
@@ -140,7 +140,7 @@ export const ProxyHead = ({
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={t("entities.proxy.page.tooltips.filter")}
|
||||
title={t("proxies.page.tooltips.filter")}
|
||||
onClick={() =>
|
||||
onHeadState({ textState: textState === "filter" ? null : "filter" })
|
||||
}
|
||||
@@ -160,7 +160,7 @@ export const ProxyHead = ({
|
||||
value={filterText}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
placeholder={t("entities.proxy.page.placeholders.filter")}
|
||||
placeholder={t("proxies.page.placeholders.filter")}
|
||||
onChange={(e) => onHeadState({ filterText: e.target.value })}
|
||||
sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
|
||||
/>
|
||||
@@ -175,7 +175,7 @@ export const ProxyHead = ({
|
||||
value={testUrl}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
placeholder={t("entities.proxy.page.placeholders.delayCheckUrl")}
|
||||
placeholder={t("proxies.page.placeholders.delayCheckUrl")}
|
||||
onChange={(e) => onHeadState({ testUrl: e.target.value })}
|
||||
sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
|
||||
/>
|
||||
|
||||
@@ -272,7 +272,7 @@ export const ProxyItemMini = (props: Props) => {
|
||||
className={proxy.name === group.now ? "the-pin" : "the-unpin"}
|
||||
title={
|
||||
group.type === "URLTest"
|
||||
? t("entities.proxy.page.labels.delayCheckReset")
|
||||
? t("proxies.page.labels.delayCheckReset")
|
||||
: ""
|
||||
}
|
||||
>
|
||||
|
||||
@@ -160,7 +160,7 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
}}
|
||||
/>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Tooltip title={t("entities.proxy.page.labels.proxyCount")} arrow>
|
||||
<Tooltip title={t("proxies.page.labels.proxyCount")} arrow>
|
||||
<Chip
|
||||
size="small"
|
||||
label={`${group.all.length}`}
|
||||
|
||||
@@ -58,11 +58,11 @@ export const ProviderButton = () => {
|
||||
await refreshRules();
|
||||
await refreshRuleProviders();
|
||||
|
||||
showNotice.success("entities.rule.page.provider.notices.updateSuccess", {
|
||||
showNotice.success("rules.page.provider.notices.updateSuccess", {
|
||||
name,
|
||||
});
|
||||
} catch (err) {
|
||||
showNotice.error("entities.rule.page.provider.notices.updateFailed", {
|
||||
showNotice.error("rules.page.provider.notices.updateFailed", {
|
||||
name,
|
||||
message: String(err),
|
||||
});
|
||||
@@ -78,7 +78,7 @@ export const ProviderButton = () => {
|
||||
// 获取所有provider的名称
|
||||
const allProviders = Object.keys(ruleProviders || {});
|
||||
if (allProviders.length === 0) {
|
||||
showNotice.info("entities.rule.page.provider.notices.none");
|
||||
showNotice.info("rules.page.provider.notices.none");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -108,9 +108,9 @@ export const ProviderButton = () => {
|
||||
await refreshRules();
|
||||
await refreshRuleProviders();
|
||||
|
||||
showNotice.success("entities.rule.page.provider.notices.allUpdated");
|
||||
showNotice.success("rules.page.provider.notices.allUpdated");
|
||||
} catch (err) {
|
||||
showNotice.error("entities.rule.page.provider.notices.genericError", {
|
||||
showNotice.error("rules.page.provider.notices.genericError", {
|
||||
message: String(err),
|
||||
});
|
||||
} finally {
|
||||
@@ -133,7 +133,7 @@ export const ProviderButton = () => {
|
||||
startIcon={<StorageOutlined />}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
{t("entities.rule.page.provider.trigger")}
|
||||
{t("rules.page.provider.trigger")}
|
||||
</Button>
|
||||
|
||||
<Dialog open={open} onClose={handleClose} maxWidth="sm" fullWidth>
|
||||
@@ -144,14 +144,14 @@ export const ProviderButton = () => {
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography variant="h6">
|
||||
{t("entities.rule.page.provider.dialogTitle")}
|
||||
{t("rules.page.provider.dialogTitle")}
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={updateAllProviders}
|
||||
>
|
||||
{t("entities.rule.page.provider.actions.updateAll")}
|
||||
{t("rules.page.provider.actions.updateAll")}
|
||||
</Button>
|
||||
</Box>
|
||||
</DialogTitle>
|
||||
@@ -252,9 +252,7 @@ export const ProviderButton = () => {
|
||||
color="primary"
|
||||
onClick={() => updateProvider(key)}
|
||||
disabled={isUpdating}
|
||||
aria-label={t(
|
||||
"entities.rule.page.provider.actions.update",
|
||||
)}
|
||||
aria-label={t("rules.page.provider.actions.update")}
|
||||
sx={{
|
||||
animation: isUpdating
|
||||
? "spin 1s linear infinite"
|
||||
@@ -264,7 +262,7 @@ export const ProviderButton = () => {
|
||||
"100%": { transform: "rotate(360deg)" },
|
||||
},
|
||||
}}
|
||||
title={t("entities.rule.page.provider.actions.update")}
|
||||
title={t("rules.page.provider.actions.update")}
|
||||
>
|
||||
<RefreshRounded />
|
||||
</IconButton>
|
||||
|
||||
@@ -84,30 +84,22 @@ export const BackupConfigViewer = memo(
|
||||
|
||||
if (!url) {
|
||||
urlRef.current?.focus();
|
||||
showNotice.error("entities.settings.backup.messages.webdavUrlRequired");
|
||||
throw new Error(
|
||||
t("entities.settings.backup.messages.webdavUrlRequired"),
|
||||
);
|
||||
showNotice.error("settings.backup.messages.webdavUrlRequired");
|
||||
throw new Error(t("settings.backup.messages.webdavUrlRequired"));
|
||||
} else if (!isValidUrl(url)) {
|
||||
urlRef.current?.focus();
|
||||
showNotice.error("entities.settings.backup.messages.invalidWebdavUrl");
|
||||
throw new Error(
|
||||
t("entities.settings.backup.messages.invalidWebdavUrl"),
|
||||
);
|
||||
showNotice.error("settings.backup.messages.invalidWebdavUrl");
|
||||
throw new Error(t("settings.backup.messages.invalidWebdavUrl"));
|
||||
}
|
||||
if (!username) {
|
||||
usernameRef.current?.focus();
|
||||
showNotice.error("entities.settings.backup.messages.usernameRequired");
|
||||
throw new Error(
|
||||
t("entities.settings.backup.messages.usernameRequired"),
|
||||
);
|
||||
showNotice.error("settings.backup.messages.usernameRequired");
|
||||
throw new Error(t("settings.backup.messages.usernameRequired"));
|
||||
}
|
||||
if (!password) {
|
||||
passwordRef.current?.focus();
|
||||
showNotice.error("entities.settings.backup.messages.passwordRequired");
|
||||
throw new Error(
|
||||
t("entities.settings.backup.messages.passwordRequired"),
|
||||
);
|
||||
showNotice.error("settings.backup.messages.passwordRequired");
|
||||
throw new Error(t("settings.backup.messages.passwordRequired"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -120,14 +112,12 @@ export const BackupConfigViewer = memo(
|
||||
data.username.trim(),
|
||||
data.password,
|
||||
).then(() => {
|
||||
showNotice.success(
|
||||
"entities.settings.backup.messages.webdavConfigSaved",
|
||||
);
|
||||
showNotice.success("settings.backup.messages.webdavConfigSaved");
|
||||
onSaveSuccess();
|
||||
});
|
||||
} catch (error) {
|
||||
showNotice.error(
|
||||
"entities.settings.backup.messages.webdavConfigSaveFailed",
|
||||
"settings.backup.messages.webdavConfigSaveFailed",
|
||||
{ error },
|
||||
3000,
|
||||
);
|
||||
@@ -141,11 +131,11 @@ export const BackupConfigViewer = memo(
|
||||
try {
|
||||
setLoading(true);
|
||||
await createWebdavBackup().then(async () => {
|
||||
showNotice.success("entities.settings.backup.messages.backupCreated");
|
||||
showNotice.success("settings.backup.messages.backupCreated");
|
||||
await onBackupSuccess();
|
||||
});
|
||||
} catch (error) {
|
||||
showNotice.error("entities.settings.backup.messages.backupFailed", {
|
||||
showNotice.error("settings.backup.messages.backupFailed", {
|
||||
error,
|
||||
});
|
||||
} finally {
|
||||
@@ -161,7 +151,7 @@ export const BackupConfigViewer = memo(
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t("entities.settings.backup.fields.webdavUrl")}
|
||||
label={t("settings.backup.fields.webdavUrl")}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
{...register("url")}
|
||||
@@ -173,7 +163,7 @@ export const BackupConfigViewer = memo(
|
||||
</Grid>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField
|
||||
label={t("entities.settings.backup.fields.username")}
|
||||
label={t("settings.backup.fields.username")}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
{...register("username")}
|
||||
@@ -185,7 +175,7 @@ export const BackupConfigViewer = memo(
|
||||
</Grid>
|
||||
<Grid size={{ xs: 6 }}>
|
||||
<TextField
|
||||
label={t("entities.settings.backup.fields.password")}
|
||||
label={t("settings.backup.fields.password")}
|
||||
type={showPassword ? "text" : "password"}
|
||||
variant="outlined"
|
||||
size="small"
|
||||
@@ -241,7 +231,7 @@ export const BackupConfigViewer = memo(
|
||||
type="button"
|
||||
size="large"
|
||||
>
|
||||
{t("entities.settings.backup.actions.backup")}
|
||||
{t("settings.backup.actions.backup")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outlined"
|
||||
|
||||
@@ -75,7 +75,7 @@ export const BackupTableViewer = memo(
|
||||
|
||||
const handleRestore = useLockFn(async (filename: string) => {
|
||||
await onRestore(filename).then(() => {
|
||||
showNotice.success("entities.settings.backup.messages.restoreSuccess");
|
||||
showNotice.success("settings.backup.messages.restoreSuccess");
|
||||
});
|
||||
await restartApp();
|
||||
});
|
||||
@@ -92,14 +92,10 @@ export const BackupTableViewer = memo(
|
||||
return;
|
||||
}
|
||||
await onExport(filename, savePath);
|
||||
showNotice.success(
|
||||
"entities.settings.backup.messages.localBackupExported",
|
||||
);
|
||||
showNotice.success("settings.backup.messages.localBackupExported");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showNotice.error(
|
||||
"entities.settings.backup.messages.localBackupExportFailed",
|
||||
);
|
||||
showNotice.error("settings.backup.messages.localBackupExportFailed");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -108,14 +104,10 @@ export const BackupTableViewer = memo(
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
{t("entities.settings.backup.table.filename")}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{t("entities.settings.backup.table.backupTime")}
|
||||
</TableCell>
|
||||
<TableCell>{t("settings.backup.table.filename")}</TableCell>
|
||||
<TableCell>{t("settings.backup.table.backupTime")}</TableCell>
|
||||
<TableCell align="right">
|
||||
{t("entities.settings.backup.table.actions")}
|
||||
{t("settings.backup.table.actions")}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
@@ -150,13 +142,9 @@ export const BackupTableViewer = memo(
|
||||
<>
|
||||
<IconButton
|
||||
color="primary"
|
||||
aria-label={t(
|
||||
"entities.settings.backup.actions.export",
|
||||
)}
|
||||
aria-label={t("settings.backup.actions.export")}
|
||||
size="small"
|
||||
title={t(
|
||||
"entities.settings.backup.actions.exportBackup",
|
||||
)}
|
||||
title={t("settings.backup.actions.exportBackup")}
|
||||
onClick={async (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
await handleExport(file.filename);
|
||||
@@ -175,15 +163,11 @@ export const BackupTableViewer = memo(
|
||||
color="secondary"
|
||||
aria-label={t("shared.actions.delete")}
|
||||
size="small"
|
||||
title={t(
|
||||
"entities.settings.backup.actions.deleteBackup",
|
||||
)}
|
||||
title={t("settings.backup.actions.deleteBackup")}
|
||||
onClick={async (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
const confirmed = await confirmAsync(
|
||||
t(
|
||||
"entities.settings.backup.messages.confirmDelete",
|
||||
),
|
||||
t("settings.backup.messages.confirmDelete"),
|
||||
);
|
||||
if (confirmed) {
|
||||
await handleDelete(file.filename);
|
||||
@@ -199,20 +183,14 @@ export const BackupTableViewer = memo(
|
||||
/>
|
||||
<IconButton
|
||||
color="primary"
|
||||
aria-label={t(
|
||||
"entities.settings.backup.actions.restore",
|
||||
)}
|
||||
aria-label={t("settings.backup.actions.restore")}
|
||||
size="small"
|
||||
title={t(
|
||||
"entities.settings.backup.actions.restoreBackup",
|
||||
)}
|
||||
title={t("settings.backup.actions.restoreBackup")}
|
||||
disabled={!file.allow_apply}
|
||||
onClick={async (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
const confirmed = await confirmAsync(
|
||||
t(
|
||||
"entities.settings.backup.messages.confirmRestore",
|
||||
),
|
||||
t("settings.backup.messages.confirmRestore"),
|
||||
);
|
||||
if (confirmed) {
|
||||
await handleRestore(file.filename);
|
||||
@@ -243,7 +221,7 @@ export const BackupTableViewer = memo(
|
||||
color="textSecondary"
|
||||
align="center"
|
||||
>
|
||||
{t("entities.settings.backup.table.noBackups")}
|
||||
{t("settings.backup.table.noBackups")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</TableCell>
|
||||
@@ -258,7 +236,7 @@ export const BackupTableViewer = memo(
|
||||
rowsPerPage={DEFAULT_ROWS_PER_PAGE}
|
||||
page={page}
|
||||
onPageChange={onPageChange}
|
||||
labelRowsPerPage={t("entities.settings.backup.table.rowsPerPage")}
|
||||
labelRowsPerPage={t("settings.backup.table.rowsPerPage")}
|
||||
/>
|
||||
</TableContainer>
|
||||
);
|
||||
|
||||
@@ -246,7 +246,7 @@ export function BackupViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.backup.title")}
|
||||
title={t("settings.backup.title")}
|
||||
contentSx={{
|
||||
minWidth: { xs: 320, sm: 620 },
|
||||
maxWidth: "unset",
|
||||
@@ -277,17 +277,11 @@ export function BackupViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
<Tabs
|
||||
value={source}
|
||||
onChange={handleChangeSource}
|
||||
aria-label={t("entities.settings.backup.actions.selectTarget")}
|
||||
aria-label={t("settings.backup.actions.selectTarget")}
|
||||
sx={{ mb: 2 }}
|
||||
>
|
||||
<Tab
|
||||
value="local"
|
||||
label={t("entities.settings.backup.tabs.local")}
|
||||
/>
|
||||
<Tab
|
||||
value="webdav"
|
||||
label={t("entities.settings.backup.tabs.webdav")}
|
||||
/>
|
||||
<Tab value="local" label={t("settings.backup.tabs.local")} />
|
||||
<Tab value="webdav" label={t("settings.backup.tabs.webdav")} />
|
||||
</Tabs>
|
||||
{source === "local" ? (
|
||||
<LocalBackupActions
|
||||
|
||||
@@ -27,12 +27,12 @@ const VALID_CORE = [
|
||||
{
|
||||
name: "Mihomo",
|
||||
core: "verge-mihomo",
|
||||
chipKey: "entities.settings.clash.variants.release",
|
||||
chipKey: "settings.clash.variants.release",
|
||||
},
|
||||
{
|
||||
name: "Mihomo Alpha",
|
||||
core: "verge-mihomo-alpha",
|
||||
chipKey: "entities.settings.clash.variants.alpha",
|
||||
chipKey: "settings.clash.variants.alpha",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -83,9 +83,7 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
try {
|
||||
setRestarting(true);
|
||||
await restartCore();
|
||||
showNotice.success(
|
||||
t("entities.settings.clash.notifications.restartSuccess"),
|
||||
);
|
||||
showNotice.success(t("settings.clash.notifications.restartSuccess"));
|
||||
setRestarting(false);
|
||||
} catch (err) {
|
||||
setRestarting(false);
|
||||
@@ -98,9 +96,7 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
setUpgrading(true);
|
||||
await upgradeCore();
|
||||
setUpgrading(false);
|
||||
showNotice.success(
|
||||
t("entities.settings.clash.notifications.versionUpdated"),
|
||||
);
|
||||
showNotice.success(t("settings.clash.notifications.versionUpdated"));
|
||||
} catch (err: any) {
|
||||
setUpgrading(false);
|
||||
const errMsg = err?.response?.data?.message ?? String(err);
|
||||
@@ -116,7 +112,7 @@ export function ClashCoreViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("entities.settings.clash.items.clashCore")}
|
||||
{t("settings.clash.items.clashCore")}
|
||||
<Box>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
|
||||
@@ -69,13 +69,10 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
setOpen(false);
|
||||
showNotice.success("entities.settings.clash.port.messages.saved");
|
||||
showNotice.success("settings.clash.port.messages.saved");
|
||||
},
|
||||
onError: (error) => {
|
||||
showNotice.error(
|
||||
"entities.settings.clash.port.messages.saveFailed",
|
||||
error,
|
||||
);
|
||||
showNotice.error("settings.clash.port.messages.saveFailed", error);
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -152,7 +149,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.clash.port.title")}
|
||||
title={t("settings.clash.port.title")}
|
||||
contentSx={{
|
||||
width: 400,
|
||||
}}
|
||||
@@ -174,7 +171,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
<List sx={{ width: "100%" }}>
|
||||
<ListItem sx={{ padding: "4px 0", minHeight: 36 }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.clash.port.fields.mixed")}
|
||||
primary={t("settings.clash.port.fields.mixed")}
|
||||
slotProps={{ primary: { sx: { fontSize: 12 } } }}
|
||||
/>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
@@ -190,7 +187,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => setMixedPort(generateRandomPort())}
|
||||
title={t("entities.settings.clash.port.actions.random")}
|
||||
title={t("settings.clash.port.actions.random")}
|
||||
sx={{ mr: 0.5 }}
|
||||
>
|
||||
<Shuffle fontSize="small" />
|
||||
@@ -206,7 +203,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "4px 0", minHeight: 36 }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.clash.port.fields.socks")}
|
||||
primary={t("settings.clash.port.fields.socks")}
|
||||
slotProps={{ primary: { sx: { fontSize: 12 } } }}
|
||||
/>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
@@ -223,7 +220,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => setSocksPort(generateRandomPort())}
|
||||
title={t("entities.settings.clash.port.actions.random")}
|
||||
title={t("settings.clash.port.actions.random")}
|
||||
disabled={!socksEnabled}
|
||||
sx={{ mr: 0.5 }}
|
||||
>
|
||||
@@ -240,7 +237,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "4px 0", minHeight: 36 }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.clash.port.fields.http")}
|
||||
primary={t("settings.clash.port.fields.http")}
|
||||
slotProps={{ primary: { sx: { fontSize: 12 } } }}
|
||||
/>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
@@ -257,7 +254,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => setHttpPort(generateRandomPort())}
|
||||
title={t("entities.settings.clash.port.actions.random")}
|
||||
title={t("settings.clash.port.actions.random")}
|
||||
disabled={!httpEnabled}
|
||||
sx={{ mr: 0.5 }}
|
||||
>
|
||||
@@ -275,7 +272,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
{OS !== "windows" && (
|
||||
<ListItem sx={{ padding: "4px 0", minHeight: 36 }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.clash.port.fields.redir")}
|
||||
primary={t("settings.clash.port.fields.redir")}
|
||||
slotProps={{ primary: { sx: { fontSize: 12 } } }}
|
||||
/>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
@@ -292,7 +289,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => setRedirPort(generateRandomPort())}
|
||||
title={t("entities.settings.clash.port.actions.random")}
|
||||
title={t("settings.clash.port.actions.random")}
|
||||
disabled={!redirEnabled}
|
||||
sx={{ mr: 0.5 }}
|
||||
>
|
||||
@@ -311,7 +308,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
{OS === "linux" && (
|
||||
<ListItem sx={{ padding: "4px 0", minHeight: 36 }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.clash.port.fields.tproxy")}
|
||||
primary={t("settings.clash.port.fields.tproxy")}
|
||||
slotProps={{ primary: { sx: { fontSize: 12 } } }}
|
||||
/>
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
@@ -328,7 +325,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => setTproxyPort(generateRandomPort())}
|
||||
title={t("entities.settings.clash.port.actions.random")}
|
||||
title={t("settings.clash.port.actions.random")}
|
||||
disabled={!tproxyEnabled}
|
||||
sx={{ mr: 0.5 }}
|
||||
>
|
||||
|
||||
@@ -27,7 +27,7 @@ export const ConfigViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
open={true}
|
||||
title={
|
||||
<Box display="flex" alignItems="center" gap={2}>
|
||||
{t("entities.settings.verge.advanced.items.runtimeConfig")}
|
||||
{t("settings.verge.advanced.items.runtimeConfig")}
|
||||
<Chip label={t("shared.labels.readOnly")} size="small" />
|
||||
</Box>
|
||||
}
|
||||
|
||||
@@ -57,14 +57,14 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
if (enableController) {
|
||||
if (!controller.trim()) {
|
||||
showNotice.error(
|
||||
"entities.settings.externalController.messages.addressRequired",
|
||||
"settings.externalController.messages.addressRequired",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!secret.trim()) {
|
||||
showNotice.error(
|
||||
"entities.settings.externalController.messages.secretRequired",
|
||||
"settings.externalController.messages.secretRequired",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -75,14 +75,10 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
await patchInfo({ "external-controller": "" });
|
||||
}
|
||||
|
||||
showNotice.success("entities.settings.common.notifications.saveSuccess");
|
||||
showNotice.success("settings.common.notifications.saveSuccess");
|
||||
setOpen(false);
|
||||
} catch (err) {
|
||||
showNotice.error(
|
||||
"entities.settings.common.notifications.saveFailed",
|
||||
err,
|
||||
4000,
|
||||
);
|
||||
showNotice.error("settings.common.notifications.saveFailed", err, 4000);
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
@@ -97,9 +93,7 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
setTimeout(() => setCopySuccess(null));
|
||||
} catch (err) {
|
||||
console.warn("[ControllerViewer] copy to clipboard failed:", err);
|
||||
showNotice.error(
|
||||
"entities.settings.externalController.messages.copyFailed",
|
||||
);
|
||||
showNotice.error("settings.externalController.messages.copyFailed");
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -107,7 +101,7 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.externalController.title")}
|
||||
title={t("settings.externalController.title")}
|
||||
contentSx={{ width: 400 }}
|
||||
okBtn={
|
||||
isSaving ? (
|
||||
@@ -133,7 +127,7 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.externalController.fields.enable")}
|
||||
primary={t("settings.externalController.fields.enable")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -151,7 +145,7 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.externalController.fields.address")}
|
||||
primary={t("settings.externalController.fields.address")}
|
||||
/>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<TextField
|
||||
@@ -163,14 +157,12 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}}
|
||||
value={controller}
|
||||
placeholder={t(
|
||||
"entities.settings.externalController.placeholders.address",
|
||||
"settings.externalController.placeholders.address",
|
||||
)}
|
||||
onChange={(e) => setController(e.target.value)}
|
||||
disabled={isSaving || !enableController}
|
||||
/>
|
||||
<Tooltip
|
||||
title={t("entities.settings.externalController.tooltips.copy")}
|
||||
>
|
||||
<Tooltip title={t("settings.externalController.tooltips.copy")}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleCopyToClipboard(controller, "controller")}
|
||||
@@ -191,7 +183,7 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.externalController.fields.secret")}
|
||||
primary={t("settings.externalController.fields.secret")}
|
||||
/>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<TextField
|
||||
@@ -202,15 +194,11 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
pointerEvents: enableController ? "auto" : "none",
|
||||
}}
|
||||
value={secret}
|
||||
placeholder={t(
|
||||
"entities.settings.externalController.placeholders.secret",
|
||||
)}
|
||||
placeholder={t("settings.externalController.placeholders.secret")}
|
||||
onChange={(e) => setSecret(e.target.value)}
|
||||
disabled={isSaving || !enableController}
|
||||
/>
|
||||
<Tooltip
|
||||
title={t("entities.settings.externalController.tooltips.copy")}
|
||||
>
|
||||
<Tooltip title={t("settings.externalController.tooltips.copy")}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleCopyToClipboard(secret, "secret")}
|
||||
@@ -231,10 +219,8 @@ export function ControllerViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
>
|
||||
<Alert severity="success">
|
||||
{copySuccess === "controller"
|
||||
? t(
|
||||
"entities.settings.externalController.messages.controllerCopied",
|
||||
)
|
||||
: t("entities.settings.externalController.messages.secretCopied")}
|
||||
? t("settings.externalController.messages.controllerCopied")
|
||||
: t("settings.externalController.messages.secretCopied")}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
</BaseDialog>
|
||||
|
||||
@@ -509,7 +509,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
// 使用YAML编辑器的值
|
||||
const parsedConfig = yaml.load(yamlContent);
|
||||
if (typeof parsedConfig !== "object" || parsedConfig === null) {
|
||||
throw new Error(t("entities.settings.dns.errors.invalid"));
|
||||
throw new Error(t("settings.dns.errors.invalid"));
|
||||
}
|
||||
config = parsedConfig as Record<string, any>;
|
||||
}
|
||||
@@ -547,10 +547,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}
|
||||
}
|
||||
|
||||
showNotice.error(
|
||||
"entities.settings.dns.messages.configError",
|
||||
cleanErrorMsg,
|
||||
);
|
||||
showNotice.error("settings.dns.messages.configError", cleanErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -561,7 +558,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
showNotice.success("entities.settings.dns.messages.saved");
|
||||
showNotice.success("settings.dns.messages.saved");
|
||||
} catch (err) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
@@ -613,7 +610,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||
{t("entities.settings.dns.dialog.title")}
|
||||
{t("settings.dns.dialog.title")}
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
@@ -657,7 +654,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
color="warning.main"
|
||||
sx={{ mb: 2, mt: 0, fontStyle: "italic" }}
|
||||
>
|
||||
{t("entities.settings.dns.dialog.warning")}
|
||||
{t("settings.dns.dialog.warning")}
|
||||
</Typography>
|
||||
|
||||
{visualization ? (
|
||||
@@ -666,11 +663,11 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
variant="subtitle1"
|
||||
sx={{ mt: 1, mb: 1, fontWeight: "bold" }}
|
||||
>
|
||||
{t("entities.settings.dns.sections.general")}
|
||||
{t("settings.dns.sections.general")}
|
||||
</Typography>
|
||||
|
||||
<Item>
|
||||
<ListItemText primary={t("entities.settings.dns.fields.enable")} />
|
||||
<ListItemText primary={t("settings.dns.fields.enable")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.enable}
|
||||
@@ -679,7 +676,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText primary={t("entities.settings.dns.fields.listen")} />
|
||||
<ListItemText primary={t("settings.dns.fields.listen")} />
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
@@ -691,9 +688,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.enhancedMode")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.dns.fields.enhancedMode")} />
|
||||
<FormControl size="small" sx={{ width: 150 }}>
|
||||
<Select
|
||||
value={values.enhancedMode}
|
||||
@@ -706,9 +701,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.fakeIpRange")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.dns.fields.fakeIpRange")} />
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
@@ -720,9 +713,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.fakeIpFilterMode")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.dns.fields.fakeIpFilterMode")} />
|
||||
<FormControl size="small" sx={{ width: 150 }}>
|
||||
<Select
|
||||
value={values.fakeIpFilterMode}
|
||||
@@ -736,8 +727,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.ipv6.label")}
|
||||
secondary={t("entities.settings.dns.fields.ipv6.description")}
|
||||
primary={t("settings.dns.fields.ipv6.label")}
|
||||
secondary={t("settings.dns.fields.ipv6.description")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -748,8 +739,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.preferH3.label")}
|
||||
secondary={t("entities.settings.dns.fields.preferH3.description")}
|
||||
primary={t("settings.dns.fields.preferH3.label")}
|
||||
secondary={t("settings.dns.fields.preferH3.description")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -760,10 +751,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.respectRules.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.respectRules.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.respectRules.label")}
|
||||
secondary={t("settings.dns.fields.respectRules.description")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -774,8 +763,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.useHosts.label")}
|
||||
secondary={t("entities.settings.dns.fields.useHosts.description")}
|
||||
primary={t("settings.dns.fields.useHosts.label")}
|
||||
secondary={t("settings.dns.fields.useHosts.description")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -786,10 +775,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.useSystemHosts.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.useSystemHosts.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.useSystemHosts.label")}
|
||||
secondary={t("settings.dns.fields.useSystemHosts.description")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -800,10 +787,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.directPolicy.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.directPolicy.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.directPolicy.label")}
|
||||
secondary={t("settings.dns.fields.directPolicy.description")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -814,12 +799,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.settings.dns.fields.defaultNameserver.label",
|
||||
)}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.defaultNameserver.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.defaultNameserver.label")}
|
||||
secondary={t("settings.dns.fields.defaultNameserver.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -835,10 +816,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.nameserver.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.nameserver.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.nameserver.label")}
|
||||
secondary={t("settings.dns.fields.nameserver.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -854,8 +833,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.fallback.label")}
|
||||
secondary={t("entities.settings.dns.fields.fallback.description")}
|
||||
primary={t("settings.dns.fields.fallback.label")}
|
||||
secondary={t("settings.dns.fields.fallback.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -871,8 +850,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.proxy.label")}
|
||||
secondary={t("entities.settings.dns.fields.proxy.description")}
|
||||
primary={t("settings.dns.fields.proxy.label")}
|
||||
secondary={t("settings.dns.fields.proxy.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -888,10 +867,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.directNameserver.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.directNameserver.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.directNameserver.label")}
|
||||
secondary={t("settings.dns.fields.directNameserver.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -907,10 +884,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.fakeIpFilter.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.fakeIpFilter.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.fakeIpFilter.label")}
|
||||
secondary={t("settings.dns.fields.fakeIpFilter.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -926,10 +901,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.nameserverPolicy.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.nameserverPolicy.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.nameserverPolicy.label")}
|
||||
secondary={t("settings.dns.fields.nameserverPolicy.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -947,15 +920,13 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
variant="subtitle2"
|
||||
sx={{ mt: 2, mb: 1, fontWeight: "bold" }}
|
||||
>
|
||||
{t("entities.settings.dns.sections.fallbackFilter")}
|
||||
{t("settings.dns.sections.fallbackFilter")}
|
||||
</Typography>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.geoipFiltering.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.geoipFiltering.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.geoipFiltering.label")}
|
||||
secondary={t("settings.dns.fields.geoipFiltering.description")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -965,9 +936,7 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.geoipCode")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.dns.fields.geoipCode")} />
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
@@ -980,10 +949,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.fallbackIpCidr.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.fallbackIpCidr.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.fallbackIpCidr.label")}
|
||||
secondary={t("settings.dns.fields.fallbackIpCidr.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -999,10 +966,8 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.fallbackDomain.label")}
|
||||
secondary={t(
|
||||
"entities.settings.dns.fields.fallbackDomain.description",
|
||||
)}
|
||||
primary={t("settings.dns.fields.fallbackDomain.label")}
|
||||
secondary={t("settings.dns.fields.fallbackDomain.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
@@ -1021,13 +986,13 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
variant="subtitle1"
|
||||
sx={{ mt: 3, mb: 0, fontWeight: "bold" }}
|
||||
>
|
||||
{t("entities.settings.dns.sections.hosts")}
|
||||
{t("settings.dns.sections.hosts")}
|
||||
</Typography>
|
||||
|
||||
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.dns.fields.hosts.label")}
|
||||
secondary={t("entities.settings.dns.fields.hosts.description")}
|
||||
primary={t("settings.dns.fields.hosts.label")}
|
||||
secondary={t("settings.dns.fields.hosts.description")}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
|
||||
@@ -140,12 +140,10 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
setOpen(false);
|
||||
showNotice.success(
|
||||
"entities.settings.common.notifications.saveSuccess",
|
||||
);
|
||||
showNotice.success("settings.common.notifications.saveSuccess");
|
||||
},
|
||||
onError: () => {
|
||||
showNotice.error("entities.settings.common.notifications.saveFailed");
|
||||
showNotice.error("settings.common.notifications.saveFailed");
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -183,7 +181,7 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.externalCors.title")}
|
||||
title={t("settings.externalCors.title")}
|
||||
contentSx={{ width: 500 }}
|
||||
okBtn={loading ? t("shared.statuses.saving") : t("shared.actions.save")}
|
||||
cancelBtn={t("shared.actions.cancel")}
|
||||
@@ -200,7 +198,7 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
width="100%"
|
||||
>
|
||||
<span style={{ fontWeight: "normal" }}>
|
||||
{t("entities.settings.externalCors.fields.allowPrivateNetwork")}
|
||||
{t("settings.externalCors.fields.allowPrivateNetwork")}
|
||||
</span>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -220,7 +218,7 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
<ListItem sx={{ padding: "8px 0" }}>
|
||||
<div style={{ width: "100%" }}>
|
||||
<div style={{ marginBottom: 8, fontWeight: "bold" }}>
|
||||
{t("entities.settings.externalCors.fields.allowedOrigins")}
|
||||
{t("settings.externalCors.fields.allowedOrigins")}
|
||||
</div>
|
||||
{originEntries.map(({ origin, index, key }) => (
|
||||
<div
|
||||
@@ -237,9 +235,7 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
sx={{ fontSize: 14, marginRight: 2 }}
|
||||
value={origin}
|
||||
onChange={(e) => handleUpdateOrigin(index, e.target.value)}
|
||||
placeholder={t(
|
||||
"entities.settings.externalCors.placeholders.origin",
|
||||
)}
|
||||
placeholder={t("settings.externalCors.placeholders.origin")}
|
||||
inputProps={{ style: { fontSize: 14 } }}
|
||||
/>
|
||||
<Button
|
||||
@@ -260,7 +256,7 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
onClick={handleAddOrigin}
|
||||
sx={addButtonStyle}
|
||||
>
|
||||
{t("entities.settings.externalCors.actions.add")}
|
||||
{t("settings.externalCors.actions.add")}
|
||||
</Button>
|
||||
|
||||
<div
|
||||
@@ -274,7 +270,7 @@ export const HeaderConfiguration = forwardRef<ClashHeaderConfigingRef>(
|
||||
<div
|
||||
style={{ color: "#666", fontSize: 12, fontStyle: "italic" }}
|
||||
>
|
||||
{t("entities.settings.externalCors.messages.alwaysIncluded", {
|
||||
{t("settings.externalCors.messages.alwaysIncluded", {
|
||||
urls: DEV_URLS.join(", "),
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -27,15 +27,13 @@ const HOTKEY_FUNC = [
|
||||
] as const;
|
||||
|
||||
const HOTKEY_FUNC_LABELS: Record<(typeof HOTKEY_FUNC)[number], string> = {
|
||||
open_or_close_dashboard:
|
||||
"entities.settings.hotkey.functions.openOrCloseDashboard",
|
||||
clash_mode_rule: "entities.settings.hotkey.functions.rule",
|
||||
clash_mode_global: "entities.settings.hotkey.functions.global",
|
||||
clash_mode_direct: "entities.settings.hotkey.functions.direct",
|
||||
toggle_system_proxy: "entities.settings.hotkey.functions.toggleSystemProxy",
|
||||
toggle_tun_mode: "entities.settings.hotkey.functions.toggleTunMode",
|
||||
entry_lightweight_mode:
|
||||
"entities.settings.hotkey.functions.entryLightweightMode",
|
||||
open_or_close_dashboard: "settings.hotkey.functions.openOrCloseDashboard",
|
||||
clash_mode_rule: "settings.hotkey.functions.rule",
|
||||
clash_mode_global: "settings.hotkey.functions.global",
|
||||
clash_mode_direct: "settings.hotkey.functions.direct",
|
||||
toggle_system_proxy: "settings.hotkey.functions.toggleSystemProxy",
|
||||
toggle_tun_mode: "settings.hotkey.functions.toggleTunMode",
|
||||
entry_lightweight_mode: "settings.hotkey.functions.entryLightweightMode",
|
||||
};
|
||||
|
||||
export const HotkeyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
@@ -101,7 +99,7 @@ export const HotkeyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.hotkey.title")}
|
||||
title={t("settings.hotkey.title")}
|
||||
contentSx={{ width: 450, maxHeight: 380 }}
|
||||
okBtn={t("shared.actions.save")}
|
||||
cancelBtn={t("shared.actions.cancel")}
|
||||
@@ -110,9 +108,7 @@ export const HotkeyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
onOk={onSave}
|
||||
>
|
||||
<ItemWrapper style={{ marginBottom: 16 }}>
|
||||
<Typography>
|
||||
{t("entities.settings.hotkey.toggles.enableGlobal")}
|
||||
</Typography>
|
||||
<Typography>{t("settings.hotkey.toggles.enableGlobal")}</Typography>
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={enableGlobalHotkey}
|
||||
|
||||
@@ -113,7 +113,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.verge.layout.title")}
|
||||
title={t("settings.verge.layout.title")}
|
||||
contentSx={{ width: 450 }}
|
||||
disableOk
|
||||
cancelBtn={t("shared.actions.close")}
|
||||
@@ -123,9 +123,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
<List>
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.settings.verge.layout.fields.preferSystemTitlebar",
|
||||
)}
|
||||
primary={t("settings.verge.layout.fields.preferSystemTitlebar")}
|
||||
/>
|
||||
<GuardState
|
||||
value={decorated}
|
||||
@@ -142,7 +140,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.layout.fields.trafficGraph")}
|
||||
primary={t("settings.verge.layout.fields.trafficGraph")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.traffic_graph ?? true}
|
||||
@@ -158,7 +156,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.layout.fields.memoryUsage")}
|
||||
primary={t("settings.verge.layout.fields.memoryUsage")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.enable_memory_usage ?? true}
|
||||
@@ -174,7 +172,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.layout.fields.proxyGroupIcon")}
|
||||
primary={t("settings.verge.layout.fields.proxyGroupIcon")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.enable_group_icon ?? true}
|
||||
@@ -192,13 +190,9 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
<ListItemText
|
||||
primary={
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
|
||||
<span>
|
||||
{t("entities.settings.verge.layout.fields.hoverNavigator")}
|
||||
</span>
|
||||
<span>{t("settings.verge.layout.fields.hoverNavigator")}</span>
|
||||
<TooltipIcon
|
||||
title={t(
|
||||
"entities.settings.verge.layout.tooltips.hoverNavigator",
|
||||
)}
|
||||
title={t("settings.verge.layout.tooltips.hoverNavigator")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
</Box>
|
||||
@@ -221,13 +215,11 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
primary={
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
|
||||
<span>
|
||||
{t(
|
||||
"entities.settings.verge.layout.fields.hoverNavigatorDelay",
|
||||
)}
|
||||
{t("settings.verge.layout.fields.hoverNavigatorDelay")}
|
||||
</span>
|
||||
<TooltipIcon
|
||||
title={t(
|
||||
"entities.settings.verge.layout.tooltips.hoverNavigatorDelay",
|
||||
"settings.verge.layout.tooltips.hoverNavigatorDelay",
|
||||
)}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
@@ -276,9 +268,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.layout.fields.navIcon")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.verge.layout.fields.navIcon")} />
|
||||
<GuardState
|
||||
value={verge?.menu_icon ?? "monochrome"}
|
||||
onCatch={onError}
|
||||
@@ -288,13 +278,13 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
>
|
||||
<Select size="small" sx={{ width: 140, "> div": { py: "7.5px" } }}>
|
||||
<MenuItem value="monochrome">
|
||||
{t("entities.settings.verge.layout.options.icon.monochrome")}
|
||||
{t("settings.verge.layout.options.icon.monochrome")}
|
||||
</MenuItem>
|
||||
<MenuItem value="colorful">
|
||||
{t("entities.settings.verge.layout.options.icon.colorful")}
|
||||
{t("settings.verge.layout.options.icon.colorful")}
|
||||
</MenuItem>
|
||||
<MenuItem value="disable">
|
||||
{t("entities.settings.verge.layout.options.icon.disable")}
|
||||
{t("settings.verge.layout.options.icon.disable")}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</GuardState>
|
||||
@@ -303,7 +293,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
{OS === "macos" && (
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.layout.fields.trayIcon")}
|
||||
primary={t("settings.verge.layout.fields.trayIcon")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.tray_icon ?? "monochrome"}
|
||||
@@ -317,10 +307,10 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
sx={{ width: 140, "> div": { py: "7.5px" } }}
|
||||
>
|
||||
<MenuItem value="monochrome">
|
||||
{t("entities.settings.verge.layout.options.icon.monochrome")}
|
||||
{t("settings.verge.layout.options.icon.monochrome")}
|
||||
</MenuItem>
|
||||
<MenuItem value="colorful">
|
||||
{t("entities.settings.verge.layout.options.icon.colorful")}
|
||||
{t("settings.verge.layout.options.icon.colorful")}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</GuardState>
|
||||
@@ -328,7 +318,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
)}
|
||||
{/* {OS === "macos" && (
|
||||
<Item>
|
||||
<ListItemText primary={t("entities.settings.verge.layout.fields.enableTraySpeed")} />
|
||||
<ListItemText primary={t("settings.verge.layout.fields.enableTraySpeed")} />
|
||||
<GuardState
|
||||
value={verge?.enable_tray_speed ?? false}
|
||||
valueProps="checked"
|
||||
@@ -343,7 +333,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
)} */}
|
||||
{/* {OS === "macos" && (
|
||||
<Item>
|
||||
<ListItemText primary={t("entities.settings.verge.layout.fields.enableTrayIcon")} />
|
||||
<ListItemText primary={t("settings.verge.layout.fields.enableTrayIcon")} />
|
||||
<GuardState
|
||||
value={
|
||||
verge?.enable_tray_icon === false &&
|
||||
@@ -363,9 +353,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
)} */}
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.settings.verge.layout.fields.showProxyGroupsInline",
|
||||
)}
|
||||
primary={t("settings.verge.layout.fields.showProxyGroupsInline")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.tray_inline_proxy_groups ?? false}
|
||||
@@ -381,7 +369,7 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.layout.fields.commonTrayIcon")}
|
||||
primary={t("settings.verge.layout.fields.commonTrayIcon")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.common_tray_icon}
|
||||
@@ -425,17 +413,15 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
}}
|
||||
>
|
||||
{verge?.common_tray_icon
|
||||
? t("entities.settings.verge.basic.actions.clear")
|
||||
: t("entities.settings.verge.basic.actions.browse")}
|
||||
? t("settings.verge.basic.actions.clear")
|
||||
: t("settings.verge.basic.actions.browse")}
|
||||
</Button>
|
||||
</GuardState>
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.settings.verge.layout.fields.systemProxyTrayIcon",
|
||||
)}
|
||||
primary={t("settings.verge.layout.fields.systemProxyTrayIcon")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.sysproxy_tray_icon}
|
||||
@@ -477,15 +463,15 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
}}
|
||||
>
|
||||
{verge?.sysproxy_tray_icon
|
||||
? t("entities.settings.verge.basic.actions.clear")
|
||||
: t("entities.settings.verge.basic.actions.browse")}
|
||||
? t("settings.verge.basic.actions.clear")
|
||||
: t("settings.verge.basic.actions.browse")}
|
||||
</Button>
|
||||
</GuardState>
|
||||
</Item>
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.layout.fields.tunTrayIcon")}
|
||||
primary={t("settings.verge.layout.fields.tunTrayIcon")}
|
||||
/>
|
||||
<GuardState
|
||||
value={verge?.tun_tray_icon}
|
||||
@@ -525,8 +511,8 @@ export const LayoutViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
}}
|
||||
>
|
||||
{verge?.tun_tray_icon
|
||||
? t("entities.settings.verge.basic.actions.clear")
|
||||
: t("entities.settings.verge.basic.actions.browse")}
|
||||
? t("settings.verge.basic.actions.clear")
|
||||
: t("settings.verge.basic.actions.browse")}
|
||||
</Button>
|
||||
</GuardState>
|
||||
</Item>
|
||||
|
||||
@@ -53,7 +53,7 @@ export function LiteModeViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.liteMode.title")}
|
||||
title={t("settings.liteMode.title")}
|
||||
contentSx={{ width: 450 }}
|
||||
okBtn={t("shared.actions.save")}
|
||||
cancelBtn={t("shared.actions.cancel")}
|
||||
@@ -63,9 +63,7 @@ export function LiteModeViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
>
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.liteMode.actions.enterNow")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.liteMode.actions.enterNow")} />
|
||||
<Typography
|
||||
variant="button"
|
||||
sx={{
|
||||
@@ -81,11 +79,11 @@ export function LiteModeViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.liteMode.toggles.autoEnter")}
|
||||
primary={t("settings.liteMode.toggles.autoEnter")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.liteMode.tooltips.autoEnter")}
|
||||
title={t("settings.liteMode.tooltips.autoEnter")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
<Switch
|
||||
@@ -101,9 +99,7 @@ export function LiteModeViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
{values.autoEnterLiteMode && (
|
||||
<>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.liteMode.fields.delay")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.liteMode.fields.delay")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
size="small"
|
||||
@@ -137,7 +133,7 @@ export function LiteModeViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
color="text.secondary"
|
||||
sx={{ fontStyle: "italic" }}
|
||||
>
|
||||
{t("entities.settings.liteMode.messages.autoEnterHint", {
|
||||
{t("settings.liteMode.messages.autoEnterHint", {
|
||||
n: values.autoEnterLiteModeDelay,
|
||||
})}
|
||||
</Typography>
|
||||
|
||||
@@ -20,13 +20,11 @@ export const LocalBackupActions = memo(
|
||||
try {
|
||||
setLoading(true);
|
||||
await createLocalBackup();
|
||||
showNotice.success(
|
||||
"entities.settings.backup.messages.localBackupCreated",
|
||||
);
|
||||
showNotice.success("settings.backup.messages.localBackupCreated");
|
||||
await onBackupSuccess();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showNotice.error("entities.settings.backup.messages.localBackupFailed");
|
||||
showNotice.error("settings.backup.messages.localBackupFailed");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -45,7 +43,7 @@ export const LocalBackupActions = memo(
|
||||
<Grid container spacing={2}>
|
||||
<Grid size={{ xs: 12, sm: 9 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{t("entities.settings.backup.fields.info")}
|
||||
{t("settings.backup.fields.info")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 3 }}>
|
||||
@@ -62,7 +60,7 @@ export const LocalBackupActions = memo(
|
||||
type="button"
|
||||
size="large"
|
||||
>
|
||||
{t("entities.settings.backup.actions.backup")}
|
||||
{t("settings.backup.actions.backup")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outlined"
|
||||
|
||||
@@ -77,7 +77,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.misc.title")}
|
||||
title={t("settings.misc.title")}
|
||||
contentSx={{ width: 450 }}
|
||||
okBtn={t("shared.actions.save")}
|
||||
cancelBtn={t("shared.actions.cancel")}
|
||||
@@ -87,9 +87,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
>
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.appLogLevel")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.misc.fields.appLogLevel")} />
|
||||
<Select
|
||||
size="small"
|
||||
sx={{ width: 100, "> div": { py: "7.5px" } }}
|
||||
@@ -111,7 +109,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.appLogMaxSize")}
|
||||
primary={t("settings.misc.fields.appLogMaxSize")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TextField
|
||||
@@ -143,7 +141,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.appLogMaxCount")}
|
||||
primary={t("settings.misc.fields.appLogMaxCount")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TextField
|
||||
@@ -175,11 +173,11 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.autoCloseConnections")}
|
||||
primary={t("settings.misc.fields.autoCloseConnections")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.misc.tooltips.autoCloseConnections")}
|
||||
title={t("settings.misc.tooltips.autoCloseConnections")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
<Switch
|
||||
@@ -193,9 +191,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.autoCheckUpdate")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.misc.fields.autoCheckUpdate")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.autoCheckUpdate}
|
||||
@@ -207,11 +203,11 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.enableBuiltinEnhanced")}
|
||||
primary={t("settings.misc.fields.enableBuiltinEnhanced")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.misc.tooltips.enableBuiltinEnhanced")}
|
||||
title={t("settings.misc.tooltips.enableBuiltinEnhanced")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
<Switch
|
||||
@@ -226,7 +222,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.proxyLayoutColumns")}
|
||||
primary={t("settings.misc.fields.proxyLayoutColumns")}
|
||||
/>
|
||||
<Select
|
||||
size="small"
|
||||
@@ -240,7 +236,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
}
|
||||
>
|
||||
<MenuItem value={6} key={6}>
|
||||
{t("entities.settings.misc.options.proxyLayoutColumns.auto")}
|
||||
{t("settings.misc.options.proxyLayoutColumns.auto")}
|
||||
</MenuItem>
|
||||
{[1, 2, 3, 4, 5].map((i) => (
|
||||
<MenuItem value={i} key={i}>
|
||||
@@ -251,9 +247,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.autoLogClean")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.misc.fields.autoLogClean")} />
|
||||
<Select
|
||||
size="small"
|
||||
sx={{ width: 160, "> div": { py: "7.5px" } }}
|
||||
@@ -268,43 +262,31 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
{/* 1: 1天, 2: 7天, 3: 30天, 4: 90天*/}
|
||||
{[
|
||||
{
|
||||
key: t("entities.settings.misc.options.autoLogClean.never"),
|
||||
key: t("settings.misc.options.autoLogClean.never"),
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
key: t(
|
||||
"entities.settings.misc.options.autoLogClean.retainDays",
|
||||
{
|
||||
n: 1,
|
||||
},
|
||||
),
|
||||
key: t("settings.misc.options.autoLogClean.retainDays", {
|
||||
n: 1,
|
||||
}),
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
key: t(
|
||||
"entities.settings.misc.options.autoLogClean.retainDays",
|
||||
{
|
||||
n: 7,
|
||||
},
|
||||
),
|
||||
key: t("settings.misc.options.autoLogClean.retainDays", {
|
||||
n: 7,
|
||||
}),
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
key: t(
|
||||
"entities.settings.misc.options.autoLogClean.retainDays",
|
||||
{
|
||||
n: 30,
|
||||
},
|
||||
),
|
||||
key: t("settings.misc.options.autoLogClean.retainDays", {
|
||||
n: 30,
|
||||
}),
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
key: t(
|
||||
"entities.settings.misc.options.autoLogClean.retainDays",
|
||||
{
|
||||
n: 90,
|
||||
},
|
||||
),
|
||||
key: t("settings.misc.options.autoLogClean.retainDays", {
|
||||
n: 90,
|
||||
}),
|
||||
value: 4,
|
||||
},
|
||||
].map((i) => (
|
||||
@@ -317,11 +299,11 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.autoDelayDetection")}
|
||||
primary={t("settings.misc.fields.autoDelayDetection")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.misc.tooltips.autoDelayDetection")}
|
||||
title={t("settings.misc.tooltips.autoDelayDetection")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
<Switch
|
||||
@@ -336,11 +318,11 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.defaultLatencyTest")}
|
||||
primary={t("settings.misc.fields.defaultLatencyTest")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.misc.tooltips.defaultLatencyTest")}
|
||||
title={t("settings.misc.tooltips.defaultLatencyTest")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
<TextField
|
||||
@@ -360,7 +342,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.misc.fields.defaultLatencyTimeout")}
|
||||
primary={t("settings.misc.fields.defaultLatencyTimeout")}
|
||||
/>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
|
||||
@@ -35,7 +35,7 @@ export function NetworkInterfaceViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("entities.settings.networkInterface.title")}
|
||||
{t("settings.networkInterface.title")}
|
||||
<Box>
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -66,17 +66,13 @@ export function NetworkInterfaceViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
address.V4 && (
|
||||
<AddressDisplay
|
||||
key={address.V4.ip}
|
||||
label={t(
|
||||
"entities.settings.networkInterface.fields.ipAddress",
|
||||
)}
|
||||
label={t("settings.networkInterface.fields.ipAddress")}
|
||||
content={address.V4.ip}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
<AddressDisplay
|
||||
label={t(
|
||||
"entities.settings.networkInterface.fields.macAddress",
|
||||
)}
|
||||
label={t("settings.networkInterface.fields.macAddress")}
|
||||
content={item.mac_addr ?? ""}
|
||||
/>
|
||||
</>
|
||||
@@ -88,17 +84,13 @@ export function NetworkInterfaceViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
address.V6 && (
|
||||
<AddressDisplay
|
||||
key={address.V6.ip}
|
||||
label={t(
|
||||
"entities.settings.networkInterface.fields.ipAddress",
|
||||
)}
|
||||
label={t("settings.networkInterface.fields.ipAddress")}
|
||||
content={address.V6.ip}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
<AddressDisplay
|
||||
label={t(
|
||||
"entities.settings.networkInterface.fields.macAddress",
|
||||
)}
|
||||
label={t("settings.networkInterface.fields.macAddress")}
|
||||
content={item.mac_addr ?? ""}
|
||||
/>
|
||||
</>
|
||||
@@ -141,9 +133,7 @@ const AddressDisplay = ({
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
await writeText(content);
|
||||
showNotice.success(
|
||||
"entities.settings.common.notifications.copySuccess",
|
||||
);
|
||||
showNotice.success("settings.common.notifications.copySuccess");
|
||||
}}
|
||||
>
|
||||
<ContentCopyRounded sx={{ fontSize: "18px" }} />
|
||||
|
||||
@@ -21,9 +21,7 @@ export const PasswordInput = (props: Props) => {
|
||||
|
||||
return (
|
||||
<Dialog open={true} maxWidth="xs" fullWidth>
|
||||
<DialogTitle>
|
||||
{t("entities.settings.password.prompts.enterRoot")}
|
||||
</DialogTitle>
|
||||
<DialogTitle>{t("settings.password.prompts.enterRoot")}</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<TextField
|
||||
|
||||
@@ -277,11 +277,11 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
const onSave = useLockFn(async () => {
|
||||
if (value.duration < 1) {
|
||||
showNotice.error("entities.settings.sysproxy.messages.durationTooShort");
|
||||
showNotice.error("settings.sysproxy.messages.durationTooShort");
|
||||
return;
|
||||
}
|
||||
if (value.bypass && !validReg.test(value.bypass)) {
|
||||
showNotice.error("entities.settings.sysproxy.messages.invalidBypass");
|
||||
showNotice.error("settings.sysproxy.messages.invalidBypass");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
!ipv6Regex.test(value.proxy_host) &&
|
||||
!hostnameRegex.test(value.proxy_host)
|
||||
) {
|
||||
showNotice.error("entities.settings.sysproxy.messages.invalidProxyHost");
|
||||
showNotice.error("settings.sysproxy.messages.invalidProxyHost");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.sysproxy.title")}
|
||||
title={t("settings.sysproxy.title")}
|
||||
contentSx={{ width: 450, maxHeight: 565 }}
|
||||
okBtn={t("shared.actions.save")}
|
||||
cancelBtn={t("shared.actions.cancel")}
|
||||
@@ -422,12 +422,12 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
>
|
||||
<List>
|
||||
<BaseFieldset
|
||||
label={t("entities.settings.sysproxy.fieldsets.currentStatus")}
|
||||
label={t("settings.sysproxy.fieldsets.currentStatus")}
|
||||
padding="15px 10px"
|
||||
>
|
||||
<FlexBox>
|
||||
<Typography className="label">
|
||||
{t("entities.settings.sysproxy.fields.enableStatus")}
|
||||
{t("settings.sysproxy.fields.enableStatus")}
|
||||
</Typography>
|
||||
<Typography className="value">
|
||||
{value.pac
|
||||
@@ -442,7 +442,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
{!value.pac && (
|
||||
<FlexBox>
|
||||
<Typography className="label">
|
||||
{t("entities.settings.sysproxy.fields.serverAddr")}
|
||||
{t("settings.sysproxy.fields.serverAddr")}
|
||||
</Typography>
|
||||
<Typography className="value">{getSystemProxyAddress}</Typography>
|
||||
</FlexBox>
|
||||
@@ -450,7 +450,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
{value.pac && (
|
||||
<FlexBox>
|
||||
<Typography className="label">
|
||||
{t("entities.settings.sysproxy.fields.pacUrl")}
|
||||
{t("settings.sysproxy.fields.pacUrl")}
|
||||
</Typography>
|
||||
<Typography className="value">
|
||||
{getCurrentPacUrl || "-"}
|
||||
@@ -459,9 +459,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
)}
|
||||
</BaseFieldset>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.sysproxy.fields.proxyHost")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.sysproxy.fields.proxyHost")} />
|
||||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ width: 150 }}
|
||||
@@ -486,9 +484,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.sysproxy.fields.usePacMode")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.sysproxy.fields.usePacMode")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
disabled={!enabled}
|
||||
@@ -499,11 +495,11 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.sysproxy.fields.proxyGuard")}
|
||||
primary={t("settings.sysproxy.fields.proxyGuard")}
|
||||
sx={{ maxWidth: "fit-content" }}
|
||||
/>
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.sysproxy.tooltips.proxyGuard")}
|
||||
title={t("settings.sysproxy.tooltips.proxyGuard")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
<Switch
|
||||
@@ -516,9 +512,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.sysproxy.fields.guardDuration")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.sysproxy.fields.guardDuration")} />
|
||||
<TextField
|
||||
disabled={!enabled}
|
||||
size="small"
|
||||
@@ -540,9 +534,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
{!value.pac && (
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t(
|
||||
"entities.settings.sysproxy.fields.alwaysUseDefaultBypass",
|
||||
)}
|
||||
primary={t("settings.sysproxy.fields.alwaysUseDefaultBypass")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -562,9 +554,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
{!value.pac && !value.use_default && (
|
||||
<>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.sysproxy.fields.proxyBypass")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.sysproxy.fields.proxyBypass")} />
|
||||
<TextField
|
||||
error={value.bypass ? !validReg.test(value.bypass) : false}
|
||||
disabled={!enabled}
|
||||
@@ -582,9 +572,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
{!value.pac && value.use_default && (
|
||||
<>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.sysproxy.fields.bypass")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.sysproxy.fields.bypass")} />
|
||||
<FlexBox>
|
||||
<TextField
|
||||
disabled={true}
|
||||
@@ -601,7 +589,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
{value.pac && (
|
||||
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.sysproxy.fields.pacScriptContent")}
|
||||
primary={t("settings.sysproxy.fields.pacScriptContent")}
|
||||
sx={{ padding: "3px 0" }}
|
||||
/>
|
||||
<Button
|
||||
@@ -611,12 +599,12 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
setEditorOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("entities.settings.sysproxy.actions.editPac")}
|
||||
{t("settings.sysproxy.actions.editPac")}
|
||||
</Button>
|
||||
{editorOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
title={t("entities.settings.sysproxy.actions.editPac")}
|
||||
title={t("settings.sysproxy.actions.editPac")}
|
||||
initialData={Promise.resolve(value.pac_content ?? "")}
|
||||
language="javascript"
|
||||
onSave={(_prev, curr) => {
|
||||
|
||||
@@ -23,7 +23,7 @@ export const ThemeModeSwitch = (props: Props) => {
|
||||
onClick={() => onChange?.(mode)}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
{t(`entities.theme.${mode}`)}
|
||||
{t(`settings.appearance.${mode}`)}
|
||||
</Button>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
|
||||
@@ -65,35 +65,35 @@ export function ThemeViewer(props: { ref?: React.Ref<DialogRef> }) {
|
||||
const fieldDefinitions: Array<{ labelKey: string; key: ThemeKey }> = useMemo(
|
||||
() => [
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.primaryColor",
|
||||
labelKey: "settings.verge.theme.fields.primaryColor",
|
||||
key: "primary_color",
|
||||
},
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.secondaryColor",
|
||||
labelKey: "settings.verge.theme.fields.secondaryColor",
|
||||
key: "secondary_color",
|
||||
},
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.primaryText",
|
||||
labelKey: "settings.verge.theme.fields.primaryText",
|
||||
key: "primary_text",
|
||||
},
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.secondaryText",
|
||||
labelKey: "settings.verge.theme.fields.secondaryText",
|
||||
key: "secondary_text",
|
||||
},
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.infoColor",
|
||||
labelKey: "settings.verge.theme.fields.infoColor",
|
||||
key: "info_color",
|
||||
},
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.warningColor",
|
||||
labelKey: "settings.verge.theme.fields.warningColor",
|
||||
key: "warning_color",
|
||||
},
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.errorColor",
|
||||
labelKey: "settings.verge.theme.fields.errorColor",
|
||||
key: "error_color",
|
||||
},
|
||||
{
|
||||
labelKey: "entities.settings.verge.theme.fields.successColor",
|
||||
labelKey: "settings.verge.theme.fields.successColor",
|
||||
key: "success_color",
|
||||
},
|
||||
],
|
||||
@@ -120,7 +120,7 @@ export function ThemeViewer(props: { ref?: React.Ref<DialogRef> }) {
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("entities.settings.verge.theme.title")}
|
||||
title={t("settings.verge.theme.title")}
|
||||
okBtn={t("shared.actions.save")}
|
||||
cancelBtn={t("shared.actions.cancel")}
|
||||
contentSx={{ width: 400, maxHeight: 505, overflow: "auto", pb: 0 }}
|
||||
@@ -132,9 +132,7 @@ export function ThemeViewer(props: { ref?: React.Ref<DialogRef> }) {
|
||||
{fieldDefinitions.map((field) => renderItem(field.labelKey, field.key))}
|
||||
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.theme.fields.fontFamily")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.verge.theme.fields.fontFamily")} />
|
||||
<TextField
|
||||
{...textProps}
|
||||
value={theme.font_family ?? ""}
|
||||
@@ -144,7 +142,7 @@ export function ThemeViewer(props: { ref?: React.Ref<DialogRef> }) {
|
||||
</Item>
|
||||
<Item>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.verge.theme.fields.cssInjection")}
|
||||
primary={t("settings.verge.theme.fields.cssInjection")}
|
||||
/>
|
||||
<Button
|
||||
startIcon={<EditRounded />}
|
||||
@@ -153,12 +151,12 @@ export function ThemeViewer(props: { ref?: React.Ref<DialogRef> }) {
|
||||
setEditorOpen(true);
|
||||
}}
|
||||
>
|
||||
{t("entities.settings.verge.theme.actions.editCss")}
|
||||
{t("settings.verge.theme.actions.editCss")}
|
||||
</Button>
|
||||
{editorOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
title={t("entities.settings.verge.theme.dialogs.editCssTitle")}
|
||||
title={t("settings.verge.theme.dialogs.editCssTitle")}
|
||||
initialData={Promise.resolve(theme.css_injection ?? "")}
|
||||
language="css"
|
||||
onSave={(_prev, curr) => {
|
||||
|
||||
@@ -80,7 +80,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
);
|
||||
try {
|
||||
await enhanceProfiles();
|
||||
showNotice.success("entities.settings.tun.messages.applied");
|
||||
showNotice.success("settings.tun.messages.applied");
|
||||
} catch (err: any) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
@@ -95,9 +95,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between" gap={1}>
|
||||
<Typography variant="h6">
|
||||
{t("entities.settings.tun.title")}
|
||||
</Typography>
|
||||
<Typography variant="h6">{t("settings.tun.title")}</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
@@ -130,7 +128,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("entities.settings.tun.actions.reset")}
|
||||
{t("settings.tun.actions.reset")}
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
@@ -143,7 +141,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
>
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("entities.settings.tun.fields.stack")} />
|
||||
<ListItemText primary={t("settings.tun.fields.stack")} />
|
||||
<StackModeSwitch
|
||||
value={values.stack}
|
||||
onChange={(value) => {
|
||||
@@ -156,7 +154,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("entities.settings.tun.fields.device")} />
|
||||
<ListItemText primary={t("settings.tun.fields.device")} />
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
@@ -173,7 +171,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("entities.settings.tun.fields.autoRoute")} />
|
||||
<ListItemText primary={t("settings.tun.fields.autoRoute")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.autoRoute}
|
||||
@@ -182,9 +180,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.tun.fields.strictRoute")}
|
||||
/>
|
||||
<ListItemText primary={t("settings.tun.fields.strictRoute")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.strictRoute}
|
||||
@@ -194,7 +190,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText
|
||||
primary={t("entities.settings.tun.fields.autoDetectInterface")}
|
||||
primary={t("settings.tun.fields.autoDetectInterface")}
|
||||
/>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -206,7 +202,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("entities.settings.tun.fields.dnsHijack")} />
|
||||
<ListItemText primary={t("settings.tun.fields.dnsHijack")} />
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
@@ -215,7 +211,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.dnsHijack.join(",")}
|
||||
placeholder={t("entities.settings.tun.tooltips.dnsHijack")}
|
||||
placeholder={t("settings.tun.tooltips.dnsHijack")}
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({ ...v, dnsHijack: e.target.value.split(",") }))
|
||||
}
|
||||
@@ -223,7 +219,7 @@ export function TunViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("entities.settings.tun.fields.mtu")} />
|
||||
<ListItemText primary={t("settings.tun.fields.mtu")} />
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
|
||||
@@ -58,12 +58,12 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
|
||||
const onUpdate = useLockFn(async () => {
|
||||
if (portableFlag) {
|
||||
showNotice.error("entities.settings.update.messages.portableError");
|
||||
showNotice.error("settings.update.messages.portableError");
|
||||
return;
|
||||
}
|
||||
if (!updateInfo?.body) return;
|
||||
if (breakChangeFlag) {
|
||||
showNotice.error("entities.settings.update.messages.breakChangeError");
|
||||
showNotice.error("settings.update.messages.breakChangeError");
|
||||
return;
|
||||
}
|
||||
if (updateState) return;
|
||||
@@ -113,7 +113,7 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("entities.settings.update.title", {
|
||||
{t("settings.update.title", {
|
||||
version: updateInfo?.version ?? "",
|
||||
})}
|
||||
<Box>
|
||||
@@ -126,13 +126,13 @@ export function UpdateViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("entities.settings.update.actions.goToRelease")}
|
||||
{t("settings.update.actions.goToRelease")}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
contentSx={{ minWidth: 360, maxWidth: 400, height: "50vh" }}
|
||||
okBtn={t("entities.settings.update.actions.update")}
|
||||
okBtn={t("settings.update.actions.update")}
|
||||
cancelBtn={t("shared.actions.cancel")}
|
||||
onClose={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
|
||||
@@ -56,9 +56,7 @@ export const WebUIItem = (props: Props) => {
|
||||
size="small"
|
||||
value={editValue}
|
||||
onChange={(e) => setEditValue(e.target.value)}
|
||||
placeholder={t(
|
||||
"entities.settings.webUI.messages.supportedPlaceholders",
|
||||
)}
|
||||
placeholder={t("settings.webUI.messages.supportedPlaceholders")}
|
||||
/>
|
||||
<IconButton
|
||||
size="small"
|
||||
@@ -129,7 +127,7 @@ export const WebUIItem = (props: Props) => {
|
||||
</Typography>
|
||||
<IconButton
|
||||
size="small"
|
||||
title={t("entities.settings.webUI.actions.openUrl")}
|
||||
title={t("settings.webUI.actions.openUrl")}
|
||||
color="inherit"
|
||||
onClick={() => onOpenUrl?.(value)}
|
||||
>
|
||||
|
||||
@@ -101,7 +101,7 @@ export function WebUIViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between">
|
||||
{t("entities.settings.webUI.title")}
|
||||
{t("settings.webUI.title")}
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
@@ -128,7 +128,7 @@ export function WebUIViewer({ ref }: { ref?: Ref<DialogRef> }) {
|
||||
<BaseEmpty
|
||||
extra={
|
||||
<Typography mt={2} sx={{ fontSize: "12px" }}>
|
||||
{t("entities.settings.webUI.messages.placeholderInstruction")}
|
||||
{t("settings.webUI.messages.placeholderInstruction")}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -67,7 +67,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
const onUpdateGeo = async () => {
|
||||
try {
|
||||
await updateGeo();
|
||||
showNotice.success("entities.settings.clash.messages.geoDataUpdated");
|
||||
showNotice.success("settings.clash.messages.geoDataUpdated");
|
||||
} catch (err: any) {
|
||||
showNotice.error(err);
|
||||
}
|
||||
@@ -93,7 +93,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<SettingList title={t("entities.settings.clash.title")}>
|
||||
<SettingList title={t("settings.clash.title")}>
|
||||
<WebUIViewer ref={webRef} />
|
||||
<ClashPortViewer ref={portRef} />
|
||||
<ControllerViewer ref={ctrlRef} />
|
||||
@@ -103,10 +103,10 @@ const SettingClash = ({ onError }: Props) => {
|
||||
<HeaderConfiguration ref={corsRef} />
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.clash.items.allowLan")}
|
||||
label={t("settings.clash.items.allowLan")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.clash.tooltips.networkInterface")}
|
||||
title={t("settings.clash.tooltips.networkInterface")}
|
||||
color={"inherit"}
|
||||
icon={LanRounded}
|
||||
onClick={() => {
|
||||
@@ -128,7 +128,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.clash.items.dnsOverwrite")}
|
||||
label={t("settings.clash.items.dnsOverwrite")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
icon={SettingsRounded}
|
||||
@@ -143,7 +143,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("entities.settings.clash.items.ipv6")}>
|
||||
<SettingItem label={t("settings.clash.items.ipv6")}>
|
||||
<GuardState
|
||||
value={ipv6 ?? false}
|
||||
valueProps="checked"
|
||||
@@ -157,10 +157,10 @@ const SettingClash = ({ onError }: Props) => {
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.clash.items.unifiedDelay")}
|
||||
label={t("settings.clash.items.unifiedDelay")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.clash.tooltips.unifiedDelay")}
|
||||
title={t("settings.clash.tooltips.unifiedDelay")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
}
|
||||
@@ -178,10 +178,10 @@ const SettingClash = ({ onError }: Props) => {
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.clash.items.logLevel")}
|
||||
label={t("settings.clash.items.logLevel")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.clash.tooltips.logLevel")}
|
||||
title={t("settings.clash.tooltips.logLevel")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
}
|
||||
@@ -198,25 +198,25 @@ const SettingClash = ({ onError }: Props) => {
|
||||
>
|
||||
<Select size="small" sx={{ width: 100, "> div": { py: "7.5px" } }}>
|
||||
<MenuItem value="debug">
|
||||
{t("entities.settings.clash.options.logLevel.debug")}
|
||||
{t("settings.clash.options.logLevel.debug")}
|
||||
</MenuItem>
|
||||
<MenuItem value="info">
|
||||
{t("entities.settings.clash.options.logLevel.info")}
|
||||
{t("settings.clash.options.logLevel.info")}
|
||||
</MenuItem>
|
||||
<MenuItem value="warning">
|
||||
{t("entities.settings.clash.options.logLevel.warning")}
|
||||
{t("settings.clash.options.logLevel.warning")}
|
||||
</MenuItem>
|
||||
<MenuItem value="error">
|
||||
{t("entities.settings.clash.options.logLevel.error")}
|
||||
{t("settings.clash.options.logLevel.error")}
|
||||
</MenuItem>
|
||||
<MenuItem value="silent">
|
||||
{t("entities.settings.clash.options.logLevel.silent")}
|
||||
{t("settings.clash.options.logLevel.silent")}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("entities.settings.clash.items.portConfig")}>
|
||||
<SettingItem label={t("settings.clash.items.portConfig")}>
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
disabled={false}
|
||||
@@ -231,10 +231,10 @@ const SettingClash = ({ onError }: Props) => {
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.clash.items.external")}
|
||||
label={t("settings.clash.items.external")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.externalCors.tooltips.open")}
|
||||
title={t("settings.externalCors.tooltips.open")}
|
||||
icon={SettingsRounded}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -249,11 +249,11 @@ const SettingClash = ({ onError }: Props) => {
|
||||
|
||||
<SettingItem
|
||||
onClick={() => webRef.current?.open()}
|
||||
label={t("entities.settings.clash.items.webUI")}
|
||||
label={t("settings.clash.items.webUI")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.clash.items.clashCore")}
|
||||
label={t("settings.clash.items.clashCore")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
icon={SettingsRounded}
|
||||
@@ -267,10 +267,10 @@ const SettingClash = ({ onError }: Props) => {
|
||||
{isWIN && (
|
||||
<SettingItem
|
||||
onClick={invoke_uwp_tool}
|
||||
label={t("entities.settings.clash.items.openUwpTool")}
|
||||
label={t("settings.clash.items.openUwpTool")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.clash.tooltips.openUwpTool")}
|
||||
title={t("settings.clash.tooltips.openUwpTool")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
}
|
||||
@@ -279,7 +279,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
|
||||
<SettingItem
|
||||
onClick={onUpdateGeo}
|
||||
label={t("entities.settings.clash.items.updateGeoData")}
|
||||
label={t("settings.clash.items.updateGeoData")}
|
||||
/>
|
||||
</SettingList>
|
||||
);
|
||||
|
||||
@@ -41,27 +41,25 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingList title={t("entities.settings.system.title")}>
|
||||
<SettingList title={t("settings.system.title")}>
|
||||
<SysproxyViewer ref={sysproxyRef} />
|
||||
<TunViewer ref={tunRef} />
|
||||
|
||||
<ProxyControlSwitches
|
||||
label={t("entities.settings.system.toggles.tunMode")}
|
||||
label={t("settings.system.toggles.tunMode")}
|
||||
onError={onError}
|
||||
/>
|
||||
|
||||
<ProxyControlSwitches
|
||||
label={t("entities.settings.system.toggles.systemProxy")}
|
||||
label={t("settings.system.toggles.systemProxy")}
|
||||
onError={onError}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.system.fields.autoLaunch")}
|
||||
label={t("settings.system.fields.autoLaunch")}
|
||||
extra={
|
||||
isAdminMode && (
|
||||
<Tooltip
|
||||
title={t("entities.settings.system.tooltips.autoLaunchAdmin")}
|
||||
>
|
||||
<Tooltip title={t("settings.system.tooltips.autoLaunchAdmin")}>
|
||||
<WarningRounded sx={{ color: "warning.main", mr: 1 }} />
|
||||
</Tooltip>
|
||||
)
|
||||
@@ -78,9 +76,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
}}
|
||||
onGuard={async (e) => {
|
||||
if (isAdminMode) {
|
||||
showNotice.info(
|
||||
"entities.settings.system.tooltips.autoLaunchAdmin",
|
||||
);
|
||||
showNotice.info("settings.system.tooltips.autoLaunchAdmin");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -101,10 +97,10 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.system.fields.silentStart")}
|
||||
label={t("settings.system.fields.silentStart")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.system.tooltips.silentStart")}
|
||||
title={t("settings.system.tooltips.silentStart")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
const info = await checkUpdate();
|
||||
if (!info?.available) {
|
||||
showNotice.success(
|
||||
"entities.settings.verge.advanced.notifications.latestVersion",
|
||||
"settings.verge.advanced.notifications.latestVersion",
|
||||
);
|
||||
} else {
|
||||
updateRef.current?.open();
|
||||
@@ -60,23 +60,20 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
|
||||
const onExportDiagnosticInfo = useCallback(async () => {
|
||||
await exportDiagnosticInfo();
|
||||
showNotice.success(
|
||||
"entities.settings.common.notifications.copySuccess",
|
||||
1000,
|
||||
);
|
||||
showNotice.success("settings.common.notifications.copySuccess", 1000);
|
||||
}, []);
|
||||
|
||||
const copyVersion = useCallback(() => {
|
||||
navigator.clipboard.writeText(`v${version}`).then(() => {
|
||||
showNotice.success(
|
||||
"entities.settings.verge.advanced.notifications.versionCopied",
|
||||
"settings.verge.advanced.notifications.versionCopied",
|
||||
1000,
|
||||
);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SettingList title={t("entities.settings.verge.advanced.title")}>
|
||||
<SettingList title={t("settings.verge.advanced.title")}>
|
||||
<ThemeViewer ref={themeRef} />
|
||||
<ConfigViewer ref={configRef} />
|
||||
<HotkeyViewer ref={hotkeyRef} />
|
||||
@@ -88,10 +85,10 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
|
||||
<SettingItem
|
||||
onClick={() => backupRef.current?.open()}
|
||||
label={t("entities.settings.verge.advanced.items.backupSetting")}
|
||||
label={t("settings.verge.advanced.items.backupSetting")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.verge.advanced.tooltips.backupInfo")}
|
||||
title={t("settings.verge.advanced.tooltips.backupInfo")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
}
|
||||
@@ -99,15 +96,15 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
|
||||
<SettingItem
|
||||
onClick={() => configRef.current?.open()}
|
||||
label={t("entities.settings.verge.advanced.items.runtimeConfig")}
|
||||
label={t("settings.verge.advanced.items.runtimeConfig")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={openAppDir}
|
||||
label={t("entities.settings.verge.advanced.items.openConfDir")}
|
||||
label={t("settings.verge.advanced.items.openConfDir")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.verge.advanced.tooltips.openConfDir")}
|
||||
title={t("settings.verge.advanced.tooltips.openConfDir")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
}
|
||||
@@ -115,29 +112,29 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
|
||||
<SettingItem
|
||||
onClick={openCoreDir}
|
||||
label={t("entities.settings.verge.advanced.items.openCoreDir")}
|
||||
label={t("settings.verge.advanced.items.openCoreDir")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={openLogsDir}
|
||||
label={t("entities.settings.verge.advanced.items.openLogsDir")}
|
||||
label={t("settings.verge.advanced.items.openLogsDir")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={onCheckUpdate}
|
||||
label={t("entities.settings.verge.advanced.items.checkUpdates")}
|
||||
label={t("settings.verge.advanced.items.checkUpdates")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={openDevTools}
|
||||
label={t("entities.settings.verge.advanced.items.openDevTools")}
|
||||
label={t("settings.verge.advanced.items.openDevTools")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.verge.advanced.items.liteModeSettings")}
|
||||
label={t("settings.verge.advanced.items.liteModeSettings")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("entities.settings.verge.advanced.tooltips.liteMode")}
|
||||
title={t("settings.verge.advanced.tooltips.liteMode")}
|
||||
sx={{ opacity: "0.7" }}
|
||||
/>
|
||||
}
|
||||
@@ -148,11 +145,11 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
onClick={() => {
|
||||
exitApp();
|
||||
}}
|
||||
label={t("entities.settings.verge.advanced.items.exit")}
|
||||
label={t("settings.verge.advanced.items.exit")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.verge.advanced.items.exportDiagnostics")}
|
||||
label={t("settings.verge.advanced.items.exportDiagnostics")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
icon={ContentCopyRounded}
|
||||
@@ -162,12 +159,12 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
||||
></SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.verge.advanced.items.vergeVersion")}
|
||||
label={t("settings.verge.advanced.items.vergeVersion")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
icon={ContentCopyRounded}
|
||||
onClick={copyVersion}
|
||||
title={t("entities.settings.verge.advanced.actions.copyVersion")}
|
||||
title={t("settings.verge.advanced.actions.copyVersion")}
|
||||
/>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -76,14 +76,11 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
|
||||
const onCopyClashEnv = useCallback(async () => {
|
||||
await copyClashEnv();
|
||||
showNotice.success(
|
||||
"entities.settings.common.notifications.copySuccess",
|
||||
1000,
|
||||
);
|
||||
showNotice.success("settings.common.notifications.copySuccess", 1000);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SettingList title={t("entities.settings.verge.basic.title")}>
|
||||
<SettingList title={t("settings.verge.basic.title")}>
|
||||
<ThemeViewer ref={themeRef} />
|
||||
<ConfigViewer ref={configRef} />
|
||||
<HotkeyViewer ref={hotkeyRef} />
|
||||
@@ -92,7 +89,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
<UpdateViewer ref={updateRef} />
|
||||
<BackupViewer ref={backupRef} />
|
||||
|
||||
<SettingItem label={t("entities.settings.verge.basic.items.language")}>
|
||||
<SettingItem label={t("settings.verge.basic.items.language")}>
|
||||
<GuardState
|
||||
value={language ?? "en"}
|
||||
onCatch={onError}
|
||||
@@ -110,7 +107,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("entities.settings.verge.basic.items.themeMode")}>
|
||||
<SettingItem label={t("settings.verge.basic.items.themeMode")}>
|
||||
<GuardState
|
||||
value={theme_mode}
|
||||
onCatch={onError}
|
||||
@@ -122,9 +119,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
</SettingItem>
|
||||
|
||||
{OS !== "linux" && (
|
||||
<SettingItem
|
||||
label={t("entities.settings.verge.basic.items.trayClickEvent")}
|
||||
>
|
||||
<SettingItem label={t("settings.verge.basic.items.trayClickEvent")}>
|
||||
<GuardState
|
||||
value={tray_event ?? "main_window"}
|
||||
onCatch={onError}
|
||||
@@ -134,19 +129,19 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
>
|
||||
<Select size="small" sx={{ width: 140, "> div": { py: "7.5px" } }}>
|
||||
<MenuItem value="main_window">
|
||||
{t("entities.settings.verge.basic.trayOptions.showMainWindow")}
|
||||
{t("settings.verge.basic.trayOptions.showMainWindow")}
|
||||
</MenuItem>
|
||||
<MenuItem value="tray_menu">
|
||||
{t("entities.settings.verge.basic.trayOptions.showTrayMenu")}
|
||||
{t("settings.verge.basic.trayOptions.showTrayMenu")}
|
||||
</MenuItem>
|
||||
<MenuItem value="system_proxy">
|
||||
{t("entities.settings.system.toggles.systemProxy")}
|
||||
{t("settings.system.toggles.systemProxy")}
|
||||
</MenuItem>
|
||||
<MenuItem value="tun_mode">
|
||||
{t("entities.settings.system.toggles.tunMode")}
|
||||
{t("settings.system.toggles.tunMode")}
|
||||
</MenuItem>
|
||||
<MenuItem value="disable">
|
||||
{t("entities.settings.verge.basic.trayOptions.disable")}
|
||||
{t("settings.verge.basic.trayOptions.disable")}
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</GuardState>
|
||||
@@ -154,7 +149,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
)}
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.verge.basic.items.copyEnvType")}
|
||||
label={t("settings.verge.basic.items.copyEnvType")}
|
||||
extra={
|
||||
<TooltipIcon icon={ContentCopyRounded} onClick={onCopyClashEnv} />
|
||||
}
|
||||
@@ -176,7 +171,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("entities.settings.verge.basic.items.startPage")}>
|
||||
<SettingItem label={t("settings.verge.basic.items.startPage")}>
|
||||
<GuardState
|
||||
value={start_page ?? "/"}
|
||||
onCatch={onError}
|
||||
@@ -196,9 +191,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("entities.settings.verge.basic.items.startupScript")}
|
||||
>
|
||||
<SettingItem label={t("settings.verge.basic.items.startupScript")}>
|
||||
<GuardState
|
||||
value={startup_script ?? ""}
|
||||
onCatch={onError}
|
||||
@@ -231,7 +224,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("entities.settings.verge.basic.actions.browse")}
|
||||
{t("settings.verge.basic.actions.browse")}
|
||||
</Button>
|
||||
{startup_script && (
|
||||
<Button
|
||||
@@ -240,7 +233,7 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
patchVerge({ startup_script: "" });
|
||||
}}
|
||||
>
|
||||
{t("entities.settings.verge.basic.actions.clear")}
|
||||
{t("settings.verge.basic.actions.clear")}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
@@ -251,22 +244,22 @@ const SettingVergeBasic = ({ onError }: Props) => {
|
||||
|
||||
<SettingItem
|
||||
onClick={() => themeRef.current?.open()}
|
||||
label={t("entities.settings.verge.basic.items.themeSetting")}
|
||||
label={t("settings.verge.basic.items.themeSetting")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={() => layoutRef.current?.open()}
|
||||
label={t("entities.settings.verge.basic.items.layoutSetting")}
|
||||
label={t("settings.verge.basic.items.layoutSetting")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={() => miscRef.current?.open()}
|
||||
label={t("entities.settings.verge.basic.items.misc")}
|
||||
label={t("settings.verge.basic.items.misc")}
|
||||
/>
|
||||
|
||||
<SettingItem
|
||||
onClick={() => hotkeyRef.current?.open()}
|
||||
label={t("entities.settings.verge.basic.items.hotkeySetting")}
|
||||
label={t("settings.verge.basic.items.hotkeySetting")}
|
||||
/>
|
||||
</SettingList>
|
||||
);
|
||||
|
||||
@@ -132,7 +132,7 @@ const ProxyControlSwitches = ({
|
||||
|
||||
const handleTunToggle = async (value: boolean) => {
|
||||
if (!isTunModeAvailable) {
|
||||
const msgKey = "entities.settings.proxyControl.tooltips.tunUnavailable";
|
||||
const msgKey = "settings.proxyControl.tooltips.tunUnavailable";
|
||||
showErrorNotice(msgKey);
|
||||
throw new Error(t(msgKey));
|
||||
}
|
||||
@@ -162,16 +162,16 @@ const ProxyControlSwitches = ({
|
||||
});
|
||||
|
||||
const isSystemProxyMode =
|
||||
label === t("entities.settings.system.toggles.systemProxy") || !label;
|
||||
const isTunMode = label === t("entities.settings.system.toggles.tunMode");
|
||||
label === t("settings.system.toggles.systemProxy") || !label;
|
||||
const isTunMode = label === t("settings.system.toggles.tunMode");
|
||||
|
||||
return (
|
||||
<Box sx={{ width: "100%", pr: noRightPadding ? 1 : 2 }}>
|
||||
{isSystemProxyMode && (
|
||||
<SwitchRow
|
||||
label={t("entities.settings.proxyControl.fields.systemProxy")}
|
||||
label={t("settings.proxyControl.fields.systemProxy")}
|
||||
active={systemProxyActualState}
|
||||
infoTitle={t("entities.settings.proxyControl.tooltips.systemProxy")}
|
||||
infoTitle={t("settings.proxyControl.tooltips.systemProxy")}
|
||||
onInfoClick={() => sysproxyRef.current?.open()}
|
||||
onToggle={(value) => toggleSystemProxy(value)}
|
||||
onError={onError}
|
||||
@@ -181,9 +181,9 @@ const ProxyControlSwitches = ({
|
||||
|
||||
{isTunMode && (
|
||||
<SwitchRow
|
||||
label={t("entities.settings.proxyControl.fields.tunMode")}
|
||||
label={t("settings.proxyControl.fields.tunMode")}
|
||||
active={enable_tun_mode || false}
|
||||
infoTitle={t("entities.settings.proxyControl.tooltips.tunMode")}
|
||||
infoTitle={t("settings.proxyControl.tooltips.tunMode")}
|
||||
onInfoClick={() => tunRef.current?.open()}
|
||||
onToggle={handleTunToggle}
|
||||
onError={onError}
|
||||
@@ -194,16 +194,12 @@ const ProxyControlSwitches = ({
|
||||
{!isTunModeAvailable && (
|
||||
<>
|
||||
<TooltipIcon
|
||||
title={t(
|
||||
"entities.settings.proxyControl.tooltips.tunUnavailable",
|
||||
)}
|
||||
title={t("settings.proxyControl.tooltips.tunUnavailable")}
|
||||
icon={WarningRounded}
|
||||
sx={{ color: "warning.main", ml: 1 }}
|
||||
/>
|
||||
<TooltipIcon
|
||||
title={t(
|
||||
"entities.settings.proxyControl.actions.installService",
|
||||
)}
|
||||
title={t("settings.proxyControl.actions.installService")}
|
||||
icon={BuildRounded}
|
||||
color="primary"
|
||||
onClick={onInstallService}
|
||||
@@ -213,9 +209,7 @@ const ProxyControlSwitches = ({
|
||||
)}
|
||||
{isServiceOk && (
|
||||
<TooltipIcon
|
||||
title={t(
|
||||
"entities.settings.proxyControl.actions.uninstallService",
|
||||
)}
|
||||
title={t("settings.proxyControl.actions.uninstallService")}
|
||||
icon={DeleteForeverRounded}
|
||||
color="secondary"
|
||||
onClick={onUninstallService}
|
||||
|
||||
@@ -192,7 +192,7 @@ export const TestItem = ({
|
||||
":hover": { bgcolor: alpha(palette.primary.main, 0.15) },
|
||||
})}
|
||||
>
|
||||
{t("entities.test.item.actions.test")}
|
||||
{t("tests.item.actions.test")}
|
||||
</Widget>
|
||||
)}
|
||||
|
||||
|
||||
@@ -126,8 +126,8 @@ export const TestViewer = forwardRef<TestViewerRef, Props>((props, ref) => {
|
||||
open={open}
|
||||
title={
|
||||
openType === "new"
|
||||
? t("entities.test.viewer.title.create")
|
||||
: t("entities.test.viewer.title.edit")
|
||||
? t("tests.viewer.title.create")
|
||||
: t("tests.viewer.title.edit")
|
||||
}
|
||||
contentSx={{ width: 375, pb: 0, maxHeight: "80%" }}
|
||||
okBtn={t("shared.actions.save")}
|
||||
@@ -166,7 +166,7 @@ export const TestViewer = forwardRef<TestViewerRef, Props>((props, ref) => {
|
||||
{...field}
|
||||
multiline
|
||||
maxRows={3}
|
||||
label={t("entities.test.viewer.fields.url")}
|
||||
label={t("tests.viewer.fields.url")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -65,14 +65,12 @@ export function useSystemState() {
|
||||
disablingTunMode = true;
|
||||
patchVerge({ enable_tun_mode: false })
|
||||
.then(() => {
|
||||
showNotice.info(
|
||||
"entities.settings.system.notifications.tunMode.autoDisabled",
|
||||
);
|
||||
showNotice.info("settings.system.notifications.tunMode.autoDisabled");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("[useVerge] 自动关闭TUN模式失败:", err);
|
||||
showNotice.error(
|
||||
"entities.settings.system.notifications.tunMode.autoDisableFailed",
|
||||
"settings.system.notifications.tunMode.autoDisableFailed",
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
@@ -28,14 +28,14 @@ export const useServiceInstaller = () => {
|
||||
const installServiceAndRestartCore = useCallback(async () => {
|
||||
await executeWithErrorHandling(
|
||||
() => installService(),
|
||||
"entities.settings.clash.service.status.installing",
|
||||
"entities.settings.clash.service.notifications.installSuccess",
|
||||
"settings.clash.service.status.installing",
|
||||
"settings.clash.service.notifications.installSuccess",
|
||||
);
|
||||
|
||||
await executeWithErrorHandling(
|
||||
() => restartCore(),
|
||||
"entities.settings.clash.status.restarting",
|
||||
"entities.settings.clash.notifications.restartSuccess",
|
||||
"settings.clash.status.restarting",
|
||||
"settings.clash.notifications.restartSuccess",
|
||||
);
|
||||
|
||||
await mutateSystemState();
|
||||
|
||||
@@ -29,19 +29,19 @@ export const useServiceUninstaller = () => {
|
||||
try {
|
||||
await executeWithErrorHandling(
|
||||
() => stopCore(),
|
||||
"entities.settings.clash.status.stopping",
|
||||
"settings.clash.status.stopping",
|
||||
);
|
||||
await executeWithErrorHandling(
|
||||
() => uninstallService(),
|
||||
"entities.settings.clash.service.status.uninstalling",
|
||||
"entities.settings.clash.service.notifications.uninstallSuccess",
|
||||
"settings.clash.service.status.uninstalling",
|
||||
"settings.clash.service.notifications.uninstallSuccess",
|
||||
);
|
||||
} catch (ignore) {
|
||||
} finally {
|
||||
await executeWithErrorHandling(
|
||||
() => restartCore(),
|
||||
"entities.settings.clash.status.restarting",
|
||||
"entities.settings.clash.notifications.restartSuccess",
|
||||
"settings.clash.status.restarting",
|
||||
"settings.clash.notifications.restartSuccess",
|
||||
);
|
||||
await mutateSystemState();
|
||||
}
|
||||
|
||||
2284
src/locales/ar.json
2284
src/locales/ar.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/de.json
2284
src/locales/de.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/en.json
2284
src/locales/en.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/es.json
2284
src/locales/es.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/fa.json
2284
src/locales/fa.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/id.json
2284
src/locales/id.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/jp.json
2284
src/locales/jp.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/ko.json
2284
src/locales/ko.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/ru.json
2284
src/locales/ru.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/tr.json
2284
src/locales/tr.json
File diff suppressed because it is too large
Load Diff
2284
src/locales/tt.json
2284
src/locales/tt.json
File diff suppressed because it is too large
Load Diff
2268
src/locales/zh.json
2268
src/locales/zh.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -437,7 +437,7 @@ const Layout = () => {
|
||||
: theme.palette.warning.dark,
|
||||
})}
|
||||
>
|
||||
{t("entities.navigation.menu.reorderMode")}
|
||||
{t("layout.navigation.menu.reorderMode")}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -515,8 +515,8 @@ const Layout = () => {
|
||||
dense
|
||||
>
|
||||
{menuUnlocked
|
||||
? t("entities.navigation.menu.lock")
|
||||
: t("entities.navigation.menu.unlock")}
|
||||
? t("layout.navigation.menu.lock")
|
||||
: t("layout.navigation.menu.unlock")}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
|
||||
@@ -12,9 +12,7 @@ export const handleNoticeMessage = (
|
||||
const handlers: Record<string, () => void> = {
|
||||
"import_sub_url::ok": () => {
|
||||
navigate("/profile", { state: { current: msg } });
|
||||
showNotice.success(
|
||||
"entities.profile.notifications.importSubscriptionSuccess",
|
||||
);
|
||||
showNotice.success("profiles.notifications.importSubscriptionSuccess");
|
||||
},
|
||||
"import_sub_url::error": () => {
|
||||
navigate("/profile");
|
||||
@@ -23,61 +21,55 @@ export const handleNoticeMessage = (
|
||||
"set_config::error": () => showNotice.error(msg),
|
||||
update_with_clash_proxy: () =>
|
||||
showNotice.success(
|
||||
"entities.settings.updater.notifications.withClashProxySuccess",
|
||||
"settings.updater.notifications.withClashProxySuccess",
|
||||
msg,
|
||||
),
|
||||
update_failed_even_with_clash: () =>
|
||||
showNotice.error(
|
||||
"entities.settings.updater.notifications.withClashProxyFailed",
|
||||
"settings.updater.notifications.withClashProxyFailed",
|
||||
msg,
|
||||
),
|
||||
update_failed: () => showNotice.error(msg),
|
||||
"config_validate::boot_error": () =>
|
||||
showNotice.error("entities.validation.config.bootFailed", msg),
|
||||
showNotice.error("settings.validation.config.bootFailed", msg),
|
||||
"config_validate::core_change": () =>
|
||||
showNotice.error("entities.validation.config.coreChangeFailed", msg),
|
||||
showNotice.error("settings.validation.config.coreChangeFailed", msg),
|
||||
"config_validate::error": () =>
|
||||
showNotice.error("entities.validation.config.failed", msg),
|
||||
showNotice.error("settings.validation.config.failed", msg),
|
||||
"config_validate::process_terminated": () =>
|
||||
showNotice.error("entities.validation.config.processTerminated"),
|
||||
showNotice.error("settings.validation.config.processTerminated"),
|
||||
"config_validate::stdout_error": () =>
|
||||
showNotice.error("entities.validation.config.failed", msg),
|
||||
showNotice.error("settings.validation.config.failed", msg),
|
||||
"config_validate::script_error": () =>
|
||||
showNotice.error("entities.validation.script.fileError", msg),
|
||||
showNotice.error("settings.validation.script.fileError", msg),
|
||||
"config_validate::script_syntax_error": () =>
|
||||
showNotice.error("entities.validation.script.syntaxError", msg),
|
||||
showNotice.error("settings.validation.script.syntaxError", msg),
|
||||
"config_validate::script_missing_main": () =>
|
||||
showNotice.error("entities.validation.script.missingMain", msg),
|
||||
showNotice.error("settings.validation.script.missingMain", msg),
|
||||
"config_validate::file_not_found": () =>
|
||||
showNotice.error("entities.validation.script.fileNotFound", msg),
|
||||
showNotice.error("settings.validation.script.fileNotFound", msg),
|
||||
"config_validate::yaml_syntax_error": () =>
|
||||
showNotice.error("entities.validation.yaml.syntaxError", msg),
|
||||
showNotice.error("settings.validation.yaml.syntaxError", msg),
|
||||
"config_validate::yaml_read_error": () =>
|
||||
showNotice.error("entities.validation.yaml.readError", msg),
|
||||
showNotice.error("settings.validation.yaml.readError", msg),
|
||||
"config_validate::yaml_mapping_error": () =>
|
||||
showNotice.error("entities.validation.yaml.mappingError", msg),
|
||||
showNotice.error("settings.validation.yaml.mappingError", msg),
|
||||
"config_validate::yaml_key_error": () =>
|
||||
showNotice.error("entities.validation.yaml.keyError", msg),
|
||||
showNotice.error("settings.validation.yaml.keyError", msg),
|
||||
"config_validate::yaml_error": () =>
|
||||
showNotice.error("entities.validation.yaml.generalError", msg),
|
||||
showNotice.error("settings.validation.yaml.generalError", msg),
|
||||
"config_validate::merge_syntax_error": () =>
|
||||
showNotice.error("entities.validation.merge.syntaxError", msg),
|
||||
showNotice.error("settings.validation.merge.syntaxError", msg),
|
||||
"config_validate::merge_mapping_error": () =>
|
||||
showNotice.error("entities.validation.merge.mappingError", msg),
|
||||
showNotice.error("settings.validation.merge.mappingError", msg),
|
||||
"config_validate::merge_key_error": () =>
|
||||
showNotice.error("entities.validation.merge.keyError", msg),
|
||||
showNotice.error("settings.validation.merge.keyError", msg),
|
||||
"config_validate::merge_error": () =>
|
||||
showNotice.error("entities.validation.merge.generalError", msg),
|
||||
showNotice.error("settings.validation.merge.generalError", msg),
|
||||
"config_core::change_success": () =>
|
||||
showNotice.success(
|
||||
"entities.settings.clash.notifications.changeSuccess",
|
||||
msg,
|
||||
),
|
||||
showNotice.success("settings.clash.notifications.changeSuccess", msg),
|
||||
"config_core::change_error": () =>
|
||||
showNotice.error(
|
||||
"entities.settings.clash.notifications.changeFailed",
|
||||
msg,
|
||||
),
|
||||
showNotice.error("settings.clash.notifications.changeFailed", msg),
|
||||
};
|
||||
|
||||
const handler = handlers[status];
|
||||
|
||||
@@ -29,49 +29,49 @@ import UnlockPage from "./unlock";
|
||||
|
||||
export const navItems = [
|
||||
{
|
||||
label: "entities.navigation.tabs.home",
|
||||
label: "layout.navigation.tabs.home",
|
||||
path: "/",
|
||||
icon: [<HomeRoundedIcon key="mui" />, <HomeSvg key="svg" />],
|
||||
Component: HomePage,
|
||||
},
|
||||
{
|
||||
label: "entities.navigation.tabs.proxies",
|
||||
label: "layout.navigation.tabs.proxies",
|
||||
path: "/proxies",
|
||||
icon: [<WifiRoundedIcon key="mui" />, <ProxiesSvg key="svg" />],
|
||||
Component: ProxiesPage,
|
||||
},
|
||||
{
|
||||
label: "entities.navigation.tabs.profiles",
|
||||
label: "layout.navigation.tabs.profiles",
|
||||
path: "/profile",
|
||||
icon: [<DnsRoundedIcon key="mui" />, <ProfilesSvg key="svg" />],
|
||||
Component: ProfilesPage,
|
||||
},
|
||||
{
|
||||
label: "entities.navigation.tabs.connections",
|
||||
label: "layout.navigation.tabs.connections",
|
||||
path: "/connections",
|
||||
icon: [<LanguageRoundedIcon key="mui" />, <ConnectionsSvg key="svg" />],
|
||||
Component: ConnectionsPage,
|
||||
},
|
||||
{
|
||||
label: "entities.navigation.tabs.rules",
|
||||
label: "layout.navigation.tabs.rules",
|
||||
path: "/rules",
|
||||
icon: [<ForkRightRoundedIcon key="mui" />, <RulesSvg key="svg" />],
|
||||
Component: RulesPage,
|
||||
},
|
||||
{
|
||||
label: "entities.navigation.tabs.logs",
|
||||
label: "layout.navigation.tabs.logs",
|
||||
path: "/logs",
|
||||
icon: [<SubjectRoundedIcon key="mui" />, <LogsSvg key="svg" />],
|
||||
Component: LogsPage,
|
||||
},
|
||||
{
|
||||
label: "entities.navigation.tabs.unlock",
|
||||
label: "layout.navigation.tabs.unlock",
|
||||
path: "/unlock",
|
||||
icon: [<LockOpenRoundedIcon key="mui" />, <UnlockSvg key="svg" />],
|
||||
Component: UnlockPage,
|
||||
},
|
||||
{
|
||||
label: "entities.navigation.tabs.settings",
|
||||
label: "layout.navigation.tabs.settings",
|
||||
path: "/settings",
|
||||
icon: [<SettingsRoundedIcon key="mui" />, <SettingsSvg key="svg" />],
|
||||
Component: SettingsPage,
|
||||
|
||||
@@ -36,7 +36,7 @@ type OrderFunc = (list: IConnectionsItem[]) => IConnectionsItem[];
|
||||
const ORDER_OPTIONS = [
|
||||
{
|
||||
id: "default",
|
||||
labelKey: "entities.connection.order.default",
|
||||
labelKey: "connections.order.default",
|
||||
fn: (list: IConnectionsItem[]) =>
|
||||
list.sort(
|
||||
(a, b) =>
|
||||
@@ -46,13 +46,13 @@ const ORDER_OPTIONS = [
|
||||
},
|
||||
{
|
||||
id: "uploadSpeed",
|
||||
labelKey: "entities.connection.order.uploadSpeed",
|
||||
labelKey: "connections.order.uploadSpeed",
|
||||
fn: (list: IConnectionsItem[]) =>
|
||||
list.sort((a, b) => b.curUpload! - a.curUpload!),
|
||||
},
|
||||
{
|
||||
id: "downloadSpeed",
|
||||
labelKey: "entities.connection.order.downloadSpeed",
|
||||
labelKey: "connections.order.downloadSpeed",
|
||||
fn: (list: IConnectionsItem[]) =>
|
||||
list.sort((a, b) => b.curDownload! - a.curDownload!),
|
||||
},
|
||||
@@ -150,7 +150,7 @@ const ConnectionsPage = () => {
|
||||
full
|
||||
title={
|
||||
<span style={{ whiteSpace: "nowrap" }}>
|
||||
{t("entities.connection.page.title")}
|
||||
{t("connections.page.title")}
|
||||
</span>
|
||||
}
|
||||
contentStyle={{
|
||||
@@ -163,11 +163,11 @@ const ConnectionsPage = () => {
|
||||
header={
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
||||
<Box sx={{ mx: 1 }}>
|
||||
{t("entities.connection.page.summary.downloaded")}:{" "}
|
||||
{t("connections.page.summary.downloaded")}:{" "}
|
||||
{parseTraffic(displayData.downloadTotal)}
|
||||
</Box>
|
||||
<Box sx={{ mx: 1 }}>
|
||||
{t("entities.connection.page.summary.uploaded")}:{" "}
|
||||
{t("connections.page.summary.uploaded")}:{" "}
|
||||
{parseTraffic(displayData.uploadTotal)}
|
||||
</Box>
|
||||
<IconButton
|
||||
@@ -183,11 +183,11 @@ const ConnectionsPage = () => {
|
||||
>
|
||||
{isTableLayout ? (
|
||||
<TableRowsRounded
|
||||
titleAccess={t("entities.connection.page.actions.listView")}
|
||||
titleAccess={t("connections.page.actions.listView")}
|
||||
/>
|
||||
) : (
|
||||
<TableChartRounded
|
||||
titleAccess={t("entities.connection.page.actions.tableView")}
|
||||
titleAccess={t("connections.page.actions.tableView")}
|
||||
/>
|
||||
)}
|
||||
</IconButton>
|
||||
@@ -197,8 +197,8 @@ const ConnectionsPage = () => {
|
||||
onClick={handlePauseToggle}
|
||||
title={
|
||||
isPaused
|
||||
? t("entities.connection.page.actions.resume")
|
||||
: t("entities.connection.page.actions.pause")
|
||||
? t("connections.page.actions.resume")
|
||||
: t("connections.page.actions.pause")
|
||||
}
|
||||
>
|
||||
{isPaused ? (
|
||||
@@ -209,7 +209,7 @@ const ConnectionsPage = () => {
|
||||
</IconButton>
|
||||
<Button size="small" variant="contained" onClick={onCloseAll}>
|
||||
<span style={{ whiteSpace: "nowrap" }}>
|
||||
{t("entities.connection.page.actions.closeAll")}
|
||||
{t("connections.page.actions.closeAll")}
|
||||
</span>
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
@@ -112,7 +112,7 @@ const HomeSettingsDialog = ({
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose} maxWidth="xs" fullWidth>
|
||||
<DialogTitle>{t("entities.home.page.settings.title")}</DialogTitle>
|
||||
<DialogTitle>{t("home.page.settings.title")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
@@ -122,7 +122,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("profile")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.profile")}
|
||||
label={t("home.page.settings.cards.profile")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -131,7 +131,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("proxy")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.currentProxy")}
|
||||
label={t("home.page.settings.cards.currentProxy")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -140,7 +140,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("network")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.network")}
|
||||
label={t("home.page.settings.cards.network")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -149,7 +149,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("mode")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.proxyMode")}
|
||||
label={t("home.page.settings.cards.proxyMode")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -158,7 +158,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("traffic")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.traffic")}
|
||||
label={t("home.page.settings.cards.traffic")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -167,7 +167,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("test")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.tests")}
|
||||
label={t("home.page.settings.cards.tests")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -176,7 +176,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("ip")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.ip")}
|
||||
label={t("home.page.settings.cards.ip")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -185,7 +185,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("clashinfo")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.clashInfo")}
|
||||
label={t("home.page.settings.cards.clashInfo")}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
@@ -194,7 +194,7 @@ const HomeSettingsDialog = ({
|
||||
onChange={() => handleToggle("systeminfo")}
|
||||
/>
|
||||
}
|
||||
label={t("entities.home.page.settings.cards.systemInfo")}
|
||||
label={t("home.page.settings.cards.systemInfo")}
|
||||
/>
|
||||
</FormGroup>
|
||||
</DialogContent>
|
||||
@@ -323,7 +323,7 @@ const HomePage = () => {
|
||||
renderCard(
|
||||
"traffic",
|
||||
<EnhancedCard
|
||||
title={t("entities.home.page.cards.trafficStats")}
|
||||
title={t("home.page.cards.trafficStats")}
|
||||
icon={<SpeedOutlined />}
|
||||
iconColor="secondary"
|
||||
>
|
||||
@@ -364,14 +364,11 @@ const HomePage = () => {
|
||||
);
|
||||
return (
|
||||
<BasePage
|
||||
title={t("entities.home.page.title")}
|
||||
title={t("home.page.title")}
|
||||
contentStyle={{ padding: 2 }}
|
||||
header={
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Tooltip
|
||||
title={t("entities.home.page.tooltips.lightweightMode")}
|
||||
arrow
|
||||
>
|
||||
<Tooltip title={t("home.page.tooltips.lightweightMode")} arrow>
|
||||
<IconButton
|
||||
onClick={async () => await entry_lightweight_mode()}
|
||||
size="small"
|
||||
@@ -380,12 +377,12 @@ const HomePage = () => {
|
||||
<HistoryEduOutlined />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={t("entities.home.page.tooltips.manual")} arrow>
|
||||
<Tooltip title={t("home.page.tooltips.manual")} arrow>
|
||||
<IconButton onClick={toGithubDoc} size="small" color="inherit">
|
||||
<HelpOutlineRounded />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={t("entities.home.page.tooltips.settings")} arrow>
|
||||
<Tooltip title={t("home.page.tooltips.settings")} arrow>
|
||||
<IconButton onClick={openSettings} size="small" color="inherit">
|
||||
<SettingsOutlined />
|
||||
</IconButton>
|
||||
@@ -416,7 +413,7 @@ const NetworkSettingsCard = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.page.cards.networkSettings")}
|
||||
title={t("home.page.cards.networkSettings")}
|
||||
icon={<DnsOutlined />}
|
||||
iconColor="primary"
|
||||
action={null}
|
||||
@@ -431,7 +428,7 @@ const ClashModeEnhancedCard = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<EnhancedCard
|
||||
title={t("entities.home.page.cards.proxyMode")}
|
||||
title={t("home.page.cards.proxyMode")}
|
||||
icon={<RouterOutlined />}
|
||||
iconColor="info"
|
||||
action={null}
|
||||
|
||||
@@ -60,7 +60,7 @@ const LogPage = () => {
|
||||
return (
|
||||
<BasePage
|
||||
full
|
||||
title={t("entities.log.page.title")}
|
||||
title={t("logs.page.title")}
|
||||
contentStyle={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
@@ -72,13 +72,13 @@ const LogPage = () => {
|
||||
<IconButton
|
||||
title={t(
|
||||
enableLog
|
||||
? "entities.log.page.actions.pause"
|
||||
: "entities.log.page.actions.resume",
|
||||
? "logs.page.actions.pause"
|
||||
: "logs.page.actions.resume",
|
||||
)}
|
||||
aria-label={t(
|
||||
enableLog
|
||||
? "entities.log.page.actions.pause"
|
||||
: "entities.log.page.actions.resume",
|
||||
? "logs.page.actions.pause"
|
||||
: "logs.page.actions.resume",
|
||||
)}
|
||||
size="small"
|
||||
color="inherit"
|
||||
@@ -98,7 +98,7 @@ const LogPage = () => {
|
||||
refreshGetClashLog(true);
|
||||
}}
|
||||
>
|
||||
{t("entities.log.page.actions.clear")}
|
||||
{t("logs.page.actions.clear")}
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
@@ -117,19 +117,11 @@ const LogPage = () => {
|
||||
value={logState}
|
||||
onChange={(e) => handleLogLevelChange(e.target.value as LogFilter)}
|
||||
>
|
||||
<MenuItem value="all">{t("entities.log.page.filters.all")}</MenuItem>
|
||||
<MenuItem value="debug">
|
||||
{t("entities.log.page.filters.debug")}
|
||||
</MenuItem>
|
||||
<MenuItem value="info">
|
||||
{t("entities.log.page.filters.info")}
|
||||
</MenuItem>
|
||||
<MenuItem value="warn">
|
||||
{t("entities.log.page.filters.warn")}
|
||||
</MenuItem>
|
||||
<MenuItem value="err">
|
||||
{t("entities.log.page.filters.error")}
|
||||
</MenuItem>
|
||||
<MenuItem value="all">{t("logs.page.filters.all")}</MenuItem>
|
||||
<MenuItem value="debug">{t("logs.page.filters.debug")}</MenuItem>
|
||||
<MenuItem value="info">{t("logs.page.filters.info")}</MenuItem>
|
||||
<MenuItem value="warn">{t("logs.page.filters.warn")}</MenuItem>
|
||||
<MenuItem value="err">{t("logs.page.filters.error")}</MenuItem>
|
||||
</BaseStyledSelect>
|
||||
<BaseSearchBox
|
||||
onSearch={(matcher, state) => {
|
||||
|
||||
@@ -146,7 +146,7 @@ const ProfilePage = () => {
|
||||
|
||||
setActivatings((prev) => prev.filter((id) => id !== previousSwitching));
|
||||
showNotice.info(
|
||||
"entities.profile.page.notifications.switchInterrupted",
|
||||
"profiles.page.notifications.switchInterrupted",
|
||||
`${previousSwitching} → ${newProfile}`,
|
||||
3000,
|
||||
);
|
||||
@@ -191,7 +191,7 @@ const ProfilePage = () => {
|
||||
|
||||
for (const file of paths) {
|
||||
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) {
|
||||
showNotice.error("entities.profile.page.errors.onlyYaml");
|
||||
showNotice.error("profiles.page.errors.onlyYaml");
|
||||
continue;
|
||||
}
|
||||
const item = {
|
||||
@@ -239,14 +239,11 @@ const ProfilePage = () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
await onEnhance(false);
|
||||
|
||||
showNotice.success(
|
||||
"entities.profile.page.notices.forceRefreshCompleted",
|
||||
2000,
|
||||
);
|
||||
showNotice.success("profiles.page.notices.forceRefreshCompleted", 2000);
|
||||
} catch (error) {
|
||||
console.error("[紧急刷新] 失败:", error);
|
||||
showNotice.error(
|
||||
"entities.profile.page.notices.emergencyRefreshFailed",
|
||||
"profiles.page.notices.emergencyRefreshFailed",
|
||||
{ message: String(error) },
|
||||
4000,
|
||||
);
|
||||
@@ -278,7 +275,7 @@ const ProfilePage = () => {
|
||||
if (!url) return;
|
||||
// 校验url是否为http/https
|
||||
if (!/^https?:\/\//i.test(url)) {
|
||||
showNotice.error("entities.profile.page.errors.invalidUrl");
|
||||
showNotice.error("profiles.page.errors.invalidUrl");
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
@@ -292,11 +289,11 @@ const ProfilePage = () => {
|
||||
try {
|
||||
// 尝试正常导入
|
||||
await importProfile(url);
|
||||
await handleImportSuccess("entities.profile.notifications.importSuccess");
|
||||
await handleImportSuccess("profiles.notifications.importSuccess");
|
||||
} catch (initialErr) {
|
||||
console.warn("[订阅导入] 首次导入失败:", initialErr);
|
||||
|
||||
showNotice.info("entities.profile.page.notifications.importRetry");
|
||||
showNotice.info("profiles.page.notifications.importRetry");
|
||||
try {
|
||||
// 使用自身代理尝试导入
|
||||
await importProfile(url, {
|
||||
@@ -304,12 +301,12 @@ const ProfilePage = () => {
|
||||
self_proxy: true,
|
||||
});
|
||||
await handleImportSuccess(
|
||||
"entities.profile.notifications.importWithClashProxy",
|
||||
"profiles.notifications.importWithClashProxy",
|
||||
);
|
||||
} catch (retryErr) {
|
||||
// 回退导入也失败
|
||||
showNotice.error(
|
||||
"entities.profile.page.notifications.importFail",
|
||||
"profiles.page.notifications.importFail",
|
||||
String(retryErr),
|
||||
);
|
||||
}
|
||||
@@ -357,16 +354,10 @@ const ProfilePage = () => {
|
||||
// 清除SWR缓存并重新获取
|
||||
await mutate("getProfiles", getProfiles(), { revalidate: true });
|
||||
await onEnhance(false);
|
||||
showNotice.error(
|
||||
"entities.profile.page.notifications.importNeedsRefresh",
|
||||
3000,
|
||||
);
|
||||
showNotice.error("profiles.page.notifications.importNeedsRefresh", 3000);
|
||||
} catch (finalError) {
|
||||
console.error(`[导入刷新] 最终刷新尝试失败:`, finalError);
|
||||
showNotice.error(
|
||||
"entities.profile.page.notifications.importSuccess",
|
||||
5000,
|
||||
);
|
||||
showNotice.error("profiles.page.notifications.importSuccess", 5000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -484,7 +475,7 @@ const ProfilePage = () => {
|
||||
|
||||
if (notifySuccess && success) {
|
||||
showNotice.success(
|
||||
"entities.profile.page.notifications.profileSwitched",
|
||||
"profiles.page.notifications.profileSwitched",
|
||||
1000,
|
||||
);
|
||||
}
|
||||
@@ -583,7 +574,7 @@ const ProfilePage = () => {
|
||||
mutateLogs();
|
||||
if (notifySuccess) {
|
||||
showNotice.success(
|
||||
"entities.profile.page.notifications.profileReactivated",
|
||||
"profiles.page.notifications.profileReactivated",
|
||||
1000,
|
||||
);
|
||||
}
|
||||
@@ -724,7 +715,7 @@ const ProfilePage = () => {
|
||||
setSelectedProfiles(new Set());
|
||||
setBatchMode(false);
|
||||
|
||||
showNotice.success("entities.profile.page.notifications.batchDeleted");
|
||||
showNotice.success("profiles.page.notifications.batchDeleted");
|
||||
} catch (err: any) {
|
||||
showNotice.error(err);
|
||||
} finally {
|
||||
@@ -804,7 +795,7 @@ const ProfilePage = () => {
|
||||
return (
|
||||
<BasePage
|
||||
full
|
||||
title={t("entities.profile.page.title")}
|
||||
title={t("profiles.page.title")}
|
||||
contentStyle={{ height: "100%" }}
|
||||
header={
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
@@ -814,7 +805,7 @@ const ProfilePage = () => {
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={t("entities.profile.page.batch.title")}
|
||||
title={t("profiles.page.batch.title")}
|
||||
onClick={toggleBatchMode}
|
||||
>
|
||||
<CheckBoxOutlineBlankRounded />
|
||||
@@ -823,7 +814,7 @@ const ProfilePage = () => {
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={t("entities.profile.page.actions.updateAll")}
|
||||
title={t("profiles.page.actions.updateAll")}
|
||||
onClick={onUpdateAll}
|
||||
>
|
||||
<RefreshRounded />
|
||||
@@ -832,7 +823,7 @@ const ProfilePage = () => {
|
||||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={t("entities.profile.page.actions.viewRuntimeConfig")}
|
||||
title={t("profiles.page.actions.viewRuntimeConfig")}
|
||||
onClick={() => configRef.current?.open()}
|
||||
>
|
||||
<TextSnippetOutlined />
|
||||
@@ -841,7 +832,7 @@ const ProfilePage = () => {
|
||||
<IconButton
|
||||
size="small"
|
||||
color="primary"
|
||||
title={t("entities.profile.page.actions.reactivate")}
|
||||
title={t("profiles.page.actions.reactivate")}
|
||||
onClick={() => onEnhance(true)}
|
||||
>
|
||||
<LocalFireDepartmentRounded />
|
||||
@@ -875,8 +866,8 @@ const ProfilePage = () => {
|
||||
color="inherit"
|
||||
title={
|
||||
isAllSelected()
|
||||
? t("entities.profile.page.batch.deselectAll")
|
||||
: t("entities.profile.page.batch.selectAll")
|
||||
? t("profiles.page.batch.deselectAll")
|
||||
: t("profiles.page.batch.selectAll")
|
||||
}
|
||||
onClick={
|
||||
isAllSelected() ? clearAllSelections : selectAllProfiles
|
||||
@@ -893,20 +884,20 @@ const ProfilePage = () => {
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
title={t("entities.profile.page.batch.delete")}
|
||||
title={t("profiles.page.batch.delete")}
|
||||
onClick={deleteSelectedProfiles}
|
||||
disabled={selectedProfiles.size === 0}
|
||||
>
|
||||
<DeleteRounded />
|
||||
</IconButton>
|
||||
<Button size="small" variant="outlined" onClick={toggleBatchMode}>
|
||||
{t("entities.profile.page.batch.done")}
|
||||
{t("profiles.page.batch.done")}
|
||||
</Button>
|
||||
<Box
|
||||
sx={{ flex: 1, textAlign: "right", color: "text.secondary" }}
|
||||
>
|
||||
{t("entities.profile.page.batch.selected")}{" "}
|
||||
{selectedProfiles.size} {t("entities.profile.page.batch.items")}
|
||||
{t("profiles.page.batch.selected")} {selectedProfiles.size}{" "}
|
||||
{t("profiles.page.batch.items")}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
@@ -939,7 +930,7 @@ const ProfilePage = () => {
|
||||
event.preventDefault();
|
||||
void onImport();
|
||||
}}
|
||||
placeholder={t("entities.profile.page.import.placeholder")}
|
||||
placeholder={t("profiles.page.import.placeholder")}
|
||||
slotProps={{
|
||||
input: {
|
||||
sx: { pr: 1 },
|
||||
@@ -947,7 +938,7 @@ const ProfilePage = () => {
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{ p: 0.5 }}
|
||||
title={t("entities.profile.page.import.paste")}
|
||||
title={t("profiles.page.import.paste")}
|
||||
onClick={onCopyLink}
|
||||
>
|
||||
<ContentPasteRounded fontSize="inherit" />
|
||||
@@ -956,7 +947,7 @@ const ProfilePage = () => {
|
||||
<IconButton
|
||||
size="small"
|
||||
sx={{ p: 0.5 }}
|
||||
title={t("entities.profile.page.import.clear")}
|
||||
title={t("profiles.page.import.clear")}
|
||||
onClick={() => setUrl("")}
|
||||
>
|
||||
<ClearRounded fontSize="inherit" />
|
||||
@@ -973,7 +964,7 @@ const ProfilePage = () => {
|
||||
sx={{ borderRadius: "6px" }}
|
||||
onClick={onImport}
|
||||
>
|
||||
{t("entities.profile.page.actions.import")}
|
||||
{t("profiles.page.actions.import")}
|
||||
</LoadingButton>
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -1018,7 +1009,7 @@ const ProfilePage = () => {
|
||||
if (prev !== curr && profiles.current === item.uid) {
|
||||
await onEnhance(false);
|
||||
// await restartCore();
|
||||
// Notice.success(t("entities.settings.clash.notifications.restartSuccess"), 1000);
|
||||
// Notice.success(t("settings.clash.notifications.restartSuccess"), 1000);
|
||||
}
|
||||
}}
|
||||
onDelete={() => {
|
||||
|
||||
@@ -142,8 +142,8 @@ const ProxyPage = () => {
|
||||
contentStyle={{ height: "101.5%" }}
|
||||
title={
|
||||
isChainMode
|
||||
? t("entities.proxy.page.title.chainMode")
|
||||
: t("entities.proxy.page.title.default")
|
||||
? t("proxies.page.title.chainMode")
|
||||
: t("proxies.page.title.default")
|
||||
}
|
||||
header={
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
@@ -157,7 +157,7 @@ const ProxyPage = () => {
|
||||
onClick={() => onChangeMode(mode)}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
{t(`entities.proxy.page.modes.${mode}`)}
|
||||
{t(`proxies.page.modes.${mode}`)}
|
||||
</Button>
|
||||
))}
|
||||
</ButtonGroup>
|
||||
@@ -168,7 +168,7 @@ const ProxyPage = () => {
|
||||
onClick={onToggleChainMode}
|
||||
sx={{ ml: 1 }}
|
||||
>
|
||||
{t("entities.proxy.page.actions.toggleChain")}
|
||||
{t("proxies.page.actions.toggleChain")}
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ const RulesPage = () => {
|
||||
return (
|
||||
<BasePage
|
||||
full
|
||||
title={t("entities.rule.page.title")}
|
||||
title={t("rules.page.title")}
|
||||
contentStyle={{
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
|
||||
@@ -36,13 +36,13 @@ const SettingPage = () => {
|
||||
|
||||
return (
|
||||
<BasePage
|
||||
title={t("entities.settings.page.title")}
|
||||
title={t("settings.page.title")}
|
||||
header={
|
||||
<ButtonGroup variant="contained" aria-label="Basic button group">
|
||||
<IconButton
|
||||
size="medium"
|
||||
color="inherit"
|
||||
title={t("entities.settings.page.actions.manual")}
|
||||
title={t("settings.page.actions.manual")}
|
||||
onClick={toGithubDoc}
|
||||
>
|
||||
<HelpOutlineRounded fontSize="inherit" />
|
||||
@@ -50,7 +50,7 @@ const SettingPage = () => {
|
||||
<IconButton
|
||||
size="medium"
|
||||
color="inherit"
|
||||
title={t("entities.settings.page.actions.telegram")}
|
||||
title={t("settings.page.actions.telegram")}
|
||||
onClick={toTelegramChannel}
|
||||
>
|
||||
<Telegram fontSize="inherit" />
|
||||
@@ -59,7 +59,7 @@ const SettingPage = () => {
|
||||
<IconButton
|
||||
size="medium"
|
||||
color="inherit"
|
||||
title={t("entities.settings.page.actions.github")}
|
||||
title={t("settings.page.actions.github")}
|
||||
onClick={toGithubRepo}
|
||||
>
|
||||
<GitHub fontSize="inherit" />
|
||||
|
||||
@@ -141,7 +141,7 @@ const TestPage = () => {
|
||||
return (
|
||||
<BasePage
|
||||
full
|
||||
title={t("entities.test.page.title")}
|
||||
title={t("tests.page.title")}
|
||||
header={
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<Button
|
||||
@@ -149,7 +149,7 @@ const TestPage = () => {
|
||||
size="small"
|
||||
onClick={() => emit("verge://test-all")}
|
||||
>
|
||||
{t("entities.test.page.actions.testAll")}
|
||||
{t("tests.page.actions.testAll")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
|
||||
@@ -38,16 +38,16 @@ const UNLOCK_RESULTS_STORAGE_KEY = "clash_verge_unlock_results";
|
||||
const UNLOCK_RESULTS_TIME_KEY = "clash_verge_unlock_time";
|
||||
|
||||
const STATUS_LABEL_KEYS: Record<string, string> = {
|
||||
Pending: "entities.test.statuses.pending",
|
||||
Yes: "entities.test.statuses.yes",
|
||||
No: "entities.test.statuses.no",
|
||||
Failed: "entities.test.statuses.failed",
|
||||
Completed: "entities.test.statuses.completed",
|
||||
"Disallowed ISP": "entities.test.statuses.disallowedIsp",
|
||||
"Originals Only": "entities.test.statuses.originalsOnly",
|
||||
"No (IP Banned By Disney+)": "entities.test.statuses.noDisney",
|
||||
"Unsupported Country/Region": "entities.test.statuses.unsupportedRegion",
|
||||
"Failed (Network Connection)": "entities.test.statuses.failedNetwork",
|
||||
Pending: "tests.statuses.pending",
|
||||
Yes: "tests.statuses.yes",
|
||||
No: "tests.statuses.no",
|
||||
Failed: "tests.statuses.failed",
|
||||
Completed: "tests.statuses.completed",
|
||||
"Disallowed ISP": "tests.statuses.disallowedIsp",
|
||||
"Originals Only": "tests.statuses.originalsOnly",
|
||||
"No (IP Banned By Disney+)": "tests.statuses.noDisney",
|
||||
"Unsupported Country/Region": "tests.statuses.unsupportedRegion",
|
||||
"Failed (Network Connection)": "tests.statuses.failedNetwork",
|
||||
};
|
||||
|
||||
const UnlockPage = () => {
|
||||
@@ -163,10 +163,7 @@ const UnlockPage = () => {
|
||||
invoke<T>(cmd, args),
|
||||
new Promise<T>((_, reject) =>
|
||||
setTimeout(
|
||||
() =>
|
||||
reject(
|
||||
new Error(t("entities.unlock.page.messages.detectionTimeout")),
|
||||
),
|
||||
() => reject(new Error(t("unlock.page.messages.detectionTimeout"))),
|
||||
timeout,
|
||||
),
|
||||
),
|
||||
@@ -266,7 +263,7 @@ const UnlockPage = () => {
|
||||
|
||||
return (
|
||||
<BasePage
|
||||
title={t("entities.unlock.page.title")}
|
||||
title={t("unlock.page.title")}
|
||||
header={
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||
<Button
|
||||
@@ -283,8 +280,8 @@ const UnlockPage = () => {
|
||||
}
|
||||
>
|
||||
{isCheckingAll
|
||||
? t("entities.unlock.page.actions.testing")
|
||||
: t("entities.test.page.actions.testAll")}
|
||||
? t("unlock.page.actions.testing")
|
||||
: t("tests.page.actions.testAll")}
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
@@ -298,7 +295,7 @@ const UnlockPage = () => {
|
||||
height: "50%",
|
||||
}}
|
||||
>
|
||||
<BaseEmpty textKey="entities.unlock.page.empty" />
|
||||
<BaseEmpty textKey="unlock.page.empty" />
|
||||
</Box>
|
||||
) : (
|
||||
<Grid container spacing={1.5} columns={{ xs: 1, sm: 2, md: 3 }}>
|
||||
@@ -340,7 +337,7 @@ const UnlockPage = () => {
|
||||
>
|
||||
{item.name}
|
||||
</Typography>
|
||||
<Tooltip title={t("entities.test.item.actions.test")}>
|
||||
<Tooltip title={t("tests.item.actions.test")}>
|
||||
<span>
|
||||
<Button
|
||||
size="small"
|
||||
|
||||
Reference in New Issue
Block a user