Skip to content

fix: opt React app shell out of Chrome Translate (#26)#28

Merged
study8677 merged 1 commit into
mainfrom
fix/issue-26-translate-blank
May 21, 2026
Merged

fix: opt React app shell out of Chrome Translate (#26)#28
study8677 merged 1 commit into
mainfrom
fix/issue-26-translate-blank

Conversation

@study8677
Copy link
Copy Markdown
Owner

Closes #26.

Summary

  • Mark the React-managed app shell (<body> and #root) with translate="no" + notranslate, plus a <meta name="google" content="notranslate"> hint. This prevents Chrome/Google Translate from rewriting text nodes that React owns, which was producing NotFoundError: Failed to execute 'insertBefore' on 'Node' and leaving #root empty on /projects/:id.
  • Keep the static SEO copy in <main id="static-site-copy"> translatable by opting it back in with translate="yes" — it lives outside #root, so it can't break React, and we still want crawlers / translated previews to render it.
  • Defensive latest.serp ?? [] in ProjectCommandCenter so a legacy / partial project-summary payload cannot crash the project detail page.

Root cause

Chrome Translate (and similar extensions) mutate the DOM in place by replacing text nodes. React's reconciler keeps pointers into the DOM it last rendered, so when Translate splices nodes out, insertBefore from React throws because the reference node is no longer a child of its expected parent. The result on production was the project detail page going blank with rootChildren: 0 and html.translated-ltr present on the document.

Test plan

  • pytest tests/test_frontend_translate_optout.py tests/test_frontend_public_byok_paths.py tests/test_web.py — 82 passed, 3 skipped
  • ruff check src/ tests/ — clean
  • tsc -b + vite build — clean; built dist/index.html still carries translate="no" on <body> and #root and the <meta name="google" content="notranslate"> hint
  • Manual check: reproduce on aidcmo.com by toggling Chrome Translate on /projects/:id after deploy

Chrome/Google Translate replaces text nodes inside the React-managed
DOM, which breaks React's reconciliation and surfaces as
`NotFoundError: Failed to execute 'insertBefore' on 'Node'` followed by
`#root` being emptied. Users with Chrome Translate active reported
`/projects/:id` rendering as a blank white page while `/console`
continued to work in the same session.

Mitigation:
- Mark `<body>` and `#root` with `translate="no"` + `notranslate` so the
  React subtree is never mutated by Translate. Add a
  `<meta name="google" content="notranslate">` hint as well.
- Keep the static SEO copy in `<main id="static-site-copy">`
  translatable by opting it back in with `translate="yes"` — it is
  outside `#root`, so it cannot break React anyway, and we still want
  crawlers / translated previews to see it.

Hardening:
- Default `latest.serp` to `[]` in ProjectCommandCenter so a partial /
  legacy project-summary payload cannot crash the project detail page.

Regression test (tests/test_frontend_translate_optout.py) asserts the
opt-out markers are present in the shipped `frontend/index.html`.
@study8677 study8677 merged commit 966b4c6 into main May 21, 2026
3 checks passed
@study8677 study8677 deleted the fix/issue-26-translate-blank branch May 21, 2026 11:25
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.

Project detail page goes blank when Chrome Translate modifies the React DOM

1 participant