1use std::env;
23
24#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
26pub enum Lang {
27 #[default]
28 En,
29 Zh,
30}
31
32impl Lang {
33 pub fn detect() -> Self {
38 for key in ["LC_ALL", "LC_MESSAGES", "LANG"] {
39 if let Ok(v) = env::var(key) {
40 let v = v.trim().to_ascii_lowercase();
41 if v.starts_with("zh") {
42 return Lang::Zh;
43 }
44 if !v.is_empty() {
45 return Lang::En;
46 }
47 }
48 }
49 Lang::En
50 }
51
52 pub fn parse_arg(s: &str) -> Self {
57 let s = s.trim().to_ascii_lowercase();
58 if s.starts_with("zh") || s == "cn" || s == "chinese" {
59 Lang::Zh
60 } else {
61 Lang::En
62 }
63 }
64
65 pub fn strings(self) -> &'static Strings {
67 match self {
68 Lang::En => &EN,
69 Lang::Zh => &ZH,
70 }
71 }
72}
73
74#[derive(Debug)]
81pub struct Strings {
82 pub connected_to: &'static str,
84 pub resolved_to: &'static str,
85 pub error_label: &'static str,
86 pub fail: &'static str,
87 pub grpc_ok: &'static str,
88
89 pub dns_lookup: &'static str,
91 pub dns_connect: &'static str,
92 pub dns_query: &'static str,
93 pub tcp_connect: &'static str,
94 pub tls_handshake: &'static str,
95 pub quic_connect: &'static str,
96 pub request_send: &'static str,
97 pub server_processing: &'static str,
98 pub server_processing_short: &'static str,
99 pub content_transfer: &'static str,
100 pub content_transfer_short: &'static str,
101 pub total: &'static str,
102
103 pub tls_label: &'static str,
105 pub cipher: &'static str,
106 pub handshake: &'static str,
107 pub handshake_full: &'static str,
108 pub handshake_resumed: &'static str,
109 pub early_data: &'static str,
110 pub early_data_accepted: &'static str,
111 pub early_data_not_accepted: &'static str,
112 pub ocsp: &'static str,
113 pub ocsp_stapled: &'static str,
114 pub ocsp_not_stapled: &'static str,
115 pub not_before: &'static str,
116 pub not_after: &'static str,
117 pub subject: &'static str,
118 pub issuer: &'static str,
119 pub cert_domains: &'static str,
120 pub cert_chain: &'static str,
121
122 pub server_timing_heading: &'static str,
124 pub st_sum_of: &'static str,
125 pub st_unaccounted: &'static str,
126
127 pub protocol_adv_heading: &'static str,
129 pub alt_svc_label: &'static str,
130 pub hsts_label: &'static str,
131
132 pub kernel_tcp_heading: &'static str,
134 pub tcp_post_connect_row: &'static str,
135 pub tcp_final_row: &'static str,
136 pub tcp_during: &'static str,
137 pub tcp_retransmit_word: &'static str,
138
139 pub body_size: &'static str,
141 pub body_discarded: &'static str,
142 pub saved_to: &'static str,
143 pub throughput: &'static str,
144 pub throughput_first_100k: &'static str,
145 pub throughput_then: &'static str,
146
147 pub benchmark_results_prefix: &'static str,
149 pub benchmark_results_requests: &'static str,
150 pub success: &'static str,
151 pub cold_connect: &'static str,
152 pub min: &'static str,
153 pub max: &'static str,
154 pub avg: &'static str,
155}
156
157pub const EN: Strings = Strings {
158 connected_to: "Connected to",
159 resolved_to: "Resolved to",
160 error_label: "Error",
161 fail: "FAIL",
162 grpc_ok: "GRPC OK",
163
164 dns_lookup: "DNS Lookup",
165 dns_connect: "DNS Connect",
166 dns_query: "DNS Query",
167 tcp_connect: "TCP Connect",
168 tls_handshake: "TLS Handshake",
169 quic_connect: "QUIC Connect",
170 request_send: "Request Send",
171 server_processing: "Server Processing",
172 server_processing_short: "Server Process",
173 content_transfer: "Content Transfer",
174 content_transfer_short: "Content Xfer",
175 total: "Total",
176
177 tls_label: "Tls",
178 cipher: "Cipher",
179 handshake: "Handshake",
180 handshake_full: "Full",
181 handshake_resumed: "Resumed",
182 early_data: "Early Data",
183 early_data_accepted: "accepted (0-RTT)",
184 early_data_not_accepted: "not accepted",
185 ocsp: "OCSP",
186 ocsp_stapled: "stapled",
187 ocsp_not_stapled: "not stapled",
188 not_before: "Not Before",
189 not_after: "Not After",
190 subject: "Subject",
191 issuer: "Issuer",
192 cert_domains: "Certificate Domains",
193 cert_chain: "Certificate Chain",
194
195 server_timing_heading: "Server-Timing:",
196 st_sum_of: "of",
197 st_unaccounted: "unaccounted",
198
199 protocol_adv_heading: "Server Advertisements:",
200 alt_svc_label: "Alt-Svc:",
201 hsts_label: "HSTS: ",
202
203 kernel_tcp_heading: "Kernel TCP:",
204 tcp_post_connect_row: "post-connect:",
205 tcp_final_row: "final:",
206 tcp_during: "during request:",
207 tcp_retransmit_word: "retransmit(s)",
208
209 body_size: "Body size",
210 body_discarded: "Body discarded",
211 saved_to: "saved to",
212 throughput: "Throughput:",
213 throughput_first_100k: "first 100KB:",
214 throughput_then: "then:",
215
216 benchmark_results_prefix: "--- Benchmark Results",
217 benchmark_results_requests: "requests",
218 success: "Success",
219 cold_connect: "Cold connect",
220 min: "min",
221 max: "max",
222 avg: "avg",
223};
224
225pub const ZH: Strings = Strings {
226 connected_to: "已连接到",
227 resolved_to: "已解析到",
228 error_label: "错误",
229 fail: "失败",
230 grpc_ok: "gRPC 正常",
231
232 dns_lookup: "DNS 解析",
233 dns_connect: "DNS 连接",
234 dns_query: "DNS 查询",
235 tcp_connect: "TCP 连接",
236 tls_handshake: "TLS 握手",
237 quic_connect: "QUIC 连接",
238 request_send: "请求发送",
239 server_processing: "服务端处理",
240 server_processing_short: "服务端处理",
241 content_transfer: "内容传输",
242 content_transfer_short: "内容传输",
243 total: "总耗时",
244
245 tls_label: "TLS",
246 cipher: "加密套件",
247 handshake: "握手",
248 handshake_full: "完整",
249 handshake_resumed: "复用",
250 early_data: "早期数据",
251 early_data_accepted: "已接受 (0-RTT)",
252 early_data_not_accepted: "未接受",
253 ocsp: "OCSP",
254 ocsp_stapled: "已 staple",
255 ocsp_not_stapled: "未 staple",
256 not_before: "生效时间",
257 not_after: "到期时间",
258 subject: "主体",
259 issuer: "颁发者",
260 cert_domains: "证书域名",
261 cert_chain: "证书链",
262
263 server_timing_heading: "Server-Timing:",
264 st_sum_of: "占",
265 st_unaccounted: "未统计",
266
267 protocol_adv_heading: "服务器声明:",
268 alt_svc_label: "Alt-Svc:",
269 hsts_label: "HSTS: ",
270
271 kernel_tcp_heading: "内核 TCP:",
272 tcp_post_connect_row: "连接后:",
273 tcp_final_row: "完成时:",
274 tcp_during: "本次请求:",
275 tcp_retransmit_word: "次重传",
276
277 body_size: "响应体大小",
278 body_discarded: "响应体已丢弃",
279 saved_to: "已保存到",
280 throughput: "吞吐:",
281 throughput_first_100k: "首 100KB:",
282 throughput_then: "之后:",
283
284 benchmark_results_prefix: "--- 基准测试结果",
285 benchmark_results_requests: "次请求",
286 success: "成功",
287 cold_connect: "冷连接",
288 min: "最小",
289 max: "最大",
290 avg: "均值",
291};
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296
297 #[test]
298 fn parse_arg_maps_languages() {
299 assert_eq!(Lang::parse_arg("zh"), Lang::Zh);
300 assert_eq!(Lang::parse_arg("ZH-CN"), Lang::Zh);
301 assert_eq!(Lang::parse_arg("zh_TW"), Lang::Zh);
302 assert_eq!(Lang::parse_arg("cn"), Lang::Zh);
303 assert_eq!(Lang::parse_arg("chinese"), Lang::Zh);
304 assert_eq!(Lang::parse_arg("en"), Lang::En);
305 assert_eq!(Lang::parse_arg("fr"), Lang::En); assert_eq!(Lang::parse_arg(""), Lang::En);
307 }
308}