chore(i18n): components.profile.*

This commit is contained in:
Slinetrac
2025-11-01 22:54:32 +08:00
Unverified
parent 730f607c68
commit d2cca2120d
22 changed files with 1679 additions and 903 deletions

View File

@@ -97,7 +97,7 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
onClose,
} = props;
const resolvedTitle = title ?? t("Edit File");
const resolvedTitle = title ?? t("components.profile.menu.editFile");
const resolvedInitialData = useMemo(
() => initialData ?? Promise.resolve(""),
[initialData],
@@ -202,7 +202,9 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
},
mouseWheelZoom: true, // 按住Ctrl滚轮调节缩放比例
readOnly: readOnly, // 只读模式
readOnlyMessage: { value: t("ReadOnlyMessage") }, // 只读模式尝试编辑时的提示信息
readOnlyMessage: {
value: t("components.profile.editor.readOnlyMessage"),
}, // 只读模式尝试编辑时的提示信息
renderValidationDecorations: "on", // 只读模式下显示校验信息
quickSuggestions: {
strings: true, // 字符串类型的建议
@@ -231,7 +233,7 @@ export const EditorViewer = <T extends Language>(props: Props<T>) => {
size="medium"
color="inherit"
sx={{ display: readOnly ? "none" : "" }}
title={t("Format document")}
title={t("components.profile.editor.format")}
onClick={() =>
editorRef.current
?.getAction("editor.action.formatDocument")

View File

@@ -369,7 +369,7 @@ export const GroupsEditorViewer = (props: Props) => {
const validateGroup = () => {
const group = formIns.getValues();
if (group.name === "") {
throw new Error(t("Group Name Required"));
throw new Error(t("components.profile.groupsEditor.errors.nameRequired"));
}
};
@@ -384,7 +384,7 @@ export const GroupsEditorViewer = (props: Props) => {
}
await saveProfileFile(property, nextData);
showNotice("success", t("Saved Successfully"));
showNotice("success", t("components.profile.notifications.saved"));
setPrevData(nextData);
onSave?.(prevData, nextData);
onClose();
@@ -398,7 +398,7 @@ export const GroupsEditorViewer = (props: Props) => {
<DialogTitle>
{
<Box display="flex" justifyContent="space-between">
{t("Edit Groups")}
{t("components.profile.groupsEditor.title")}
<Box>
<Button
variant="contained"
@@ -407,7 +407,9 @@ export const GroupsEditorViewer = (props: Props) => {
setVisualization((prev) => !prev);
}}
>
{visualization ? t("Advanced") : t("Visualization")}
{visualization
? t("common.editorModes.advanced")
: t("common.editorModes.visualization")}
</Button>
</Box>
</Box>
@@ -436,7 +438,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Group Type")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.type",
)}
/>
<Autocomplete
size="small"
sx={{ width: "calc(100% - 150px)" }}
@@ -464,7 +470,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Group Name")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.name",
)}
/>
<TextField
autoComplete="new-password"
size="small"
@@ -481,7 +491,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Proxy Group Icon")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.icon",
)}
/>
<TextField
autoComplete="new-password"
size="small"
@@ -496,7 +510,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Use Proxies")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.proxies",
)}
/>
<Autocomplete
size="small"
sx={{
@@ -521,7 +539,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Use Provider")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.provider",
)}
/>
<Autocomplete
size="small"
sx={{ width: "calc(100% - 150px)" }}
@@ -539,7 +561,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Health Check Url")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.healthCheckUrl",
)}
/>
<TextField
autoComplete="new-password"
placeholder="https://cp.cloudflare.com/generate_204"
@@ -555,7 +581,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Expected Status")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.expectedStatus",
)}
/>
<TextField
autoComplete="new-password"
placeholder="*"
@@ -573,7 +603,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Interval")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.interval",
)}
/>
<TextField
autoComplete="new-password"
placeholder="300"
@@ -601,7 +635,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Timeout")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.timeout",
)}
/>
<TextField
autoComplete="new-password"
placeholder="5000"
@@ -629,7 +667,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Max Failed Times")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.maxFailedTimes",
)}
/>
<TextField
autoComplete="new-password"
placeholder="5"
@@ -648,7 +690,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Interface Name")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.interfaceName",
)}
/>
<Autocomplete
size="small"
sx={{ width: "calc(100% - 150px)" }}
@@ -665,7 +711,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Routing Mark")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.routingMark",
)}
/>
<TextField
autoComplete="new-password"
type="number"
@@ -683,7 +733,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Filter")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.filter",
)}
/>
<TextField
autoComplete="new-password"
size="small"
@@ -698,7 +752,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Exclude Filter")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.excludeFilter",
)}
/>
<TextField
autoComplete="new-password"
size="small"
@@ -713,7 +771,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Exclude Type")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.excludeType",
)}
/>
<Autocomplete
multiple
options={[
@@ -759,7 +821,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Include All")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.includeAll",
)}
/>
<Switch checked={field.value} {...field} />
</Item>
)}
@@ -769,7 +835,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Include All Proxies")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.includeAllProxies",
)}
/>
<Switch checked={field.value} {...field} />
</Item>
)}
@@ -779,7 +849,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Include All Providers")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.fields.includeAllProviders",
)}
/>
<Switch checked={field.value} {...field} />
</Item>
)}
@@ -789,7 +863,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Lazy")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.toggles.lazy",
)}
/>
<Switch checked={field.value} {...field} />
</Item>
)}
@@ -799,7 +877,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Disable UDP")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.toggles.disableUdp",
)}
/>
<Switch checked={field.value} {...field} />
</Item>
)}
@@ -809,7 +891,11 @@ export const GroupsEditorViewer = (props: Props) => {
control={control}
render={({ field }) => (
<Item>
<ListItemText primary={t("Hidden")} />
<ListItemText
primary={t(
"components.profile.groupsEditor.toggles.hidden",
)}
/>
<Switch checked={field.value} {...field} />
</Item>
)}
@@ -825,7 +911,11 @@ export const GroupsEditorViewer = (props: Props) => {
validateGroup();
for (const item of [...prependSeq, ...groupList]) {
if (item.name === formIns.getValues().name) {
throw new Error(t("Group Name Already Exists"));
throw new Error(
t(
"components.profile.groupsEditor.errors.nameExists",
),
);
}
}
setPrependSeq([formIns.getValues(), ...prependSeq]);
@@ -834,7 +924,7 @@ export const GroupsEditorViewer = (props: Props) => {
}
}}
>
{t("Prepend Group")}
{t("components.profile.groupsEditor.actions.prepend")}
</Button>
</Item>
<Item>
@@ -847,7 +937,11 @@ export const GroupsEditorViewer = (props: Props) => {
validateGroup();
for (const item of [...appendSeq, ...groupList]) {
if (item.name === formIns.getValues().name) {
throw new Error(t("Group Name Already Exists"));
throw new Error(
t(
"components.profile.groupsEditor.errors.nameExists",
),
);
}
}
setAppendSeq([...appendSeq, formIns.getValues()]);
@@ -856,7 +950,7 @@ export const GroupsEditorViewer = (props: Props) => {
}
}}
>
{t("Append Group")}
{t("components.profile.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("Script Console")}</DialogTitle>
<DialogTitle>{t("components.profile.logViewer.title")}</DialogTitle>
<DialogContent
sx={{

View File

@@ -120,34 +120,42 @@ export const ProfileItem = (props: Props) => {
// 如果已经过期,显示"更新失败"
if (nextUpdateDate.isBefore(now)) {
setNextUpdateTime(t("Last Update failed"));
setNextUpdateTime(
t("components.profile.item.status.lastUpdateFailed"),
);
} else {
// 否则显示剩余时间
const diffMinutes = nextUpdateDate.diff(now, "minute");
if (diffMinutes < 60) {
if (diffMinutes <= 0) {
setNextUpdateTime(`${t("Next Up")} <1m`);
setNextUpdateTime(
`${t("components.profile.item.status.nextUp")} <1m`,
);
} else {
setNextUpdateTime(`${t("Next Up")} ${diffMinutes}m`);
setNextUpdateTime(
`${t("components.profile.item.status.nextUp")} ${diffMinutes}m`,
);
}
} else {
const hours = Math.floor(diffMinutes / 60);
const mins = diffMinutes % 60;
setNextUpdateTime(`${t("Next Up")} ${hours}h ${mins}m`);
setNextUpdateTime(
`${t("components.profile.item.status.nextUp")} ${hours}h ${mins}m`,
);
}
}
} else {
console.log(`返回的下次更新时间为空`);
setNextUpdateTime(t("No schedule"));
setNextUpdateTime(t("components.profile.item.status.noSchedule"));
}
} catch (err) {
console.error(`获取下次更新时间出错:`, err);
setNextUpdateTime(t("Unknown"));
setNextUpdateTime(t("components.profile.item.status.unknown"));
}
} else {
console.log(`该配置未设置更新间隔或间隔为0`);
setNextUpdateTime(t("Auto update disabled"));
setNextUpdateTime(t("components.profile.item.status.autoUpdateDisabled"));
}
});
@@ -354,42 +362,95 @@ export const ProfileItem = (props: Props) => {
}
});
const urlModeMenu = (
hasHome ? [{ label: "Home", handler: onOpenHome, disabled: false }] : []
).concat([
{ label: "Select", handler: onForceSelect, disabled: false },
{ label: "Edit Info", handler: onEditInfo, disabled: false },
{ label: "Edit File", handler: onEditFile, disabled: false },
type ContextMenuItem = {
label: string;
handler: () => void;
disabled: boolean;
};
const menuLabels = {
home: "components.profile.menu.home",
select: "components.profile.menu.select",
editInfo: "components.profile.menu.editInfo",
editFile: "components.profile.menu.editFile",
editRules: "components.profile.menu.editRules",
editProxies: "components.profile.menu.editProxies",
editGroups: "components.profile.menu.editGroups",
extendConfig: "components.profile.menu.extendConfig",
extendScript: "components.profile.menu.extendScript",
openFile: "components.profile.menu.openFile",
update: "components.profile.menu.update",
updateViaProxy: "components.profile.menu.updateViaProxy",
delete: "components.profile.menu.delete",
} as const;
const urlModeMenu: ContextMenuItem[] = [
...(hasHome
? [
{
label: menuLabels.home,
handler: onOpenHome,
disabled: false,
} satisfies ContextMenuItem,
]
: []),
{
label: "Edit Rules",
label: menuLabels.select,
handler: onForceSelect,
disabled: false,
},
{
label: menuLabels.editInfo,
handler: onEditInfo,
disabled: false,
},
{
label: menuLabels.editFile,
handler: onEditFile,
disabled: false,
},
{
label: menuLabels.editRules,
handler: onEditRules,
disabled: !option?.rules,
},
{
label: "Edit Proxies",
label: menuLabels.editProxies,
handler: onEditProxies,
disabled: !option?.proxies,
},
{
label: "Edit Groups",
label: menuLabels.editGroups,
handler: onEditGroups,
disabled: !option?.groups,
},
{
label: "Extend Config",
label: menuLabels.extendConfig,
handler: onEditMerge,
disabled: !option?.merge,
},
{
label: "Extend Script",
label: menuLabels.extendScript,
handler: onEditScript,
disabled: !option?.script,
},
{ label: "Open File", handler: onOpenFile, disabled: false },
{ label: "Update", handler: () => onUpdate(0), disabled: false },
{ label: "Update via proxy", handler: () => onUpdate(2), disabled: false },
{
label: "Delete",
label: menuLabels.openFile,
handler: onOpenFile,
disabled: false,
},
{
label: menuLabels.update,
handler: () => onUpdate(0),
disabled: false,
},
{
label: menuLabels.updateViaProxy,
handler: () => onUpdate(2),
disabled: false,
},
{
label: menuLabels.delete,
handler: () => {
setAnchorEl(null);
if (batchMode) {
@@ -403,39 +464,55 @@ export const ProfileItem = (props: Props) => {
},
disabled: false,
},
]);
const fileModeMenu = [
{ label: "Select", handler: onForceSelect, disabled: false },
{ label: "Edit Info", handler: onEditInfo, disabled: false },
{ label: "Edit File", handler: onEditFile, disabled: false },
];
const fileModeMenu: ContextMenuItem[] = [
{
label: "Edit Rules",
label: menuLabels.select,
handler: onForceSelect,
disabled: false,
},
{
label: menuLabels.editInfo,
handler: onEditInfo,
disabled: false,
},
{
label: menuLabels.editFile,
handler: onEditFile,
disabled: false,
},
{
label: menuLabels.editRules,
handler: onEditRules,
disabled: !option?.rules,
},
{
label: "Edit Proxies",
label: menuLabels.editProxies,
handler: onEditProxies,
disabled: !option?.proxies,
},
{
label: "Edit Groups",
label: menuLabels.editGroups,
handler: onEditGroups,
disabled: !option?.groups,
},
{
label: "Extend Config",
label: menuLabels.extendConfig,
handler: onEditMerge,
disabled: !option?.merge,
},
{
label: "Extend Script",
label: menuLabels.extendScript,
handler: onEditScript,
disabled: !option?.script,
},
{ label: "Open File", handler: onOpenFile, disabled: false },
{
label: "Delete",
label: menuLabels.openFile,
handler: onOpenFile,
disabled: false,
},
{
label: menuLabels.delete,
handler: () => {
setAnchorEl(null);
if (batchMode) {
@@ -657,8 +734,8 @@ export const ProfileItem = (props: Props) => {
textAlign="right"
title={
showNextUpdate
? t("Click to show last update time")
: `${t("Update Time")}: ${parseExpire(updated)}\n${t("Click to show next update")}`
? t("components.profile.item.tooltips.showLast")
: `${t("Update Time")}: ${parseExpire(updated)}\n${t("components.profile.item.tooltips.showNext")}`
}
sx={{
cursor: "pointer",
@@ -728,7 +805,7 @@ export const ProfileItem = (props: Props) => {
(theme) => {
return {
color:
item.label === "Delete"
item.label === menuLabels.delete
? theme.palette.error.main
: undefined,
};
@@ -813,8 +890,8 @@ export const ProfileItem = (props: Props) => {
)}
<ConfirmViewer
title={t("Confirm deletion")}
message={t("This operation is not reversible")}
title={t("components.profile.confirm.delete.title")}
message={t("components.profile.confirm.delete.message")}
open={confirmOpen}
onClose={() => setConfirmOpen(false)}
onConfirm={() => {

View File

@@ -54,9 +54,19 @@ export const ProfileMore = (props: Props) => {
const hasError = entries.some(([level]) => level === "exception");
const globalTitles: Record<Props["id"], string> = {
Merge: "components.profile.more.global.merge",
Script: "components.profile.more.global.script",
};
const chipLabels: Record<Props["id"], string> = {
Merge: "components.profile.more.chips.merge",
Script: "components.profile.more.chips.script",
};
const itemMenu = [
{ label: "Edit File", handler: onEditFile },
{ label: "Open File", handler: onOpenFile },
{ label: "components.profile.menu.editFile", handler: onEditFile },
{ label: "components.profile.menu.openFile", handler: onOpenFile },
];
const boxStyle = {
@@ -89,13 +99,13 @@ export const ProfileMore = (props: Props) => {
variant="h6"
component="h2"
noWrap
title={t(`Global ${id}`)}
title={t(globalTitles[id])}
>
{t(`Global ${id}`)}
{t(globalTitles[id])}
</Typography>
<Chip
label={id}
label={t(chipLabels[id])}
color="primary"
size="small"
variant="outlined"
@@ -111,7 +121,7 @@ export const ProfileMore = (props: Props) => {
size="small"
edge="start"
color="error"
title={t("Script Console")}
title={t("components.profile.logViewer.title")}
onClick={() => setLogOpen(true)}
>
<FeaturedPlayListRounded fontSize="inherit" />
@@ -122,7 +132,7 @@ export const ProfileMore = (props: Props) => {
size="small"
edge="start"
color="inherit"
title={t("Script Console")}
title={t("components.profile.logViewer.title")}
onClick={() => setLogOpen(true)}
>
<FeaturedPlayListRounded fontSize="inherit" />
@@ -170,7 +180,7 @@ export const ProfileMore = (props: Props) => {
{fileOpen && (
<EditorViewer
open={true}
title={`${t("Global " + id)}`}
title={t(globalTitles[id])}
initialData={readProfileFile(id)}
language={id === "Merge" ? "yaml" : "javascript"}
schema={id === "Merge" ? "clash" : undefined}

View File

@@ -263,7 +263,7 @@ export const ProxiesEditorViewer = (props: Props) => {
const handleSave = useLockFn(async () => {
try {
await saveProfileFile(property, currData);
showNotice("success", t("Saved Successfully"));
showNotice("success", t("components.profile.notifications.saved"));
onSave?.(prevData, currData);
onClose();
} catch (err: any) {
@@ -276,7 +276,7 @@ export const ProxiesEditorViewer = (props: Props) => {
<DialogTitle>
{
<Box display="flex" justifyContent="space-between">
{t("Edit Proxies")}
{t("components.profile.proxiesEditor.title")}
<Box>
<Button
variant="contained"
@@ -285,7 +285,9 @@ export const ProxiesEditorViewer = (props: Props) => {
setVisualization((prev) => !prev);
}}
>
{visualization ? t("Advanced") : t("Visualization")}
{visualization
? t("common.editorModes.advanced")
: t("common.editorModes.visualization")}
</Button>
</Box>
</Box>
@@ -312,7 +314,9 @@ export const ProxiesEditorViewer = (props: Props) => {
<Item>
<TextField
autoComplete="new-password"
placeholder={t("Use newlines for multiple uri")}
placeholder={t(
"components.profile.proxiesEditor.placeholders.multiUri",
)}
fullWidth
rows={9}
multiline
@@ -332,7 +336,7 @@ export const ProxiesEditorViewer = (props: Props) => {
});
}}
>
{t("Prepend Proxy")}
{t("components.profile.proxiesEditor.actions.prepend")}
</Button>
</Item>
<Item>
@@ -346,7 +350,7 @@ export const ProxiesEditorViewer = (props: Props) => {
});
}}
>
{t("Append Proxy")}
{t("components.profile.proxiesEditor.actions.append")}
</Button>
</Item>
</List>

View File

@@ -479,7 +479,7 @@ export const RulesEditorViewer = (props: Props) => {
const handleSave = useLockFn(async () => {
try {
await saveProfileFile(property, currData);
showNotice("success", t("Saved Successfully"));
showNotice("success", t("components.profile.notifications.saved"));
onSave?.(prevData, currData);
onClose();
} catch (err: any) {
@@ -501,7 +501,9 @@ export const RulesEditorViewer = (props: Props) => {
setVisualization((prev) => !prev);
}}
>
{visualization ? t("Advanced") : t("Visualization")}
{visualization
? t("common.editorModes.advanced")
: t("common.editorModes.visualization")}
</Button>
</Box>
</Box>

View File

@@ -631,7 +631,9 @@ export function DnsViewer({ ref }: { ref?: Ref<DialogRef> }) {
setVisualization((prev) => !prev);
}}
>
{visualization ? t("Advanced") : t("Visualization")}
{visualization
? t("common.editorModes.advanced")
: t("common.editorModes.visualization")}
</Button>
</Box>
</Box>