fix(translation): preserve latest language selection during async loads
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.
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.