mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 11:42:21 +08:00
feat: complete i18n
This commit is contained in:
parent
820d1e7570
commit
ab58968f4d
|
@ -1,5 +1,6 @@
|
|||
import useSWR from "swr";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Box, Grid, IconButton, Stack } from "@mui/material";
|
||||
import { RestartAltRounded } from "@mui/icons-material";
|
||||
import {
|
||||
|
@ -20,6 +21,7 @@ interface Props {
|
|||
const EnhancedMode = (props: Props) => {
|
||||
const { items, chain } = props;
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { mutate: mutateProfiles } = useSWR("getProfiles", getProfiles);
|
||||
const { data: chainLogs = {}, mutate: mutateLogs } = useSWR(
|
||||
"getRuntimeLogs",
|
||||
|
@ -96,7 +98,7 @@ const EnhancedMode = (props: Props) => {
|
|||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title="refresh enhanced profiles"
|
||||
title={t("Refresh profiles")}
|
||||
onClick={onEnhance}
|
||||
>
|
||||
<RestartAltRounded />
|
||||
|
|
|
@ -82,7 +82,7 @@ const InfoEditor = (props: Props) => {
|
|||
<TextField
|
||||
{...textFieldProps}
|
||||
disabled
|
||||
label="Type"
|
||||
label={t("Type")}
|
||||
value={type}
|
||||
sx={{ input: { textTransform: "capitalize" } }}
|
||||
/>
|
||||
|
@ -90,7 +90,7 @@ const InfoEditor = (props: Props) => {
|
|||
<TextField
|
||||
{...textFieldProps}
|
||||
autoFocus
|
||||
label="Name"
|
||||
label={t("Name")}
|
||||
value={form.name}
|
||||
onChange={(e) => setForm({ name: e.target.value })}
|
||||
onKeyDown={(e) => e.key === "Enter" && onUpdate()}
|
||||
|
@ -98,7 +98,7 @@ const InfoEditor = (props: Props) => {
|
|||
|
||||
<TextField
|
||||
{...textFieldProps}
|
||||
label="Descriptions"
|
||||
label={t("Descriptions")}
|
||||
value={form.desc}
|
||||
onChange={(e) => setForm({ desc: e.target.value })}
|
||||
onKeyDown={(e) => e.key === "Enter" && onUpdate()}
|
||||
|
@ -107,7 +107,7 @@ const InfoEditor = (props: Props) => {
|
|||
{type === "remote" && (
|
||||
<TextField
|
||||
{...textFieldProps}
|
||||
label="Subscription URL"
|
||||
label={t("Subscription URL")}
|
||||
value={form.url}
|
||||
onChange={(e) => setForm({ url: e.target.value })}
|
||||
onKeyDown={(e) => e.key === "Enter" && onUpdate()}
|
||||
|
@ -128,7 +128,7 @@ const InfoEditor = (props: Props) => {
|
|||
{((type === "remote" && showOpt) || type === "local") && (
|
||||
<TextField
|
||||
{...textFieldProps}
|
||||
label="Update Interval (mins)"
|
||||
label={t("Update Interval(mins)")}
|
||||
value={option.update_interval}
|
||||
onChange={(e) => {
|
||||
const str = e.target.value?.replace(/\D/, "");
|
||||
|
|
|
@ -91,7 +91,7 @@ const ProfileNew = (props: Props) => {
|
|||
<InputLabel>Type</InputLabel>
|
||||
<Select
|
||||
autoFocus
|
||||
label="Type"
|
||||
label={t("Type")}
|
||||
value={form.type}
|
||||
onChange={(e) => setForm({ type: e.target.value })}
|
||||
>
|
||||
|
@ -104,7 +104,7 @@ const ProfileNew = (props: Props) => {
|
|||
|
||||
<TextField
|
||||
{...textFieldProps}
|
||||
label="Name"
|
||||
label={t("Name")}
|
||||
autoComplete="off"
|
||||
value={form.name}
|
||||
onChange={(e) => setForm({ name: e.target.value })}
|
||||
|
@ -112,7 +112,7 @@ const ProfileNew = (props: Props) => {
|
|||
|
||||
<TextField
|
||||
{...textFieldProps}
|
||||
label="Descriptions"
|
||||
label={t("Descriptions")}
|
||||
autoComplete="off"
|
||||
value={form.desc}
|
||||
onChange={(e) => setForm({ desc: e.target.value })}
|
||||
|
@ -121,7 +121,7 @@ const ProfileNew = (props: Props) => {
|
|||
{form.type === "remote" && (
|
||||
<TextField
|
||||
{...textFieldProps}
|
||||
label="Subscription URL"
|
||||
label={t("Subscription URL")}
|
||||
autoComplete="off"
|
||||
value={form.url}
|
||||
onChange={(e) => setForm({ url: e.target.value })}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Box, IconButton, TextField, SxProps } from "@mui/material";
|
||||
import {
|
||||
AccessTimeRounded,
|
||||
|
@ -31,11 +32,13 @@ const ProxyHead = (props: Props) => {
|
|||
|
||||
const { showType, sortType, filterText, textState, testUrl } = headState;
|
||||
|
||||
const { t } = useTranslation();
|
||||
const [autoFocus, setAutoFocus] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// fix the focus conflict
|
||||
setTimeout(() => setAutoFocus(true), 100);
|
||||
const timer = setTimeout(() => setAutoFocus(true), 100);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -46,8 +49,8 @@ const ProxyHead = (props: Props) => {
|
|||
<Box sx={{ display: "flex", alignItems: "center", ...sx }}>
|
||||
<IconButton
|
||||
size="small"
|
||||
title="location"
|
||||
color="inherit"
|
||||
title={t("Location")}
|
||||
onClick={props.onLocation}
|
||||
>
|
||||
<MyLocationRounded />
|
||||
|
@ -56,7 +59,7 @@ const ProxyHead = (props: Props) => {
|
|||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title="delay check"
|
||||
title={t("Delay check")}
|
||||
onClick={() => {
|
||||
// Remind the user that it is custom test url
|
||||
if (testUrl?.trim() && textState !== "filter") {
|
||||
|
@ -71,7 +74,11 @@ const ProxyHead = (props: Props) => {
|
|||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title={["sort by default", "sort by delay", "sort by name"][sortType]}
|
||||
title={
|
||||
[t("Sort by default"), t("Sort by delay"), t("Sort by name")][
|
||||
sortType
|
||||
]
|
||||
}
|
||||
onClick={() =>
|
||||
onHeadState({ sortType: ((sortType + 1) % 3) as ProxySortType })
|
||||
}
|
||||
|
@ -84,7 +91,7 @@ const ProxyHead = (props: Props) => {
|
|||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title="edit test url"
|
||||
title={t("Delay check URL")}
|
||||
onClick={() =>
|
||||
onHeadState({ textState: textState === "url" ? null : "url" })
|
||||
}
|
||||
|
@ -99,7 +106,7 @@ const ProxyHead = (props: Props) => {
|
|||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title="proxy detail"
|
||||
title={t("Proxy detail")}
|
||||
onClick={() => onHeadState({ showType: !showType })}
|
||||
>
|
||||
{showType ? <VisibilityRounded /> : <VisibilityOffRounded />}
|
||||
|
@ -108,7 +115,7 @@ const ProxyHead = (props: Props) => {
|
|||
<IconButton
|
||||
size="small"
|
||||
color="inherit"
|
||||
title="filter"
|
||||
title={t("Filter")}
|
||||
onClick={() =>
|
||||
onHeadState({ textState: textState === "filter" ? null : "filter" })
|
||||
}
|
||||
|
@ -127,7 +134,7 @@ const ProxyHead = (props: Props) => {
|
|||
value={filterText}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
placeholder="Filter conditions"
|
||||
placeholder={t("Filter conditions")}
|
||||
onChange={(e) => onHeadState({ filterText: e.target.value })}
|
||||
sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
|
||||
/>
|
||||
|
@ -142,7 +149,7 @@ const ProxyHead = (props: Props) => {
|
|||
value={testUrl}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
placeholder="Test url"
|
||||
placeholder={t("Delay check URL")}
|
||||
onChange={(e) => onHeadState({ testUrl: e.target.value })}
|
||||
sx={{ ml: 0.5, flex: "1 1 auto", input: { py: 0.65, px: 1 } }}
|
||||
/>
|
||||
|
|
|
@ -34,6 +34,23 @@
|
|||
"To Top": "To Top",
|
||||
"To End": "To End",
|
||||
|
||||
"Location": "Location",
|
||||
"Delay check": "Delay check",
|
||||
"Sort by default": "Sort by default",
|
||||
"Sort by delay": "Sort by delay",
|
||||
"Sort by name": "Sort by name",
|
||||
"Delay check URL": "Delay check URL",
|
||||
"Proxy detail": "Proxy detail",
|
||||
"Filter": "Filter",
|
||||
"Filter conditions": "Filter conditions",
|
||||
"Refresh profiles": "Refresh profiles",
|
||||
|
||||
"Type": "Type",
|
||||
"Name": "Name",
|
||||
"Descriptions": "Descriptions",
|
||||
"Subscription URL": "Subscription URL",
|
||||
"Update Interval(mins)": "Update Interval(mins)",
|
||||
|
||||
"Settings": "Settings",
|
||||
"Clash Setting": "Clash Setting",
|
||||
"System Setting": "System Setting",
|
||||
|
|
|
@ -34,6 +34,23 @@
|
|||
"To Top": "移到最前",
|
||||
"To End": "移到末尾",
|
||||
|
||||
"Location": "当前节点",
|
||||
"Delay check": "延迟测试",
|
||||
"Sort by default": "默认排序",
|
||||
"Sort by delay": "按延迟排序",
|
||||
"Sort by name": "按名称排序",
|
||||
"Delay check URL": "延迟测试链接",
|
||||
"Proxy detail": "展示节点细节",
|
||||
"Filter": "过滤节点",
|
||||
"Filter conditions": "过滤条件",
|
||||
"Refresh profiles": "刷新配置",
|
||||
|
||||
"Type": "类型",
|
||||
"Name": "名称",
|
||||
"Descriptions": "描述",
|
||||
"Subscription URL": "订阅链接",
|
||||
"Update Interval(mins)": "更新间隔(分钟)",
|
||||
|
||||
"Settings": "设置",
|
||||
"Clash Setting": "Clash 设置",
|
||||
"System Setting": "系统设置",
|
||||
|
|
|
@ -114,7 +114,7 @@ const ConnectionsPage = () => {
|
|||
size="small"
|
||||
autoComplete="off"
|
||||
variant="outlined"
|
||||
placeholder="Filter conditions"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
|
|
|
@ -67,7 +67,7 @@ const LogPage = () => {
|
|||
size="small"
|
||||
autoComplete="off"
|
||||
variant="outlined"
|
||||
placeholder="Filter conditions"
|
||||
placeholder={t("Filter conditions")}
|
||||
value={filterText}
|
||||
onChange={(e) => setFilterText(e.target.value)}
|
||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||
|
|
Loading…
Reference in New Issue
Block a user