Skip to content

F182 B2: i18n sweep — daily ops (DailyEntry, Dashboard, Water, Grades) — stacked on #238#239

Merged
mforce merged 9 commits into
mainfrom
f182-i18n-b2-dailyops
Jul 27, 2026
Merged

F182 B2: i18n sweep — daily ops (DailyEntry, Dashboard, Water, Grades) — stacked on #238#239
mforce merged 9 commits into
mainfrom
f182-i18n-b2-dailyops

Conversation

@mforce

@mforce mforce commented Jul 27, 2026

Copy link
Copy Markdown
Owner

B2 — daily operations. Third batch of the #182 string sweep. Externalizes the four daily-ops screens to the catalog, English-first, and wires their closed-vocabulary displays through the B0 typed enums helpers.

Base main. Stacked on B1 (#238) — merge #238 first, then this (GitHub retargets to main on that merge). Behavior-preserving except one intentional label harmonization (below). i18n:scan on src/routes+src/components: 827 → 707.

Screens externalized (English-only namespaces)

  • DailyEntryPagedailyEntry (~47 keys) — form labels, validation, section headings; the locked-entry banner now resolves its status via statusLabel.
  • Dashboarddashboard — panel/stat labels, empty states; both status pills (entries table + recent-sales panel) wired via statusLabel.
  • WaterPagewater — form + table; the Source select/cells and unit displays now go through waterSourceLabel/waterUnitLabel (were raw {r.source}/{r.unit}).
  • GradesPagegrades — grade-type select/cell via gradeTypeLabel; the Active/Inactive badge via statusLabel.

One intentional visible change

ManagerAdjusted status now displays as "Adjusted" (matching HistoryPage's existing badge), applied consistently in DailyEntryPage (locked banner, lowercased inline) and Dashboard (entries pill). Every other enum label is identity — no other visible text moved. Free-form data (grade/flock/customer names, notes) stays raw.

Guarantees held

  • es/tl byte-unchanged across all 5 commits; the 4 namespaces are en.ts-only, not in TRANSLATED_NAMESPACES — parity green.
  • Formatting stays farm-locale-driven — zero i18n.language in any screen; the formatting-independence guard passes (a Dashboard test even asserts an unformatted 1560 to prove no Intl.NumberFormat crept in).
  • Enum coupling intact — the typed exhaustive helpers keep catalog↔union drift a compile error; StatusBadge's status prop stays raw so pill tint is unchanged.
  • No common atom duplicated; shared verbs reuse common (incl. common.all).

Testing / review

Wiring tests use the i18n.addResource override technique (a hardcoded literal fails — verified by reverted mutation probes on each screen). npm run test 807 green; coverage above the (unchanged) floors — no locked path touched; npm run typecheck clean; npm run build succeeds. Each of the 4 screens was individually reviewed (spec + quality, with empirical probes; GradesPage got one fix — wiring its status badge), then a whole-branch review (Claude comprehensive — READY).

Not in scope

es/tl for these screens (deferred native-review pass, #182); B3–B6.

mforce added 9 commits July 26, 2026 20:53
…182)

First screen-externalization batch (B1, Task 7): navGroups()/tabEntries()
are pure functions, so nav items now carry a typed labelKey into the new
English-only `nav` namespace instead of a hardcoded label; AppLayout and
BottomNav translate it at their render sites — one label source for the
sidebar, the bottom tab bar, and the More sheet.

Also externalizes AppLayout's landmark aria-labels, sign-out, the
farm-load-failed banners + retry button, adds a skip-to-content link, and
composes document.title from the active nav entry's label + a shared
suffix. BottomNav gets its first dedicated test file.

`nav` stays out of TRANSLATED_NAMESPACES (English-first); es/tl untouched.
i18n:scan (src/routes src/components) count: 843 -> 835.
Batch B1, Task 8 of the i18n string sweep. Dialog's close button reuses
common.close; NumberField's Increase/Decrease aria-labels and
ErrorBoundary's crash-fallback copy get their own English-only
namespaces (numberField, errorBoundary), following the same
not-yet-translated treatment Task 7 gave `nav`. Wiring tests use the
i18n.addResource override technique to prove the catalog is actually
read, not just falling back to hardcoded English.
…182)

Adds themeToggle/useConfirm/pwa namespaces (English-only, like nav and
numberField from Task 7/8) and wires each component to t(). useConfirm's
Cancel button reuses the existing common.cancel atom instead of a new key.
…talog-sourced (#182)

Two deferred review findings from the B1 chrome/primitives batch (Tasks
7-9): the nav.help comment claimed the key was reused for both the Help
destination and the Help group heading, but nav.tsx actually uses two
distinct keys (groupHelp for the heading, help for the destination),
matching every other group's group*/entry-key pairing — reword to say
so. Also add a wiring test proving AppLayout's document.title reads its
per-page label from the catalog: the existing test only asserted the
titleSuffix half via an addResource override, so a hardcoded label
would have passed the label half under default lng:"en".
Task 11 (batch B2): every user-facing string in DailyEntryPage now flows
through a new `dailyEntry` namespace (English-first, en.ts only). The
entry-locked banner's status word is wired through enums.statusLabel,
which harmonizes ManagerAdjusted's visible text from raw "manageradjusted"
to "Adjusted" (matching HistoryPage's own bespoke badge).
Adds a new English-first `dashboard` namespace (en.ts only, not in
TRANSLATED_NAMESPACES) covering the landing page's headings, stat
labels, empty-state copy, and table headers. Wires both StatusBadge
render sites (today's per-flock entry status, recent order status)
through the B0 enums `statusLabel` helper, which harmonizes a
ManagerAdjusted entry from raw "ManagerAdjusted" to "Adjusted",
matching HistoryPage's existing badge for the same state. Also
removes a stray blank line left after the function signature.

(#182)
Externalizes WaterPage.tsx to a new `water` namespace (en.ts only,
English-first), wiring the Source and Unit displays through the B0
waterSourceLabel/waterUnitLabel enum helpers everywhere they render
(select options, table cells, and the quantity label's unit suffix).
Both families are identity-labelled in English, so nothing renders
differently. Adds i18n.addResource wiring tests alongside the existing
suite, which stays green untouched since the English text is
unchanged.
Externalizes GradesPage.tsx to a new English-first `grades` namespace
(en.ts only, not in TRANSLATED_NAMESPACES) — form labels, table
headers, buttons, the intro paragraph, load-failure message, and the
saleable "yes" badge. The grade-type select/table-cell now render
through the B0 gradeTypeLabel enum helper instead of the raw wire
value; grade NAMES (g.name) stay raw as free-form farm data. Adds
i18n.addResource wiring tests confirming the screen reads the catalog
(and the enums catalog for grade type) rather than hardcoded literals.
Review fix round 1 on Task 14: the Active/Inactive StatusBadge cell was
left unwired, inconsistent with sibling B2 screen Dashboard (Task 12),
which wires its bare StatusBadge sites through statusLabel. Adds
label={statusLabel(...)} alongside the existing raw status= (kept for
the variant class) — 100% text-preserving today (identity labels) and
future-proofs the badge for the eventual status translation pass.
Base automatically changed from f182-i18n-b1-chrome to main July 27, 2026 07:06
@mforce
mforce merged commit 49fc6c4 into main Jul 27, 2026
1 check passed
@mforce
mforce deleted the f182-i18n-b2-dailyops branch July 27, 2026 07:08
mforce added a commit that referenced this pull request Jul 27, 2026
…locks) — stacked on #239 (#240)

* feat(web): externalize InventoryPage strings (#182)

Move every user-facing string in InventoryPage.tsx into a new flat
`inventory` namespace in en.ts (English-only, 60 keys), following the
Screen Externalization Pattern from B1/B2. Wires category and status
displays through the B0 enum helpers (inventoryCategoryLabel,
statusLabel), and the movement ledger's Type cell through
inventoryMovementLabel — while keeping the Correct-stock dialog's
decorated Type picker options ("Adjustment (±)", "Discard (write-off)")
as plain screen copy, since that text is not the ledger's identity
label. All enum families are identity-mapped in English today, so the
retrofit is text-preserving.

Adds 11 i18n-wiring tests (i18n.addResource override technique) on top
of the unchanged, still-green functional suite, including a pair of
tests that prove the adjust-type picker reads screen copy rather than
the movement enum. i18n:scan count drops from 707 to 645.

* feat(web): externalize ProductsPage strings (#182)

Task 17 (batch B3, the last B3 screen): moves every user-facing string in
ProductsPage.tsx into a new flat `products` namespace in en.ts (English-only,
not in TRANSLATED_NAMESPACES). Wires both the products table's StatusBadge
and the packed-unit table's plain-text status cell through the shared
statusLabel enum helper; unitCode/defaultUnit and product/grade names stay
raw as free-form farm data. Adds i18n.addResource wiring tests covering the
heading, button labels, both status-enum sites, the two data-interpolated
templates (price-with-currency label, eggs-per-unit dialog title), and the
price-precision validation message.

* feat(web): externalize StockPage strings (#182)

Adds the `stock` namespace (English-first, not in TRANSLATED_NAMESPACES)
and wires the movement ledger's Type cell through the B0
stockMovementLabel helper. Grade/lot names, dates, and quantity/delta
values stay raw farm data.

* feat(web): externalize FlocksPage strings (#182)

Adds the `flocks` namespace (English-first) and wires the bird-ledger
movement-type select/cells through flockMovementLabel and the status
badge through statusLabel — the last B3 screen of the i18n sweep.

* docs(web): correct stale B3 ordinal comments in en.ts (#182)

---------

Co-authored-by: mforce <>
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.

1 participant