Skip to content

Bugfix FXIOS-16715 Keep a translation from landing on the wrong document - #35451

Open
razvanlitianu wants to merge 1 commit into
rlitianu/fxios-15893-pageshow-statefrom
rlitianu/fxios-16715-cross-document-translation
Open

Bugfix FXIOS-16715 Keep a translation from landing on the wrong document#35451
razvanlitianu wants to merge 1 commit into
rlitianu/fxios-15893-pageshow-statefrom
rlitianu/fxios-16715-cross-document-translation

Conversation

@razvanlitianu

@razvanlitianu razvanlitianu commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

📜 Tickets

Jira ticket
Github issue

💡 Description

Stacked on #35450, review that first.

Ask for a translation, navigate before it starts, and it lands on the page you moved to, with a
grey icon over visibly translated text.

translateCurrentPage awaited the model prewarm and then called into the page, with no
cancellation or document check in between. A tab's WKWebView outlives its documents, so a slow
prewarm, which is what the first use of a language pair gives you, means the JS arrives in
whatever loaded meanwhile.

The page now exposes a per-document id. Native reads it before the prewarm and passes it back
when starting, and startTranslations refuses a mismatch. Only an explicit false maps to
documentChanged, so a broken bridge still reports as a failure instead of going quiet.
Navigating away clears the icon and closes the telemetry flow rather than showing a translation
error on the new page.

🎥 Demos

Translate with a model that has never been downloaded, then navigate away within a second. The page you land on used to be rendered in the target language under a grey icon, despite never being translated. Now it stays in its original language and no error toast appears.

Before After
pr35451-before-leak-english-on-untranslated-page pr35451-after-page-stays-french

🧪 Testing

Needs a language model that has never been downloaded on the device. With a cached model the
gap is a few hundred ms and the race cannot be hit.

  1. Settings, Translation, Preferred Languages, add a language you have never translated to.
  2. Open a page in a foreign language.
  3. Tap Translate and pick that new language.
  4. Within about two seconds, navigate away (tap Back, or follow a link).
  5. Wait about 30 seconds.
  6. The page you land on stays in its original language with a grey icon, and no error toast
    appears. The icon is not left spinning.
  7. Translate normally with a cached model and confirm it still works.

📝 Checklist

  • I filled in the ticket numbers and a description of my work
  • I updated the PR name to follow our PR naming guidelines
  • I ensured unit tests pass and wrote tests for new code
  • If working on UI, I checked and implemented accessibility (Dynamic Text and VoiceOver)
  • If adding telemetry, I read the data stewardship requirements and will request a data review
  • If adding or modifying strings, I read the guidelines and will request a string review from l10n
  • If needed, I updated documentation and added comments to complex code

@razvanlitianu
razvanlitianu force-pushed the rlitianu/fxios-16715-cross-document-translation branch from 7c49c47 to 5b2d776 Compare August 31, 2026 12:40
@mobiletest-ci-bot

mobiletest-ci-bot commented Aug 31, 2026

Copy link
Copy Markdown
Messages
📖 Project coverage: 44.39%

💪 Quality guardian

1 tests files modified. You're a champion of test coverage! 🚀

🧹 Tidy commit

Just 5 file(s) touched. Thanks for keeping it clean and review-friendly!

🙌 Friday high-five

Thanks for pushing us across the finish line this week! 🙌

💬 Description craftsman

Great PR description! Reviewers salute you 🫡

✅ Code coverage

  • No new files detected so the coverage gate wasn't run.
  • All modified files meet their coverage thresholds.

Client.app: Coverage: 46.09

File Coverage
TranslationsServiceError.swift 77.27%
TranslationsMiddleware.swift 89.52%
TranslationsService.swift 37.5% ⚠️

Generated by 🚫 Danger Swift against 215365e

@razvanlitianu

Copy link
Copy Markdown
Collaborator Author

And sorry, there's one more stacked on top of it: #35451 (#35451). i know that's a lot to ask in one go. it fixes the translation landing on the page you navigated to, the thing you'd flagged. needs a language model that's never been downloaded to reproduce, steps are in the description. whenever you have room 🙏 @ih-codes

@razvanlitianu
razvanlitianu requested review from ih-codes and a lite review from Copilot September 1, 2026 06:04
@razvanlitianu
razvanlitianu marked this pull request as ready for review September 1, 2026 06:04
@razvanlitianu
razvanlitianu requested a review from a team as a code owner September 1, 2026 06:04

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.

Pull request overview

This pull request fixes a race where translation JS could be applied to a different document than the one the user requested (e.g., navigating during slow model prewarm), causing incorrect UI state on the destination page.

Changes:

  • Add a per-document identifier in the translations page script and require an expectedDocumentId match before starting translations.
  • In native, capture the document id before prewarm, re-check cancellation after prewarm, and treat a mismatch as a dedicated .documentChanged error.
  • Suppress user-facing error/toast for .documentChanged, while still clearing the translation icon and closing out the telemetry flow; add a middleware test for the dropped-translation behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
firefox-ios/firefox-ios-tests/Tests/ClientTests/TranslationsTests/TranslationsMiddlewareTests.swift Adds a test ensuring .documentChanged does not surface an error/toast and clears loading state.
firefox-ios/Client/Frontend/UserContent/UserScripts/MainFrame/AtDocumentStart/TranslationsEntrypoint.js Exposes documentId() and makes startTranslations return false on document mismatch.
firefox-ios/Client/Frontend/Translations/TranslationsMiddleware.swift Treats .documentChanged as a drop: clears icon and flow id without dispatching translation failure UI.
firefox-ios/Client/Frontend/Translations/Service/TranslationsServiceError.swift Introduces .documentChanged and a stable telemetry token.
firefox-ios/Client/Frontend/Translations/Service/TranslationsService.swift Captures document id pre-prewarm, checks cancellation post-prewarm, and maps JS false to .documentChanged.

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

Comment on lines +112 to +116
private func currentDocumentIdJS(on webView: WKWebView) async throws -> String {
let failure = TranslationsServiceError.jsEvaluationFailed(
reason: "JS evaluation failed: currentDocumentIdJS"
)
let js = "return window.__firefox__.Translations.documentId()"
translateCurrentPage resolved the tab's WKWebView, awaited the model
prewarm, then called into the page. Nothing between the await and the JS
call checked for cancellation or for the document having changed, and a
tab's WKWebView is a single object that outlives its documents. When the
prewarm was slow, which happens the first time a language pair is used,
the translation was applied to whatever page the user had navigated to.

The page now mints a document identifier that native captures before the
prewarm and hands back when starting; startTranslations refuses a request
addressed to a different document. A cancellation check after the prewarm
covers the case where the task is cancelled while the model downloads.

Navigating away is not a failure, so the request is dropped silently
rather than showing a translation error on the new page.
@razvanlitianu
razvanlitianu force-pushed the rlitianu/fxios-16715-cross-document-translation branch from 5b2d776 to 215365e Compare September 4, 2026 08:49
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.

3 participants