Skip to content

fix(experience): opt out of browser auto-translation - #9591

Open
nicolaj0 wants to merge 1 commit into
logto-io:masterfrom
nicolaj0:fix/experience-opt-out-of-auto-translation
Open

fix(experience): opt out of browser auto-translation#9591
nicolaj0 wants to merge 1 commit into
logto-io:masterfrom
nicolaj0:fix/experience-opt-out-of-auto-translation

Conversation

@nicolaj0

Copy link
Copy Markdown

Fixes the crash reported in #9590 — or rather, removes its trigger.

The problem

Browser auto-translation replaces the text nodes React created with <font><font>…</font></font> wrappers. React's bookkeeping no longer matches the document, so the next update throws:

NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

The experience app has no error boundary, so the whole tree unmounts: the user is left on a blank page in the middle of signing in or signing up, and only a reload gets them out. A one-time link is already consumed at that point, so on an invitation flow the second click lands on "token consumed" and the user is stuck.

On our self-hosted 1.41.0 tenant this cost 14 of 68 invited users over three weeks, every one of them on Chrome (no occurrence on Edge, Firefox or Safari). The trigger there is the /one-time-token screen keeping lang="en" while rendering the tenant's French phrases (#9590) — but the attribute bug is only what invites the translation; the crash itself can be triggered by any user who asks their browser to translate an auth page.

The change

Ship translate="no" and <meta name="google" content="notranslate"> in packages/experience/index.html.

The experience app is already localized per tenant — custom phrases, language detection, ui_locales — so a browser translation on top of it adds little and can take the whole page down. This is what Chrome, Edge and Safari read before offering or applying a translation.

What this PR deliberately does not do

  • It does not fix the lang attribute (experience: html lang stays "en" on the one-time-token page, so browsers auto-translate a localized page and React crashes (blank page) #9590). document.documentElement.lang stays at the index.html fallback on /one-time-token while window.logtoSsr.phrases.lng is fr and the UI renders in French — and data-react-helmet is absent from <html> there, so AppMeta's Helmet never applied. I could not pin down the timing well enough to propose a fix I'd trust, and did not want to guess in a PR. The reproduction is in the issue.
  • It does not add an error boundary to the experience router, which would turn any such DOM mismatch into a retry screen instead of an unmount. Happy to open a separate PR if you'd like one.

Testing

Reproduced and verified against a self-hosted 1.41.0 tenant: with the text nodes wrapped as the translator does, confirming the terms modal unmounted the app on /continue/password; with translate="no" in place, Chrome no longer offers or applies the translation on those screens, and the flow completes.

Browser auto-translation rewrites the text nodes React created, so the next
update throws `NotFoundError: removeChild` and, with no error boundary, unmounts
the whole app: users land on a blank page mid sign-in/sign-up.

The experience is already localized per tenant, so the page now ships
`translate="no"` and `<meta name="google" content="notranslate">`.

Closes logto-io#9590

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The reviewed changes address the translation-triggered DOM mismatch with no unresolved blocking issues.

Pull request overview

Prevents browser auto-translation from mutating React-managed DOM in the experience authentication app.

Changes:

  • Adds translation opt-out markers.
  • Adds a patch changeset for @logto/experience.
File summaries
File Summary
packages/experience/index.html Disables browser auto-translation.
.changeset/khaki-pumas-invite.md Documents the patch release.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite (auto)

Note

Copilot is running an experiment and ran this review at Lite.


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants