codex-helper-tui 0.15.0

Terminal UI crate for codex-helper.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Language {
    Zh,
    En,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct TextKey(&'static str);

impl TextKey {
    pub(crate) const fn new(id: &'static str) -> Self {
        Self(id)
    }

    pub(crate) const fn id(self) -> &'static str {
        self.0
    }
}

macro_rules! define_messages {
    ($($name:ident => { zh: $zh:literal, en: $en:literal },)*) => {
        pub(crate) mod msg {
            use super::TextKey;

            $(
                pub(crate) const $name: TextKey = TextKey::new(stringify!($name));
            )*
        }

        static ZH_MESSAGES: &[(&str, &str)] = &[
            $((stringify!($name), $zh),)*
        ];

        static EN_MESSAGES: &[(&str, &str)] = &[
            $((stringify!($name), $en),)*
        ];

        #[cfg(test)]
        fn all_message_ids() -> &'static [&'static str] {
            &[$(stringify!($name),)*]
        }
    };
}

define_messages! {
    LANGUAGE_LABEL => { zh: "语言:", en: "language: " },
    LANGUAGE_SAVED => { zh: "(已保存)", en: " (saved)" },
    LANGUAGE_SAVE_FAILED_PREFIX => { zh: "(保存失败:", en: " (save failed: " },
    LANGUAGE_SAVE_FAILED_SUFFIX => { zh: "", en: ")" },
    LANGUAGE_TOGGLE_HINT => { zh: "  (按 L 切换,并落盘到 ui.language)", en: "  (press L to cycle and persist to ui.language)" },

    LANGUAGE_NAME_ZH => { zh: "中文", en: "Chinese" },
    LANGUAGE_NAME_EN => { zh: "English", en: "English" },

    PAGE_DASHBOARD => { zh: "1 总览", en: "1 Dashboard" },
    PAGE_ROUTING => { zh: "2 路由", en: "2 Routing" },
    PAGE_STATIONS => { zh: "2 站点", en: "2 Stations" },
    PAGE_SESSIONS => { zh: "3 会话", en: "3 Sessions" },
    PAGE_REQUESTS => { zh: "4 请求", en: "4 Requests" },
    PAGE_STATS => { zh: "5 用量", en: "5 Usage" },
    PAGE_SETTINGS => { zh: "6 设置", en: "6 Settings" },
    PAGE_HISTORY => { zh: "7 历史", en: "7 History" },
    PAGE_RECENT => { zh: "8 最近", en: "8 Recent" },

    FOCUS_SESSIONS => { zh: "会话", en: "Sessions" },
    FOCUS_REQUESTS => { zh: "请求", en: "Requests" },
    FOCUS_ROUTING => { zh: "路由", en: "Routing" },
    FOCUS_STATIONS => { zh: "站点", en: "Stations" },
    FOCUS_LABEL => { zh: "焦点:", en: "focus: " },

    STATUS_ACTIVE_SHORT => { zh: "活跃 ", en: "active " },
    STATUS_ERRORS_SHORT => { zh: "错误(80) ", en: "errors(80) " },
    STATUS_CURRENT_SHORT => { zh: "当前 ", en: "cur " },
    STATUS_HEALTH_CHECK_SHORT => { zh: "健康检查 ", en: "hc " },
    STATUS_OVERRIDES_SHORT => { zh: "覆盖(M/E/C/T) ", en: "overrides(M/E/C/T) " },
    STATUS_OVERRIDES_ROUTE_SHORT => { zh: "覆盖(M/E/R/T) ", en: "overrides(M/E/R/T) " },
    STATUS_GLOBAL_STATION_OVERRIDE_SHORT => { zh: "覆盖(全局站点) ", en: "override(global station) " },
    STATUS_GLOBAL_ROUTE_TARGET_SHORT => { zh: "覆盖(全局路由) ", en: "override(global route) " },
    STATUS_UPDATED_SHORT => { zh: "刷新 ", en: "updated " },
    STATUS_ACTIVE_TINY => { zh: "", en: "act " },
    STATUS_ERRORS_TINY => { zh: "", en: "err " },
    STATUS_UPDATED_TINY => { zh: "", en: "upd " },

    OVERLAY_SESSION_PROVIDER_OVERRIDE => { zh: "会话 Provider 覆盖", en: "Session provider override" },
    OVERLAY_GLOBAL_STATION_PIN => { zh: "全局站点 pin", en: "Global station pin" },
    OVERLAY_HELP_TITLE => { zh: "帮助", en: "Help" },
    OVERLAY_STATION_DETAILS => { zh: "站点详情", en: "Station details" },
    OVERLAY_SESSION_TRANSCRIPT => { zh: "会话对话记录", en: "Session transcript" },
    OVERLAY_SET_SESSION_MODEL => { zh: "设置 Session Model", en: "Set session model" },
    OVERLAY_SET_SERVICE_TIER => { zh: "设置 Fast / Service Tier", en: "Set Fast / Service Tier" },
    OVERLAY_INPUT_SESSION_MODEL => { zh: "输入自定义 Session Model", en: "Enter custom session model" },
    OVERLAY_INPUT_SERVICE_TIER => { zh: "输入自定义 Service Tier", en: "Enter custom service tier" },
    OVERLAY_MANAGE_RUNTIME_PROFILE => { zh: "管理运行时默认 Profile", en: "Manage runtime default profile" },
    OVERLAY_MANAGE_CONFIGURED_PROFILE => { zh: "管理配置默认 Profile", en: "Manage configured default profile" },
    OVERLAY_MANAGE_SESSION_PROFILE => { zh: "管理 Session Profile Binding", en: "Manage session profile binding" },

    FOOTER_DASHBOARD => { zh: "1-8 页面  q 退出  L 语言  Tab 焦点  ↑/↓ 移动  b/M/f 覆盖  p/P 站点  ? 帮助", en: "1-8 pages  q quit  L language  Tab focus  ↑/↓ move  b/M/f overrides  p/P station  ? help" },
    FOOTER_DASHBOARD_ROUTE_GRAPH => { zh: "1-8 页面  q 退出  L 语言  Tab 焦点  ↑/↓ 移动  b/M/f 覆盖  p/P 路由  ? 帮助", en: "1-8 pages  q quit  L language  Tab focus  ↑/↓ move  b/M/f overrides  p/P route  ? help" },
    FOOTER_ROUTING => { zh: "1-8 页面  q 退出  L 语言  ↑/↓ provider  r/Enter 编辑  g 刷新余额  ? 帮助", en: "1-8 pages  q quit  L language  ↑/↓ provider  r/Enter edit  g refresh balances  ? help" },
    FOOTER_STATIONS => { zh: "1-8 页面  q 退出  L 语言  ↑/↓ 选择  Enter pin  i 详情  h/H 检查  ? 帮助", en: "1-8 pages  q quit  L language  ↑/↓ select  Enter pin  i details  h/H check  ? help" },
    FOOTER_REQUESTS => { zh: "1-8 页面  q 退出  L 语言  ↑/↓ 选择  e 错误  s scope  o/h 跳转  ? 帮助", en: "1-8 pages  q quit  L language  ↑/↓ select  e errors  s scope  o/h navigate  ? help" },
    FOOTER_SESSIONS => { zh: "1-8 页面  q 退出  L 语言  ↑/↓ 选择  b/M/f 覆盖  a/e/v 筛选  t 记录  ? 帮助", en: "1-8 pages  q quit  L language  ↑/↓ select  b/M/f overrides  a/e/v filters  t transcript  ? help" },
    FOOTER_STATS => { zh: "1-8 页面  q 退出  L 语言  Tab 焦点  ↑/↓ 选择  a 关注  g 刷新余额  PgUp/PgDn 详情  ? 帮助", en: "1-8 pages  q quit  L language  Tab focus  ↑/↓ select  a attention  g refresh balances  PgUp/PgDn detail  ? help" },
    FOOTER_SETTINGS_CODEX => { zh: "1-8 页面  q 退出  L 语言  p/P profile  R 重载  O 导入 ~/.codex  ? 帮助", en: "1-8 pages  q quit  L language  p/P profile  R reload  O import ~/.codex  ? help" },
    FOOTER_SETTINGS_OTHER => { zh: "1-8 页面  q 退出  L 语言  p/P profile  R 重载  ? 帮助", en: "1-8 pages  q quit  L language  p/P profile  R reload  ? help" },
    FOOTER_HISTORY => { zh: "1-8 页面  q 退出  L 语言  ↑/↓ 选择  r 刷新  t/Enter 记录  s/f 跳转  ? 帮助", en: "1-8 pages  q quit  L language  ↑/↓ select  r refresh  t/Enter transcript  s/f navigate  ? help" },
    FOOTER_RECENT => { zh: "1-8 页面  q 退出  L 语言  ↑/↓ 选择  [] 时间  Enter/y 复制  t 记录  ? 帮助", en: "1-8 pages  q quit  L language  ↑/↓ select  [] window  Enter/y copy  t transcript  ? help" },
    FOOTER_HELP => { zh: "Esc 关闭帮助  L 语言", en: "Esc close help  L language" },
    FOOTER_SELECT_APPLY => { zh: "↑/↓ 选择  Enter 应用  Esc 取消", en: "↑/↓ select  Enter apply  Esc cancel" },
    FOOTER_MODEL_MENU => { zh: "↑/↓ 选择 model  Enter 应用  Esc 取消", en: "↑/↓ select model  Enter apply  Esc cancel" },
    FOOTER_MODEL_INPUT => { zh: "输入 model  Enter 应用  Esc 返回菜单  Backspace 删除  Delete/Ctrl+U 清空", en: "type model  Enter apply  Esc back to menu  Backspace delete  Delete/Ctrl+U clear" },
    FOOTER_SERVICE_TIER_MENU => { zh: "↑/↓ 选择 service tier  Enter 应用  Esc 取消", en: "↑/↓ select service tier  Enter apply  Esc cancel" },
    FOOTER_SERVICE_TIER_INPUT => { zh: "输入 service_tier  Enter 应用  Esc 返回菜单  Backspace 删除  Delete/Ctrl+U 清空", en: "type service_tier  Enter apply  Esc back to menu  Backspace delete  Delete/Ctrl+U clear" },
    FOOTER_PROFILE_SESSION => { zh: "↑/↓ 选择 profile 操作  Enter 应用/清除绑定  Esc 取消", en: "↑/↓ select profile action  Enter apply/clear binding  Esc cancel" },
    FOOTER_PROFILE_RUNTIME => { zh: "↑/↓ 选择运行时默认 profile  Enter 应用/清除覆盖  Esc 取消", en: "↑/↓ select runtime default profile  Enter apply/clear override  Esc cancel" },
    FOOTER_PROFILE_CONFIGURED => { zh: "↑/↓ 选择配置默认 profile  Enter 应用/清除默认值  Esc 取消", en: "↑/↓ select configured default profile  Enter apply/clear default  Esc cancel" },
    FOOTER_ROUTING_MENU => { zh: "↑/↓ 选择  Enter pin  a 顺序  e/f/s 策略  1/2/0 billing  []/u/d 重排  g 刷新  Esc 关闭", en: "↑/↓ select  Enter pin  a order  e/f/s policy  1/2/0 billing  []/u/d reorder  g refresh  Esc close" },
    FOOTER_STATION_INFO => { zh: "↑/↓ 滚动  PgUp/PgDn 翻页  Esc 关闭  L 语言", en: "↑/↓ scroll  PgUp/PgDn page  Esc close  L language" },
    FOOTER_SESSION_TRANSCRIPT => { zh: "↑/↓ 滚动  PgUp/PgDn 翻页  g/G 顶/底  A 全量/尾部  y 复制  t/Esc 关闭  L 语言", en: "↑/↓ scroll  PgUp/PgDn page  g/G top/bottom  A all/tail  y copy  t/Esc close  L language" },

    DECLARED_LABEL => { zh: "声明:", en: "declared:" },
    RESOLVED_LABEL => { zh: "生效:", en: "resolved:" },
    RESOLVE_FAILED_LABEL => { zh: "解析失败:", en: "resolve failed:" },
    SESSION_LABEL => { zh: "会话:", en: "session: " },
    PINNED_LABEL => { zh: "固定:", en: "pinned: " },
    KEYS_LABEL => { zh: "按键:", en: "keys: " },
    ALIAS_LABEL => { zh: "别名:", en: "alias: " },
    STATUS_LABEL => { zh: "状态:", en: "status: " },
    ENABLED_LABEL => { zh: "启用", en: "enabled" },
    DISABLED_LABEL => { zh: "禁用", en: "disabled" },
    RUNTIME_HEALTH_TITLE => { zh: "运行态(可用性/体验)", en: "Runtime health / experience" },
    OK_PREFIX => { zh: "成功 ", en: "ok " },
    UPSTREAMS_TITLE => { zh: "上游(Providers)", en: "Upstreams (providers)" },
    NONE_PARENS => { zh: "(无)", en: "(none)" },
    NOT_CHECKED => { zh: "未检查", en: "not checked" },
    MODELS_ALL => { zh: "模型:全部", en: "models: all" },
    NO_STATION_SELECTED => { zh: "未选中任何站点。", en: "No station selected." },
    NO_TRANSCRIPT_MESSAGES => { zh: "未找到可展示的对话消息(可能该会话不在 ~/.codex/sessions,或格式发生变化)。", en: "No displayable transcript messages were found; the session may be outside ~/.codex/sessions or the format changed." },
    CURRENT_INPUT_LABEL => { zh: "当前输入: ", en: "current: " },
    SESSION_MODEL_HINT_LABEL => { zh: "当前会话模型: ", en: "session hint: " },
    SESSION_TIER_HINT_LABEL => { zh: "当前会话 tier: ", en: "session hint: " },
    CLEAR_MODEL_OVERRIDE => { zh: "Clear (清除会话 model 覆盖)", en: "Clear (remove session model override)" },
    RESTORE_DEFAULT_ROUTING => { zh: "恢复为 request / binding / runtime 的默认路由", en: "Restore the request / binding / runtime default route" },
    APPLY_SESSION_MODEL_OVERRIDE => { zh: "应用为当前会话的 model override", en: "Apply as the current session model override" },
    CUSTOM_MODEL => { zh: "Custom...(输入任意 model)", en: "Custom... (enter any model)" },
    CUSTOM_MODEL_HELP => { zh: "打开输入框,手动填写 model override", en: "Open an input box to enter a model override" },
    MODEL_INPUT_HELP => { zh: "输入任意 model 名称。Enter 应用,Esc 返回菜单,Backspace 删除,Delete / Ctrl+U 清空。空值会清除会话 model 覆盖。", en: "Enter any model name. Enter applies, Esc returns to the menu, Backspace deletes, Delete / Ctrl+U clears. Empty input clears the session model override." },
    CLEAR_SERVICE_TIER_OVERRIDE => { zh: "移除当前会话的 service tier 覆盖", en: "Remove the current session service tier override" },
    USE_DEFAULT_SERVICE_TIER => { zh: "显式使用 default", en: "Explicitly use default" },
    USE_PRIORITY_SERVICE_TIER => { zh: "通常可视为 fast mode", en: "Usually maps to fast mode" },
    USE_FLEX_SERVICE_TIER => { zh: "显式使用 flex", en: "Explicitly use flex" },
    CUSTOM_SERVICE_TIER => { zh: "Custom...(输入任意 service_tier)", en: "Custom... (enter any service_tier)" },
    CUSTOM_SERVICE_TIER_HELP => { zh: "打开输入框,手动填写 service_tier override", en: "Open an input box to enter a service_tier override" },
    SERVICE_TIER_INPUT_HELP => { zh: "输入任意 service_tier。Enter 应用,Esc 返回菜单,Backspace 删除,Delete / Ctrl+U 清空。空值会清除会话 service_tier 覆盖。", en: "Enter any service_tier. Enter applies, Esc returns to the menu, Backspace deletes, Delete / Ctrl+U clears. Empty input clears the session service_tier override." },
    CLEAR_RUNTIME_PROFILE => { zh: "Clear runtime override(回退到配置默认 profile)", en: "Clear runtime override (fall back to configured default profile)" },
    CLEAR_RUNTIME_PROFILE_HELP => { zh: "只清理运行时 default_profile 覆盖;保留配置文件里的 default_profile", en: "Only clears the runtime default_profile override; keeps the configured default_profile" },
    CLEAR_CONFIGURED_PROFILE => { zh: "Clear configured default(移除配置默认 profile)", en: "Clear configured default (remove configured default profile)" },
    CLEAR_CONFIGURED_PROFILE_HELP => { zh: "会修改并重载代理配置;新的会话将不再继承配置级 default_profile", en: "Edits and reloads proxy config; new sessions stop inheriting the configured default_profile" },
    CLEAR_SESSION_PROFILE_BINDING => { zh: "Clear binding(移除会话已存储的 profile 绑定)", en: "Clear binding (remove stored session profile binding)" },
    CLEAR_SESSION_PROFILE_BINDING_HELP => { zh: "只清理 profile binding;保留当前会话的 model / effort / provider / service_tier 覆盖", en: "Only clears the profile binding; keeps the current session model / effort / provider / service_tier overrides" },

    HISTORY_TITLE => { zh: "历史会话 (Codex)", en: "History sessions (Codex)" },
    RECENT_TITLE => { zh: "最近会话 (Codex)", en: "Recent sessions (Codex)" },
    DETAILS_TITLE => { zh: "详情", en: "Details" },
    FIRST_USER_MESSAGE => { zh: "首条用户消息", en: "First user message" },
    BULLET_DASH => { zh: "  -", en: "  -" },
    HISTORY_EMPTY => { zh: "未找到历史会话。按 r 刷新;或确认 ~/.codex/sessions 存在。", en: "No history sessions found. Press r to refresh, or check that ~/.codex/sessions exists." },
    HISTORY_KEYS => { zh: "  ↑/↓ 选择  r 刷新  t/Enter 打开对话记录  s 打开到 Sessions  f 打开到 Requests", en: "  ↑/↓ select  r refresh  t/Enter transcript  s open Sessions  f open Requests" },
    HISTORY_EXTERNAL_NO_TRANSCRIPT => { zh: "  当前条目来自外部桥接,没有本地 transcript 文件。", en: "  This entry came from an external bridge and has no local transcript file." },
    RECENT_EMPTY => { zh: "未加载最近会话。按 r 刷新;或确认 ~/.codex/sessions 存在。", en: "Recent sessions are not loaded. Press r to refresh, or check that ~/.codex/sessions exists." },
    RECENT_KEYS_PRIMARY => { zh: "  Enter 复制条目  y 复制可见列表  t 打开 transcript", en: "  Enter copy entry  y copy visible list  t open transcript" },
    RECENT_KEYS_NAV => { zh: "  s 打开到 Sessions  f 打开到 Requests  h 打开到 History", en: "  s open Sessions  f open Requests  h open History" },
    NO_SELECTION => { zh: "未选中任何条目。", en: "No selection." },

    SETTINGS_TITLE => { zh: "设置", en: "Settings" },
    RUNTIME_OVERVIEW_TITLE => { zh: "运行态概览", en: "Runtime overview" },
    BALANCE_OVERVIEW_TITLE => { zh: "余额 / 配额概览", en: "Balance / quota overview" },
    PRICING_CATALOG_TITLE => { zh: "价格目录", en: "Pricing catalog" },
    TUI_OPTIONS_TITLE => { zh: "TUI 选项", en: "TUI options" },
    REFRESH_LABEL => { zh: "刷新间隔:", en: "refresh: " },
    WINDOW_SAMPLES_LABEL => { zh: "窗口采样:", en: "window samples: " },
    PROFILE_CONTROL_TITLE => { zh: "Profile 控制", en: "Profile control" },
    CONFIGURED_DEFAULT_LABEL => { zh: "配置默认:", en: "configured default: " },
    PRESS_P_MANAGE => { zh: "  (按 p 管理)", en: "  (press p to manage)" },
    RUNTIME_OVERRIDE_LABEL => { zh: "运行时覆盖:", en: "runtime override: " },
    PRESS_CAPITAL_P_MANAGE => { zh: "  (按 P 管理)", en: "  (press P to manage)" },
    EFFECTIVE_DEFAULT_LABEL => { zh: "当前生效:", en: "effective default: " },
    NO_PROFILES => { zh: "<no profiles>", en: "<no profiles>" },
    AVAILABLE_PROFILES_LABEL => { zh: "可用 profile:", en: "available profiles: " },
    HEALTH_CHECK_TITLE => { zh: "Health Check", en: "Health Check" },
    PATHS_TITLE => { zh: "路径", en: "Paths" },
    RUNTIME_CONFIG_TITLE => { zh: "运行态配置", en: "Runtime config" },
    PRESS_R_RELOAD => { zh: "  (按 R 立即重载)", en: "  (press R to reload)" },
    COMMON_KEYS_TITLE => { zh: "常用快捷键", en: "Common keys" },
    COMMON_KEYS_CODEX => { zh: "  1-8 切页  ? 帮助  q 退出  L 语言  (Stations: i 详情  Stats: y 导出/复制  Settings: R 重载配置  O 覆盖导入(二次确认))", en: "  1-8 pages  ? help  q quit  L language  (Stations: i details  Stats: y export/copy  Settings: R reload  O overwrite(confirm))" },
    COMMON_KEYS_OTHER => { zh: "  1-8 切页  ? 帮助  q 退出  L 语言  (Stations: i 详情  Stats: y 导出/复制)", en: "  1-8 pages  ? help  q quit  L language  (Stations: i details  Stats: y export/copy)" },

    CONFIRM_OVERWRITE => { zh: "再次按 O 确认覆盖导入(3s 内)", en: "Press O again to confirm overwrite (within 3s)" },
    CONFIG_RELOADED => { zh: "已重载配置(", en: "Config reloaded (" },
    CONFIG_CHANGED => { zh: "检测到变更", en: "changed" },
    CONFIG_NO_CHANGE => { zh: "无变更", en: "no change" },
    CONFIG_RELOADED_SUFFIX => { zh: "", en: ")" },
    HISTORY_REFRESHING => { zh: "history: 刷新中…", en: "history: refreshing…" },
    RECENT_REFRESHING => { zh: "recent: 刷新中…", en: "recent: refreshing…" },
    PROFILE_NO_OPTIONS => { zh: "profile: 当前服务没有可用 profile", en: "profile: no profiles available for this service" },
    DEFAULT_PROFILE_NO_OPTIONS => { zh: "default profile: 当前服务没有可用 profile", en: "default profile: no profiles available for this service" },
    DEFAULT_PROFILE_MANAGE_CONFIGURED => { zh: "default profile: 管理配置默认值", en: "default profile: manage configured default" },
    RUNTIME_DEFAULT_PROFILE_NO_OPTIONS => { zh: "runtime default profile: 当前服务没有可用 profile", en: "runtime default profile: no profiles available for this service" },
    RUNTIME_DEFAULT_PROFILE_MANAGE => { zh: "runtime default profile: 管理运行时默认值", en: "runtime default profile: manage runtime default" },
    MODEL_NO_CATALOG => { zh: "model: 当前服务没有可用模型目录", en: "model: no model catalog available for this service" },
    RECENT_COPIED_SELECTED => { zh: "recent: 已复制选中条目", en: "recent: copied selected entry" },
    RECENT_SESSION_NOT_OBSERVED => { zh: "sessions: 当前 runtime 未观测到这个 recent session", en: "sessions: this recent session is not observed by the current runtime" },
    RECENT_COPIED_VISIBLE => { zh: "recent: 已复制可见列表", en: "recent: copied visible list" },
    SESSION_NOT_OBSERVED => { zh: "sessions: 当前 runtime 未观测到这个 session", en: "sessions: this session is not observed by the current runtime" },
    HISTORY_NO_TRANSCRIPT_FILE => { zh: "history: 当前选中项没有本地 transcript 文件", en: "history: selected item has no local transcript file" },

    ROUTING_ACTION_PROVIDER_DETAILS => { zh: "  i            Provider 详情(可滚动)", en: "  i            provider details (scrollable)" },
}

