feat(i18n): serve language packs as versioned, immutable-cacheable scripts#41780
feat(i18n): serve language packs as versioned, immutable-cacheable scripts#41780rusackas wants to merge 3 commits into
Conversation
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #41780 +/- ##
==========================================
- Coverage 64.72% 64.70% -0.02%
==========================================
Files 2686 2686
Lines 148651 148688 +37
Branches 34309 34315 +6
==========================================
- Hits 96213 96211 -2
- Misses 50676 50709 +33
- Partials 1762 1768 +6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
CI status: everything is green now except |
…ripts Follow-up to #39357, which inlined the Jed language pack into the bootstrap HTML to fix the code-split translation race (#35330). That made non-English full-page loads carry ~67KB (gzipped) of pack on every request since HTML is uncacheable. This keeps the synchronous-configuration guarantee but moves the pack to a content-addressed script: spa.html emits <script src="/language_pack/<lang>/<version>/script.js"> before the entry bundle, where <version> is a short content hash of the pack file. The endpoint serves window.__SUPERSET_LANGUAGE_PACK__ = {...} with Cache-Control: public, max-age=31536000, immutable, so browsers fetch the pack once per translation change instead of once per page load, and cache-bust automatically on upgrade (fixing the stale-pack window the unversioned /language_pack/<lang>/ fetch had under the 1-year SEND_FILE_MAX_AGE_DEFAULT). Details: - English emits no tag and pays nothing. - A stale version in a cached HTML page still gets current content, served no-cache so it can't pin under the wrong address. - Packs provided via COMMON_BOOTSTRAP_OVERRIDES_FUNC still ride the bootstrap payload and suppress the script tag (spa.html stashes them on window instead), preserving the historical workaround. - The endpoint is deliberately unauthenticated: catalogs are static public repo content with no user data, and must load for anonymous principals (login page, embedded). - preamble.ts fallback chain unchanged: bootstrap pack, window global, then async fetch if the script failed to load. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…antics Fixes the two CI failures (generator fixture annotated Iterator[None], stray unused import in the test package init) and adds tests encoding the delivery contract: - English configures the translator bare and never loads a pack (zero payload, no fetch). - Non-English configures synchronously from the window global set by the versioned classic script tag, with no fetch and no English flash. - An operator-supplied bootstrap pack takes precedence over the window global. - The fallback fetch requests only the selected locale and resolves before initPreamble() returns, so even that path renders translated. - The endpoint resolves exactly the locale in the URL and nothing else. - Static guard: spa.html's pack script tag precedes the entry bundle and carries no async/defer, preserving execution order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…list the script route Fixes the three real CI failures: - unit-tests: get_spa_template_context called common_bootstrap_payload() a second time just to derive the language pack context, which requires user/auth request state that tests mocking get_spa_payload don't set up. get_language_pack_template_context now takes the already-built common payload dict, so template context and payload can't diverge and the theme-helper tests pass unchanged. - test-sqlite/mysql/postgres: register the deliberately-unauthenticated language_pack_script route in test_views_are_secured's allowlist with its justification (static public catalog data, must load for anonymous principals). - lint-frontend: type the preamble test fixture as LanguagePack (plural_forms was missing) via a type-only import that the jest module mock doesn't affect. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9f6de65 to
dc475a1
Compare
Code Review Agent Run #1af492Actionable Suggestions - 0Additional Suggestions - 1
Filtered by Review RulesBito filtered these suggestions based on rules created automatically for your feedback. Manage rules.
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
SUMMARY
Follow-up to #39357 (now merged), rebased onto master so the diff is the follow-up only.
#39357 fixes the code-split translation race (#35330) by inlining the Jed language pack into the bootstrap HTML. That's correct but ships ~237KB raw / ~67KB gzipped of pack in every non-English full-page response, since HTML isn't cacheable. This follow-up keeps the synchronous-configuration guarantee while making the pack a first-class cacheable asset:
spa.htmlemits<script src="/language_pack/<lang>/<version>/script.js">before the entry bundle, where<version>is a short content hash of the pack file (cached in-process alongside the pack itself).window.__SUPERSET_LANGUAGE_PACK__ = {…};withCache-Control: public, max-age=31536000, immutable— browsers fetch the pack once per translation change instead of once per page load, and cache-bust automatically on upgrade. (The pre-existing unversioned/language_pack/<lang>/fetch could serve packs up to a year stale after an upgrade, thanks toSEND_FILE_MAX_AGE_DEFAULT.)no-cacheso it can't pin under the wrong address.COMMON_BOOTSTRAP_OVERRIDES_FUNCstill ride the bootstrap payload and suppress the script tag;spa.htmlstashes them onwindowinstead, so the historical [6.0.0rc1] Partial Translations on pt_BR #35330 workaround keeps working and takes precedence.preamble.ts's fallback chain is unchanged (bootstrap pack → window global → async fetch), so a failed script load degrades gracefully./language_pack/<lang>/fetch endpoint's@has_accesswould 302 for embedded anonymous users, which the script tag avoids).EmbeddedViewpasses the same template context.BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A — no visual changes. Behavior change is in caching headers and HTML size.
TESTING INSTRUCTIONS
Manual: set a non-English locale, load any page, and confirm (1) the
<script src="/language_pack/…/script.js">tag precedes the entry bundle, (2) the response carriesimmutable, (3) a hard reload serves it from browser cache, (4) translations render in code-split chunks on first paint.ADDITIONAL INFORMATION
/language_pack/<lang>/<version>/script.jsroute)🤖 Generated with Claude Code