Skip to content

feat(i18n): add FanoutCounts MessageId, wire into FanoutCard#2566

Open
gordonlu wants to merge 5 commits into
Hmbown:mainfrom
gordonlu:feat/i18n-fanout-card
Open

feat(i18n): add FanoutCounts MessageId, wire into FanoutCard#2566
gordonlu wants to merge 5 commits into
Hmbown:mainfrom
gordonlu:feat/i18n-fanout-card

Conversation

@gordonlu
Copy link
Copy Markdown
Contributor

@gordonlu gordonlu commented Jun 2, 2026

Summary

Add FanoutCounts MessageId and wire it into FanoutCard::render_lines() for i18n of the aggregate worker stats line.

Changes

  • localization.rs — new FanoutCounts variant with named placeholders ({done}, {running}, {failed}, {pending}) in all 7 shipped locales
  • agent_card.rs — add locale: Locale field to FanoutCard, new(kind, locale), render stats via tr(locale, FanoutCounts).replace(...)
  • subagent_routing.rs — pass app.ui_locale at the one production call site
  • views/mod.rs — test caller passes app.ui_locale

Testing

  • Existing fanout_card_aggregate_counts_match_dot_grid ensures English still renders correctly
  • New fanout_counts_are_localized smokes ZhHans output for 已完成/运行中/失败/等待中
  • All 19 fanout + localization tests pass, fmt + clippy clean

Greptile Summary

This PR adds i18n support for the fanout card's aggregate worker stats line, replacing a hardcoded English format string with a localized template resolved through the existing tr() / MessageId system. The locale is captured once at FanoutCard creation and stored as a struct field.

  • FanoutCounts is added to MessageId with translations in all 7 shipped locales (En, Vi, ZhHant, Ja, ZhHans, PtBr, Es419); the existing English fallback path in fallback_translation covers any future locale additions automatically.
  • FanoutCard::new gains a locale parameter; every call site (one production, one view test) is updated to pass app.ui_locale.
  • Two existing timer-based tests in ui/tests.rs are refactored to build their time values by addition rather than subtraction from Instant::now(), avoiding potential subtraction-before-boot panics on very short-running test environments.

Confidence Score: 5/5

Safe to merge — the change is well-scoped, all call sites are updated, and the fallback to English ensures no blank output even for future locale additions.

All seven shipped locales include the new FanoutCounts translation, the existing English fallback covers any gaps, every FanoutCard::new call site has been updated, and the new localization test verifies Chinese Simplified output end-to-end. The timer-test refactor in ui/tests.rs is a correctness improvement with no behavioral regression risk.

No files require special attention.

Important Files Changed

Filename Overview
crates/tui/src/localization.rs Adds FanoutCounts MessageId and translations in all 7 locales; the fallback chain to English is preserved. No coverage gaps.
crates/tui/src/tui/widgets/agent_card.rs Adds locale field to FanoutCard, threads it through new(), and uses tr().replace() in render_lines(). All test call sites updated to Locale::En.
crates/tui/src/tui/subagent_routing.rs Passes app.ui_locale to FanoutCard::new at the single production call site. Minimal, correct change.
crates/tui/src/tui/views/mod.rs Updates test FanoutCard construction to pass app.ui_locale; no behavioral change.
crates/tui/src/tui/ui/tests.rs Refactors two timer-based liveness tests to build Instant values by addition rather than subtraction, making them more robust against very short-lived environments.

Sequence Diagram

sequenceDiagram
    participant SR as subagent_routing
    participant FC as FanoutCard
    participant L as localization::tr()
    participant UI as render_lines()

    SR->>FC: new(kind, app.ui_locale)
    Note over FC: stores locale as field
    FC->>FC: upsert_worker(id, lifecycle)

    UI->>FC: render_lines(width)
    FC->>FC: counts() → (done, running, failed, pending)
    FC->>L: tr(self.locale, FanoutCounts)
    L-->>FC: "&'static str template"
    FC->>FC: ".replace("{done}", ...).replace("{running}", ...)..."
    FC-->>UI: "Vec<Line<'static>> with localized stats line"
Loading

Reviews (3): Last reviewed commit: "Revert "fix: restore two-line draft head..." | Re-trigger Greptile

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 2, 2026

Thanks @gordonlu. Localizing the fanout counts line is a good, contained idea, and the production call site is small.

The blocker I see from CI is Windows, not the fanout localization itself: turn_liveness_uses_recent_turn_activity_not_turn_start and turn_liveness_does_not_abort_running_tool overflow when subtracting a long duration from Instant::now() on Windows. Please apply the same shape as your later #2568 test hardening: start from a base Instant::now(), add the watchdog duration to construct the synthetic timeline, and then run cargo fmt --all.

After that Windows test fix and a green CI rerun, this should be much easier to review/harvest as an i18n-only change.

@Hmbown
Copy link
Copy Markdown
Owner

Hmbown commented Jun 2, 2026

Hey @gordonlu — the FanoutCounts i18n has been harvested into v0.8.50 (#2504)! Clean work with the named placeholders ({done}, {running}, etc.) and the ZhHans smoke test. One small note: there was a duplicate fix commit shared with #2568 (the Instant overflow and fmt commits), which I skipped during cherry-pick — no issue, just FYI for future stacked PRs. Thank you! 🌐🐋

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants