Search Blocks: enable @wordpress/i18n in the IAPI view bundle (SEARCH-168)#48551
Search Blocks: enable @wordpress/i18n in the IAPI view bundle (SEARCH-168)#48551
Conversation
This comment has been minimized.
This comment has been minimized.
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
3cf1b71 to
74f8b90
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…-168) Externalize @wordpress/i18n to a script-module reference (via DEP's requestToExternalModule) and register a tiny ESM shim that re-exports window.wp.i18n as the @wordpress/i18n module. The classic wp-i18n script is enqueued on every search-blocks page so window.wp.i18n is populated synchronously before any deferred module evaluates; translations are inlined as setLocaleData() against PHP's already-loaded gettext entries for jetpack-search-pkg, so __() / _n() / sprintf() return localized strings on first paint without depending on per-handle .json files. Use the new path in: - result-utils.js buildRatingAriaLabel — fixes the SEARCH-168 frontend product-rating aria label (was hardcoded English when used outside the editor preview). - store/index.js computeResultsCountText — replaces the PHP-seeded state.strings reads with native __()/_n()/sprintf(). - active-filters/view.js activePills — same swap. Drop the now-unused build_initial_strings() PHP seed and the test assertions that pinned its shape.
…hangelog Type - Fix the inverted "first-wins" claim in register_i18n_module()'s docblock: ours wins because we register first; flag the maintenance hazard if WP core later ships a native @wordpress/i18n module (raised by both Copilot and claude[bot]). - Extract build_locale_data_payload() out of collect_locale_data() and cover it with two unit tests (Jed shape from a fake Translations, default Plural-Forms fallback when the header is missing). Closes the gap both reviewers flagged for the new PHP code. - Make webpack.blocks.config.js's requestToExternalModule explicit: early-return for non-i18n requests so the DEP fall-through is visible at a glance (claude[bot] nit). - Update changelog Type from "changed" to "fixed" to match the SEARCH-168 framing (Copilot nit).
74f8b90 to
ef8151e
Compare
Review-cycle summary —
|
| Source | Comment | Resolution |
|---|---|---|
| claude[bot] | (#IC_kwDOAOho7M8AAAABBVwvcA) inverted "first-wins" docblock; missing collect_locale_data() test coverage; explicit DEP fall-through; Plural-Forms casing; _nx fallback signature |
Docblock rewritten to match actual semantics (ef8151e); build_locale_data_payload() extracted with two new PHPUnit cases; requestToExternalModule now leads with an explicit early-return; casing handled via ?? fallback to the Western 2-form rule; shim fallback signature scoped to the unreachable wp-i18n-missing case. |
| copilot-swe-agent | (#IC_kwDOAOho7M8AAAABBVyIQQ) same three actionable items + changelog Type: changed → Type: fixed |
Same commit ef8151e; changelog Type updated. |
| claude[bot] (re-review) | (#IC_kwDOAOho7M8AAAABBV05Wg) "Ready to merge." | No action — confirmation. |
| copilot-swe-agent (re-review) | (#IC_kwDOAOho7M8AAAABBV1YTA) "Looks good to merge." | No action — confirmation. |
| jp-launch-control | (#IC_kwDOAOho7M8AAAABBVz1Cw) Code-coverage delta (-6.80% in class-search-blocks.php; new i18n-shim.js at 0/16) |
Coverage check itself is pass. The drop is enqueue_i18n_runtime() / register_i18n_module() / collect_locale_data() wrapping WP registry functions (not unit-testable without a WP bootstrap), and i18n-shim.js is a browser-only ESM shim whose runtime path is exercised through result-utils.test.js / store.test.js against the real @wordpress/i18n npm package. Both reviewers explicitly accepted the gap as "no action needed." |
Unaddressed (flagged for owner): None.
CI: all required checks passing (Test plugin upgrades is pending, deploy-preview only — not blocking).
Fixes SEARCH-168
Why
A shopper using a screen reader on a non-English Jetpack Search store currently hears the product rating in English ("4.5 out of 5 stars based on 42 reviews") even though everything else on the page is translated. The fix gives the Interactivity API view bundle a real
@wordpress/i18nit can call, so the rating aria-label — and every other JS-emitted view-bundle string — picks up the page locale on first paint.This also unblocks any future Jetpack Search block code that wants to call
__()/_n()/sprintf()directly instead of detouring throughstate.strings.*seeded from PHP.Proposed changes
@wordpress/i18nas a script module.tools/webpack.blocks.config.jsnow passes arequestToExternalModulecallback that returns'module @wordpress/i18n'so the IAPI bundle emits a hoisted staticimport * from "@wordpress/i18n"(same pattern DEP already uses for@wordpress/interactivity). DEP previously threw "Attempted to use WordPress script in a module" because core only registers@wordpress/interactivity(and a11y / router) as script modules.src/search-blocks/store/i18n-shim.js. Re-exportswindow.wp.i18n's methods (__,_x,_n,_nx,sprintf,isRTL,hasTranslation,setLocaleData) with identity fallbacks ifwp-i18nsomehow didn't load. Built as its own webpack entry →build/search-blocks/store/i18n-shim.js.@wordpress/i18nmodule ID inSearch_Blocks::register_i18n_module()viawp_register_script_module(). Browser's import map now resolves@wordpress/i18nto the shim.window.wp.i18nwith the page locale.Search_Blocks::enqueue_i18n_runtime()enqueues the classicwp-i18nscript andwp_add_inline_scripts asetLocaleData()call built fromget_translations_for_domain( 'jetpack-search-pkg' ). Classic scripts run synchronously before deferred modules, so by the time the shim evaluates,window.wp.i18n.__()already knows the locale's translations. The JSON payload is encoded withJSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOTso a translation containing</script>can't break out of the inline tag.result-utils.jsbuildRatingAriaLabel— the original SEARCH-168 offender. Now calls__( '%s out of 5 stars', ... )for the no-reviews branch and_n( '%1$s out of 5 stars based on %2$d review', '%1$s out of 5 stars based on %2$d reviews', reviewCount, ... )+sprintffor the with-reviews branch (matches the source strings the editor'sedit.jsalready extracts).store/index.jscomputeResultsCountText— drops thestate.strings?.searching ?? 'Searching…'indirection in favour of native__/_n/sprintf.active-filters/view.jsactivePills— same swap on the "Remove %s" pill aria-label.build_initial_strings()PHP seed and its test assertions. Strings live in JS source now.Related product discussion/links
state.strings.*workaround)Does this pull request change what data or activity we track or use?
No.
Testing instructions
cd projects/packages/search && pnpm run test-scripts— 416/416 JS tests pass.cd projects/packages/search && composer phpunit -- --filter=Search_Blocks_Test— 18/18 PHP tests pass.add_filter( 'jetpack_search_blocks_enabled', '__return_true' )):search-results).__/_n/sprintfpath, not the old PHP-seededstate.strings.search-resultsblock to theproductlayout and inspect a card's rating row: thearia-labelshould now be the translated "X out of 5 stars based on N reviews" string (front end matches editor preview).