Skip to content

refactor(i18n): fold the supplementary table into the dictionary literal - #654

Merged
PathGao merged 2 commits into
masterfrom
refactor/one-literal-for-the-dictionary
Aug 12, 2026
Merged

refactor(i18n): fold the supplementary table into the dictionary literal#654
PathGao merged 2 commits into
masterfrom
refactor/one-literal-for-the-dictionary

Conversation

@PathGao

@PathGao PathGao commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

i18n.ts merged a supplementary table into the exported translations with Object.assign at module load, so the source literal and the exported value were different objects.

One Object.assign, not several: a nested top-level loop merging interactiveLabelTranslations (26 locales, sections settings/toc/common). Added wholesale by #196 — appending a table rather than editing 26 places in a 6,700-line literal. No locale-override machinery, no merge-conflict residue, nothing load-bearing. Folded.

What the merge was actually doing: 259 keys added, 23 restated identically (dead rows), 20 locales got their entire toc section from the loop's else-branch, and 4 keys overwritten with a different value.

The four keys that depended on the overwrite

locale key value in the literal (lost) value from the table (won)
zh-TW settings.toolbarOnBar 工具列
ko settings.toolbarPlacement 툴바 위치 도구 모음 위치
ko settings.toolbarOnBar 표시줄 막대
ko settings.resetToolbar 툴바 초기화 도구 모음 초기화

All four winners preserved. The three losing Korean values no longer appear in the source at all — which is the point: two rows claimed the same key and only one could ever win, and now only one is written down.

The proof is the deliverable, not the fold

The fold is mechanical; showing nothing moved is not. A snapshot of the fully-merged dictionary, flattened to 6,210 sorted dotted keys, taken before and after: byte-identical, sha256 cd46b9b1…. Independently re-taken on the reviewer's side: same 6,210 keys, same digest.

The literal is regenerated by a printer that was first proved to reproduce the pre-fold literal byte-for-byte, so only the merge's own effects appear in the semantic diff.

That forced two commits. The literal had drifted into three styles at once — 165 tab-indented lines, 26 double-quoted values, 25 trailing commas — which the printer would have silently normalised inside the interesting diff. Commit 1 is that normalisation alone, snapshot verified unchanged; commit 2 is the fold.

The two tests were not deleted, and the premise for deleting them was wrong

I asked for two i18nCoverage tests to be removed as workarounds for the merge. They are not workarounds.

dictionaries in i18nCoverage.test.ts is built from the imported runtime translations — already post-merge. It is not static analysis of the literal, so no test ever had to reach past the merge; there was no barrier to work around.

  • "Simplified Chinese directly translates the window organization labels" checks menu.* / toast.* / home.*, sections the supplementary table never carried. Measured against the pre-merge dictionary: 0 of its 11 keys missing. No relationship to the merge at all.
  • "interactive button labels are directly translated for every supported language" does read keys that lived in the table, but its purpose — documented above it — is per-locale enforcement: the suite's general rules only require a key in English, and per-locale completeness is reported, never asserted. It is the only test that fails when a specific locale silently falls back to English, and after the fold it is the only thing standing between those 26 locales and a deleted translation.

Both still pass unchanged.

Guardrail

A RULES row, the translation dictionary is one literal, allowed: [].

The marker pins unqualified Object.assign( rather than a pattern naming translations, because the loop reached the dictionary through a local alias (const currentSection = translations[language][section]) that a translations-anchored regex cannot see — which is precisely how the mutation would come back. src contains no other Object.assign, so the blanket ban costs nothing. A second alternative catches the direct translations[l][s] = … spelling of the else-branch.

✖ single implementation: the translation dictionary is one literal
  AssertionError: second implementation found — `translations` was a 6,700-line
  literal *plus* a second table…

Numbers

npm test 903 → 904 · vitest 357 · check 0 errors.

The node count rises by one — the new rule — rather than dropping by the two tests I expected to delete.

i18n.ts 7,326 → 7,114 lines, shorter despite the literal growing 299 lines (259 keys plus 40 lines of new toc braces): removing the 510-line table, its two now-unused types and the loop more than paid for it. Duplicate-key scan across the folded literal: 0.

🤖 Generated with Claude Code

PathGao and others added 2 commits August 13, 2026 01:15
The literal had drifted into three styles at once: 165 tab-indented lines
among 6,600 space-indented ones, 26 values in double quotes where every
other value uses single, and 25 objects with a trailing comma on their
last property.

Mechanical and semantically inert: the flattened dictionary (6,210 keys)
is byte-identical before and after. Separated from the fold that follows
so that diff contains nothing but the change in meaning.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`translations` was declared as a 6,700-line literal and then quietly
rewritten at module load: a second table, `interactiveLabelTranslations`,
was merged in by a top-level loop with `Object.assign`. The object the
app read was therefore never the object the source declares — 259 keys
existed only after the merge, and 20 locales got their whole `toc`
section from the loop's else-branch.

Four keys were declared twice, with different values, where whichever
table ran last silently won. The fold preserves every winner and drops
the dead row:

    zh-TW settings.toolbarOnBar       列 → 工具列
    ko    settings.toolbarPlacement   툴바 위치 → 도구 모음 위치
    ko    settings.toolbarOnBar       표시줄 → 막대
    ko    settings.resetToolbar       툴바 초기화 → 도구 모음 초기화

Those are the real find. Two rows of source claiming one key, across 26
locales, is not something review catches — and a reader who greps for
the losing value finds it and believes it.

Proof the fold moved nothing: the fully-merged dictionary, flattened to
6,210 dotted keys and sorted, is byte-identical before and after
(sha256 cd46b9b1…). The literal was reprinted by a generator first
verified to reproduce the pre-fold literal exactly, so only the merge's
own effects appear in the diff.

The guardrail bans the mutation from coming back. It pins `Object.assign(`
unqualified rather than a pattern naming `translations`, because the loop
reached the dictionary through a local alias that such a pattern cannot
see; `src` contains no other use.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@PathGao
PathGao merged commit 4990100 into master Aug 12, 2026
3 of 4 checks passed
@PathGao
PathGao deleted the refactor/one-literal-for-the-dictionary branch August 12, 2026 17:37
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