i18n: localize pending-input preview messages#2929
Conversation
- Add 10 MessageIds for PendingInput surface (section headers, delivery-mode labels, action hints) - Store locale on PendingInputPreview widget; thread through from build_pending_input_preview in ui.rs - Replace hardcoded prefix constants with tr()-based helpers - Keep layout characters (arrows, indentation) hardcoded
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Code Review
This pull request introduces localization support for the pending input preview widget, adding new message IDs and translations across multiple languages, and updating the widget to render localized strings based on the active locale. The reviewer feedback focuses on performance optimizations in the rendering path, specifically avoiding unnecessary heap allocations and string formatting, as well as correcting a translation inconsistency in Traditional Chinese.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| push_section_header( | ||
| &mut lines, | ||
| Line::from(vec![Span::raw("• "), Span::raw("Context for next send")]), | ||
| Line::from(vec![ | ||
| Span::raw("• "), | ||
| Span::raw(tr(self.locale, MessageId::PendingContextHeader).to_string()), | ||
| ]), | ||
| ); |
There was a problem hiding this comment.
Unnecessary heap allocation. tr returns a &'static str, which can be coerced directly into Span::raw without calling .to_string(). This avoids a heap allocation in the rendering path.
| push_section_header( | |
| &mut lines, | |
| Line::from(vec![Span::raw("• "), Span::raw("Context for next send")]), | |
| Line::from(vec![ | |
| Span::raw("• "), | |
| Span::raw(tr(self.locale, MessageId::PendingContextHeader).to_string()), | |
| ]), | |
| ); | |
| push_section_header( | |
| &mut lines, | |
| Line::from(vec![ | |
| Span::raw("• "), | |
| Span::raw(tr(self.locale, MessageId::PendingContextHeader)), | |
| ]), | |
| ); |
| push_section_header( | ||
| &mut lines, | ||
| Line::from(vec![Span::raw("• "), Span::raw("Pending inputs")]), | ||
| Line::from(vec![ | ||
| Span::raw("• "), | ||
| Span::raw(tr(self.locale, MessageId::PendingInputHeader).to_string()), | ||
| ]), | ||
| ); |
There was a problem hiding this comment.
Unnecessary heap allocation. tr returns a &'static str, which can be coerced directly into Span::raw without calling .to_string(). This avoids a heap allocation in the rendering path.
| push_section_header( | |
| &mut lines, | |
| Line::from(vec![Span::raw("• "), Span::raw("Pending inputs")]), | |
| Line::from(vec![ | |
| Span::raw("• "), | |
| Span::raw(tr(self.locale, MessageId::PendingInputHeader).to_string()), | |
| ]), | |
| ); | |
| push_section_header( | |
| &mut lines, | |
| Line::from(vec![ | |
| Span::raw("• "), | |
| Span::raw(tr(self.locale, MessageId::PendingInputHeader)), | |
| ]), | |
| ); |
| lines.push(Line::from(vec![Span::styled( | ||
| " Esc restores queued follow-up".to_string(), | ||
| format!(" {}", tr(self.locale, MessageId::PendingRestoreHint)), | ||
| dim, | ||
| )])); |
There was a problem hiding this comment.
Unnecessary heap allocation. Instead of using format! to prepend spaces to the translated hint, we can construct the Line with separate Spans. This avoids a heap allocation in the rendering path.
| lines.push(Line::from(vec![Span::styled( | |
| " Esc restores queued follow-up".to_string(), | |
| format!(" {}", tr(self.locale, MessageId::PendingRestoreHint)), | |
| dim, | |
| )])); | |
| lines.push(Line::from(vec![ | |
| Span::styled(" ", dim), | |
| Span::styled(tr(self.locale, MessageId::PendingRestoreHint), dim), | |
| ])); |
| lines.push(Line::from(vec![Span::styled( | ||
| format!(" {} edit last queued message", self.edit_binding.label), | ||
| format!( | ||
| " {}", | ||
| tr(self.locale, MessageId::PendingEditHint) | ||
| .replace("{key}", self.edit_binding.label) | ||
| ), | ||
| dim, | ||
| )])); |
There was a problem hiding this comment.
Unnecessary heap allocation. Instead of using format! to prepend spaces to the translated hint, we can construct the Line with separate Spans. This avoids a heap allocation in the rendering path.
if !self.queued_messages.is_empty() {
lines.push(Line::from(vec![
Span::styled(" ", dim),
Span::styled(
tr(self.locale, MessageId::PendingEditHint)
.replace("{key}", self.edit_binding.label),
dim,
),
]));
}| let action = if item.selected { | ||
| " · Backspace/Delete removes" | ||
| format!(" · {}", tr(locale, MessageId::PendingDeleteHint)) | ||
| } else if item.removable { | ||
| " · removable" | ||
| format!(" · {}", tr(locale, MessageId::PendingRemovable)) | ||
| } else { | ||
| "" | ||
| String::new() | ||
| }; | ||
| let body = format!("[{}] {}{}{}", item.kind, item.label, detail, action); |
There was a problem hiding this comment.
Unnecessary double formatting and heap allocations. Instead of formatting action as an intermediate String and then formatting it again into body, we can determine the action label first and perform a single formatting step. This is cleaner and more efficient.
let action_label = if item.selected {
Some(tr(locale, MessageId::PendingDeleteHint))
} else if item.removable {
Some(tr(locale, MessageId::PendingRemovable))
} else {
None
};
let body = if let Some(label) = action_label {
format!("[{}] {}{} · {}", item.kind, item.label, detail, label)
} else {
format!("[{}] {}{}", item.kind, item.label, detail)
};| MessageId::PendingQueuedLabel => "已排隊後續消息:", | ||
| MessageId::PendingEditingLabel => "正在編輯已排隊的後續消息:", | ||
| MessageId::PendingRestoreHint => "Esc 恢復已排隊的後續消息", | ||
| MessageId::PendingEditHint => "{key} 編輯最後一條已排隊消息", |
There was a problem hiding this comment.
In Traditional Chinese (especially Taiwan/Hong Kong), "訊息" is the standard translation for "message" (as in chat messages, API messages), which is already used elsewhere in this file (e.g., MessageId::CtxInspApiMessages => "API 訊息"). "消息" is more commonly used in Simplified Chinese. Let's use "訊息" consistently for Traditional Chinese.
| MessageId::PendingQueuedLabel => "已排隊後續消息:", | |
| MessageId::PendingEditingLabel => "正在編輯已排隊的後續消息:", | |
| MessageId::PendingRestoreHint => "Esc 恢復已排隊的後續消息", | |
| MessageId::PendingEditHint => "{key} 編輯最後一條已排隊消息", | |
| MessageId::PendingQueuedLabel => "已排隊後續訊息:", | |
| MessageId::PendingEditingLabel => "正在編輯已排隊的後續訊息:", | |
| MessageId::PendingRestoreHint => "Esc 恢復已排隊的後續訊息", | |
| MessageId::PendingEditHint => "{key} 編輯最後一條已排隊訊息", |
- Remove unnecessary .to_string() on tr() results (2 spots) - Use separate Span for indentation + hint text instead of format! - Single-step action label formatting in push_context_item - Fix Traditional Chinese: 消息 → 訊息 for consistency
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
All 6 review items addressed in dcded84: 1-2. Removed on results for section headers |
|
Thanks @gordonlu — we merged #2891 and #2896 from your i18n batch tonight, which moved Since the slices all touch |
Summary
Localize the PendingInput preview widget (10 MessageIds) across all 7 shipped locales.
Section headers
PendingContextHeader—"Context for next send"PendingInputHeader—"Pending inputs"Delivery-mode labels
PendingSteerLabel—"Steer pending: "PendingRejectedLabel—"Rejected steer: "PendingQueuedLabel—"Queued follow-up: "PendingEditingLabel—"Editing queued follow-up: "Action hints
PendingRestoreHint—"Esc restores queued follow-up"PendingEditHint—"{key} edit last queued message"PendingDeleteHint—"Backspace/Delete removes"PendingRemovable—"removable"Infrastructure
locale: Localefield toPendingInputPreviewwidgetPENDING_STEER_PREFIX, etc.) into dynamictr()-based helpersbuild_pending_input_preview(app)inui.rs↳,▸, indentation) remain hardcodedVerification
cargo clippy: cleancargo fmt --all --check: clean