Commit Graph
1 Commits
Author SHA1 Message Date
Juan DenisandClaude Opus 5 7de4d10eda feat(i18n): codemod for the long tail; census fixes; Intl component options
Built to convert the WordPress extension (1,099 strings across 44 files) and
kept because the same job remains for 12 more extension repos and the panel's
own 8,034-literal tail.

i18n-codemod.mjs keys the same four shapes the census counts, using the same
isCopy rule, so what it converts is exactly what the ratchet measures. It
REFUSES rather than guesses: a hit outside a component needs `t` threaded
through a helper's arguments, which is a design decision, not a rewrite.
Five bugs it had, all caught by building the result rather than by reading it:

- multi-line JSX text became a string literal containing raw newlines. JSX
  collapses that whitespace at render, so the default must too.
- a literal already containing \n (an SSH key placeholder) was emitted raw and
  produced an unterminated string.
- `confirm({ title: 'x' })` matched BOTH the data-object rule and the copy-call
  rule; applying both corrupted the file. Innermost edit wins -- for a call,
  t() is right because nothing resolves a `titleKey` there.
- copy hides in `err.message || 'Failed…'` and `x ? 'A' : 'B'` as often as it
  sits directly in a call, so argument recursion matches the census.
- that recursion then had to stop at nested JSX, or it "translated" a
  `rel="noopener noreferrer"`.

Two census corrections, both of which were inflating the numbers:

- check-i18n-literals recursed into nested JSX inside a copy prop and counted
  the nested element's own attributes. `rel` is not copy; the ratchet was
  unreachable on correct code.
- check-intl-door walked dist/, so an extension repo's bundle double-counted
  every call in it. WordPress reported 56 where the source had 28.

Both censuses and the extractor now take --root (and --out) so an extension
repo runs the panel's own checks instead of copying them -- copying is how the
vendor shims drifted. --update refuses a foreign root: those ceilings are the
panel's.

The format door takes `parts`, passing Intl.DateTimeFormat component options
through for what a named style cannot express -- chart ticks, month labels.
That was the actual reason callers reached for toLocaleDateString([], {...}),
which silently follows the browser; now they keep the format and the locale.

Ceilings re-seeded to the corrected numbers: literals 8034, intl door 123.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 08:50:13 -04:00