Skip to content

fix(styles): apply appearance changes to live translations - #1981

Open
JohnathanT55 wants to merge 4 commits into
mengxi-ream:mainfrom
JohnathanT55:fix/live-translation-style-updates
Open

fix(styles): apply appearance changes to live translations#1981
JohnathanT55 wants to merge 4 commits into
mengxi-ream:mainfrom
JohnathanT55:fix/live-translation-style-updates

Conversation

@JohnathanT55

@JohnathanT55 JohnathanT55 commented Jul 28, 2026

Copy link
Copy Markdown

AI model(s) used (required): OpenAI GPT-5 (Codex)

Type of Changes

  • ✨ New feature (feat)
  • πŸ› Bug fix (fix)
  • πŸ“ Documentation change (docs)
  • πŸ’„ UI/style change (style)
  • ♻️ Code refactoring (refactor)
  • ⚑ Performance improvement (perf)
  • βœ… Test related (test)
  • πŸ”§ Build or dependencies update (build)
  • πŸ”„ CI/CD related (ci)
  • 🌐 Internationalization (i18n)
  • 🧠 AI model related (ai)
  • πŸ”„ Revert a previous commit (revert)
  • πŸ“¦ Other changes that do not modify src or test files (chore)

Description

Apply translation appearance changes to translations already present on an actively translated page.

The options preview cannot reproduce every website's typography and CSS. Refreshing the host page to verify an appearance change rebuilds the page state and translated DOM, which can be disruptive on long or interactive pages.

This implementation is lifecycle-scoped:

  • registers the config listener only while page translation is active;
  • disposes of the listener as soon as page translation stops;
  • reacts only when translationNodeStyle changes;
  • re-decorates existing block and inline translations, including translations inside open shadow roots;
  • ensures translations that finish after a style change use the latest style;
  • reconciles missed changes when a frozen tab becomes visible again;
  • serializes style application to avoid concurrent custom stylesheet replacement;
  • avoids another provider request or page-translation restart when only appearance changes.

Related Issue

N/A

How Has This Been Tested?

  • Added unit tests
  • Verified through manual testing

Validation:

  • full Vitest suite β€” 237 files and 2236 tests passed
  • lifecycle/style targeted suite β€” 4 files and 10 tests passed
  • type-aware lint and formatting checks passed for all changed files
  • manually switched translation styles on an already translated page in Chrome and confirmed existing and late-arriving translations updated without another provider request

Screenshots

N/A β€” this fixes live application of existing appearance settings rather than adding a new visual preset.

Checklist

  • I have tested these changes locally
  • I have updated the documentation accordingly if necessary
  • My code follows the code style of this project
  • My changes do not break existing functionality
  • If my code was generated by AI, I have proofread and improved it as necessary.

Additional Information

@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

πŸ¦‹ Changeset detected

Latest commit: 24ac93e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@read-frog/extension Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the fix label Jul 28, 2026
@JohnathanT55
JohnathanT55 marked this pull request as ready for review July 28, 2026 05:39
Copilot AI review requested due to automatic review settings July 28, 2026 05:39
@github-actions github-actions Bot added contrib-trust:new PR author trust score is 0-29. needs-maintainer-review Contributor trust automation recommends maintainer review. labels Jul 28, 2026
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Contributor trust score

10/100 β€” New contributor

This score estimates contributor familiarity with mengxi-ream/read-frog using public GitHub signals. It is advisory only and does not block merges automatically.

Outcome

Score breakdown

Dimension Score Signals
Repo familiarity 0/35 commits in repo, merged PRs, reviews
Community standing 5/25 account age, followers, repo role
OSS influence 0/20 stars on owned non-fork repositories
PR track record 5/20 merge rate across resolved PRs in this repo