fn lookup(table: &'static [(&'static str, &'static str)], key: TextKey) -> Option<&'static str> {
    table
        .iter()
        .find_map(|(id, value)| (*id == key.id()).then_some(*value))
}

pub(crate) fn text(lang: Language, key: TextKey) -> &'static str {
    match lang {
        Language::Zh => lookup(ZH_MESSAGES, key)
            .or_else(|| lookup(EN_MESSAGES, key))
            .unwrap_or_else(|| key.id()),
        Language::En => lookup(EN_MESSAGES, key).unwrap_or_else(|| key.id()),
    }
}

pub(crate) fn label(lang: Language, en: &'static str) -> &'static str {
    match lang {
        Language::En => en,
        Language::Zh => zh_label(en).unwrap_or(en),
    }
}

fn zh_label(en: &'static str) -> Option<&'static str> {
    Some(match en {
        "Actions" => "操作",
        "A" => "",
        "Age" => "耗时",
        "<auto>" => "<自动>",
        "<clear>" => "<清除>",
        "<configured fallback>" => "<配置回退>",
        "<none>" => "<无>",
        "Balance / quota" => "余额 / 配额",
        "Balance/Quota" => "余额/配额",
        "Cache & speed" => "缓存 / 速度",
        "Clear override" => "清除覆盖",
        "Clear (use request value)" => "清除(使用请求值)",
        "Clear (use request/binding value)" => "清除(使用请求/绑定值)",
        "CNew" => "新缓存",
        "CRead" => "读缓存",
        "CWD" => "目录",
        "Details" => "详情",
        "Dur" => "耗时",
        "Effective route" => "生效路由",
        "First user message" => "第一条用户消息",
        "Health" => "健康",
        "In" => "输入",
        "Keys" => "按键",
        "Last" => "最近",
        "Live health" => "实时健康",
        "Lvl" => "级别",
        "Model" => "模型",
        "Name" => "名称",
        "No data in this window." => "当前窗口没有数据。",
        "No requests match the current filters." => "没有请求匹配当前筛选。",
        "No sessions match the current filters." => "没有会话匹配当前筛选。",
        "No stations available." => "没有可用站点。",
        "Observed route" => "观测路由",
        "On" => "启用",
        "Out" => "输出",
        "Path" => "路径",
        "Provider" => "提供商",
        "Provider routing" => "Provider 路由",
        "Recent sample" => "最近样本",
        "Requests" => "请求",
        "Requests page" => "请求页",
        "Retry / route chain" => "重试 / 路由链",
        "Routing" => "路由",
        "Routing page" => "路由页",
        "Route" => "路由",
        "Session" => "会话",
        "Session details" => "会话详情",
        "Sessions" => "会话",
        "Sessions page" => "会话页",
        "Set reasoning effort" => "设置推理强度",
        "Spend & tokens" => "花费 / Token",
        "St" => "状态",
        "Station details" => "站点详情",
        "Stations" => "站点",
        "Stats page" => "统计页",
        "TTFB" => "首包",
        "Tok" => "Tok",
        "Tokens / day" => "每日 Token",
        "Tokens / day (window, zero-filled)" => "每日 Token(窗口,补零)",
        "Total" => "总耗时",
        "Up" => "上游",
        "Upstreams" => "上游",
        "Updated" => "更新时间",
        "ΣTok" => "总Tok",
        "active" => "活跃",
        "activity" => "活动",
        "active_only" => "仅活跃",
        "age" => "耗时",
        "alias" => "别名",
        "all_exhausted" => "全部耗尽",
        "all" => "全部",
        "all requests" => "全部请求",
        "allow" => "允许",
        "attempts" => "尝试",
        "assistant" => "助手",
        "auth" => "认证",
        "auto" => "自动",
        "auto(level fallback)" => "自动(按级别回退)",
        "auto(single-level fallback)" => "自动(同级回退)",
        "attention only" => "仅关注项",
        "avg" => "平均",
        "balance" => "余额",
        "balance refresh already requested" => "余额刷新已在进行中",
        "balance lookup failed" => "余额查询失败",
        "balance refresh started" => "余额刷新已开始",
        "balance/quota" => "余额/配额",
        "breaker_open_blocks_pin" => "熔断阻断 pin",
        "branch" => "分支",
        "budget" => "预算",
        "binding" => "绑定",
        "cache" => "缓存",
        "cache read/create" => "缓存 读/新建",
        "cache hit" => "缓存命中",
        "cache hit rate" => "缓存命中率",
        "Hit%" => "命中率",
        "client" => "客户端",
        "client(last)" => "最近客户端",
        "clipboard failed" => "剪贴板失败",
        "config file" => "配置文件",
        "configured default profile" => "配置默认 profile",
        "configured default profile apply failed" => "配置默认 profile 应用失败",
        "configured default profile refresh failed" => "配置默认 profile 刷新失败",
        "context" => "上下文",
        "control" => "控制",
        "cooldown" => "冷却",
        "copy" => "复制",
        "cost" => "成本",
        "cost_parts" => "成本拆分",
        "coverage" => "覆盖",
        "coverage warning" => "覆盖提醒",
        "cancel" => "取消",
        "canceled" => "已取消",
        "cwd" => "目录",
        "dashboard: no request selected" => "dashboard: 未选择请求",
        "dashboard: no session selected" => "dashboard: 未选择会话",
        "dashboard: selected request has no session id" => "dashboard: 所选请求没有 session id",
        "dashboard: selected row has no session id" => "dashboard: 所选行没有 session id",
        "disabled" => "已禁用",
        "done" => "完成",
        "effort" => "推理强度",
        "effort override" => "推理强度覆盖",
        "effort override cleared" => "推理强度覆盖已清除",
        "effort set" => "推理强度已设置",
        "enabled" => "启用",
        "err" => "错误",
        "error" => "错误",
        "errors" => "错误",
        "errors_only" => "仅错误",
        "estimated" => "估算",
        "exact" => "精确",
        "exh" => "耗尽",
        "exhausted" => "已耗尽",
        "explain" => "说明",
        "explicit session focus" => "显式会话聚焦",
        "failed to load transcript" => "加载 transcript 失败",
        "follow selected session" => "跟随选中会话",
        "focus" => "焦点",
        "focused from" => "聚焦来源",
        "generation" => "生成",
        "global" => "全局",
        "global override" => "全局覆盖",
        "global station pin" => "全局站点 pin",
        "global route target" => "全局 route target",
        "global_station" => "全局站点",
        "health_check" => "健康检查",
        "health" => "健康",
        "health check already running" => "健康检查已在运行",
        "health check cancel requested" => "已请求取消健康检查",
        "health check load failed" => "健康检查加载失败",
        "health check not running" => "健康检查未运行",
        "health check queued" => "健康检查已排队",
        "history: failed to prepare request focus" => "history: 准备请求聚焦失败",
        "history: failed to prepare session focus" => "history: 准备会话聚焦失败",
        "history: focused session" => "history: 已聚焦会话",
        "history: no selection" => "history: 未选择条目",
        "history: resolve session file failed" => "history: 解析会话文件失败",
        "host-local enriched" => "本机 transcript 增强",
        "home" => "主目录",
        "identity" => "身份",
        "in/out" => "输入/输出",
        "last_response" => "最近响应",
        "lazy" => "不降级",
        "lazy reset" => "不降级耗尽",
        "lb" => "负载",
        "left" => "剩余",
        "limit" => "上限",
        "linked under ~/.codex/sessions" => "已链接到 ~/.codex/sessions",
        "loaded" => "已加载",
        "loaded days with data" => "有数据的已加载天数",
        "loaded total req" => "已加载请求总数",
        "local transcript" => "本地对话记录",
        "logs" => "日志",
        "lookup_failed" => "查询失败",
        "map" => "映射",
        "messages" => "消息",
        "meta" => "元数据",
        "method" => "方法",
        "missing_pinned_station" => "缺少固定站点",
        "mode" => "模式",
        "model" => "模型",
        "model override" => "模型覆盖",
        "models" => "模型",
        "mtime" => "修改时间",
        "name" => "名称",
        "nested route graph: edit route nodes in TOML for grouped reorder" => {
            "嵌套路由图:请在 TOML 中编辑路由节点来分组排序"
        }
        "no" => "",
        "no balance/quota data" => "没有余额/配额数据",
        "no Codex session file found for this session id" => {
            "没有找到该 session id 对应的 Codex 会话文件"
        }
        "no price rows" => "没有价格行",
        "no session selected" => "未选择会话",
        "no transcript file loaded" => "未加载对话记录文件",
        "no host-local transcript detected" => "未检测到本机 transcript",
        "no stored binding or session override" => "没有已存储绑定或会话覆盖",
        "no_upstreams" => "没有可路由上游",
        "now" => "当前",
        "observed bridge" => "观测桥接",
        "observed only" => "仅运行时观测",
        "ok" => "成功",
        "on" => "",
        "on_exhausted" => "耗尽策略",
        "off" => "",
        "order" => "顺序",
        "order_rule" => "排序规则",
        "out_tok/s" => "输出 tok/s",
        "overwrite-from-codex is only supported for Codex service" => {
            "overwrite-from-codex 仅支持 Codex 服务"
        }
        "override" => "覆盖",
        "overrides_only" => "仅覆盖",
        "partial" => "部分",
        "partial_exhausted" => "部分耗尽",
        "path" => "路径",
        "paygo" => "按量",
        "pinned" => "固定",
        "policy" => "策略",
        "prefer_tags" => "偏好标签",
        "profile applied" => "profile 已应用",
        "profile apply failed" => "profile 应用失败",
        "profile binding cleared" => "profile 绑定已清除",
        "profile default" => "profile 默认值",
        "provider" => "提供商",
        "provider enable failed" => "provider 启用失败",
        "provider tag failed" => "provider 标签失败",
        "providers" => "提供商",
        "provider is referenced by the route graph but missing from catalog" => {
            "路由图引用了该 provider,但目录中缺失"
        }
        "quota" => "配额",
        "raw_cwd" => "原始 cwd",
        "read/create" => "读取/创建",
        "recent filter" => "recent 筛选",
        "recent window" => "recent 窗口",
        "recent: no local transcript file found for this session" => {
            "recent: 没有找到该会话的本地对话记录文件"
        }
        "recent: no selection" => "recent: 未选择条目",
        "recent: nothing to copy" => "recent: 没有可复制内容",
        "recent: resolve session file failed" => "recent: 解析会话文件失败",
        "requests" => "请求",
        "requests filter" => "requests 筛选",
        "requests scope" => "requests 范围",
        "requests: cleared explicit session focus" => "requests: 已清除显式会话聚焦",
        "requests: focused session" => "requests: 已聚焦会话",
        "requests: no selection" => "requests: 未选择条目",
        "requests: selected request has no session id" => "requests: 所选请求没有 session id",
        "request payload" => "请求负载",
        "req" => "请求",
        "Rounds" => "轮次",
        "reports" => "报告",
        "resolved policy unavailable" => "未解析到策略",
        "retry" => "重试",
        "retry policy" => "重试策略",
        "root" => "根目录",
        "rounds" => "轮次",
        "rt" => "运行态",
        "route graph" => "路由图",
        "routing" => "路由",
        "routing update failed" => "routing 更新失败",
        "routing: apply failed" => "routing: 应用失败",
        "routing spec not loaded" => "routing 规格未加载",
        "routing: edit persisted policy/order" => "routing: 编辑持久化策略/顺序",
        "routing: edit provider policy/order/tags" => "routing: 编辑 provider 策略/顺序/标签",
        "routing: load failed" => "routing: 加载失败",
        "routing: move failed" => "routing: 移动失败",
        "routing: moved down" => "routing: 已下移",
        "routing: moved up" => "routing: 已上移",
        "routing: ordered-failover" => "routing: ordered-failover",
        "routing: pin failed" => "routing: pin 失败",
        "routing: pinned" => "routing: 已 pin",
        "routing: prefer billing=monthly" => "routing: 优先 billing=monthly",
        "routing: provider details/edit" => "routing: provider 详情/编辑",
        "routing: refresh failed" => "routing: 刷新失败",
        "routing: refreshed" => "routing: 已刷新",
        "run" => "运行",
        "running" => "运行中",
        "runtime default profile" => "运行时默认 profile",
        "runtime default profile apply failed" => "运行时默认 profile 应用失败",
        "runtime default profile refresh failed" => "运行时默认 profile 刷新失败",
        "runtime fallback" => "运行时回退",
        "scope" => "范围",
        "selected session" => "选中会话",
        "session_affinity" => "会话粘性",
        "selected window starts before loaded log data" => "所选窗口早于已加载日志数据",
        "selected session has no session id" => "所选会话没有 session id",
        "set global pin failed" => "设置全局 pin 失败",
        "set global route target failed" => "设置全局 route target 失败",
        "session" => "会话",
        "session-controlled route" => "会话控制路由",
        "session manual overrides reset" => "会话手动覆盖已重置",
        "session override" => "会话覆盖",
        "session overrides already clear" => "会话覆盖已为空",
        "session station override" => "会话站点覆盖",
        "session station override: <clear>" => "会话站点覆盖:<清除>",
        "session station override: <no session>" => "会话站点覆盖:<无会话>",
        "session route target" => "会话 route target",
        "session route target: <no session>" => "会话 route target:<无会话>",
        "route_target" => "路由目标",
        "sessions filter" => "sessions 筛选",
        "sessions filter: reset" => "sessions 筛选:已重置",
        "sessions: focused" => "sessions: 已聚焦",
        "sessions: no session selected" => "sessions: 未选择会话",
        "sessions: selected row has no session id" => "sessions: 所选行没有 session id",
        "service_tier" => "服务层级",
        "service_tier set" => "service_tier 已设置",
        "sid" => "会话 ID",
        "skipped" => "跳过",
        "source" => "来源",
        "stale" => "过期",
        "station" => "站点",
        "station mapping" => "站点映射",
        "status" => "状态",
        "strategy" => "策略",
        "stream" => "流式",
        "success" => "成功",
        "subscription" => "订阅",
        "tags" => "标签",
        "tail" => "尾部",
        "target" => "目标",
        "tier" => "服务层级",
        "not in catalog" => "不在目录中",
        "today" => "今天",
        "today used" => "今日已用",
        "tok" => "tok",
        "tok in/out/rsn" => "tok 输入/输出/推理",
        "tok in/out/rsn/ttl" => "tok 输入/输出/推理/总计",
        "tok/s" => "tok/s",
        "tokens" => "Token",
        "top models by tokens" => "按 Token 排名前列模型",
        "top paths by tokens" => "按 Token 排名前列路径",
        "top status" => "状态排名",
        "total" => "总数",
        "trace" => "追踪",
        "transcript" => "对话记录",
        "file" => "文件",
        "transcript: copied to clipboard" => "transcript: 已复制到剪贴板",
        "transcript: copy failed" => "transcript: 复制失败",
        "transcript: loaded all" => "transcript: 已加载全部",
        "transcript: loaded tail" => "transcript: 已加载尾部",
        "transcript: reload failed" => "transcript: 重新加载失败",
        "ttfb" => "首包",
        "turns" => "轮次",
        "usage" => "用量",
        "updated" => "已更新",
        "upstream" => "上游",
        "upstreams" => "上游",
        "user" => "用户",
        "unknown" => "未知",
        "unlimited" => "不限量",
        "used" => "已用",
        "usd" => "USD",
        "v4 routing owns provider choice; press r to edit routing" => {
            "v4 routing 接管 provider 选择;按 r 编辑路由"
        }
        "v4 routing is global; editing persisted routing" => {
            "v4 routing 是全局配置;正在编辑持久化 routing"
        }
        "window" => "窗口",
        "yes" => "",
        "pinned target only; breaker_open / empty upstreams block." => {
            "仅固定目标;breaker_open 或空上游会阻断。"
        }
        "known fully exhausted stations are demoted by default; provider-level exceptions only show balance/quota." => {
            "默认降低已知完全耗尽站点的优先级;provider 级例外只展示余额/配额。"
        }
        "known fully exhausted stations are demoted by default unless a provider opts out of routing trust." => {
            "默认降低已知完全耗尽站点的优先级,除非 provider 不信任余额参与路由。"
        }
        "This session keeps its stored binding until another profile or override rewrites it." => {
            "该会话会保留已存储绑定,直到其他 profile 或覆盖写入新值。"
        }
        "Session overrides currently take priority over the bound profile:" => {
            "当前优先生效的是会话覆盖字段:"
        }
        "This session is currently pinned by overrides on:" => "该会话当前由这些覆盖字段固定:",
        "Without a stored profile or session override, runtime/global routing explains the effective route." => {
            "没有已存储 profile 或会话覆盖时,生效路由由运行态/全局路由解释。"
        }
        "Effective route comes from request payloads, station defaults, and runtime fallback." => {
            "生效路由来自请求负载、站点默认值和运行时回退。"
        }
        "Effective route comes from request payloads, route graph defaults, route target overrides, and runtime fallback." => {
            "生效路由来自请求负载、路由图默认值、route target 覆盖和运行时回退。"
        }
        _ => return None,
    })
}

pub(crate) fn language_name(lang: Language) -> &'static str {
    match lang {
        Language::Zh => text(Language::Zh, msg::LANGUAGE_NAME_ZH),
        Language::En => text(Language::En, msg::LANGUAGE_NAME_EN),
    }
}

pub(crate) fn next_language(lang: Language) -> Language {
    match lang {
        Language::Zh => Language::En,
        Language::En => Language::Zh,
    }
}

pub(crate) fn storage_code(lang: Language) -> &'static str {
    match lang {
        Language::Zh => "zh-CN",
        Language::En => "en-US",
    }
}

