feat(i18n): localize ToolFamily labels (10 MessageIds) (#2901)
* feat(i18n): localize ToolFamily labels (10 MessageIds) - localization.rs: Add 10 ToolFamily* MessageId variants + ALL_MESSAGE_IDS + all 7 locales - tool_card.rs: tool_activity_label_for_name() accepts locale, uses tr() for labels - footer_ui.rs, ui.rs: thread locale to tool_activity_label_for_name() callers - Tests: 2 negative i18n tests + updated existing tests for new signatures * chore: add .claude/ to gitignore * fixup: make tool_display_label_for_name private + deduplicate family→MessageId mapping --------- Co-authored-by: gordonlu <gordonlu@users.noreply.github.com>
This commit is contained in:
@@ -120,6 +120,7 @@ docs/*_PLAN.md
|
|||||||
.envrc
|
.envrc
|
||||||
.direnv
|
.direnv
|
||||||
scripts/run_deep_swe.py
|
scripts/run_deep_swe.py
|
||||||
|
.claude/
|
||||||
|
|
||||||
# Benchmark artifacts and caches re-included by !scripts/**
|
# Benchmark artifacts and caches re-included by !scripts/**
|
||||||
results/
|
results/
|
||||||
|
|||||||
@@ -610,6 +610,17 @@ pub enum MessageId {
|
|||||||
CtxInspChangesByTurn,
|
CtxInspChangesByTurn,
|
||||||
CtxInspStablePrefixOnly,
|
CtxInspStablePrefixOnly,
|
||||||
CtxInspCacheTip,
|
CtxInspCacheTip,
|
||||||
|
// Tool family labels (card headers, sidebar, footer).
|
||||||
|
ToolFamilyRead,
|
||||||
|
ToolFamilyPatch,
|
||||||
|
ToolFamilyRun,
|
||||||
|
ToolFamilyFind,
|
||||||
|
ToolFamilyDelegate,
|
||||||
|
ToolFamilyFanout,
|
||||||
|
ToolFamilyRlm,
|
||||||
|
ToolFamilyVerify,
|
||||||
|
ToolFamilyThink,
|
||||||
|
ToolFamilyGeneric,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -990,6 +1001,16 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[
|
|||||||
MessageId::CtxInspChangesByTurn,
|
MessageId::CtxInspChangesByTurn,
|
||||||
MessageId::CtxInspStablePrefixOnly,
|
MessageId::CtxInspStablePrefixOnly,
|
||||||
MessageId::CtxInspCacheTip,
|
MessageId::CtxInspCacheTip,
|
||||||
|
MessageId::ToolFamilyRead,
|
||||||
|
MessageId::ToolFamilyPatch,
|
||||||
|
MessageId::ToolFamilyRun,
|
||||||
|
MessageId::ToolFamilyFind,
|
||||||
|
MessageId::ToolFamilyDelegate,
|
||||||
|
MessageId::ToolFamilyFanout,
|
||||||
|
MessageId::ToolFamilyRlm,
|
||||||
|
MessageId::ToolFamilyVerify,
|
||||||
|
MessageId::ToolFamilyThink,
|
||||||
|
MessageId::ToolFamilyGeneric,
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn tr(locale: Locale, id: MessageId) -> &'static str {
|
pub fn tr(locale: Locale, id: MessageId) -> &'static str {
|
||||||
@@ -1696,6 +1717,16 @@ fn english(id: MessageId) -> &'static str {
|
|||||||
"Tip: Stable prefix blocks are DeepSeek V4 prefix-cache eligible. \
|
"Tip: Stable prefix blocks are DeepSeek V4 prefix-cache eligible. \
|
||||||
Volatile working-set changes break the cache only for the tail."
|
Volatile working-set changes break the cache only for the tail."
|
||||||
}
|
}
|
||||||
|
MessageId::ToolFamilyRead => "read",
|
||||||
|
MessageId::ToolFamilyPatch => "patch",
|
||||||
|
MessageId::ToolFamilyRun => "run",
|
||||||
|
MessageId::ToolFamilyFind => "find",
|
||||||
|
MessageId::ToolFamilyDelegate => "delegate",
|
||||||
|
MessageId::ToolFamilyFanout => "fanout",
|
||||||
|
MessageId::ToolFamilyRlm => "rlm",
|
||||||
|
MessageId::ToolFamilyVerify => "verify",
|
||||||
|
MessageId::ToolFamilyThink => "think",
|
||||||
|
MessageId::ToolFamilyGeneric => "tool",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2270,6 +2301,16 @@ fn vietnamese(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CtxInspCacheTip => {
|
MessageId::CtxInspCacheTip => {
|
||||||
"Gợi ý: Các khối ổn định đủ điều kiện cho bộ nhớ đệm tiền tố DeepSeek V4. Thay đổi vùng làm việc chỉ phá vỡ bộ nhớ đệm ở phần cuối."
|
"Gợi ý: Các khối ổn định đủ điều kiện cho bộ nhớ đệm tiền tố DeepSeek V4. Thay đổi vùng làm việc chỉ phá vỡ bộ nhớ đệm ở phần cuối."
|
||||||
}
|
}
|
||||||
|
MessageId::ToolFamilyRead => "đọc",
|
||||||
|
MessageId::ToolFamilyPatch => "vá",
|
||||||
|
MessageId::ToolFamilyRun => "chạy",
|
||||||
|
MessageId::ToolFamilyFind => "tìm",
|
||||||
|
MessageId::ToolFamilyDelegate => "ủy quyền",
|
||||||
|
MessageId::ToolFamilyFanout => "fanout",
|
||||||
|
MessageId::ToolFamilyRlm => "rlm",
|
||||||
|
MessageId::ToolFamilyVerify => "xác minh",
|
||||||
|
MessageId::ToolFamilyThink => "suy nghĩ",
|
||||||
|
MessageId::ToolFamilyGeneric => "công cụ",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2398,6 +2439,16 @@ fn traditional_chinese(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::StatusPickerActionNone => "無 ",
|
MessageId::StatusPickerActionNone => "無 ",
|
||||||
MessageId::StatusPickerActionSave => "儲存 ",
|
MessageId::StatusPickerActionSave => "儲存 ",
|
||||||
MessageId::StatusPickerActionCancel => "取消 ",
|
MessageId::StatusPickerActionCancel => "取消 ",
|
||||||
|
MessageId::ToolFamilyRead => "讀取",
|
||||||
|
MessageId::ToolFamilyPatch => "修補",
|
||||||
|
MessageId::ToolFamilyRun => "執行",
|
||||||
|
MessageId::ToolFamilyFind => "搜尋",
|
||||||
|
MessageId::ToolFamilyDelegate => "委派",
|
||||||
|
MessageId::ToolFamilyFanout => "扇出",
|
||||||
|
MessageId::ToolFamilyRlm => "rlm",
|
||||||
|
MessageId::ToolFamilyVerify => "驗證",
|
||||||
|
MessageId::ToolFamilyThink => "思考",
|
||||||
|
MessageId::ToolFamilyGeneric => "工具",
|
||||||
other => chinese_simplified(other)?,
|
other => chinese_simplified(other)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -2931,6 +2982,16 @@ fn japanese(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CtxInspCacheTip => {
|
MessageId::CtxInspCacheTip => {
|
||||||
"ヒント:安定プレフィックスブロックはDeepSeek V4プレフィックスキャッシュの対象です。揮発性ワーキングセットの変更は末尾のキャッシュのみを破壊します。"
|
"ヒント:安定プレフィックスブロックはDeepSeek V4プレフィックスキャッシュの対象です。揮発性ワーキングセットの変更は末尾のキャッシュのみを破壊します。"
|
||||||
}
|
}
|
||||||
|
MessageId::ToolFamilyRead => "読込",
|
||||||
|
MessageId::ToolFamilyPatch => "パッチ",
|
||||||
|
MessageId::ToolFamilyRun => "実行",
|
||||||
|
MessageId::ToolFamilyFind => "検索",
|
||||||
|
MessageId::ToolFamilyDelegate => "委任",
|
||||||
|
MessageId::ToolFamilyFanout => "ファンアウト",
|
||||||
|
MessageId::ToolFamilyRlm => "rlm",
|
||||||
|
MessageId::ToolFamilyVerify => "検証",
|
||||||
|
MessageId::ToolFamilyThink => "思考",
|
||||||
|
MessageId::ToolFamilyGeneric => "ツール",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3399,6 +3460,16 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CtxInspCacheTip => {
|
MessageId::CtxInspCacheTip => {
|
||||||
"提示:稳定前缀区块符合 DeepSeek V4 前缀缓存条件。易变工作集的更改仅会破坏缓存尾部。"
|
"提示:稳定前缀区块符合 DeepSeek V4 前缀缓存条件。易变工作集的更改仅会破坏缓存尾部。"
|
||||||
}
|
}
|
||||||
|
MessageId::ToolFamilyRead => "读取",
|
||||||
|
MessageId::ToolFamilyPatch => "修补",
|
||||||
|
MessageId::ToolFamilyRun => "运行",
|
||||||
|
MessageId::ToolFamilyFind => "搜索",
|
||||||
|
MessageId::ToolFamilyDelegate => "委派",
|
||||||
|
MessageId::ToolFamilyFanout => "扇出",
|
||||||
|
MessageId::ToolFamilyRlm => "rlm",
|
||||||
|
MessageId::ToolFamilyVerify => "验证",
|
||||||
|
MessageId::ToolFamilyThink => "思考",
|
||||||
|
MessageId::ToolFamilyGeneric => "工具",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3957,6 +4028,16 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CtxInspCacheTip => {
|
MessageId::CtxInspCacheTip => {
|
||||||
"Dica: Blocos de prefixo estável são elegíveis para cache de prefixo DeepSeek V4. Alterações no conjunto de trabalho volátil quebram o cache apenas no final."
|
"Dica: Blocos de prefixo estável são elegíveis para cache de prefixo DeepSeek V4. Alterações no conjunto de trabalho volátil quebram o cache apenas no final."
|
||||||
}
|
}
|
||||||
|
MessageId::ToolFamilyRead => "ler",
|
||||||
|
MessageId::ToolFamilyPatch => "corrigir",
|
||||||
|
MessageId::ToolFamilyRun => "executar",
|
||||||
|
MessageId::ToolFamilyFind => "buscar",
|
||||||
|
MessageId::ToolFamilyDelegate => "delegar",
|
||||||
|
MessageId::ToolFamilyFanout => "fanout",
|
||||||
|
MessageId::ToolFamilyRlm => "rlm",
|
||||||
|
MessageId::ToolFamilyVerify => "verificar",
|
||||||
|
MessageId::ToolFamilyThink => "pensar",
|
||||||
|
MessageId::ToolFamilyGeneric => "ferramenta",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4525,6 +4606,16 @@ fn spanish_latin_america(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CtxInspCacheTip => {
|
MessageId::CtxInspCacheTip => {
|
||||||
"Consejo: Los bloques de prefijo estable son elegibles para caché de prefijo DeepSeek V4. Los cambios en el conjunto de trabajo volátil solo rompen la caché al final."
|
"Consejo: Los bloques de prefijo estable son elegibles para caché de prefijo DeepSeek V4. Los cambios en el conjunto de trabajo volátil solo rompen la caché al final."
|
||||||
}
|
}
|
||||||
|
MessageId::ToolFamilyRead => "leer",
|
||||||
|
MessageId::ToolFamilyPatch => "parchear",
|
||||||
|
MessageId::ToolFamilyRun => "ejecutar",
|
||||||
|
MessageId::ToolFamilyFind => "buscar",
|
||||||
|
MessageId::ToolFamilyDelegate => "delegar",
|
||||||
|
MessageId::ToolFamilyFanout => "fanout",
|
||||||
|
MessageId::ToolFamilyRlm => "rlm",
|
||||||
|
MessageId::ToolFamilyVerify => "verificar",
|
||||||
|
MessageId::ToolFamilyThink => "pensar",
|
||||||
|
MessageId::ToolFamilyGeneric => "herramienta",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::time::Instant;
|
|||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::core::coherence::CoherenceState;
|
use crate::core::coherence::CoherenceState;
|
||||||
use crate::localization::MessageId;
|
use crate::localization::{Locale, MessageId};
|
||||||
use crate::palette;
|
use crate::palette;
|
||||||
use crate::tools::subagent::SubAgentStatus;
|
use crate::tools::subagent::SubAgentStatus;
|
||||||
use crate::tui::app::App;
|
use crate::tui::app::App;
|
||||||
@@ -314,7 +314,7 @@ pub(crate) fn active_tool_status_label(app: &App) -> Option<String> {
|
|||||||
|
|
||||||
let mut snapshot = ActiveToolStatusSnapshot::default();
|
let mut snapshot = ActiveToolStatusSnapshot::default();
|
||||||
for cell in active.entries() {
|
for cell in active.entries() {
|
||||||
collect_active_tool_status(cell, &mut snapshot);
|
collect_active_tool_status(cell, &mut snapshot, app.ui_locale);
|
||||||
}
|
}
|
||||||
if snapshot.total() == 0 {
|
if snapshot.total() == 0 {
|
||||||
return None;
|
return None;
|
||||||
@@ -345,7 +345,11 @@ pub(crate) fn active_tool_status_label(app: &App) -> Option<String> {
|
|||||||
Some(parts.join(" \u{00B7} "))
|
Some(parts.join(" \u{00B7} "))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_active_tool_status(cell: &HistoryCell, snapshot: &mut ActiveToolStatusSnapshot) {
|
fn collect_active_tool_status(
|
||||||
|
cell: &HistoryCell,
|
||||||
|
snapshot: &mut ActiveToolStatusSnapshot,
|
||||||
|
locale: Locale,
|
||||||
|
) {
|
||||||
let HistoryCell::Tool(tool) = cell else {
|
let HistoryCell::Tool(tool) = cell else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -401,7 +405,7 @@ fn collect_active_tool_status(cell: &HistoryCell, snapshot: &mut ActiveToolStatu
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snapshot.record(
|
snapshot.record(
|
||||||
tool_activity_label_for_name(&generic.name),
|
tool_activity_label_for_name(&generic.name, locale),
|
||||||
generic.status,
|
generic.status,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9523,7 +9523,10 @@ fn activity_cell_label(app: &App, cell_index: usize, cell: &HistoryCell) -> Stri
|
|||||||
HistoryCell::Error { .. } => "error".to_string(),
|
HistoryCell::Error { .. } => "error".to_string(),
|
||||||
HistoryCell::SubAgent(_) => "sub-agent".to_string(),
|
HistoryCell::SubAgent(_) => "sub-agent".to_string(),
|
||||||
HistoryCell::Tool(ToolCell::Generic(generic)) => {
|
HistoryCell::Tool(ToolCell::Generic(generic)) => {
|
||||||
crate::tui::widgets::tool_card::tool_activity_label_for_name(&generic.name)
|
crate::tui::widgets::tool_card::tool_activity_label_for_name(
|
||||||
|
&generic.name,
|
||||||
|
app.ui_locale,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
HistoryCell::Tool(_) => {
|
HistoryCell::Tool(_) => {
|
||||||
detail_target_label(app, cell_index).unwrap_or_else(|| "tool activity".to_string())
|
detail_target_label(app, cell_index).unwrap_or_else(|| "tool activity".to_string())
|
||||||
@@ -9958,9 +9961,12 @@ pub(crate) fn detail_target_label(app: &App, cell_index: usize) -> Option<String
|
|||||||
Some(format!("image {}", image.path.display()))
|
Some(format!("image {}", image.path.display()))
|
||||||
}
|
}
|
||||||
HistoryCell::Tool(ToolCell::WebSearch(search)) => Some(format!("search {}", search.query)),
|
HistoryCell::Tool(ToolCell::WebSearch(search)) => Some(format!("search {}", search.query)),
|
||||||
HistoryCell::Tool(ToolCell::Generic(generic)) => {
|
HistoryCell::Tool(ToolCell::Generic(generic)) => Some(
|
||||||
Some(crate::tui::widgets::tool_card::tool_activity_label_for_name(&generic.name))
|
crate::tui::widgets::tool_card::tool_activity_label_for_name(
|
||||||
}
|
&generic.name,
|
||||||
|
app.ui_locale,
|
||||||
|
),
|
||||||
|
),
|
||||||
HistoryCell::SubAgent(_) => Some("sub-agent".to_string()),
|
HistoryCell::SubAgent(_) => Some("sub-agent".to_string()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
//! module is the vocabulary, not the layout engine. Keeping it small means
|
//! module is the vocabulary, not the layout engine. Keeping it small means
|
||||||
//! a future visual refresh only has to touch the constants here.
|
//! a future visual refresh only has to touch the constants here.
|
||||||
|
|
||||||
|
use crate::localization::Locale;
|
||||||
|
|
||||||
/// Tool family — the verb the agent is performing. Used to pick a glyph
|
/// Tool family — the verb the agent is performing. Used to pick a glyph
|
||||||
/// and label for the card header.
|
/// and label for the card header.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -97,8 +99,9 @@ pub fn tool_family_for_name(name: &str) -> ToolFamily {
|
|||||||
|
|
||||||
/// User-facing label for an arbitrary tool name. Known tools collapse to the
|
/// User-facing label for an arbitrary tool name. Known tools collapse to the
|
||||||
/// semantic verb; unknown tools keep their exact name for debugging.
|
/// semantic verb; unknown tools keep their exact name for debugging.
|
||||||
|
#[cfg(test)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tool_display_label_for_name(name: &str) -> String {
|
fn tool_display_label_for_name(name: &str) -> String {
|
||||||
let family = tool_family_for_name(name);
|
let family = tool_family_for_name(name);
|
||||||
if matches!(family, ToolFamily::Generic) {
|
if matches!(family, ToolFamily::Generic) {
|
||||||
name.to_string()
|
name.to_string()
|
||||||
@@ -107,15 +110,31 @@ pub fn tool_display_label_for_name(name: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn family_message_id(family: ToolFamily) -> crate::localization::MessageId {
|
||||||
|
match family {
|
||||||
|
ToolFamily::Read => crate::localization::MessageId::ToolFamilyRead,
|
||||||
|
ToolFamily::Patch => crate::localization::MessageId::ToolFamilyPatch,
|
||||||
|
ToolFamily::Run => crate::localization::MessageId::ToolFamilyRun,
|
||||||
|
ToolFamily::Find => crate::localization::MessageId::ToolFamilyFind,
|
||||||
|
ToolFamily::Delegate => crate::localization::MessageId::ToolFamilyDelegate,
|
||||||
|
ToolFamily::Fanout => crate::localization::MessageId::ToolFamilyFanout,
|
||||||
|
ToolFamily::Rlm => crate::localization::MessageId::ToolFamilyRlm,
|
||||||
|
ToolFamily::Verify => crate::localization::MessageId::ToolFamilyVerify,
|
||||||
|
ToolFamily::Think => crate::localization::MessageId::ToolFamilyThink,
|
||||||
|
ToolFamily::Generic => crate::localization::MessageId::ToolFamilyGeneric,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Compact activity/status label for arbitrary tool names. Known built-ins use
|
/// Compact activity/status label for arbitrary tool names. Known built-ins use
|
||||||
/// the semantic verb; unknown tools keep the `tool NAME` form.
|
/// the semantic verb; unknown tools keep the `tool NAME` form.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tool_activity_label_for_name(name: &str) -> String {
|
pub fn tool_activity_label_for_name(name: &str, locale: Locale) -> String {
|
||||||
let family = tool_family_for_name(name);
|
let family = tool_family_for_name(name);
|
||||||
|
let mid = family_message_id(family);
|
||||||
if matches!(family, ToolFamily::Generic) {
|
if matches!(family, ToolFamily::Generic) {
|
||||||
format!("tool {name}")
|
format!("{} {name}", crate::localization::tr(locale, mid))
|
||||||
} else {
|
} else {
|
||||||
tool_display_label_for_name(name)
|
crate::localization::tr(locale, mid).to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +256,7 @@ mod tests {
|
|||||||
tool_display_label_for_name, tool_family_for_name, tool_family_for_title,
|
tool_display_label_for_name, tool_family_for_name, tool_family_for_title,
|
||||||
tool_header_summary_for_name,
|
tool_header_summary_for_name,
|
||||||
};
|
};
|
||||||
|
use crate::localization::{Locale, MessageId, tr};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn legacy_titles_route_to_expected_families() {
|
fn legacy_titles_route_to_expected_families() {
|
||||||
@@ -275,10 +295,16 @@ mod tests {
|
|||||||
"future_private_tool"
|
"future_private_tool"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(tool_activity_label_for_name("exec_shell"), "run");
|
|
||||||
assert_eq!(tool_activity_label_for_name("run_verifiers"), "verify");
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tool_activity_label_for_name("future_private_tool"),
|
tool_activity_label_for_name("exec_shell", Locale::En),
|
||||||
|
"run"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tool_activity_label_for_name("run_verifiers", Locale::En),
|
||||||
|
"verify"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tool_activity_label_for_name("future_private_tool", Locale::En),
|
||||||
"tool future_private_tool"
|
"tool future_private_tool"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -344,4 +370,80 @@ mod tests {
|
|||||||
assert_eq!(rail_glyph(CardRail::Bottom), "\u{2570}");
|
assert_eq!(rail_glyph(CardRail::Bottom), "\u{2570}");
|
||||||
assert!(rail_glyph(CardRail::Single).is_empty());
|
assert!(rail_glyph(CardRail::Single).is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tool_family_labels_localized_no_english_leak() {
|
||||||
|
let checks: &[(MessageId, &str, &str)] = &[
|
||||||
|
(MessageId::ToolFamilyRead, "read", "đọc,读,読,读取,ler,leer"),
|
||||||
|
(
|
||||||
|
MessageId::ToolFamilyPatch,
|
||||||
|
"patch",
|
||||||
|
"vá,補,パ,修补,corrigir,parchear",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
MessageId::ToolFamilyRun,
|
||||||
|
"run",
|
||||||
|
"chạy,執,実,运行,executar,ejecutar",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
MessageId::ToolFamilyFind,
|
||||||
|
"find",
|
||||||
|
"tìm,搜,検,搜索,buscar,buscar",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
MessageId::ToolFamilyVerify,
|
||||||
|
"verify",
|
||||||
|
"xác minh,驗,検,验,verificar,verificar",
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for locale in [
|
||||||
|
Locale::Ja,
|
||||||
|
Locale::ZhHans,
|
||||||
|
Locale::ZhHant,
|
||||||
|
Locale::PtBr,
|
||||||
|
Locale::Es419,
|
||||||
|
Locale::Vi,
|
||||||
|
] {
|
||||||
|
for (id, eng, _) in checks {
|
||||||
|
let msg = tr(locale, *id);
|
||||||
|
assert!(
|
||||||
|
!msg.eq_ignore_ascii_case(eng),
|
||||||
|
"{} leaked exact English '{}' for '{:?}': {msg}",
|
||||||
|
locale.tag(),
|
||||||
|
eng,
|
||||||
|
id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tool_family_activity_label_localized_no_english_leak() {
|
||||||
|
let known = [
|
||||||
|
"exec_shell",
|
||||||
|
"read_file",
|
||||||
|
"apply_patch",
|
||||||
|
"grep_files",
|
||||||
|
"run_verifiers",
|
||||||
|
];
|
||||||
|
let english_labels = ["run", "read", "patch", "find", "verify"];
|
||||||
|
for locale in [
|
||||||
|
Locale::Ja,
|
||||||
|
Locale::ZhHans,
|
||||||
|
Locale::ZhHant,
|
||||||
|
Locale::PtBr,
|
||||||
|
Locale::Es419,
|
||||||
|
Locale::Vi,
|
||||||
|
] {
|
||||||
|
for (tool, eng) in known.iter().zip(english_labels.iter()) {
|
||||||
|
let label = tool_activity_label_for_name(tool, locale);
|
||||||
|
assert!(
|
||||||
|
!label.eq_ignore_ascii_case(eng),
|
||||||
|
"{} leaked English '{}' for tool '{tool}': {label}",
|
||||||
|
locale.tag(),
|
||||||
|
eng,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user