mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 11:42:21 +08:00
chore: rule types locale
This commit is contained in:
parent
83947b6725
commit
b558202441
|
@ -17,6 +17,7 @@ import {
|
|||
} from "@dnd-kit/sortable";
|
||||
import {
|
||||
Autocomplete,
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
|
@ -43,100 +44,197 @@ interface Props {
|
|||
onChange?: (prev?: string, curr?: string) => void;
|
||||
}
|
||||
|
||||
const RuleTypeList = [
|
||||
"DOMAIN",
|
||||
"DOMAIN-SUFFIX",
|
||||
"DOMAIN-KEYWORD",
|
||||
"DOMAIN-REGEX",
|
||||
"GEOSITE",
|
||||
"IP-CIDR",
|
||||
"IP-SUFFIX",
|
||||
"IP-ASN",
|
||||
"GEOIP",
|
||||
"SRC-GEOIP",
|
||||
"SRC-IP-ASN",
|
||||
"SRC-IP-CIDR",
|
||||
"SRC-IP-SUFFIX",
|
||||
"DST-PORT",
|
||||
"SRC-PORT",
|
||||
"IN-PORT",
|
||||
"IN-TYPE",
|
||||
"IN-USER",
|
||||
"IN-NAME",
|
||||
"PROCESS-PATH",
|
||||
"PROCESS-PATH-REGEX",
|
||||
"PROCESS-NAME",
|
||||
"PROCESS-NAME-REGEX",
|
||||
"UID",
|
||||
"NETWORK",
|
||||
"DSCP",
|
||||
"RULE-SET",
|
||||
"SUB-RULE",
|
||||
"AND",
|
||||
"OR",
|
||||
"NOT",
|
||||
"MATCH",
|
||||
] as const;
|
||||
|
||||
const NoResolveList = [
|
||||
"GEOIP",
|
||||
"IP-ASN",
|
||||
"IP-CIDR",
|
||||
"IP-CIDR6",
|
||||
"IP-SUFFIX",
|
||||
"RULE-SET",
|
||||
];
|
||||
const ExampleMap = {
|
||||
DOMAIN: "example.com",
|
||||
"DOMAIN-SUFFIX": "example.com",
|
||||
"DOMAIN-KEYWORD": "example",
|
||||
"DOMAIN-REGEX": "example.*",
|
||||
GEOSITE: "youtube",
|
||||
"IP-CIDR": "127.0.0.0/8",
|
||||
"IP-SUFFIX": "8.8.8.8/24",
|
||||
"IP-ASN": "13335",
|
||||
GEOIP: "CN",
|
||||
"SRC-GEOIP": "cn",
|
||||
"SRC-IP-ASN": "9808",
|
||||
"SRC-IP-CIDR": "192.168.1.201/32",
|
||||
"SRC-IP-SUFFIX": "192.168.1.201/8",
|
||||
"DST-PORT": "80",
|
||||
"SRC-PORT": "7777",
|
||||
"IN-PORT": "7890",
|
||||
"IN-TYPE": "SOCKS/HTTP",
|
||||
"IN-USER": "mihomo",
|
||||
"IN-NAME": "ss",
|
||||
"PROCESS-PATH":
|
||||
getSystem() === "windows"
|
||||
? "C:Program FilesGoogleChromeApplicationchrome.exe"
|
||||
: "/usr/bin/wget",
|
||||
"PROCESS-PATH-REGEX":
|
||||
getSystem() === "windows" ? "(?i).*Application\\chrome.*" : ".*bin/wget",
|
||||
"PROCESS-NAME": getSystem() === "windows" ? "chrome.exe" : "curl",
|
||||
"PROCESS-NAME-REGEX": ".*telegram.*",
|
||||
UID: "1001",
|
||||
NETWORK: "udp",
|
||||
DSCP: "4",
|
||||
"RULE-SET": "providername",
|
||||
"SUB-RULE": "",
|
||||
AND: "((DOMAIN,baidu.com),(NETWORK,UDP))",
|
||||
OR: "((NETWORK,UDP),(DOMAIN,baidu.com))",
|
||||
NOT: "((DOMAIN,baidu.com))",
|
||||
MATCH: "",
|
||||
const portValidator = (value: string): boolean => {
|
||||
return new RegExp(
|
||||
"^(?:[1-9]\\d{0,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$"
|
||||
).test(value);
|
||||
};
|
||||
const ipv4CIDRValidator = (value: string): boolean => {
|
||||
return new RegExp(
|
||||
"^(?:(?:[1-9]?[0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))\\.){3}(?:[1-9]?[0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))(?:\\/(?:[12]?[0-9]|3[0-2]))$"
|
||||
).test(value);
|
||||
};
|
||||
const ipv6CIDRValidator = (value: string): boolean => {
|
||||
return new RegExp(
|
||||
"^([0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4}){7}|::|:(?::[0-9a-fA-F]{1,4}){1,6}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,5}|(?:[0-9a-fA-F]{1,4}:){2}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){3}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){4}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){5}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,6}:)\\/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9])$"
|
||||
).test(value);
|
||||
};
|
||||
|
||||
const BuiltinProxyPolicyList = ["DIRECT", "REJECT", "REJECT-DROP", "PASS"];
|
||||
const rules: {
|
||||
name: string;
|
||||
required?: boolean;
|
||||
example?: string;
|
||||
noResolve?: boolean;
|
||||
validator?: (value: string) => boolean;
|
||||
}[] = [
|
||||
{
|
||||
name: "DOMAIN",
|
||||
example: "example.com",
|
||||
},
|
||||
{
|
||||
name: "DOMAIN-SUFFIX",
|
||||
example: "example.com",
|
||||
},
|
||||
{
|
||||
name: "DOMAIN-KEYWORD",
|
||||
example: "example",
|
||||
},
|
||||
{
|
||||
name: "DOMAIN-REGEX",
|
||||
example: "example.*",
|
||||
},
|
||||
{
|
||||
name: "GEOSITE",
|
||||
example: "youtube",
|
||||
},
|
||||
{
|
||||
name: "GEOIP",
|
||||
example: "CN",
|
||||
noResolve: true,
|
||||
},
|
||||
{
|
||||
name: "SRC-GEOIP",
|
||||
example: "CN",
|
||||
},
|
||||
{
|
||||
name: "IP-ASN",
|
||||
example: "13335",
|
||||
noResolve: true,
|
||||
validator: (value) => (+value ? true : false),
|
||||
},
|
||||
{
|
||||
name: "SRC-IP-ASN",
|
||||
example: "9808",
|
||||
validator: (value) => (+value ? true : false),
|
||||
},
|
||||
{
|
||||
name: "IP-CIDR",
|
||||
example: "127.0.0.0/8",
|
||||
noResolve: true,
|
||||
validator: (value) => ipv4CIDRValidator(value) || ipv6CIDRValidator(value),
|
||||
},
|
||||
{
|
||||
name: "IP-CIDR6",
|
||||
example: "2620:0:2d0:200::7/32",
|
||||
noResolve: true,
|
||||
validator: (value) => ipv4CIDRValidator(value) || ipv6CIDRValidator(value),
|
||||
},
|
||||
{
|
||||
name: "SRC-IP-CIDR",
|
||||
example: "192.168.1.201/32",
|
||||
validator: (value) => ipv4CIDRValidator(value) || ipv6CIDRValidator(value),
|
||||
},
|
||||
{
|
||||
name: "IP-SUFFIX",
|
||||
example: "8.8.8.8/24",
|
||||
noResolve: true,
|
||||
validator: (value) => ipv4CIDRValidator(value) || ipv6CIDRValidator(value),
|
||||
},
|
||||
{
|
||||
name: "SRC-IP-SUFFIX",
|
||||
example: "192.168.1.201/8",
|
||||
validator: (value) => ipv4CIDRValidator(value) || ipv6CIDRValidator(value),
|
||||
},
|
||||
{
|
||||
name: "SRC-PORT",
|
||||
example: "7777",
|
||||
validator: (value) => portValidator(value),
|
||||
},
|
||||
{
|
||||
name: "DST-PORT",
|
||||
example: "80",
|
||||
validator: (value) => portValidator(value),
|
||||
},
|
||||
{
|
||||
name: "IN-PORT",
|
||||
example: "7890",
|
||||
validator: (value) => portValidator(value),
|
||||
},
|
||||
{
|
||||
name: "DSCP",
|
||||
example: "4",
|
||||
},
|
||||
{
|
||||
name: "PROCESS-NAME",
|
||||
example: getSystem() === "windows" ? "chrome.exe" : "curl",
|
||||
},
|
||||
{
|
||||
name: "PROCESS-PATH",
|
||||
example:
|
||||
getSystem() === "windows"
|
||||
? "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
|
||||
: "/usr/bin/wget",
|
||||
},
|
||||
{
|
||||
name: "PROCESS-NAME-REGEX",
|
||||
example: ".*telegram.*",
|
||||
},
|
||||
{
|
||||
name: "PROCESS-PATH-REGEX",
|
||||
example:
|
||||
getSystem() === "windows" ? "(?i).*Application\\chrome.*" : ".*bin/wget",
|
||||
},
|
||||
{
|
||||
name: "NETWORK",
|
||||
example: "udp",
|
||||
validator: (value) => ["tcp", "udp"].includes(value),
|
||||
},
|
||||
{
|
||||
name: "UID",
|
||||
example: "1001",
|
||||
validator: (value) => (+value ? true : false),
|
||||
},
|
||||
{
|
||||
name: "IN-TYPE",
|
||||
example: "SOCKS/HTTP",
|
||||
},
|
||||
{
|
||||
name: "IN-USER",
|
||||
example: "mihomo",
|
||||
},
|
||||
{
|
||||
name: "IN-NAME",
|
||||
example: "ss",
|
||||
},
|
||||
{
|
||||
name: "SUB-RULE",
|
||||
example: "(NETWORK,tcp)",
|
||||
},
|
||||
{
|
||||
name: "RULE-SET",
|
||||
example: "providername",
|
||||
noResolve: true,
|
||||
},
|
||||
{
|
||||
name: "AND",
|
||||
example: "((DOMAIN,baidu.com),(NETWORK,UDP))",
|
||||
},
|
||||
{
|
||||
name: "OR",
|
||||
example: "((NETWORK,UDP),(DOMAIN,baidu.com))",
|
||||
},
|
||||
{
|
||||
name: "NOT",
|
||||
example: "((DOMAIN,baidu.com))",
|
||||
},
|
||||
{
|
||||
name: "MATCH",
|
||||
required: false,
|
||||
},
|
||||
];
|
||||
|
||||
const builtinProxyPolicies = ["DIRECT", "REJECT", "REJECT-DROP", "PASS"];
|
||||
|
||||
export const RulesEditorViewer = (props: Props) => {
|
||||
const { title, profileUid, property, open, onClose, onChange } = props;
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [prevData, setPrevData] = useState("");
|
||||
const [ruleType, setRuleType] =
|
||||
useState<(typeof RuleTypeList)[number]>("DOMAIN");
|
||||
|
||||
const [ruleType, setRuleType] = useState<(typeof rules)[number]>(rules[0]);
|
||||
const [ruleContent, setRuleContent] = useState("");
|
||||
const [noResolve, setNoResolve] = useState(false);
|
||||
const [proxyPolicy, setProxyPolicy] = useState("DIRECT");
|
||||
const [proxyPolicy, setProxyPolicy] = useState(builtinProxyPolicies[0]);
|
||||
const [proxyPolicyList, setProxyPolicyList] = useState<string[]>([]);
|
||||
const [ruleList, setRuleList] = useState<string[]>([]);
|
||||
const [ruleSetList, setRuleSetList] = useState<string[]>([]);
|
||||
|
@ -195,7 +293,7 @@ export const RulesEditorViewer = (props: Props) => {
|
|||
let ruleSetObj = yaml.load(data) as { "rule-providers": [] };
|
||||
let subRuleObj = yaml.load(data) as { "sub-rules": [] };
|
||||
setProxyPolicyList(
|
||||
BuiltinProxyPolicyList.concat(
|
||||
builtinProxyPolicies.concat(
|
||||
groupsObj["proxy-groups"]
|
||||
? groupsObj["proxy-groups"].map((item: any) => item.name)
|
||||
: []
|
||||
|
@ -217,29 +315,17 @@ export const RulesEditorViewer = (props: Props) => {
|
|||
fetchProfile();
|
||||
}, [open]);
|
||||
|
||||
const spliceRule = () => {
|
||||
if (ruleContent === "") return "";
|
||||
// Check valid by regex
|
||||
switch (ruleType) {
|
||||
case "IP-CIDR": {
|
||||
let v4regex = new RegExp(
|
||||
"^((?:(?:[1-9]?[0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5]))\\.){3}(?:[1-9]?[0-9]|1[0-9][0-9]|2(?:[0-4][0-9]|5[0-5])))?:(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-5]{2}[0-3][0-5])$"
|
||||
);
|
||||
let v6regex = new RegExp(
|
||||
"^([0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4}){7}|::|:(?::[0-9a-fA-F]{1,4}){1,6}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,5}|(?:[0-9a-fA-F]{1,4}:){2}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){3}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){4}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){5}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,6}:)\\/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9])$"
|
||||
);
|
||||
if (!v4regex.test(ruleContent) && !v6regex.test(ruleContent)) return "";
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
const validateRule = () => {
|
||||
if ((ruleType.required ?? true) && !ruleContent) {
|
||||
throw new Error(t("Rule Condition Required"));
|
||||
}
|
||||
return `${ruleType}${
|
||||
ruleType === "MATCH" ? "" : "," + ruleContent
|
||||
},${proxyPolicy}${
|
||||
NoResolveList.includes(ruleType) && noResolve ? ",no-resolve" : ""
|
||||
}`;
|
||||
if (ruleType.validator && !ruleType.validator(ruleContent)) {
|
||||
throw new Error(t("Invalid Rule"));
|
||||
}
|
||||
|
||||
return `${ruleType.name}${
|
||||
ruleContent ? "," + ruleContent : ""
|
||||
},${proxyPolicy}${ruleType.noResolve && noResolve ? ",no-resolve" : ""}`;
|
||||
};
|
||||
|
||||
const onSave = useLockFn(async () => {
|
||||
|
@ -274,49 +360,50 @@ export const RulesEditorViewer = (props: Props) => {
|
|||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ minWidth: "240px" }}
|
||||
value={ruleType}
|
||||
options={RuleTypeList}
|
||||
onChange={(_, v) => {
|
||||
if (v) setRuleType(v);
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
options={rules}
|
||||
value={ruleType}
|
||||
getOptionLabel={(option) => option.name}
|
||||
renderOption={(props, option) => (
|
||||
<li {...props} title={t(option.name)}>
|
||||
{option.name}
|
||||
</li>
|
||||
)}
|
||||
onChange={(_, value) => value && setRuleType(value)}
|
||||
/>
|
||||
</Item>
|
||||
<Item>
|
||||
<Item sx={{ display: !(ruleType.required ?? true) ? "none" : "" }}>
|
||||
<ListItemText primary={t("Rule Content")} />
|
||||
{ruleType === "RULE-SET" && (
|
||||
|
||||
{ruleType.name === "RULE-SET" && (
|
||||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ minWidth: "240px" }}
|
||||
value={ruleContent}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
options={ruleSetList}
|
||||
onChange={(_, v) => {
|
||||
if (v) setRuleContent(v);
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={ruleContent}
|
||||
onChange={(_, value) => value && setRuleContent(value)}
|
||||
/>
|
||||
)}
|
||||
{ruleType === "SUB-RULE" && (
|
||||
{ruleType.name === "SUB-RULE" && (
|
||||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ minWidth: "240px" }}
|
||||
value={ruleContent}
|
||||
options={subRuleList}
|
||||
onChange={(_, v) => {
|
||||
if (v) setRuleContent(v);
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
options={subRuleList}
|
||||
value={ruleContent}
|
||||
onChange={(_, value) => value && setRuleContent(value)}
|
||||
/>
|
||||
)}
|
||||
{ruleType !== "RULE-SET" && ruleType !== "SUB-RULE" && (
|
||||
{ruleType.name !== "RULE-SET" && ruleType.name !== "SUB-RULE" && (
|
||||
<TextField
|
||||
size="small"
|
||||
sx={{ minWidth: "240px" }}
|
||||
value={ruleContent}
|
||||
placeholder={ExampleMap[ruleType]}
|
||||
onChange={(e) => {
|
||||
setRuleContent(e.target.value);
|
||||
}}
|
||||
required={ruleType.required ?? true}
|
||||
error={(ruleType.required ?? true) && !ruleContent}
|
||||
placeholder={ruleType.example}
|
||||
onChange={(e) => setRuleContent(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</Item>
|
||||
|
@ -325,22 +412,23 @@ export const RulesEditorViewer = (props: Props) => {
|
|||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ minWidth: "240px" }}
|
||||
value={proxyPolicy}
|
||||
options={proxyPolicyList}
|
||||
onChange={(_, v) => {
|
||||
if (v) setProxyPolicy(v);
|
||||
}}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
options={proxyPolicyList}
|
||||
value={proxyPolicy}
|
||||
renderOption={(props, option) => (
|
||||
<li {...props} title={t(option)}>
|
||||
{option}
|
||||
</li>
|
||||
)}
|
||||
onChange={(_, value) => value && setProxyPolicy(value)}
|
||||
/>
|
||||
</Item>
|
||||
{NoResolveList.includes(ruleType) && (
|
||||
{ruleType.noResolve && (
|
||||
<Item>
|
||||
<ListItemText primary={t("No Resolve")} />
|
||||
<Switch
|
||||
checked={noResolve}
|
||||
onChange={() => {
|
||||
setNoResolve(!noResolve);
|
||||
}}
|
||||
onChange={() => setNoResolve(!noResolve)}
|
||||
/>
|
||||
</Item>
|
||||
)}
|
||||
|
@ -350,16 +438,18 @@ export const RulesEditorViewer = (props: Props) => {
|
|||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
let raw = spliceRule();
|
||||
if (raw === "") {
|
||||
Notice.error(t("Invalid Rule"));
|
||||
return;
|
||||
try {
|
||||
let raw = validateRule();
|
||||
console.log(raw);
|
||||
|
||||
if (prependSeq.includes(raw)) return;
|
||||
setPrependSeq([...prependSeq, raw]);
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
if (prependSeq.includes(raw)) return;
|
||||
setPrependSeq([...prependSeq, raw]);
|
||||
}}
|
||||
>
|
||||
{t("Add Prepend Rule")}
|
||||
{t("Prepend Rule")}
|
||||
</Button>
|
||||
</Item>
|
||||
<Item>
|
||||
|
@ -367,16 +457,16 @@ export const RulesEditorViewer = (props: Props) => {
|
|||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
let raw = spliceRule();
|
||||
if (raw === "") {
|
||||
Notice.error(t("Invalid Rule"));
|
||||
return;
|
||||
try {
|
||||
let raw = validateRule();
|
||||
if (appendSeq.includes(raw)) return;
|
||||
setPrependSeq([...appendSeq, raw]);
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
if (appendSeq.includes(raw)) return;
|
||||
setAppendSeq([...appendSeq, raw]);
|
||||
}}
|
||||
>
|
||||
{t("Add Append Rule")}
|
||||
{t("Append Rule")}
|
||||
</Button>
|
||||
</Item>
|
||||
</div>
|
||||
|
|
|
@ -54,12 +54,50 @@
|
|||
"Edit Rules": "Edit Rules",
|
||||
"Rule Type": "Rule Type",
|
||||
"Rule Content": "Rule Content",
|
||||
"Proxy Policy": "roxy Policy",
|
||||
"Proxy Policy": "Proxy Policy",
|
||||
"No Resolve": "No Resolve",
|
||||
"Add Prepend Rule": "Add Prepend Rule",
|
||||
"Add Append Rule": "Add Append Rule",
|
||||
"Invalid Rule": "Invalid Rule",
|
||||
"Prepend Rule": "Prepend Rule",
|
||||
"Append Rule": "Append Rule",
|
||||
"Delete Rule": "Delete Rule",
|
||||
"Rule Condition Required": "Rule Condition Required",
|
||||
"Invalid Rule": "Invalid Rule",
|
||||
"DOMAIN": "Matches the full domain name",
|
||||
"DOMAIN-SUFFIX": "Matches the domain suffix",
|
||||
"DOMAIN-KEYWORD": "Matches the domain keyword",
|
||||
"DOMAIN-REGEX": "Matches the domain using regular expressions",
|
||||
"GEOSITE": "Matches domains within the Geosite",
|
||||
"GEOIP": "Matches the country code of the IP address",
|
||||
"SRC-GEOIP": "Matches the country code of the source IP address",
|
||||
"IP-ASN": "Matches the IP address's ASN",
|
||||
"SRC-IP-ASN": "Matches the source IP address's ASN",
|
||||
"IP-CIDR": "Matches the IP address range",
|
||||
"IP-CIDR6": "Matches the IPv6 address range",
|
||||
"SRC-IP-CIDR": "Matches the source IP address range",
|
||||
"IP-SUFFIX": "Matches the IP address suffix range",
|
||||
"SRC-IP-SUFFIX": "Matches the source IP address suffix range",
|
||||
"SRC-PORT": "Matches the source port range",
|
||||
"DST-PORT": "Matches the destination port range",
|
||||
"IN-PORT": "Matches the inbound port",
|
||||
"DSCP": "DSCP marking (only for tproxy UDP inbound)",
|
||||
"PROCESS-NAME": "Matches the process name (Android package name)",
|
||||
"PROCESS-PATH": "Matches the full process path",
|
||||
"PROCESS-NAME-REGEX": "Matches the full process name using regular expressions (Android package name)",
|
||||
"PROCESS-PATH-REGEX": "Matches the full process path using regular expressions",
|
||||
"NETWORK": "Matches the transport protocol (tcp/udp)",
|
||||
"UID": "Matches the Linux USER ID",
|
||||
"IN-TYPE": "Matches the inbound type",
|
||||
"IN-USER": "Matches the inbound username",
|
||||
"IN-NAME": "Matches the inbound name",
|
||||
"SUB-RULE": "Sub-rule",
|
||||
"RULE-SET": "Matches the rule set",
|
||||
"AND": "Logical AND",
|
||||
"OR": "Logical OR",
|
||||
"NOT": "Logical NOT",
|
||||
"MATCH": "Matches all requests",
|
||||
"DIRECT": "Data goes directly outbound",
|
||||
"REJECT": "Intercepts requests",
|
||||
"REJECT-DROP": "Discards requests",
|
||||
"PASS": "Skips this rule when matched",
|
||||
"Edit Groups": "Edit Proxy Groups",
|
||||
"Extend Config": "Extend Config",
|
||||
"Extend Script": "Extend Script",
|
||||
|
@ -163,12 +201,20 @@
|
|||
"Auto Launch": "Auto Launch",
|
||||
"Silent Start": "Silent Start",
|
||||
"Silent Start Info": "Start the program in background mode without displaying the panel",
|
||||
"TG Channel": "Telegram Channel",
|
||||
"Manual": "Manual",
|
||||
"Github Repo": "Github Repo",
|
||||
"Clash Setting": "Clash Setting",
|
||||
"Allow Lan": "Allow Lan",
|
||||
"Allow Lan": "Allow LAN",
|
||||
"IPv6": "IPv6",
|
||||
"Log Level": "Log Level",
|
||||
"Port Config": "Port Config",
|
||||
"Random Port": "Random Port",
|
||||
"Mixed Port": "Mixed Port",
|
||||
"Socks Port": "Socks Port",
|
||||
"Http Port": "Http(s) Port",
|
||||
"Redir Port": "Redir Port",
|
||||
"Tproxy Port": "Tproxy Port",
|
||||
"External": "External",
|
||||
"External Controller": "External Controller",
|
||||
"Core Secret": "Core Secret",
|
||||
|
@ -186,9 +232,6 @@
|
|||
"Open UWP tool": "Open UWP tool",
|
||||
"Open UWP tool Info": "Since Windows 8, UWP apps (such as Microsoft Store) are restricted from directly accessing local host network services, and this tool can be used to bypass this restriction",
|
||||
"Update GeoData": "Update GeoData",
|
||||
"TG Channel": "Telegram Channel",
|
||||
"Manual": "Manual",
|
||||
"Github Repo": "Github Repo",
|
||||
"Verge Setting": "Verge Setting",
|
||||
"Language": "Language",
|
||||
"Theme Mode": "Theme Mode",
|
||||
|
|
|
@ -50,6 +50,55 @@
|
|||
"Expire Time": "زمان انقضا",
|
||||
"Create Profile": "ایجاد پروفایل",
|
||||
"Edit Profile": "ویرایش پروفایل",
|
||||
"Edit Proxies": "ویرایش پروکسیها",
|
||||
"Edit Rules": "ویرایش قوانین",
|
||||
"Rule Type": "نوع قانون",
|
||||
"Rule Content": "محتوای قانون",
|
||||
"Proxy Policy": "سیاست پروکسی",
|
||||
"No Resolve": "بدون حل",
|
||||
"Prepend Rule": "اضافه کردن قانون به ابتدا",
|
||||
"Append Rule": "اضافه کردن قانون به انتها",
|
||||
"Delete Rule": "حذف قانون",
|
||||
"Rule Condition Required": "شرط قانون الزامی است",
|
||||
"Invalid Rule": "قانون نامعتبر",
|
||||
"DOMAIN": "مطابقت با نام کامل دامنه",
|
||||
"DOMAIN-SUFFIX": "مطابقت با پسوند دامنه",
|
||||
"DOMAIN-KEYWORD": "مطابقت با کلمه کلیدی دامنه",
|
||||
"DOMAIN-REGEX": "مطابقت با دامنه با استفاده از عبارات منظم",
|
||||
"GEOSITE": "مطابقت با دامنههای درون Geosite",
|
||||
"GEOIP": "مطابقت با کد کشور IP",
|
||||
"SRC-GEOIP": "مطابقت با کد کشور IP مبدا",
|
||||
"IP-ASN": "مطابقت با ASN آدرس IP",
|
||||
"SRC-IP-ASN": "مطابقت با ASN آدرس IP مبدا",
|
||||
"IP-CIDR": "مطابقت با محدوده آدرس IP",
|
||||
"IP-CIDR6": "مطابقت با محدوده آدرس IPv6",
|
||||
"SRC-IP-CIDR": "مطابقت با محدوده آدرس IP مبدا",
|
||||
"IP-SUFFIX": "مطابقت با محدوده پسوند آدرس IP",
|
||||
"SRC-IP-SUFFIX": "مطابقت با محدوده پسوند آدرس IP مبدا",
|
||||
"SRC-PORT": "مطابقت با محدوده پورت مبدا",
|
||||
"DST-PORT": "مطابقت با محدوده پورت مقصد",
|
||||
"IN-PORT": "مطابقت با پورت ورودی",
|
||||
"DSCP": "علامتگذاری DSCP (فقط برای tproxy UDP ورودی)",
|
||||
"PROCESS-NAME": "مطابقت با نام فرآیند (نام بسته Android)",
|
||||
"PROCESS-PATH": "مطابقت با مسیر کامل فرآیند",
|
||||
"PROCESS-NAME-REGEX": "مطابقت با نام فرآیند با استفاده از عبارات منظم (نام بسته Android)",
|
||||
"PROCESS-PATH-REGEX": "مطابقت با مسیر کامل فرآیند با استفاده از عبارات منظم",
|
||||
"NETWORK": "مطابقت با پروتکل انتقال (tcp/udp)",
|
||||
"UID": "مطابقت با شناسه کاربری Linux",
|
||||
"IN-TYPE": "مطابقت با نوع ورودی",
|
||||
"IN-USER": "مطابقت با نام کاربری ورودی",
|
||||
"IN-NAME": "مطابقت با نام ورودی",
|
||||
"SUB-RULE": "قانون فرعی",
|
||||
"RULE-SET": "مطابقت با مجموعه قوانین",
|
||||
"AND": "منطق AND",
|
||||
"OR": "منطق OR",
|
||||
"NOT": "منطق NOT",
|
||||
"MATCH": "مطابقت با تمام درخواستها",
|
||||
"DIRECT": "دادهها به صورت مستقیم خروجی میشوند",
|
||||
"REJECT": "درخواستها را متوقف میکند",
|
||||
"REJECT-DROP": "درخواستها را نادیده میگیرد",
|
||||
"PASS": "این قانون را در صورت تطابق نادیده میگیرد",
|
||||
"Edit Groups": "ویرایش گروههای پروکسی",
|
||||
"Extend Config": "توسعه پیکربندی",
|
||||
"Extend Script": "ادغام اسکریپت",
|
||||
"Global Merge": "تنظیمات گستردهی سراسری",
|
||||
|
|
|
@ -50,6 +50,55 @@
|
|||
"Expire Time": "Время окончания",
|
||||
"Create Profile": "Создать профиль",
|
||||
"Edit Profile": "Изменить профиль",
|
||||
"Edit Proxies": "Редактировать прокси",
|
||||
"Edit Rules": "Редактировать правила",
|
||||
"Rule Type": "Тип правила",
|
||||
"Rule Content": "Содержимое правила",
|
||||
"Proxy Policy": "Политика прокси",
|
||||
"No Resolve": "Без разрешения",
|
||||
"Prepend Rule": "Добавить правило в начало",
|
||||
"Append Rule": "Добавить правило в конец",
|
||||
"Delete Rule": "Удалить правило",
|
||||
"Rule Condition Required": "Требуется условие правила",
|
||||
"Invalid Rule": "Недействительное правило",
|
||||
"DOMAIN": "Соответствует полному доменному имени",
|
||||
"DOMAIN-SUFFIX": "Соответствует суффиксу домена",
|
||||
"DOMAIN-KEYWORD": "Соответствует ключевому слову домена",
|
||||
"DOMAIN-REGEX": "Соответствует домену с использованием регулярных выражений",
|
||||
"GEOSITE": "Соответствует доменам в Geosite",
|
||||
"GEOIP": "Соответствует коду страны IP-адреса",
|
||||
"SRC-GEOIP": "Соответствует коду страны исходного IP-адреса",
|
||||
"IP-ASN": "Соответствует ASN IP-адреса",
|
||||
"SRC-IP-ASN": "Соответствует ASN исходного IP-адреса",
|
||||
"IP-CIDR": "Соответствует диапазону IP-адресов",
|
||||
"IP-CIDR6": "Соответствует диапазону IPv6-адресов",
|
||||
"SRC-IP-CIDR": "Соответствует диапазону исходных IP-адресов",
|
||||
"IP-SUFFIX": "Соответствует диапазону суффиксов IP-адресов",
|
||||
"SRC-IP-SUFFIX": "Соответствует диапазону суффиксов исходных IP-адресов",
|
||||
"SRC-PORT": "Соответствует диапазону исходных портов",
|
||||
"DST-PORT": "Соответствует диапазону целевых портов",
|
||||
"IN-PORT": "Соответствует входящему порту",
|
||||
"DSCP": "Маркировка DSCP (только для tproxy UDP входящего)",
|
||||
"PROCESS-NAME": "Соответствует имени процесса (имя пакета Android)",
|
||||
"PROCESS-PATH": "Соответствует полному пути процесса",
|
||||
"PROCESS-NAME-REGEX": "Соответствует имени процесса с использованием регулярных выражений (имя пакета Android)",
|
||||
"PROCESS-PATH-REGEX": "Соответствует полному пути процесса с использованием регулярных выражений",
|
||||
"NETWORK": "Соответствует транспортному протоколу (tcp/udp)",
|
||||
"UID": "Соответствует USER ID в Linux",
|
||||
"IN-TYPE": "Соответствует типу входящего соединения",
|
||||
"IN-USER": "Соответствует имени пользователя входящего соединения",
|
||||
"IN-NAME": "Соответствует имени входящего соединения",
|
||||
"SUB-RULE": "Подправило",
|
||||
"RULE-SET": "Соответствует набору правил",
|
||||
"AND": "Логическое И",
|
||||
"OR": "Логическое ИЛИ",
|
||||
"NOT": "Логическое НЕ",
|
||||
"MATCH": "Соответствует всем запросам",
|
||||
"DIRECT": "Данные направляются напрямую наружу",
|
||||
"REJECT": "Перехватывает запросы",
|
||||
"REJECT-DROP": "Отклоняет запросы",
|
||||
"PASS": "Пропускает это правило при совпадении",
|
||||
"Edit Groups": "Редактировать группы прокси",
|
||||
"Extend Config": "Изменить Merge.",
|
||||
"Extend Script": "Изменить Script",
|
||||
"Global Merge": "Глобальный расширенный Настройки",
|
||||
|
@ -152,6 +201,9 @@
|
|||
"Auto Launch": "Автозапуск",
|
||||
"Silent Start": "Тихий запуск",
|
||||
"Silent Start Info": "Запускать программу в фоновом режиме без отображения панели",
|
||||
"TG Channel": "Канал Telegram",
|
||||
"Manual": "Документация",
|
||||
"Github Repo": "GitHub репозиторий",
|
||||
"Clash Setting": "Настройки Clash",
|
||||
"Allow Lan": "Разрешить локальную сеть",
|
||||
"IPv6": "IPv6",
|
||||
|
@ -180,9 +232,6 @@
|
|||
"Open UWP tool": "Открыть UWP инструмент",
|
||||
"Open UWP tool Info": "С Windows 8 приложения UWP (такие как Microsoft Store) ограничены в прямом доступе к сетевым службам локального хоста, и этот инструмент позволяет обойти это ограничение",
|
||||
"Update GeoData": "Обновление GeoData",
|
||||
"TG Channel": "Канал Telegram",
|
||||
"Manual": "Документация",
|
||||
"Github Repo": "GitHub репозиторий",
|
||||
"Verge Setting": "Настройки Verge",
|
||||
"Language": "Язык",
|
||||
"Theme Mode": "Режим темы",
|
||||
|
|
|
@ -56,10 +56,48 @@
|
|||
"Rule Content": "规则内容",
|
||||
"Proxy Policy": "代理策略",
|
||||
"No Resolve": "跳过DNS解析",
|
||||
"Add Prepend Rule": "添加前置规则",
|
||||
"Add Append Rule": "添加后置规则",
|
||||
"Invalid Rule": "无效规则",
|
||||
"Prepend Rule": "添加前置规则",
|
||||
"Append Rule": "添加后置规则",
|
||||
"Delete Rule": "删除规则",
|
||||
"Rule Condition Required": "规则条件缺失",
|
||||
"Invalid Rule": "无效规则",
|
||||
"DOMAIN": "匹配完整域名",
|
||||
"DOMAIN-SUFFIX": "匹配域名后缀",
|
||||
"DOMAIN-KEYWORD": "匹配域名关键字",
|
||||
"DOMAIN-REGEX": "匹配域名正则表达式",
|
||||
"GEOSITE": "匹配Geosite内的域名",
|
||||
"GEOIP": "匹配IP所属国家代码",
|
||||
"SRC-GEOIP": "匹配来源IP所属国家代码",
|
||||
"IP-ASN": "匹配IP所属ASN",
|
||||
"SRC-IP-ASN": "匹配来源IP所属ASN",
|
||||
"IP-CIDR": "匹配IP地址范围",
|
||||
"IP-CIDR6": "匹配IP地址范围",
|
||||
"SRC-IP-CIDR": "匹配来源IP地址范围",
|
||||
"IP-SUFFIX": "匹配IP后缀范围",
|
||||
"SRC-IP-SUFFIX": "匹配来源IP后缀范围",
|
||||
"SRC-PORT": "匹配请求来源端口范围",
|
||||
"DST-PORT": "匹配请求目标端口范围",
|
||||
"IN-PORT": "匹配入站端口",
|
||||
"DSCP": "DSCP标记(仅限tproxy udp入站)",
|
||||
"PROCESS-NAME": "匹配进程名称(Android包名)",
|
||||
"PROCESS-PATH": "匹配完整进程路径",
|
||||
"PROCESS-NAME-REGEX": "正则匹配完整进程名称(Android包名)",
|
||||
"PROCESS-PATH-REGEX": "正则匹配完整进程路径",
|
||||
"NETWORK": "匹配传输协议(tcp/udp)",
|
||||
"UID": "匹配Linux USER ID",
|
||||
"IN-TYPE": "匹配入站类型",
|
||||
"IN-USER": "匹配入站用户名",
|
||||
"IN-NAME": "匹配入站名称",
|
||||
"SUB-RULE": "子规则",
|
||||
"RULE-SET": "匹配规则集",
|
||||
"AND": "逻辑和",
|
||||
"OR": "逻辑或",
|
||||
"NOT": "逻辑非",
|
||||
"MATCH": "匹配所有请求",
|
||||
"DIRECT": "直连",
|
||||
"REJECT": "拦截请求",
|
||||
"REJECT-DROP": "抛弃请求",
|
||||
"PASS": "跳过此规则",
|
||||
"Edit Groups": "编辑代理组",
|
||||
"Extend Config": "扩展配置",
|
||||
"Extend Script": "扩展脚本",
|
||||
|
|
Loading…
Reference in New Issue
Block a user