Skip to content

i18n audit: ~200 hardcoded English strings remain across 40 frontend components #775

Description

@ioanalytica

Summary

An automated audit of the frontend (at af65d697) found ~203 hardcoded English UI strings across 40 components, despite the app maintaining 4 locales (en, de, it, es). 216 of 256 scanned components are clean.

The root cause of the invisibility: npm run check:locales (scripts/check-locale-parity.js) only enforces key parity between locale files — it never checks whether components actually use translation keys. So a component can ship fully hardcoded and CI stays green.

LogManagementTab.tsx is a good reference for the target state (flat keys under a component namespace, {{var}} interpolation).

Method

Heuristic regex scan over frontend/src/{components,pages}/**/*.tsx (excluding stories/tests) for:

  • JSX text nodes
  • user-facing string props (label=, helperText=, placeholder=, title=, alt=, tooltip=, …)
  • window.confirm / alert messages
  • toast.* messages
  • UI strings in ternaries ({cond ? 'Copied!' : 'Copy to clipboard'})

with filtering for TS generics artifacts, Tailwind/sx values, CSS, type names, and non-UI values. Both wiring styles were recognized as "translated": useTranslation() and t: TFunction passed as a prop (e.g. SourceSelectionDialog.tsx is fully translated via the prop style).

Counts are a ranking tool, not an exact work order — expect ~10% noise in both directions (strings built in .ts helpers weren't scanned; a few counted strings like "Linux" or plan names may legitimately stay untranslated).

Findings, ranked

Tier 1 — Managed Agents surface (109 hits, 54% of the total)

File Hits Notes
pages/ManagedAgents.tsx 81 (60 unique) imports useTranslation, but the managedAgents namespace contains exactly 1 key — the page was wired but never translated
pages/managed-agents/AddAgentDialog.tsx 22 no i18n wiring at all
pages/managed-agents/AgentInstallCommand.tsx 6 no i18n wiring at all

Examples: "Add Agent", "Enrollment token created" (toast), "Deleting removes it from the fleet list…", "Run this on the Linux machine that owns the files…", the 4-step "Agent Setup Help", "TCP reachable"/"TCP failed".

Tier 2 — API tokens & account/auth (32 hits)

File Hits
components/ApiTokensSection.tsx 19 — full token-reveal flow ("Copy this token now. You won't be able to see it again.", "Close without copying?")
components/AccountPasswordDialog.tsx 7 — all form labels
pages/FirstLoginPasswordSetup.tsx 4 — "Hide/Show password"
pages/Login.tsx 2 — same pair

Tier 3 — shared wizard & layout components (~28 hits)

WizardStepReview (5, "Hide/Show passphrase", "Ready to Initialize"), MountSuccessToast (4, "Copied!"/"Copy command"), WizardStepLocation (3), WizardStepIndicator (3), RepositoryEncryptionFields, WizardStepScheduleReview, BackupPlanSelect ("Scheduled"/"Manual"), PlanScheduleCard + UnassignedReposSection ("Collapse"/"Expand"), NavGroup, RepoMenuItem, RepositoryWizard, and 5 more wizard steps with 1 hit each.

Tier 4 — long tail (~34 hits, ~17 files)

SystemKeyCard (5), CacheManagementTab (3), ScheduledChecksSection, ArchivesList, AuthLayout, AppHeader, AnnouncementModal, Scripts (2 each), plus 1-hit files — including two untranslated window.confirm sentences (pages/Repositories.tsx "Are you sure you want to delete repository…", and one in RunningBackupsSection).

Effort estimate

~180–195 new en keys (≈ 720–780 locale lines across the 4 files):

Batch New keys
managedAgents.* ~80–85
apiTokens.* + account/auth ~28
shared wizard/layout ~25
long tail ~35
common.* staples ~10

A side finding: common has only 30 keys and is missing even Cancel and Close (actions, status, name exist). "Cancel" alone is hardcoded in 4 different files — repeated strings should route through common.* instead of being duplicated per namespace.

Suggested plan

Fix in 4 independent, reviewable PRs following the logManagement.* pattern, each keeping check:locales green:

  1. Managed Agents surface (~85 keys, 3 files) — biggest win, one coherent feature area; also adds the missing common.* staples.
  2. API tokens + account security (~28 keys, 4 files).
  3. Shared wizard/layout components (~25 keys, ~15 files).
  4. Long-tail sweep (~35 keys, ~17 files), including the window.confirm sentences (interpolated via {{name}}).

And to make this class of debt visible to CI permanently:

  1. Add eslint-plugin-i18next (i18next/no-literal-string) scoped to src/components + src/pages. Without it, check:locales keeps passing while new hardcoded strings accrue — which is exactly how ManagedAgents.tsx reached 81 strings after being wired for i18n.

I'm happy to send these PRs one at a time as the review queue allows — filing the audit first so the scope is agreed before any code moves.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions