---
name: ba-translate-prd
description: >
  Backfills the i18n translations of an already-written PRD. Scans a module's
  `pagespecs/*.md` for untranslated `i18nKeys` placeholders of the form
  `"[en] <fr>"` / `"[it] <fr>"` / `"[de] <fr>"` (the abandoned "author FR, defer
  the rest" convention), translates each from its authoritative FR sibling into
  idiomatic en/it/de, and rewrites the JSON blocks in place — preserving every
  other value. Also fills FR-only `form.section.*` labels (the
  derive-form-sections backfill seeds fr and leaves en/it/de absent — PRD-111).
  Conversational: reports what it found, asks the user to validate
  the translations (Swiss house terms), then writes. Run when `/ba-audit-prd`
  PRD-089/PRD-111 or `DEV-UI-029` flags placeholders in an existing PRD;
  re-scaffold the Frontend afterwards to regenerate the shipped bundle.
allowed-tools: [Read, Write, Edit, Glob, Grep]
---

# ba-translate-prd — backfill PRD i18n placeholders with real translations

You fill the untranslated i18n placeholders of an **existing** PRD. This is a
remediation tool: the pipeline authors FR and, historically, left `en/it/de` as
`"[xx] <fr>"` placeholders that no downstream step ever translated — so a raw
`[en] Absences` marker shipped to the end user. You translate those placeholders
in place, at the source (the pagespec `i18nKeys`), so a re-scaffold produces a
correct bundle.

> **Prevention lives upstream.** `/ba-create-prd` now authors all four locales
> for real, and `/ba-audit-prd` **PRD-089** + `DEV-UI-029` reject placeholders.
> This skill exists ONLY to remediate PRDs written before that gate, or a batch
> that slipped through. New PRDs should never need it.

## Scope

Pick the working scope (ask if the invocation did not name one):
- A single module: `.smartstack/ba/<APP>/<MODULE>/`.
- A whole app: every `<MODULE>/` under `.smartstack/ba/<APP>/`.

Never touch anything outside the chosen scope. You edit ONLY
`<MODULE>/pagespecs/*.md`. You do **not** touch the generated app's
`src/i18n/**` (regenerating the Frontend is what propagates your fix — call it
out at the end).

## 1. Detect — find the placeholders (deterministic)

For the scope, read every `pagespecs/*.md`. Each carries one fenced ```json block
with an `i18nKeys` object of shape `{ "fr": {...}, "en": {...}, "it": {...},
"de": {...} }`. A value is a **placeholder** when it matches:

```
^\s*\[(fr|en|it|de)\]\s
```

Use Grep to locate offending files fast, then Read each to parse its JSON block:

```
Grep  pattern: "\[(fr|en|it|de)\]\s   glob: **/pagespecs/*.md   output_mode: content
```

For every placeholder value, the **authoritative source** is the FR sibling —
the same key under `i18nKeys.fr` (which is always authored). Example: if
`i18nKeys.en["list.title"]` is `"[en] Opportunités"`, translate the FR value
`i18nKeys.fr["list.title"]` = `"Opportunités"` into English → `"Opportunities"`.
If the FR sibling is missing (should not happen — PRD-072 enforces key parity),
fall back to the text after the `[xx] ` marker.

A `fr` value that itself starts with `[fr] ` is a rare authoring slip — translate
it to clean French (strip the marker, fix wording) and use THAT as the source for
the other three locales.

**Second detection axis — FR-only section labels.** The `derive-form-sections`
backfill CLI (create-prd) promotes the uiDesign overlay into first-order
`sections[]` and seeds ONLY `i18nKeys.fr["form.section.<key>"]` — the en/it/de
legs are deliberately left ABSENT (no `[xx]` marker to grep). So additionally,
for every pagespec whose block carries `sections[]`: any `form.section.*` (or
explicit `sections[].labelKey`) present under `i18nKeys.fr` but MISSING under
`en`/`it`/`de` is an untranslated section label — translate the FR value and ADD
the missing keys (this is the one case where you add a key rather than replace a
placeholder; PRD-072 key parity and PRD-111 require it).

**Same FR-only sweep for the list uplift key families** (plan UI 2.x): on every
`view: list` pagespec, apply the identical present-in-`fr`-missing-in-`en/it/de`
detection to `stats.*` (KPI tiles — PRD-115), `segments.*` (cohort tabs —
PRD-116) and `empty.*` / the keys named by `emptyState.titleKey`/
`descriptionKey` (PRD-118). These are authored per-locale by create-prd, but a
backfilled or hand-edited pagespec can carry the FR leg only — translate and
add the missing legs exactly like the section labels.

## 2. Translate — real, idiomatic UI wording

These are short UI strings: page titles, column headers, button labels, filter
labels, widget titles, form section names. Translate them the way a native
professional UI would read, not word-for-word:
- Keep the register consistent with the FR (a title stays a title, an
  imperative button stays imperative).
- Preserve any interpolation tokens verbatim (`{{count}}`, `{name}`, `%s`).
- Preserve trailing ellipsis / punctuation (`Rechercher…` → `Search…`).
- Do NOT translate proper nouns, product names, or codes.
- Business/domain terms (HR, finance, Swiss-specific): when a term is ambiguous
  or house-specific, surface it in the validation step rather than guessing.

Target locales: `en` (English), `it` (Italian), `de` (German — Swiss business
German; no ß, use ss).

## 3. Validate — show, then confirm (conversational)

Before writing anything, present a compact per-locale preview so the user can
correct house terms:

```
absences/pagespecs/Absence.list.md — 12 placeholders
  list.title            FR "Absences"              → EN "Absences"  IT "Assenze"      DE "Abwesenheiten"
  list.columns.status   FR "Statut"                → EN "Status"    IT "Stato"        DE "Status"
  form.createTitle      FR "Créer une absence"     → EN "Create an absence" …
  …
```

Ask the user to validate or amend (especially any term you flagged as
ambiguous). Apply their corrections. Only then write.

## 4. Write — surgical, in place

Rewrite each pagespec's `i18nKeys` block **replacing only placeholder values**:
- Every non-placeholder value stays byte-for-byte identical.
- The key sets stay parallel across the 4 locales (do not add/remove keys).
- Keep the JSON block's formatting/indentation as it was (edit values only).
- Leave `needsRefinement` / `refinementNotes` untouched — they are orthogonal to
  i18n (a pagespec can be structurally refined yet still hold placeholders, and
  vice-versa). Do not flip them.

Prefer targeted `Edit` calls over rewriting the whole file, so unrelated content
and any hand-edits are preserved.

## 5. Report + hand-off

Summarise: files touched, placeholders resolved per locale, any term the user
overrode. Then state the two follow-ups explicitly:
1. **Re-audit** — run `/ba-audit-prd` for the module; PRD-089 must now be clean.
2. **Regenerate the app bundle** — the shipped `src/i18n/locales/**` still holds
   the old placeholders until the Frontend is re-scaffolded. Re-run the
   `/ba-develop` Frontend phase (or `scaffold-component`) for the module, then
   `DEV-UI-029` should pass. This skill deliberately does not edit generated code.

## Guardrails

- **Never invent keys or values beyond translation.** You only translate existing
  placeholders; you do not add screens, keys, or business copy.
- **Never touch FR business meaning** except to clean a stray `[fr] ` marker.
- **Idempotent**: a second run finds nothing to do and reports "no placeholders".
- **Scope-locked**: only `pagespecs/*.md` inside the chosen module(s).