pub(crate) fn format_language_saved(current_lang: Language, selected_lang: Language) -> String {
    format!(
        "{}{}{}",
        text(current_lang, msg::LANGUAGE_LABEL),
        language_name(selected_lang),
        text(current_lang, msg::LANGUAGE_SAVED)
    )
}

pub(crate) fn format_language_save_failed(
    current_lang: Language,
    selected_lang: Language,
    err: &dyn std::fmt::Display,
) -> String {
    format!(
        "{}{}{}{}{}",
        text(current_lang, msg::LANGUAGE_LABEL),
        language_name(selected_lang),
        text(current_lang, msg::LANGUAGE_SAVE_FAILED_PREFIX),
        err,
        text(current_lang, msg::LANGUAGE_SAVE_FAILED_SUFFIX)
    )
}

pub(crate) fn format_history_loaded(lang: Language, count: usize) -> String {
    match lang {
        Language::Zh => format!("history: 已加载 {count} 个会话"),
        Language::En => format!("history: loaded {count} sessions"),
    }
}

pub(crate) fn format_history_load_failed(lang: Language, err: &dyn std::fmt::Display) -> String {
    match lang {
        Language::Zh => format!("history: 加载失败:{err}"),
        Language::En => format!("history: load failed: {err}"),
    }
}

