返回 DeepSeek-TUI-2026
language.rs
根目录 / crates / tui / src / tui / onboarding / language.rs
1 //! Language picker for first-run onboarding (#566).
2 //!
3 //! Surfaces every locale the TUI ships translations for, plus an `auto`
4 //! option that defers to `LC_ALL` / `LANG`. Selection persists via
5 //! `Settings::save` immediately so the rest of onboarding (and every
6 //! subsequent session) reads the chosen tag.
7
8 use ratatui::style::{Modifier, Style};
9 use ratatui::text::{Line, Span};
10
11 use crate::palette;
12 use crate::tui::app::App;
13
14 /// Locale options shown in the picker. Order matches the keyboard hotkeys
15 /// (1-5). Each entry is `(hotkey, settings_tag, native_name, english_label)`.
16 /// `settings_tag` is what `Settings::set("locale", …)` accepts and what
17 /// `localization::Locale` resolves on next read.
18 pub const LANGUAGE_OPTIONS: &[(char, &str, &str, &str)] = &[
19 ('1', "auto", "Auto-detect", "(LC_ALL / LANG)"),
20 ('2', "en", "English", ""),
21 ('3', "ja", "日本語", "(Japanese)"),
22 ('4', "zh-Hans", "简体中文", "(Simplified Chinese)"),
23 ('5', "pt-BR", "Português (Brasil)", "(Brazilian Portuguese)"),
24 ];
25
26 pub fn lines(app: &App) -> Vec<Line<'static>> {
27 let current_owned = app.current_locale_tag();
28 let current = current_owned.as_str();
29
30 let mut out: Vec<Line<'static>> = vec![
31 Line::from(Span::styled(
32 "Choose your language",
33 Style::default()
34 .fg(palette::DEEPSEEK_SKY)
35 .add_modifier(Modifier::BOLD),
36 )),
37 Line::from(""),
38 Line::from(Span::styled(
39 "Pick the UI language. You can change it any time with `/settings set locale <tag>`.",
40 Style::default().fg(palette::TEXT_MUTED),
41 )),
42 Line::from(""),
43 ];
44
45 for (hotkey, tag, native, english) in LANGUAGE_OPTIONS {
46 let is_current = current == *tag;
47 let bullet = if is_current { "●" } else { "○" };
48 let bullet_color = if is_current {
49 palette::DEEPSEEK_BLUE
50 } else {
51 palette::TEXT_MUTED
52 };
53 let mut spans: Vec<Span<'static>> = vec![
54 Span::styled(format!(" {bullet} "), Style::default().fg(bullet_color)),
55 Span::styled(
56 format!("[{hotkey}] "),
57 Style::default()
58 .fg(palette::TEXT_PRIMARY)
59 .add_modifier(Modifier::BOLD),
60 ),
61 Span::styled(
62 native.to_string(),
63 Style::default().fg(palette::TEXT_PRIMARY),
64 ),
65 ];
66 if !english.is_empty() {
67 spans.push(Span::styled(
68 format!(" {english}"),
69 Style::default().fg(palette::TEXT_MUTED),
70 ));
71 }
72 out.push(Line::from(spans));
73 }
74
75 out.push(Line::from(""));
76 out.push(Line::from(vec![
77 Span::styled("Press ", Style::default().fg(palette::TEXT_MUTED)),
78 Span::styled(
79 "1-5",
80 Style::default()
81 .fg(palette::TEXT_PRIMARY)
82 .add_modifier(Modifier::BOLD),
83 ),
84 Span::styled(" to choose, or ", Style::default().fg(palette::TEXT_MUTED)),
85 Span::styled(
86 "Enter",
87 Style::default()
88 .fg(palette::TEXT_PRIMARY)
89 .add_modifier(Modifier::BOLD),
90 ),
91 Span::styled(
92 " to keep the current setting",
93 Style::default().fg(palette::TEXT_MUTED),
94 ),
95 ]));
96
97 out
98 }
99
99 lines RUST