i18n-locale-fill
levy-street/world-of-claudecraft/.claude/skills/i18n-locale-fill/SKILL.md
Fill pending i18n rows across every locale for World of ClaudeCraft, the release-time workflow. Use when the release-tier gate (I18N_RELEASE_TIER=1) fails on pending rows, when asked to translate or fill locales, overlays, or matcher DICTs, or when preparing a release branch whose registry still has pending entries. Covers the worklist generator, where each scope's fills land, the placeholder and glossary contracts, and the known traps (English-in-overlay, shared DICT references, the "todo" guard, reword staleness, native punctuation in overlays).
What's in it
- i18n locale fill (release time)
- 1. Generate the worklist
- 1b. The chunk families OUTSIDE the registry (deeds and reliquary)
- 2. The fill contract
- 3. Regenerate, verify
- 4. Reword staleness (the silent trap)
---
name: i18n-locale-fill
description: Fill pending i18n rows across every locale for World of ClaudeCraft, the release-time workflow. Use when the release-tier gate (I18N_RELEASE_TIER=1) fails on pending rows, when asked to translate or fill locales, overlays, or matcher DICTs, or when preparing a release branch whose registry still has pending entries. Covers the worklist generator, where each scope's fills land, the placeholder and glossary contracts, and the known traps (English-in-overlay, shared DICT references, the "todo" guard, reword staleness, native punctuation in overlays).
user-invocable: true
---
# i18n locale fill (release time)
Contributors add ENGLISH only; the maintainer fills every locale at release. This skill is
that fill workflow. The release-tier gate (`I18N_RELEASE_TIER=1`, automatic on `release/**`
branches) hard-fails on any `pending` registry row, so a release is not shippable until the
fill lands.
## 1. Generate the worklist
```
npm run i18n:gen # refresh the registry first
npm run i18n:worklist # writes one batch per language under docs/i18n-scaling/worklist/ (gitignored)
```
`scripts/i18n_fill_worklist.mjs` is data-only (no translation): each batch entry carries
`{ scope, key, english, placeholders, siblings }`.
- `main`-scope keys are filled in the matching `src/ui/i18n.locales/<lang>.ts` overlay.
- `sim` / `server` / `admin` scope keys are filled in their matcher DICTs (the worklist
header in `scripts/i18n_fill_worklist.mjs` names the exact files).
- **Sim-scope keys DO reach the worklist** (since Masterwrought Phase 19F, ruling
qr-19-sim-scope-pending-is-unreachable): the registry reads each locale's OWN source
blocks through `simDictProvidedKeys` in `src/ui/sim_i18n.ts`, never the assembled `DICT`
(which is dense by construction, `baseEnTable` spread under every locale), so a sim row
with no fill in a locale's block is `pending` and lands in that locale's batch. Fill a
sim key in the locale's `BASE_DICT` block of `src/ui/sim_i18n.ts` (the eight newest
locales keep theirs in `BASE_NEW` of `src/ui/sim_i18n.newlocales.ts`, a hand-maintained
file despite its old banner; each of those locales' own block in `sim_i18n.ts` spreads
`BASE_NEW` in the MIDDLE of its literal rows, so a key spelled in both is read from
whichever spelling comes last in the block, and the registry's row-count anchor in
`tests/i18n_status_registry.test.ts` reds on the duplicate either way), and NEVER paste
the English into a locale block: a copied row reads `translated` and ships English (the
sim scope has no copied-English guard; only `tests/localization_fixes.test.ts`'s
release-tier `s3_localized` arm sees it late). Run `npm run i18n:gen` before the suites:
the registry pin compares the artifact against the live source and reds on a stale one.
The five per-locale `*_EXTRA` tables the RULES matchers read (arena, battleground,
quest, item, raid) are tsc-forced dense and stay outside the registry; check them by eye
at release.
- **`humanRequired` entries are blocked by default** (quest narratives, names, lore, SEO
copy): never machine-fill them; only `autoFillable` entries are fair game for a model pass.
Batches are per-language and independent: fan out one fill agent per language when the
volume is large, then regenerate once at the end.
## 1b. The chunk families OUTSIDE the registry (deeds and reliquary)
The Deeds and Reliquary systems keep their locale tables in lazy per-base-locale chunks
that the registry and `scripts/i18n_fill_worklist.mjs` never see:
`src/ui/deed_i18n.locales/<locale>.ts` and `src/ui/reliquary_i18n.locales/<locale>.ts`
(loader contract pinned by `tests/deed_i18n_lazy.test.ts` and
`tests/reliquary_i18n_lazy.test.ts`). Consequences:
- **Zero pending registry rows does NOT prove full coverage.** A fill pass driven only by
the worklist ships English deed/reliquary rows while the registry reads clean. Their
coverage is enforced only by the release-tier arms (`it.runIf(I18N_RELEASE_TIER === '1')`)
in `tests/deed_i18n.test.ts` and `tests/reliquary_i18n.test.ts`, which walk
`deedTranslationManifest()` / `reliquaryTranslationManifest()` against every base
locale table. Run those release-tier to prove this surface, not the pending count.
- Fill every base locale chunk in the family; a chunk carries only real catalog ids (the
same tests reject a stale id or a title on a deed that rewards none).
- **The overlay punctuation exemption does NOT extend here.** These chunk files sit
outside the `src/ui/i18n.locales` copy-scan exemption: no em/en dashes or emoji in any
value, even where the locale would natively use them (the pin tests enforce it).
## 2. The fill contract
- **Translate, never transplant.** The registry counts PRESENCE, not language: pasting the
English value into an overlay marks the row filled and silently ships English. Do not.
- **Placeholder parity.** Every `{token}` in the English value must appear verbatim in the
fill (the worklist lists them). The scanner checks parity; a dropped token is a break.
- **Locked terminology.** Classic-MMO terms per locale live in `scripts/i18n_glossary.json`
and are locked; follow them, and extend the glossary when a new recurring term appears.
- **Matcher DICT values must be literal string copies.** Never alias or share a reference
between DICT rows; the matcher relies on per-row literals.
- **Native punctuation in overlays is legitimate.** Russian and other locales use real em
dashes; NEVER strip them. The repo copy scans deliberately exclude `src/ui/i18n.locales`.
- **The placeholder guard flags a bare "todo" value**, which is also a real word in es/pt.
Phrase such fills differently (for example "por hacer") so the guard does not trip.
## 3. Regenerate, verify
1. `npm run i18n:gen` regenerates the resolved bundles and the status registry.
2. **Biome-format every overlay file the fill touched** in the same change:
`npx @biomejs/biome check --write src/ui/i18n.locales/<touched>.ts ...`. CJK and other
wide-glyph fills blow the 100-column lineWidth silently (the line LOOKS short in an
editor but is over by bytes), and the changed-files biome gate then fails a later round
on a format diff you never saw (it cost the phase 13 closing gate its first round).
Note biome SIZE-SKIPS files over 1.0 MiB (ru_RU is there already): gate green is not
format evidence for those, and that is a known accepted state, not something to fix.
3. **Stage the regenerated artifacts in the SAME commit as the fills.** The freshness gate
diffs the regenerated output against the staged/committed copies; unstaged artifacts fail it.
4. Prove completion: run the i18n steps release-tier,
`I18N_RELEASE_TIER=1 npm run gate` (or at minimum `i18n:gen` + the guard tests), and
confirm zero `pending` rows remain. Zero pending covers the REGISTRY only: the
deed/reliquary chunk families (section 1b) are proven by their own release-tier test
arms, not by the pending count.
## 4. Reword staleness (the silent trap)
Rewording an EXISTING English value does not mark its translations pending: every locale
silently keeps the old meaning. After any English copy change, diff the resolved `en` output
between the base branch and HEAD and re-fill the touched keys in the same change.
More agent context in levy-street/world-of-claudecraft
36 other files this repository gives its agents.
AGENTS.md
CLAUDE.md
llms.txt
Skill
- woc-codex-audit.agents/skills/woc-codex-audit/SKILL.md
- woc-extract-and-test.agents/skills/woc-extract-and-test/SKILL.md
- woc-feature-plan.agents/skills/woc-feature-plan/SKILL.md
- woc-file-issue.agents/skills/woc-file-issue/SKILL.md
- woc-image-to-glb.agents/skills/woc-image-to-glb/SKILL.md
- woc-qa.agents/skills/woc-qa/SKILL.md
- woc-release-malware-audit.agents/skills/woc-release-malware-audit/SKILL.md
- woc-release-merge-audit.agents/skills/woc-release-merge-audit/SKILL.md
- woc-review-pr.agents/skills/woc-review-pr/SKILL.md
- woc-write-game-tooltips.agents/skills/woc-write-game-tooltips/SKILL.md
- asset-pipeline.claude/skills/asset-pipeline/SKILL.md
- blender-anim-pipeline.claude/skills/blender-anim-pipeline/SKILL.md
- ci-triage.claude/skills/ci-triage/SKILL.md
- extract-and-test.claude/skills/extract-and-test/SKILL.md
- feature-plan.claude/skills/feature-plan/SKILL.md
- file-issue.claude/skills/file-issue/SKILL.md
- hunt-live-programs.claude/skills/hunt-live-programs/SKILL.md
- image-to-glb.claude/skills/image-to-glb/SKILL.md
- pr-screenshots.claude/skills/pr-screenshots/SKILL.md
- qa.claude/skills/qa/SKILL.md
- release-malware-audit.claude/skills/release-malware-audit/SKILL.md
- release-merge-audit.claude/skills/release-merge-audit/SKILL.md
- review-pr.claude/skills/review-pr/SKILL.md
- write-game-tooltips.claude/skills/write-game-tooltips/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