pub(crate) fn format_recent_loaded(lang: Language, count: usize) -> String {
    match lang {
        Language::Zh => format!("recent: 已加载 {count} 个会话"),
        Language::En => format!("recent: loaded {count} sessions"),
    }
}

pub(crate) fn format_recent_load_failed(lang: Language, err: &dyn std::fmt::Display) -> String {
    match lang {
        Language::Zh => format!("recent: 加载失败:{err}"),
        Language::En => format!("recent: load failed: {err}"),
    }
}

pub(crate) fn format_config_reloaded(lang: Language, changed: bool) -> String {
    format!(
        "{}{}{}",
        text(lang, msg::CONFIG_RELOADED),
        if changed {
            text(lang, msg::CONFIG_CHANGED)
        } else {
            text(lang, msg::CONFIG_NO_CHANGE)
        },
        text(lang, msg::CONFIG_RELOADED_SUFFIX)
    )
}

pub fn parse_language(s: &str) -> Option<Language> {
    let s = normalize_language_tag(s)?;
    match s.as_str() {
        "zh" | "zh-cn" | "zh-hans" | "zh-hans-cn" | "cn" | "chinese" | "中文" => {
            Some(Language::Zh)
        }
        "en" | "en-us" | "en-gb" | "english" => Some(Language::En),
        _ if s.starts_with("zh-") => Some(Language::Zh),
        _ if s.starts_with("en-") => Some(Language::En),
        _ => None,
    }
}

