Bundle WordPress translation files with download retry and failure handling#2575
Bundle WordPress translation files with download retry and failure handling#2575ivan-ottinger merged 9 commits intotrunkfrom
Conversation
e4d9c7d to
dcd9d36
Compare
|
@ivan-ottinger I think we need to address the request limits part, too, so we don't have flaky builds. |
b4ee240 to
73d516c
Compare
I have applied logic with three retries with delay of 1, 2 and 4 seconds. We could also add a small delay between each request on top of that. What do you think? Or would you prefer adding that caching logic as well? I wonder if it is not too much though - in case it turns out there are no issues with the current approach anymore. |
There was a problem hiding this comment.
@ivan-ottinger I tested and everything works well, only one step which I didn't get how to test - The WordPress admin is displayed in the selected language.. What is WP admin?
Also left some small comments.
But I would also wait for Wojtek's feedback on his comment, so I propose postponing this PR to the next release. WDYT, is it ok?
|
Thank you for the review, Vova!
Yes, WP Admin. I have updated it in the description to make it clear. 🙂
Thanks! I will take a look at them.
I agree, let's leave this PR for the next release. |
📊 Performance Test ResultsComparing dd1270d vs trunk site-editor
site-startup
Results are median values from multiple test runs. Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff) |
fredrikekelund
left a comment
There was a problem hiding this comment.
This works as expected and LGTM 👍 I left a couple of nit comments, but nothing blocking. We could potentially land this PR and follow up with a separate PR for addressing any small tweaks we want to do.
| export async function setupWPServerFiles() { | ||
| await copyBundledLatestWPVersion(); | ||
| await copyBundledSqlite(); | ||
| await copyBundledWPCLI(); | ||
| await copyBundledSQLiteCommand(); | ||
| await copyBundledTranslations(); | ||
| const steps: Array< [ string, () => Promise< void > ] > = [ | ||
| [ 'WordPress version', copyBundledLatestWPVersion ], | ||
| [ 'SQLite integration', copyBundledSqlite ], | ||
| [ 'WP-CLI', copyBundledWPCLI ], | ||
| [ 'SQLite command', copyBundledSQLiteCommand ], | ||
| [ 'translations', copyBundledTranslations ], | ||
| [ 'language packs', copyBundledLanguagePacks ], | ||
| ]; | ||
|
|
||
| for ( const [ name, step ] of steps ) { | ||
| try { | ||
| await step(); | ||
| } catch ( error ) { | ||
| console.error( `Failed to set up bundled ${ name }:`, error ); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
This isn't the fault of this PR, but I really want to revisit why we need to do this. We're basically copying the entire wp-files directory to a single server-files location. Why do we need to do this? Seems like potential legacy logic that we could simplify…
There was a problem hiding this comment.
Good observation. I let Claude look at this and here are its observations (I haven't verified everything):
1. The app bundle is read-only — Electron's Resources/ directory
(ASAR-packed) can't be modified at runtime. The app needs a writable
location because it downloads newer versions of WordPress, SQLite, and
WP-CLI from the internet.
2. Auto-updates — The app checks for and downloads newer WordPress
versions, storing them in server-files/. The bundled version is just the
initial seed.
3. Version management — server-files/wordpress-versions/ holds multiple WP
versions side by side (e.g., latest/, 6.4.3/). Not possible in the static
app bundle.
4. Offline resilience — The bundled files guarantee the app works on first
launch without internet.
* Bundle WordPress core language packs to speed up non-English site creation Instead of downloading translation files from WordPress.org at runtime via the setSiteLanguage blueprint step, bundle core language packs for all 19 supported non-English locales at build time. During site creation for the latest WP version, files are copied locally and WPLANG is set via defineWpConfigConsts + setSiteOptions. Falls back to setSiteLanguage for non-latest versions or when bundled packs are unavailable. Also makes setupWPServerFiles resilient so individual step failures don't prevent subsequent steps from running. * Drop .po and .mo files from bundled language packs WordPress 6.5+ uses .l10n.php files, making .po (source) and .mo (legacy binary) files unnecessary at runtime. Removing them reduces the language packs from 80MB to 27MB. Also fixes ts-node module resolution by inlining the locale list in the download script instead of importing from common/lib/locale.ts. * Bundle translations for default plugins and themes Download and bundle translation files for akismet, twentytwentyfive, twentytwentyfour, and twentytwentythree alongside core translations. Plugin/theme translations are stored in languages/plugins/ and languages/themes/ subdirectories and copied to the site during creation. Adds ~2MB to the bundle. * Fix temp file path for plugin/theme language pack downloads Replace slashes in the label used for temp zip filenames to avoid creating subdirectories in the temp folder. * Extract WordPress locale list to shared module Move the list of WordPress locale codes to common/lib/wp-locales.ts so it can be imported by both the download script (ts-node) and app code (Vite) without module resolution issues. Remove the unused studioToWpLocaleMap from common/lib/locale.ts. * Add hello-dolly to bundled plugin translations * Remove as const from WP_LOCALES to fix ts-node compilation * Align language pack download messages with existing status format * Auto-detect bundled plugins and themes for translation downloads Read the wp-content/plugins and wp-content/themes directories from the extracted WordPress installation instead of hardcoding the list. Handles single-file plugins like hello.php via a slug mapping. * Remove redundant comment in site creation language setup
Prevents flaky CI builds by retrying failed requests up to 3 times with exponential backoff (1s, 2s, 4s). Failed downloads now fail the build instead of silently skipping, ensuring all translations are included.
942a060 to
dd1270d
Compare
Okay, let's try with that. It seems that the chance of getting rate-limited is lower after moving the script out from |
Thanks, Wojtek! Yes, I think it should be far less likely to hit the limit now. In case we still run into issues, I am happy to revert again and we can apply additional measures. |
|
I realize we still package the app at least four times for every PR push (E2E tests for macOS and Windows, and performance job builds for the PR branch and trunk). So, there's still a fair amount of downloading going on, even with this optimization. We previously discussed improving CI efficiency by reusing a single packaging artifact across multiple jobs. We should look into that. |
That would be great. I see we have a related Linear issue here already: STU-1045. |
Related issues
Closes STU-1250
Related to STU-980
Context
#2558 bundled WordPress translation files for faster site creation but was reverted in #2572 due to CI build failures —
ConnectTimeoutErrorwhen downloading ~114 translation ZIP files sequentially fromdownloads.wordpress.orgduringnpm install. The root cause was that language pack downloads ran on everynpm installviapostinstall.Related discussion: p1770812916266539-slack-C06DRMD6VPZ.
What changed from the original PR
This PR re-applies #2558 with the following fixes:
postinstallinto a standalone script (scripts/download-language-packs.ts) that runs duringnpm run makevia the forgeprePackagehook.npm installno longer downloads language packsConnectTimeoutError.make— if a download still fails after retries, the build fails, ensuring all translations are included in the release.npm run download-language-packsavailable as a standalone command for manual use.Proposed Changes (from original PR)
server-files/language-packs/directory..l10n.phpand.jsonfiles directly into the site'swp-content/languages/directory and setWPLANGvia blueprint steps (defineWpConfigConsts+setSiteOptions) — no network round-trip needed.setSiteLanguageblueprint step for non-latest WP versions or when bundled packs are unavailable..l10n.phpand.jsonfiles (WordPress 6.5+ format), skipping.poand.moto reduce size (~29MB vs ~82MB).setupWPServerFilesresilient so individual step failures don't prevent subsequent steps from running.Testing Instructions
Testing the built app
npm run make.Studio.app/Contents/Resources/wp-files/latest/languages:trunk.wp-content.wp-content.Testing the dev environment
npm install.languagesdirectory present inwp-files/latest.npm run download-language-packsand verify language packs are downloaded. You can find them in the project root:wp-files/latest/languages.npm startand set the locale in the app settings to a non-English language (e.g. Swedish).npm testand verify all tests pass.Pre-merge Checklist