Skip to content

Commit 2bdf8be

Browse files
montfortclaude
andauthored
fix(cli): translate metadata panel and welcome screen (cli-3.5.1) (#62)
The 3.5.0 i18n pass covered the navigation tree, status bar, and help popup but missed two surfaces that stay visible on every session: the Metadata panel (title plus all field labels) and the Document panel's welcome screen (panel title plus the "DevTrail Explorer" landing page). Add ~25 new entries to tui::i18n_strings::t and wire them into both widgets. Field labels in the Metadata panel are padded to a single visual-column width (LABEL_WIDTH = 13) so values line up across en, es (longer words like "Confianza:") and zh-CN (shorter, e.g. "状态:"). Brand and company strings ("DevTrail Explorer", "Strange Days Tech") stay in their canonical form on purpose. Frontmatter values themselves remain unchanged — those are authored content read directly from each markdown file, not UI strings. Patch bump 3.5.0 → 3.5.1, CHANGELOG entry, and 6 doc files updated. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cb026b3 commit 2bdf8be

12 files changed

Lines changed: 182 additions & 60 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project uses [independent versioning](README.md#versioning) for Framewo
77

88
---
99

10+
## CLI 3.5.1 — Metadata Panel and Welcome Screen i18n Coverage
11+
12+
### Fixed (CLI)
13+
- The Metadata panel (title `Metadata`, the empty-state `No document selected`, and field labels `Status:`, `Created:`, `Agent:`, `Confidence:`, `Risk:`, `Review:`, `Tags:`, `Related:`, plus the `(Enter: search)` / `(Enter: follow)` hints and `⚠ REQUIRED`) now switches with the active language. Field labels are padded to a consistent visual width so values stay aligned across `en` / `es` / `zh-CN`.
14+
- The Document panel title and welcome screen (`DevTrail Explorer` brand line aside) now translate: `Documentation Governance for AI-Assisted Development`, `Total documents:`, `Quick start`, the keyboard-shortcut descriptions, `Developed by`, and the repo-root fallback notice. Brand and company names stay in their canonical form on purpose.
15+
- Frontmatter values themselves (status, tags, related IDs, dates) are still read verbatim from each document — they're authored content, not UI strings.
16+
17+
---
18+
1019
## CLI 3.5.0 — TUI i18n Polish: Translated Shell, Live Switcher, Locale Auto-Detect
1120

1221
Three changes that complete the language-aware `devtrail explore` work started in 3.4.0. Together they make the TUI feel native to non-English users instead of just "translated docs inside an English shell."

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ DevTrail uses independent version tags for each component:
207207
| Component | Tag prefix | Example | Includes |
208208
|-----------|-----------|---------|----------|
209209
| Framework | `fw-` | `fw-4.3.0` | Templates (12 types), governance, directives |
210-
| CLI | `cli-` | `cli-3.5.0` | The `devtrail` binary |
210+
| CLI | `cli-` | `cli-3.5.1` | The `devtrail` binary |
211211

212212
Check installed versions with `devtrail status` or `devtrail about`.
213213

cli/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "devtrail-cli"
3-
version = "3.5.0"
3+
version = "3.5.1"
44
edition = "2021"
55
description = "CLI tool for DevTrail - Documentation Governance for AI-Assisted Development"
66
license = "MIT"

cli/src/tui/i18n_strings.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,80 @@ pub fn t<'a>(en: &'a str, lang: &str) -> &'a str {
153153
("Cycle display language", "zh-CN") => "切换显示语言",
154154
("Language", "es") => "Idioma",
155155
("Language", "zh-CN") => "语言",
156+
157+
// ── Metadata panel ────────────────────────────────────────────
158+
("Metadata", "es") => "Metadatos",
159+
("Metadata", "zh-CN") => "元数据",
160+
("No document selected", "es") => "Sin documento seleccionado",
161+
("No document selected", "zh-CN") => "未选择文档",
162+
("File:", "es") => "Archivo:",
163+
("File:", "zh-CN") => "文件:",
164+
("No frontmatter", "es") => "Sin frontmatter",
165+
("No frontmatter", "zh-CN") => "无 frontmatter",
166+
("Status:", "es") => "Estado:",
167+
("Status:", "zh-CN") => "状态:",
168+
("Created:", "es") => "Creado:",
169+
("Created:", "zh-CN") => "创建:",
170+
("Agent:", "es") => "Agente:",
171+
("Agent:", "zh-CN") => "代理:",
172+
("Confidence:", "es") => "Confianza:",
173+
("Confidence:", "zh-CN") => "可信度:",
174+
("Risk:", "es") => "Riesgo:",
175+
("Risk:", "zh-CN") => "风险:",
176+
("Review:", "es") => "Revisión:",
177+
("Review:", "zh-CN") => "审查:",
178+
("⚠ REQUIRED", "es") => "⚠ REQUERIDA",
179+
("⚠ REQUIRED", "zh-CN") => "⚠ 需要",
180+
("Tags:", "es") => "Etiquetas:",
181+
("Tags:", "zh-CN") => "标签:",
182+
("Related:", "es") => "Relacionados:",
183+
("Related:", "zh-CN") => "关联:",
184+
(" (Enter: search)", "es") => " (Enter: buscar)",
185+
(" (Enter: search)", "zh-CN") => "(Enter: 搜索)",
186+
(" (Enter: follow)", "es") => " (Enter: seguir)",
187+
(" (Enter: follow)", "zh-CN") => "(Enter: 跳转)",
188+
189+
// ── Document panel ────────────────────────────────────────────
190+
("Document", "es") => "Documento",
191+
("Document", "zh-CN") => "文档",
192+
193+
// ── Welcome screen (empty doc state) ──────────────────────────
194+
("Documentation Governance for AI-Assisted Development", "es") => {
195+
"Gobernanza de documentación para desarrollo asistido por IA"
196+
}
197+
("Documentation Governance for AI-Assisted Development", "zh-CN") => {
198+
"AI 辅助开发的文档治理"
199+
}
200+
("Using repo root: ", "es") => "Usando raíz del repo: ",
201+
("Using repo root: ", "zh-CN") => "使用仓库根目录:",
202+
("Total documents: ", "es") => "Total de documentos: ",
203+
("Total documents: ", "zh-CN") => "文档总数:",
204+
("Quick start", "es") => "Inicio rápido",
205+
("Quick start", "zh-CN") => "快速开始",
206+
("Navigate groups in the left panel", "es") => {
207+
"Navega grupos en el panel izquierdo"
208+
}
209+
("Navigate groups in the left panel", "zh-CN") => "在左侧面板中导航分组",
210+
("Expand a group and open a document", "es") => {
211+
"Expande un grupo y abre un documento"
212+
}
213+
("Expand a group and open a document", "zh-CN") => "展开分组并打开文档",
214+
("Next panel / ", "es") => "Panel siguiente / ",
215+
("Next panel / ", "zh-CN") => "下一面板 / ",
216+
("Previous panel", "es") => "Panel anterior",
217+
("Previous panel", "zh-CN") => "上一面板",
218+
("Search by filename, title, tags, or date", "es") => {
219+
"Buscar por archivo, título, etiquetas o fecha"
220+
}
221+
("Search by filename, title, tags, or date", "zh-CN") => {
222+
"按文件名、标题、标签或日期搜索"
223+
}
224+
("Toggle document fullscreen", "es") => "Alternar pantalla completa",
225+
("Toggle document fullscreen", "zh-CN") => "切换文档全屏",
226+
("Show all keyboard shortcuts", "es") => "Mostrar todos los atajos",
227+
("Show all keyboard shortcuts", "zh-CN") => "显示所有快捷键",
228+
("Developed by ", "es") => "Desarrollado por ",
229+
("Developed by ", "zh-CN") => "由 ",
156230
("Quit", "es") => "Salir",
157231
("Quit", "zh-CN") => "退出",
158232
("Force quit", "es") => "Forzar salida",

cli/src/tui/widgets/doc_viewer.rs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use ratatui::widgets::{Block, Borders, Paragraph, Scrollbar, ScrollbarOrientatio
66
use unicode_width::UnicodeWidthStr;
77

88
use crate::tui::app::{ActivePanel, App};
9+
use crate::tui::i18n_strings::t;
910
use crate::tui::markdown::markdown_to_lines;
1011
use crate::tui::theme;
1112

@@ -26,9 +27,10 @@ impl<'a> DocViewer<'a> {
2627
Style::default().fg(theme::SUBTLE)
2728
};
2829

30+
let lang = self.app.language.as_str();
2931
let title = match &self.app.current_doc {
3032
Some(doc) => format!(" {} ", doc.filename),
31-
None => " Document ".to_string(),
33+
None => format!(" {} ", t("Document", lang)),
3234
};
3335

3436
let block = Block::default()
@@ -53,7 +55,7 @@ impl<'a> DocViewer<'a> {
5355
} else {
5456
None
5557
};
56-
let welcome = render_welcome(self.app.index.total_docs, fallback_info);
58+
let welcome = render_welcome(self.app.index.total_docs, fallback_info, lang);
5759
let paragraph = Paragraph::new(welcome);
5860
paragraph.render(inner, buf);
5961
return;
@@ -129,7 +131,11 @@ impl<'a> DocViewer<'a> {
129131
}
130132
}
131133

132-
fn render_welcome(total_docs: usize, fallback_path: Option<String>) -> Vec<Line<'static>> {
134+
fn render_welcome(
135+
total_docs: usize,
136+
fallback_path: Option<String>,
137+
lang: &str,
138+
) -> Vec<Line<'static>> {
133139
let title = Style::default()
134140
.fg(theme::ACCENT)
135141
.add_modifier(Modifier::BOLD);
@@ -142,69 +148,86 @@ fn render_welcome(total_docs: usize, fallback_path: Option<String>) -> Vec<Line<
142148
let mut lines = vec![
143149
Line::from(""),
144150
Line::from(""),
151+
// Brand name stays English in every locale.
145152
Line::from(Span::styled(" DevTrail Explorer", title)),
146153
Line::from(Span::styled(
147-
" Documentation Governance for AI-Assisted Development",
154+
format!(
155+
" {}",
156+
t("Documentation Governance for AI-Assisted Development", lang)
157+
),
148158
dim,
149159
)),
150160
];
151161

152162
if let Some(ref path) = fallback_path {
153163
lines.push(Line::from(""));
154164
lines.push(Line::from(vec![
155-
Span::styled(" → Using repo root: ", Style::default().fg(Color::Yellow)),
165+
Span::styled(
166+
format!(" → {}", t("Using repo root: ", lang)),
167+
Style::default().fg(Color::Yellow),
168+
),
156169
Span::styled(path.clone(), text),
157170
]));
158171
}
159172

160173
lines.push(Line::from(""));
161174
lines.push(Line::from(vec![
162-
Span::styled(" Total documents: ", dim),
175+
Span::styled(format!(" {}", t("Total documents: ", lang)), dim),
163176
Span::styled(
164177
total_docs.to_string(),
165178
text.add_modifier(Modifier::BOLD),
166179
),
167180
]));
168181
lines.push(Line::from(""));
169-
lines.push(Line::from(Span::styled(" Quick start", title)));
182+
lines.push(Line::from(Span::styled(
183+
format!(" {}", t("Quick start", lang)),
184+
title,
185+
)));
170186
lines.push(Line::from(""));
171187
lines.push(Line::from(vec![
172188
Span::styled(" ↑↓ ", key),
173-
Span::styled("Navigate groups in the left panel", text),
189+
Span::styled(t("Navigate groups in the left panel", lang).to_string(), text),
174190
]));
175191
lines.push(Line::from(vec![
176192
Span::styled(" Enter ", key),
177-
Span::styled("Expand a group and open a document", text),
193+
Span::styled(
194+
t("Expand a group and open a document", lang).to_string(),
195+
text,
196+
),
178197
]));
179198
lines.push(Line::from(vec![
180199
Span::styled(" Tab ", key),
181-
Span::styled("Next panel / ", text),
200+
Span::styled(t("Next panel / ", lang).to_string(), text),
182201
Span::styled("Shift+Tab ", key),
183-
Span::styled("Previous panel", text),
202+
Span::styled(t("Previous panel", lang).to_string(), text),
184203
]));
185204
lines.push(Line::from(vec![
186205
Span::styled(" / ", key),
187-
Span::styled("Search by filename, title, tags, or date", text),
206+
Span::styled(
207+
t("Search by filename, title, tags, or date", lang).to_string(),
208+
text,
209+
),
188210
]));
189211
lines.push(Line::from(vec![
190212
Span::styled(" f ", key),
191-
Span::styled("Toggle document fullscreen", text),
213+
Span::styled(t("Toggle document fullscreen", lang).to_string(), text),
192214
]));
193215
lines.push(Line::from(vec![
194216
Span::styled(" ? ", key),
195-
Span::styled("Show all keyboard shortcuts", text),
217+
Span::styled(t("Show all keyboard shortcuts", lang).to_string(), text),
196218
]));
197219
lines.push(Line::from(vec![
198220
Span::styled(" q ", key),
199-
Span::styled("Quit", text),
221+
Span::styled(t("Quit", lang).to_string(), text),
200222
]));
201223
lines.push(Line::from(""));
202224
lines.push(Line::from(Span::styled(
203225
" ─────────────────────────────────────────────",
204226
dim,
205227
)));
206228
lines.push(Line::from(vec![
207-
Span::styled(" Developed by ", dim),
229+
Span::styled(format!(" {}", t("Developed by ", lang)), dim),
230+
// Company name stays in its canonical form.
208231
Span::styled("Strange Days Tech, S.A.S.", text),
209232
]));
210233
lines.push(Line::from(vec![

0 commit comments

Comments
 (0)