Skip to content

fix(translation): preserve latest language selection during async loads - #7

Draft
knowlet wants to merge 1 commit into
mainfrom
fix/latest-language-selection-20261105
Draft

knowlet wants to merge 1 commit into
mainfrom
fix/latest-language-selection-20261105

Conversation

@knowlet

@knowlet knowlet commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Confirmed defect

Out-of-order language-file responses can overwrite a newer language choice. Selecting the already-active language also leaves an older pending selection live, and a failed latest load can allow an older selection to apply unexpectedly.

Change

Give each setLanguage invocation a unique request token, including active/cached selections. Only the latest successful asynchronous selection may apply translations and refresh windows. Stale successful loads still populate the existing cache. No request cancellation or loadLanguage API changes.

Verification

Base: 83ceac969392e7ea1948652d0b2dd6d06233ddeb.
Head: aa91a9b72b80731cfe6e3071e8b31ad5c62658cd.
Published tree: 695333552faad3c2f236de56664cafad6c6789cf, identical to the locally tested tree.

  • Seven controlled-XHR tests on the original implementation: 5 failed / 2 passed.
  • Final locked npm ci and npm test -- --runInBand --silent: 75 tests passed on Node 24.22.1 / npm 11.9.0.
  • Existing Python installer controls: 27 tests passed on Python 3.12.14 / pytest 9.2.0.
  • JavaScript syntax, Python compileall and git diff --cached --check passed. No separate build or lint script exists.
  • Independent read-only review found no blocking issue and reran all 75 JavaScript tests successfully.

Hosted CI run 42042252813 completed successfully for head aa91a9b72b80731cfe6e3071e8b31ad5c62658cd. Node 18.20.8 and 20.20.2 each passed all 75 tests; Python 3.11.18 passed all 27 tests. Checkout logs confirm merge ref 035ba0e4474d48eb606ba62fdae0beb8e47e46dc, whose parents are the exact head/base above and whose tree equals the tested head tree. This is verified merge-ref CI, not bare-head checkout. Existing action-runtime deprecation and dependency warnings remain. Tests use synthetic XHR responses; no real RPG Maker installation or browser acceptance is claimed. Existing dependency refresh #6 and installer #5 are independent and unchanged; this PR leaves the main lockfile and its known development-dependency findings unchanged. No credentials, live game files, user computer, deployment, merge or release used.


Summary by cubic

Fixes a race condition in TranslationManager.setLanguage where out-of-order async language-file responses could overwrite a newer selection, a failed latest load could let an older selection apply, and reselecting the active language left an older pending request live. Each setLanguage call now gets a unique request token, and only the latest successful async selection applies translations and refreshes windows; stale successful loads still populate the cache.

Adds seven tests covering backward responses, reselecting the active language, cached selections superseding pending loads, failed loads, single selections, and retries.

Written for commit aa91a9b. Summary will update on new commits.

View guided diff Turn on auto-fix

Summary by Sourcery

Prevent stale asynchronous language loads from overriding the latest language selection.

Bug Fixes:

  • Ensure only the latest language selection can apply asynchronously loaded translations and refresh windows, preventing stale or failed requests from overriding newer choices.

Enhancements:

  • Treat active and cached language selections as superseding pending requests while retaining stale successful loads in the translation cache.

Tests:

  • Add coverage for out-of-order, stale, cached, failed, retried, and single-request language selections.

@coderabbitai

coderabbitai Bot commented Nov 5, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@sourcery-ai

sourcery-ai Bot commented Nov 5, 2026

Copy link
Copy Markdown

Reviewer's Guide

Language selection now uses per-invocation request tokens to make asynchronous loads last-selection-wins: stale successes remain cached but cannot update the active language or UI, while cached and active selections also supersede pending requests. New controlled-XHR tests cover ordering, cancellation, failures, caching, and retries.

Sequence diagram for latest language selection during async loads

sequenceDiagram
    actor User
    participant TranslationManager
    participant XHR
    participant Windows as GameWindows

    User->>TranslationManager: setLanguage(languageA)
    TranslationManager->>XHR: loadLanguage(languageA)
    User->>TranslationManager: setLanguage(languageB)
    TranslationManager->>XHR: loadLanguage(languageB)
    XHR-->>TranslationManager: languageA response
    TranslationManager->>TranslationManager: cache languageA
    XHR-->>TranslationManager: languageB response
    TranslationManager->>TranslationManager: apply languageB
    TranslationManager->>Windows: _refreshAllWindows()
Loading

State diagram for language request supersession

stateDiagram-v2
    [*] --> Pending
    Pending --> Pending: setLanguage(language)
    Pending --> Cached: stale successful load
    Pending --> Active: latest successful load
    Pending --> Pending: latest load failure
    Active --> Pending: setLanguage(newLanguage)
    Active --> Active: setLanguage(activeLanguage)
    Cached --> Active: latest cached selection
Loading

File-Level Changes

Change Details Files
Added latest-request tracking so only the most recent language selection can commit UI state after asynchronous loading.
  • Creates and stores a unique request token for every setLanguage call, including active-language reselects and cached selections.
  • Guards current-language updates, translation application, and window refreshes with the latest-token check.
  • Continues caching stale successful responses without allowing them to become active. More recent failures no longer permit older requests to apply.
DynamicTranslation.js
Added controlled-XHR regression coverage for asynchronous language-selection races and retry behavior.
  • Covers reverse response ordering and prevents stale intermediate application.
  • Covers active-language cancellation, cached selections, latest-load failures, successful application, and retrying failures.
  • Asserts both active language and translation/window-refresh side effects.
tests/language-race.test.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

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.

1 participant