diff --git a/common/Cargo.toml b/common/Cargo.toml index 80fa20b..fae5719 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -16,6 +16,7 @@ serde_yaml = "0.9.32" getopts = "0.2.21" gethostname = "0.4.3" uuid = { version = "1.8.0", features = ["v4"] } +sys-locale = "0.3.1" [features] default = [] diff --git a/common/src/cli.rs b/common/src/cli.rs index 23f533b..d340ade 100644 --- a/common/src/cli.rs +++ b/common/src/cli.rs @@ -5,10 +5,12 @@ use crate::{config, generated_serial_number}; use anyhow::anyhow; use console::style; use getopts::Options; +use std::collections::HashMap; use std::io; use std::net::Ipv4Addr; use std::path::PathBuf; use std::str::FromStr; +use sys_locale::get_locale; use vnt::channel::punch::PunchModel; use vnt::channel::UseChannelType; use vnt::cipher::CipherModel; @@ -343,38 +345,122 @@ pub fn parse_args_config() -> anyhow::Result, bool)> Ok(Some((config, vnt_link_config, cmd))) } +fn get_description(key: &str, language: &str) -> String { + // 设置一个全局的映射来存储中英文对照 + let descriptions: HashMap<&str, (&str, &str)> = [ + ("-k ", ("使用相同的token,就能组建一个局域网络", "Use the same token to form a local network")), + ("-n ", ("给设备一个名字,便于区分不同设备,默认使用系统版本", "Give the device a name to distinguish it, defaults to system version")), + ("-d ", ("设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复", "Device unique identifier, used by the server to allocate virtual IP when --ip parameter is not used, must be unique")), + ("-s ", ("注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://", "Registration and relay server address, protocols support using tcp://, ws://, and wss://, default is udp://")), + ("-e ", ("stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com", "STUN server for detecting NAT type, can specify multiple addresses, e.g., -e stun.miwifi.com -e turn.cloudflare.com")), + ("-a", ("使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡", "Use tap mode, default is tun mode, specify '--nic' parameter with tap network card")), + ("-i ", ("配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据并转发到10.26.0.3,可指定多个网段", "Used when configuring point-to-point network (IP proxy), -i 192.168.0.0/24,10.26.0.3 allows receiving data from subnet 192.168.0.0/24 and forwarding to 10.26.0.3, specify multiple subnets")), + ("-o ", ("配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段", "Used when configuring point-to-point network, -o 192.168.0.0/24 allows forwarding data to 192.168.0.0/24, specify multiple subnets")), + ("-w ", ("使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信", "Encrypt client data with keys generated by this password, server cannot decrypt, clients must use the same password to communicate")), + ("-W", ("加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确", "Encrypt the data currently being communicated between the client and server, please pay attention to whether the server fingerprint is correct")), + ("-u ", ("自定义mtu(不加密默认为1450,加密默认为1410", "Customize MTU (1450 by default without encryption, 1410 with encryption)")), + ("-f ", ("读取配置文件中的配置", "Read configuration from file")), + ("--ip ", ("指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配", "Specify virtual IP, must be unique and valid within server subnet, by default allocated by server")), + ("--model ", ("加密模式(默认aes_gcm),可选值{}", "Encryption mode (default aes_gcm), options {}")), + ("--finger", ("增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启", "Add data fingerprint verification for increased security, client must enable if server does")), + ("--punch ", ("取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞", "Values ipv4/ipv6/all, ipv4 for IPv4 hole punching only")), + ("--ports ", ("取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担", "Values 0~65535, specify a group of local listening ports, defaults to two random ports, using many ports increases network load")), + ("--cmd", ("开启交互式命令,使用此参数开启控制台输入", "Enable interactive command mode, use this parameter to enable console input")), + ("--no-proxy", ("关闭内置代理,如需点对网则需要配置网卡NAT转发", "Disable built-in proxy, configure network card NAT forwarding for point-to-point networking")), + ("--first-latency", ("优先低延迟的通道,默认情况优先使用p2p通道", "Prioritize low-latency channels, defaults to prioritizing p2p channel")), + ("--use-channel ", ("使用通道 relay/p2p/all,默认两者都使用", "Use channel relay/p2p/all, defaults to using both")), + ("--nic ", ("指定虚拟网卡名称", "Specify virtual network card name")), + ("--packet-loss <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate packet loss, value between 0 and 1, program actively drops packets based on set probability, useful for simulating weak networks")), + ("--packet-delay <0>", ("模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网", "Simulate latency, integer, in milliseconds (ms). The program will delay sending packets according to the set value and can be used to simulate weak networks")), + ("--dns ", ("DNS服务器地址,可使用多个dns,不指定时使用系统解析", "DNS server address, can specify multiple DNS servers, defaults to system resolution if not specified")), + ("--mapping ", ("端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备", "Port mapping, e.g., --mapping udp:0.0.0.0:80-domain:80 maps to a device accessible by local routing")), + ("--compressor-all ", ("启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10", "Enable compression, options lz4/zstd<,level>, level is compression level, e.g., --compressor lz4 or --compressor zstd,10")), + ("--compressor-lz4 ", ("启用压缩,可选值lz4,例如 --compressor lz4", "Enable compression, option lz4, e.g., --compressor lz4")), + ("--compressor-zstd ", ("启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10", "Enable compression, options zstd<,level>, level is compression level, e.g., --compressor zstd,10")), + ("--vnt-mapping ", ("vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备", "VNT address mapping, e.g., --vnt-mapping tcp:80-10.26.0.10:80 maps to a device in VNT network or its subnet")), + ("--disable-stats", ("关闭流量统计", "Disable traffic statistics")), + ("--list", ("后台运行时,查看其他设备列表", "View list of other devices when running in background")), + ("--all", ("后台运行时,查看其他设备完整信息", "View complete information of other devices when running in background")), + ("--info", ("后台运行时,查看当前设备信息", "View information of current device when running in background")), + ("--route", ("后台运行时,查看数据转发路径", "View data forwarding path when running in background")), + ("--chart_a", ("后台运行时,查看所有IP的流量统计", "View traffic statistics of all IPs when running in background")), + ("--chart_b ", ("后台运行时,查看单个IP的历史流量", "View historical traffic of a single IP when running in background")), + ("--stop", ("停止后台运行", "Stop running in background")) + // ... 其他选项 + ] + .iter() + .cloned() + .collect(); + + if let Some(&(zh, en)) = descriptions.get(key) { + if language.starts_with("zh") { + return zh.to_string(); // 返回 String 类型 + } + // 默认返回英文 + return en.to_string(); // 返回 String 类型 + } + // 如果没有找到对应的键,则返回空字符串 + String::new() +} + fn print_usage(program: &str, _opts: Options) { + // 获取系统语言 Locale::user_default().unwrap_or_else(|_| Locale::default()); + let language = get_locale().unwrap_or_else(|| String::from("en-US")); println!("Usage: {} [options]", program); println!("version:{}", vnt::VNT_VERSION); println!("Serial:{}", generated_serial_number::SERIAL_NUMBER); println!("Options:"); println!( " -k {}", - green("使用相同的token,就能组建一个局域网络".to_string()) + green(get_description("-k ", &language).to_string()) + ); + println!( + " -n {}", + get_description("-n ", &language) ); - println!(" -n 给设备一个名字,便于区分不同设备,默认使用系统版本"); - println!(" -d 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复"); println!( - " -s 注册和中继服务器地址,协议支持使用tcp://和ws://和wss://,默认为udp://" + " -d {}", + get_description("-d ", &language) + ); + println!( + " -s {}", + get_description("-s ", &language) + ); + println!( + " -e {}", + get_description("-e ", &language) ); - println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun.miwifi.com -e turn.cloudflare.com"); #[cfg(target_os = "windows")] #[cfg(feature = "integrated_tun")] + println!(" -a {}", get_description("-a", &language)); println!( - " -a 使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡" + " -i {}", + get_description("-i ", &language) + ); + println!( + " -o {}", + get_description("-o ", &language) + ); + println!( + " -w {}", + get_description("-w ", &language) ); - println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); - println!(" 并转发到10.26.0.3,可指定多个网段"); - println!(" -o 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段"); - - println!(" -w 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信"); #[cfg(feature = "server_encrypt")] - println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确"); - println!(" -u 自定义mtu(不加密默认为1450,加密默认为1410)"); + println!(" -W {}", get_description("-W", &language)); + println!( + " -u {}", + get_description("-u ", &language) + ); #[cfg(feature = "file_config")] - println!(" -f 读取配置文件中的配置"); + println!( + " -f {}", + get_description("-f ", &language) + ); - println!(" --ip 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配"); + println!( + " --ip {}", + get_description("--ip ", &language) + ); let mut enums = String::new(); #[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))] enums.push_str("/aes_gcm"); @@ -388,7 +474,8 @@ fn print_usage(program: &str, _opts: Options) { enums.push_str("/sm4_cbc"); enums.push_str("/xor"); println!( - " --model 加密模式(默认aes_gcm),可选值{}", + " --model {}{}", + get_description("--model ", &language), &enums[1..] ); #[cfg(any( @@ -399,45 +486,88 @@ fn print_usage(program: &str, _opts: Options) { feature = "aes_ecb", feature = "sm4_cbc" ))] - println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启"); - println!(" --punch 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞"); - println!(" --ports 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担"); + println!( + " --finger {}", + get_description("--finger", &language) + ); + println!( + " --punch {}", + get_description("--punch ", &language) + ); + println!( + " --ports {}", + get_description("--ports ", &language) + ); #[cfg(feature = "command")] - println!(" --cmd 开启交互式命令,使用此参数开启控制台输入"); + println!( + " --cmd {}", + get_description("--cmd", &language) + ); #[cfg(feature = "ip_proxy")] #[cfg(feature = "integrated_tun")] - println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发"); - println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道"); - println!(" --use-channel 使用通道 relay/p2p/all,默认两者都使用"); + println!( + " --no-proxy {}", + get_description("--no-proxy", &language) + ); + println!( + " --first-latency {}", + get_description("--first-latency", &language) + ); + println!( + " --use-channel {}", + get_description("--use-channel ", &language) + ); #[cfg(not(feature = "vn-link-model"))] - println!(" --nic 指定虚拟网卡名称"); - println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网"); println!( - " --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网" + " --nic {}", + get_description("--nic ", &language) + ); + println!( + " --packet-loss <0> {}", + get_description("--packet-loss <0>", &language) + ); + println!( + " --packet-delay <0> {}", + get_description("--packet-delay <0>", &language) + ); + println!( + " --dns {}", + get_description("--dns ", &language) ); - println!(" --dns DNS服务器地址,可使用多个dns,不指定时使用系统解析"); #[cfg(feature = "port_mapping")] - println!(" --mapping 端口映射,例如 --mapping udp:0.0.0.0:80-domain:80 映射目标是本地路由能访问的设备"); + println!( + " --mapping {}", + get_description("--mapping ", &language) + ); #[cfg(all(feature = "lz4", feature = "zstd"))] - println!(" --compressor 启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10"); + println!( + " --compressor {}", + get_description("--compressor-all ", &language) + ); #[cfg(feature = "lz4")] #[cfg(not(feature = "zstd"))] - println!(" --compressor 启用压缩,可选值lz4,例如 --compressor lz4"); + println!( + " --compressor {}", + get_description("--compressor-lz4 ", &language) + ); #[cfg(feature = "zstd")] #[cfg(not(feature = "lz4"))] - println!(" --compressor 启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10"); + println!( + " --compressor {}", + get_description("--compressor-zstd ", &language) + ); #[cfg(not(feature = "integrated_tun"))] println!( " --vnt-mapping {}", - green( - "vnt地址映射,例如 --vnt-mapping tcp:80-10.26.0.10:80 映射目标是vnt网络或其子网中的设备" - .to_string() - ) + green(get_description("--vnt-mapping ", &language).to_string()) + ); + println!( + " --disable-stats {}", + get_description("--disable-stats", &language) ); - println!(" --disable-stats 关闭流量统计"); println!(" --allow-wg 允许接入WireGuard客户端"); println!(); #[cfg(feature = "command")] @@ -449,34 +579,34 @@ fn print_usage(program: &str, _opts: Options) { // ); println!( " --list {}", - yellow("后台运行时,查看其他设备列表".to_string()) + yellow(get_description("--list", &language).to_string()) ); println!( " --all {}", - yellow("后台运行时,查看其他设备完整信息".to_string()) + yellow(get_description("--all", &language).to_string()) ); println!( " --info {}", - yellow("后台运行时,查看当前设备信息".to_string()) + yellow(get_description("--info", &language).to_string()) ); println!( " --route {}", - yellow("后台运行时,查看数据转发路径".to_string()) + yellow(get_description("--route", &language).to_string()) ); println!( " --chart_a {}", - yellow("后台运行时,查看所有IP的流量统计".to_string()) + yellow(get_description("--chart_a", &language).to_string()) ); println!( " --chart_b {}", - yellow("后台运行时,查看单个IP的历史流量".to_string()) + yellow(get_description("--chart_b ", &language).to_string()) ); println!( " --stop {}", - yellow("停止后台运行".to_string()) + yellow(get_description("--stop", &language).to_string()) ); } - println!(" -h, --help 帮助"); + println!(" -h, --help display help information(显示帮助信息)"); } fn green(str: String) -> impl std::fmt::Display {