Signals used

  • Repo commits: 0 (author commits reachable from the repository default branch)
  • Repo PR history: merged 0, open 1, closed-unmerged 0
  • Repo reviews: 0
  • PR counted changed lines: 404 (+398 / -6)
  • Repo permission: read
  • Followers: 1
  • Account age: 74 months
  • Owned non-fork repos considered: max 0, total 0 (JohnathanT55/MLLM-Safety-Bench (0), JohnathanT55/pa1 (0), JohnathanT55/CSE368GroupProject (0), JohnathanT55/eco-AI-tourism-FE (0), JohnathanT55/JohnathanT55 (0), JohnathanT55/IOS-Planner (0), JohnathanT55/Amplify-demo (0), JohnathanT55/Front-end-and-Web-server-to-show-Covid-information (0), JohnathanT55/Self-Simulate-Super-Mario (0), JohnathanT55/enemy-ai (0), JohnathanT55/PointOfSale (0), JohnathanT55/PaleBlueDot (0), JohnathanT55/IOS-Tip-Calculator (0))

Policy

  • Low-score review threshold: < 30
  • Auto-close: score < 20 and counted changed lines > 1000
  • Migration-related files are excluded from the auto-close line count
  • Policy version: v1.2

Updated automatically when the PR changes or when a maintainer reruns the workflow.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31537c01ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +45 to +48
const translatedNodes = deepQueryAllSelector(document, isTranslatedContentNode)
await Promise.all(
translatedNodes.map((node) =>
decorateTranslationNode(node, newConfig.translate.translationNodeStyle),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reapply styles to translations that finish after the scan

When a style change occurs while provider requests are still in flight, this one-time scan only updates translation nodes that already exist. The in-flight paths retain the old Config across the request and later call insertTranslatedNodeIntoWrapper with config.translate.translationNodeStyle, so nodes appended after this scan keep the previous appearance indefinitely. Ensure late insertions read the current style or otherwise re-decorate nodes created after the configuration event.

Useful? React with πŸ‘Β / πŸ‘Ž.

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

Updates the host content script so translation appearance settings (preset/custom CSS) are applied to translations already present in the DOM, without re-requesting translation results.

Changes:

  • Added a style-change handler that finds existing translated nodes (including in open shadow roots) and re-decorates them with the latest translationNodeStyle.
  • Updated the runtime bootstrap to watch persisted config changes and trigger either a restart (mode change) or a re-decoration (style change).
  • Added unit tests for the new style-change behavior and included a patch changeset for @read-frog/extension.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/entrypoints/host.content/translation-control/handle-config-change.ts Adds handleTranslationStyleChange and changes handleTranslationModeChange to return whether it restarted translation.
src/entrypoints/host.content/translation-control/tests/handle-config-change.test.ts Adds jsdom-based tests validating re-decoration across document + open shadow roots.
src/entrypoints/host.content/runtime.ts Watches config storage updates and triggers either restart or re-decoration accordingly.
.changeset/tidy-frogs-style.md Patch changeset to release the live appearance-update fix.

πŸ’‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +37 to +43
if (
!newConfig ||
!oldConfig ||
dequal(newConfig.translate.translationNodeStyle, oldConfig.translate.translationNodeStyle)
) {
return
}
Comment thread src/entrypoints/host.content/runtime.ts Outdated
Comment on lines +53 to +56
const didRestart = handleTranslationModeChange(newConfig, oldConfig, manager)
if (!didRestart) {
void handleTranslationStyleChange(newConfig, oldConfig)
}

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e5342c5435

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/entrypoints/host.content/runtime.ts Outdated
const cleanupTranslationModeShortcut = await bindTranslationModeShortcutKey()

let currentConfig = initialConfig
const cleanupConfigListener = storageAdapter.watch<Config>(CONFIG_STORAGE_KEY, (newConfig) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reconcile styles after a frozen tab resumes

When the appearance is changed while this tab is frozen or inactive, the storage event can be missed, so this callback never runs and currentConfig remains stale after the tab becomes visible. The repository already accounts for this behavior by reloading config on visibilitychange in configAtom and by reading config on demand in node-translation.ts; without equivalent reconciliation here, existing translations retain their old appearance until another observed config write or a retranslation.

Useful? React with πŸ‘Β / πŸ‘Ž.

Comment on lines +46 to +48
await Promise.all(
translatedNodes.map((node) =>
decorateTranslationNode(node, newConfig.translate.translationNodeStyle),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize custom stylesheet updates per root

When custom CSS is active and a root contains multiple translated nodes, this Promise.all makes every decoration call ensureCustomCSS concurrently; on the constructable-stylesheet path those calls invoke replace() on the same cached CSSStyleSheet before its CSS cache is updated. Browsers reject a second replace() while that sheet is already being modified, producing an unhandled rejection on every such refresh, and a rapid subsequent custom-CSS save can consequently leave the earlier CSS installed. Update each root's stylesheet once or serialize replacements rather than starting one replacement per node.

Useful? React with πŸ‘Β / πŸ‘Ž.

@mengxi-ream mengxi-ream left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Hi,

We are reluctant to add the listener for this, since users can refresh the page to get the new translation style.

Any specific reason you think we should merge this PR?

JohnathanT55 commented Jul 29, 2026

Copy link
Copy Markdown
Author

Hi,

We are reluctant to add the listener for this, since users can refresh the page to get the new translation style.

Any specific reason you think we should merge this PR?

Hi, thanks for the feedback.

The main use case is adjusting translation appearance while actively reading. The preview in the options page cannot fully reproduce a website's own typography and CSS, so users may need to verify colors, font size, and other appearance settings on the actual translated page.

Refreshing rebuilds both the page state and the translated DOM, which can be disruptive on long or interactive pages. Applying the new style directly to existing translation nodes provides immediate feedback without restarting the page translation flow.

This also seems consistent with the recent same-origin navigation change in #1982, which preserves the live translation session instead of tearing it down and rebuilding it, avoiding translated-content flicker.

I understand the concern about adding a broad config listener to every host content script. I can narrow the implementation so that the listener is registered only while page translation is active, disposed of as soon as translation stops, and reacts only when translationNodeStyle changes.

Would that narrower lifecycle-scoped implementation address your concern?

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24ac93efb9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +242 to +244
this.cleanupTranslationStyleListener = registerTranslationStyleListener(
config.translate.translationNodeStyle,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reconcile style after installing the session listener

When appearance settings are saved after start() reads its initial config but before the awaited setAndNotifyPageTranslationStateChangedByManager call returns, no watcher is registered to receive that storage event. This registration then seeds the listener with the stale style and performs no immediate config reread, so a page that remains visible keeps using the old appearance until another style write or visibility transition. Reconcile storage immediately after installing the watcher to close this startup window.

Useful? React with πŸ‘Β / πŸ‘Ž.

Comment on lines +177 to +180
await decorateTranslationNode(
translatedNode,
resolveLiveTranslationNodeStyle(translationNodeStyle),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Serialize late insertions with custom CSS refreshes

When a provider response is being inserted as a custom stylesheet change arrives, this decoration can call ensureCustomCSS concurrently with the refresh in handleTranslationStyleChange. Although the scan is now sequential, this newly changed insertion path remains outside that queue; on the constructable-stylesheet path, overlapping CSSStyleSheet.replace() calls reject, so the refresh can be logged as failed and leave the previous custom CSS active until another update or insertion. Serialize replacements per root in the style injector rather than only serializing scan nodes.

Useful? React with πŸ‘Β / πŸ‘Ž.

@mengxi-ream

Copy link
Copy Markdown
Owner

Hi, thank you for the update! Could you give me an example website you think it really need instant change of the translation style css?

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

Labels

contrib-trust:new PR author trust score is 0-29. fix needs-maintainer-review Contributor trust automation recommends maintainer review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants