fix(experience): opt out of browser auto-translation - #9591
Open
nicolaj0 wants to merge 1 commit into
Open
Conversation
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
nicolaj0
requested review from
charIeszhao,
gao-sun and
simeng-li
as code owners
September 12, 2026 11:48
Contributor
There was a problem hiding this comment.
🟢 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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: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-tokenscreen keepinglang="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">inpackages/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
langattribute (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.langstays at theindex.htmlfallback on/one-time-tokenwhilewindow.logtoSsr.phrases.lngisfrand the UI renders in French — anddata-react-helmetis absent from<html>there, soAppMeta'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.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; withtranslate="no"in place, Chrome no longer offers or applies the translation on those screens, and the flow completes.