refactor(i18n): flatten locales and move theme/validation strings

This commit is contained in:
Slinetrac
2025-11-05 15:18:30 +08:00
Unverified
parent b48426236b
commit 173c41c3f7
91 changed files with 15616 additions and 16064 deletions

View File

@@ -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"
}
}
}

View File

@@ -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"
},

View File

@@ -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);
});

View File

@@ -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>

View File

@@ -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>

View File

@@ -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,
},

View File

@@ -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}

View File

@@ -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]);
// 模式图标映射

View File

@@ -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>
)}

View File

@@ -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>

View File

@@ -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,

View File

@@ -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]);

View File

@@ -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"

View File

@@ -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}
/>

View File

@@ -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}

View File

@@ -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>

View File

@@ -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",

View File

@@ -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")

View File

@@ -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

View File

@@ -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>

View File

@@ -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={{

View File

@@ -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={() => {

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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 } }}
/>

View File

@@ -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")
: ""
}
>

View File

@@ -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}`}

View File

@@ -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>

View File

@@ -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"

View File

@@ -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>
);

View File

@@ -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

View File

@@ -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"

View File

@@ -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 }}
>

View File

@@ -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>
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"

View File

@@ -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"

View File

@@ -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" }} />

View File

@@ -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

View File

@@ -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) => {

View File

@@ -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>

View File

@@ -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) => {

View File

@@ -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"

View File

@@ -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)}

View File

@@ -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)}
>

View File

@@ -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>
}
/>

View File

@@ -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>
);

View File

@@ -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" }}
/>
}

View File

@@ -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")}
/>
}
>

View File

@@ -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>
);

View File

@@ -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}

View File

@@ -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>
)}

View File

@@ -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")}
/>
)}
/>

View File

@@ -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(() => {

View File

@@ -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();

View File

@@ -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();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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>

View File

@@ -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];

View File

@@ -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,

View File

@@ -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>

View File

@@ -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}

View File

@@ -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) => {

View File

@@ -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={() => {

View File

@@ -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>
}

View File

@@ -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",

View File

@@ -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" />

View File

@@ -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"

View File

@@ -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"