fn normalize_language_tag(s: &str) -> Option<String> {
    let s = s.trim();
    if s.is_empty() {
        return None;
    }
    let s = s
        .split('.')
        .next()
        .unwrap_or(s)
        .replace('_', "-")
        .to_ascii_lowercase();
    Some(s)
}

pub fn detect_system_language() -> Language {
    // Best-effort: prefer env vars to avoid platform-specific commands.
    // Common values:
    // - LANG=zh_CN.UTF-8
    // - LC_ALL=zh_CN.UTF-8
    // - LANGUAGE=zh_CN:en_US
    for key in ["LC_ALL", "LC_MESSAGES", "LANGUAGE", "LANG"] {
        if let Ok(v) = std::env::var(key) {
            for part in v.split(':') {
                if let Some(lang) = parse_language(part) {
                    return lang;
                }
            }
        }
    }
    Language::En
}

pub fn resolve_language_preference(value: Option<&str>) -> Language {
    match value.map(str::trim).filter(|s| !s.is_empty()) {
        Some(value) if value.eq_ignore_ascii_case("auto") => detect_system_language(),
        Some(value) => parse_language(value).unwrap_or_else(detect_system_language),
        None => detect_system_language(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_common_language_tags() {
        assert_eq!(parse_language("zh_CN.UTF-8"), Some(Language::Zh));
        assert_eq!(parse_language("zh-Hans-CN"), Some(Language::Zh));
        assert_eq!(parse_language("en_US"), Some(Language::En));
        assert_eq!(parse_language("en-GB"), Some(Language::En));
        assert_eq!(parse_language("auto"), None);
    }

    #[test]
    fn every_declared_message_is_available_in_all_locales() {
        for id in all_message_ids() {
            let key = TextKey::new(id);
            assert!(
                lookup(EN_MESSAGES, key).is_some(),
                "missing en message: {id}"
            );
            assert!(
                lookup(ZH_MESSAGES, key).is_some(),
                "missing zh message: {id}"
            );
        }
    }

    #[test]
    fn zh_messages_fallback_to_english_then_key() {
        assert_eq!(text(Language::Zh, msg::PAGE_DASHBOARD), "1 总览");
        assert_eq!(
            text(Language::En, TextKey::new("missing.test.key")),
            "missing.test.key"
        );
    }
}