Summary
The Korean UI mode shows large amounts of untranslated English copy — header counters, search filter buttons, tag empty states, settings labels, and timeline filters all leak through. The existing i18n guard test (tests/test_i18n.py) misses them because it only inspects showToast(...) and showConfirm(...) call sites in 6 specific JS modules, not textContent / innerHTML assignments or HTML literals.
Found by Playwright UX review of v0.1.34 prod (2026-05-02). See docs/reports/mm-web-prod-v0.1.34-playwright-review.md (P1 — Korean UI contains many untranslated English strings).
Evidence — strings bypassing the dictionary
Hardcoded textContent templates:
-
packages/memtomem/src/memtomem/web/static/app.js:931-932 — header counter
qs('stat-chunks').textContent = `${data.total_chunks} chunks`;
qs('stat-sources').textContent = `${data.total_sources} sources`;
Translation keys (header.stat_chunks, header.stat_sources) exist in the locales but are never invoked.
-
packages/memtomem/src/memtomem/web/static/app.js:2561 — ${n} chunks · ${m} files template (no plural key in either locale).
-
packages/memtomem/src/memtomem/web/static/settings-config.js:187 — Max chunk: ${n} tokens.
Hardcoded innerHTML empty states:
packages/memtomem/src/memtomem/web/static/app.js:3793 — emptyState('🏷', 'No tags yet', 'Run Auto-Tag to generate tags') — both strings absent from en.json / ko.json.
HTML literal button text without data-i18n:
- "Advanced", "Delete Selected" buttons in
packages/memtomem/src/memtomem/web/static/index.html — no data-i18n attribute.
Evidence — guard scope
packages/memtomem/tests/test_i18n.py scans only:
showToast(\...`)` template literals
showToast('English ...', ...) literals
showConfirm({ title: 'English...' }) titles
…in 6 explicit files (app.js, settings-*.js, context-gateway.js). Direct DOM updates (textContent =, innerHTML =, attribute assignment) and HTML literals are unscanned.
Suggested fix
- Extend
test_i18n.py to AST-scan / regex-scan for:
el.textContent = "<English string>" or `${expr} <English suffix>` patterns.
el.innerHTML = "..." containing English sentences.
- HTML files with element text not wrapped in
data-i18n.
- Cover the static HTML templates as well as JS — the audit shows HTML-side hardcoding is just as common.
- Patch the offenders listed above. The header counters likely need plural-form keys (
{n, plural, ...} or two keys for one/other) since "1 chunks" reads poorly.
This is the canonical-fixture approach (per repo's feedback_docs_parity_canonical_fixture.md): the guard should fail loudly with the file:line so contributors don't have to grep the whole tree.
References
Summary
The Korean UI mode shows large amounts of untranslated English copy — header counters, search filter buttons, tag empty states, settings labels, and timeline filters all leak through. The existing i18n guard test (
tests/test_i18n.py) misses them because it only inspectsshowToast(...)andshowConfirm(...)call sites in 6 specific JS modules, nottextContent/innerHTMLassignments or HTML literals.Found by Playwright UX review of v0.1.34 prod (2026-05-02). See
docs/reports/mm-web-prod-v0.1.34-playwright-review.md(P1 — Korean UI contains many untranslated English strings).Evidence — strings bypassing the dictionary
Hardcoded
textContenttemplates:packages/memtomem/src/memtomem/web/static/app.js:931-932— header counterTranslation keys (
header.stat_chunks,header.stat_sources) exist in the locales but are never invoked.packages/memtomem/src/memtomem/web/static/app.js:2561—${n} chunks · ${m} filestemplate (no plural key in either locale).packages/memtomem/src/memtomem/web/static/settings-config.js:187—Max chunk: ${n} tokens.Hardcoded
innerHTMLempty states:packages/memtomem/src/memtomem/web/static/app.js:3793—emptyState('🏷', 'No tags yet', 'Run Auto-Tag to generate tags')— both strings absent fromen.json/ko.json.HTML literal button text without
data-i18n:packages/memtomem/src/memtomem/web/static/index.html— nodata-i18nattribute.Evidence — guard scope
packages/memtomem/tests/test_i18n.pyscans only:showToast(\...`)` template literalsshowToast('English ...', ...)literalsshowConfirm({ title: 'English...' })titles…in 6 explicit files (
app.js,settings-*.js,context-gateway.js). Direct DOM updates (textContent =,innerHTML =, attribute assignment) and HTML literals are unscanned.Suggested fix
test_i18n.pyto AST-scan / regex-scan for:el.textContent = "<English string>"or`${expr} <English suffix>`patterns.el.innerHTML = "..."containing English sentences.data-i18n.{n, plural, ...}or two keys for one/other) since "1 chunks" reads poorly.This is the canonical-fixture approach (per repo's
feedback_docs_parity_canonical_fixture.md): the guard should fail loudly with the file:line so contributors don't have to grep the whole tree.References
docs/reports/mm-web-prod-v0.1.34-playwright-review.md