Skip to content

Commit 1eaaa51

Browse files
committed
I18N: Auto-detect script module translations.
Stop requiring explicit wp_set_script_module_translations() calls to enable translation loading. Instead, print_script_module_translations() now iterates every enqueued script module (and its dependencies) and calls load_script_module_textdomain() with the 'default' text domain by default. This removes the need to maintain a hardcoded list of modules that use wp-i18n in wp_default_script_modules(), and lets translations flow through automatically as long as the JSON chunk for a module exists on disk. Modules that use a non-default text domain or a custom translation path can still opt in via set_translations().
1 parent 1e9d62f commit 1eaaa51

3 files changed

Lines changed: 71 additions & 23 deletions

File tree

src/wp-includes/class-wp-script-modules.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,13 @@ public function deregister( string $id ) {
349349
}
350350

351351
/**
352-
* Sets translated strings for a script module.
352+
* Overrides the text domain and path used to load translations for a script module.
353353
*
354-
* Works similar to {@see WP_Scripts::set_translations()} but for script modules.
355-
* The translations will be loaded and output as inline scripts before
356-
* the script modules are printed, calling `wp.i18n.setLocaleData()`.
354+
* This is only needed for modules whose text domain differs from 'default'
355+
* or whose translation files live outside the standard locations, for
356+
* example plugin modules that register their own text domain. Translations
357+
* for modules that use the default domain are loaded automatically by
358+
* {@see WP_Script_Modules::print_script_module_translations()}.
357359
*
358360
* @since 7.0.0
359361
*
@@ -376,26 +378,32 @@ public function set_translations( string $id, string $domain = 'default', string
376378
}
377379

378380
/**
379-
* Prints translations for all enqueued script modules that have translations set.
381+
* Prints translations for all enqueued script modules.
380382
*
381383
* Outputs inline `<script>` tags that call `wp.i18n.setLocaleData()` with
382384
* the translated strings for each script module. This must run before
383385
* the script modules execute.
384386
*
387+
* Auto-detects the text domain and translation path for each module from
388+
* its source URL. Modules whose text domain or path differs from the
389+
* defaults can opt into a specific domain/path via
390+
* {@see WP_Script_Modules::set_translations()}.
391+
*
385392
* @since 7.0.0
386393
*/
387394
public function print_script_module_translations(): void {
388395
// Collect all module IDs that will be on the page (enqueued + their dependencies).
389396
$module_ids = $this->get_sorted_dependencies( $this->queue );
390397

391398
foreach ( $module_ids as $id ) {
392-
if ( ! isset( $this->translations[ $id ] ) ) {
393-
continue;
399+
if ( isset( $this->translations[ $id ] ) ) {
400+
$domain = $this->translations[ $id ]['domain'];
401+
$path = $this->translations[ $id ]['path'];
402+
} else {
403+
$domain = 'default';
404+
$path = '';
394405
}
395406

396-
$domain = $this->translations[ $id ]['domain'];
397-
$path = $this->translations[ $id ]['path'];
398-
399407
$json_translations = load_script_module_textdomain( $id, $domain, $path );
400408

401409
if ( ! $json_translations ) {

src/wp-includes/script-modules.php

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,12 @@ function wp_deregister_script_module( string $id ) {
139139
}
140140

141141
/**
142-
* Sets translated strings for a script module.
142+
* Overrides the text domain and path used to load translations for a script module.
143143
*
144-
* Works similar to {@see wp_set_script_translations()} but for script modules
145-
* registered via {@see wp_register_script_module()}.
144+
* Translations for script modules are loaded automatically from the default
145+
* text domain and language directory. Use this function only when a module's
146+
* text domain differs from `'default'` or when translation files live outside
147+
* the standard location, for example plugin modules using their own text domain.
146148
*
147149
* @since 7.0.0
148150
*
@@ -151,7 +153,7 @@ function wp_deregister_script_module( string $id ) {
151153
* @param string $id The identifier of the script module.
152154
* @param string $domain Optional. Text domain. Default 'default'.
153155
* @param string $path Optional. The full file path to the directory containing translation files.
154-
* @return bool True if the text domain was successfully localized, false otherwise.
156+
* @return bool True if the text domain was registered, false if the module is not registered.
155157
*/
156158
function wp_set_script_module_translations( string $id, string $domain = 'default', string $path = '' ): bool {
157159
return wp_script_modules()->set_translations( $id, $domain, $path );
@@ -216,11 +218,6 @@ function wp_default_script_modules() {
216218
$path = includes_url( "js/dist/script-modules/{$file_name}" );
217219
$module_deps = $script_module_data['module_dependencies'] ?? array();
218220
wp_register_script_module( $script_module_id, $path, $module_deps, $script_module_data['version'], $args );
219-
220-
// Set up translations for script modules that use wp-i18n.
221-
if ( isset( $script_module_data['dependencies'] ) && in_array( 'wp-i18n', $script_module_data['dependencies'], true ) ) {
222-
wp_set_script_module_translations( $script_module_id, 'default' );
223-
}
224221
}
225222

226223
wp_register_script_module(

tests/phpunit/tests/script-modules/wpScriptModules.php

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2682,8 +2682,8 @@ public function test_print_script_module_translations_outputs_nothing_for_non_en
26822682
}
26832683

26842684
/**
2685-
* Tests that print_script_module_translations() outputs an inline script
2686-
* calling wp.i18n.setLocaleData() when translations are available.
2685+
* Tests that print_script_module_translations() auto-detects translations
2686+
* for enqueued modules without requiring an explicit set_translations() call.
26872687
*
26882688
* @ticket 65015
26892689
*
@@ -2693,7 +2693,6 @@ public function test_print_script_module_translations_outputs_nothing_for_non_en
26932693
public function test_print_script_module_translations_outputs_set_locale_data() {
26942694
$this->script_modules->register( 'test-module', '/wp-includes/js/test-module.js' );
26952695
$this->script_modules->enqueue( 'test-module' );
2696-
$this->script_modules->set_translations( 'test-module', 'default' );
26972696

26982697
// Provide test translations via the pre_load_script_translations filter
26992698
// so no fixture files are needed.
@@ -2763,7 +2762,6 @@ public function test_print_script_module_translations_includes_dependencies() {
27632762
$this->script_modules->register( 'dep-module', '/wp-includes/js/dep-module.js' );
27642763
$this->script_modules->register( 'main-module', '/wp-includes/js/main-module.js', array( 'dep-module' ) );
27652764
$this->script_modules->enqueue( 'main-module' );
2766-
$this->script_modules->set_translations( 'dep-module', 'default' );
27672765

27682766
add_filter(
27692767
'pre_load_script_translations',
@@ -2815,4 +2813,49 @@ static function ( $relative, $src, $is_module ) use ( &$filtered ) {
28152813
$this->assertStringContainsString( 'dep-module-js-module-translations', $script_text, 'Dependency module translations should be printed.' );
28162814
$this->assertStringContainsString( 'Mundo', $script_text, 'Output should contain the dependency translation.' );
28172815
}
2816+
2817+
/**
2818+
* Tests that set_translations() can override the auto-detected text domain.
2819+
*
2820+
* @ticket 65015
2821+
*
2822+
* @covers WP_Script_Modules::print_script_module_translations
2823+
* @covers WP_Script_Modules::set_translations
2824+
*/
2825+
public function test_print_script_module_translations_respects_set_translations_override() {
2826+
$this->script_modules->register( 'test-module', '/wp-includes/js/test-module.js' );
2827+
$this->script_modules->enqueue( 'test-module' );
2828+
$this->script_modules->set_translations( 'test-module', 'my-plugin' );
2829+
2830+
$seen_domain = null;
2831+
add_filter(
2832+
'pre_load_script_translations',
2833+
static function ( $translations, $file, $handle, $domain ) use ( &$seen_domain ) {
2834+
if ( 'test-module' !== $handle ) {
2835+
return $translations;
2836+
}
2837+
$seen_domain = $domain;
2838+
return wp_json_encode(
2839+
array(
2840+
'locale_data' => array(
2841+
'messages' => array(
2842+
'' => array(
2843+
'domain' => 'my-plugin',
2844+
'lang' => 'es',
2845+
),
2846+
'Hello' => array( 'Hola' ),
2847+
),
2848+
),
2849+
)
2850+
);
2851+
},
2852+
10,
2853+
4
2854+
);
2855+
2856+
$output = get_echo( array( $this->script_modules, 'print_script_module_translations' ) );
2857+
2858+
$this->assertSame( 'my-plugin', $seen_domain, 'load_script_module_textdomain() should be called with the overridden domain.' );
2859+
$this->assertStringContainsString( 'Hola', $output );
2860+
}
28182861
}

0 commit comments

Comments
 (0)