JavaScript Translations Not Working with ES6 Modules in WordPress
-
Summary:
WordPress’ i18n foreign language translation functionality does not work as expected in JavaScript when a plugin utilizes ES6 modules. The translation data, which should be injected into the webpage, is removed after the
script_loader_tagfilter is applied. This behavior prevents JavaScript/.json translations from being displayed.Context:
WordPress version 6.2.2. This issue occurs specifically in the context of plugin development with ES6 modules and i18n language translations.
We are aware that new functions
wp_register_script_moduleandwp_enqueue_script_modulewere introduced in WordPress v6.5, which directly support ES6 modules. However, as plugin developers, we want to maintain backward compatibility and do not want WordPress v6.5 to be our minimum required version at this time. Therefore, we’re utilizing the existing method to register and enqueue our scripts.Plugin Setup:
Here is the relevant code used to register and enqueue the ES6 module in our plugin:
// Enqueue scripts and styles
function ac_test_buttons_2_enqueue_scripts() {
wp_enqueue_style('ac-test-buttons-2-style', plugin_dir_url(__FILE__) . 'dist/css/styles.css');
// Enqueue the ES6 module and include wp-i18n as a dependency
wp_enqueue_script('ac-test-buttons-2-script', plugin_dir_url(__FILE__) . 'dist/js/click-handlers.js', array('wp-i18n'), null, true);
// Set the script to be an ES6 module
wp_script_add_data('ac-test-buttons-2-script', 'type', 'module');
// Ensure that translations are available for the JS
wp_set_script_translations('ac-test-buttons-2-script', 'ac-test-buttons-2', plugin_dir_path(__FILE__) . 'languages');
}
add_action('wp_enqueue_scripts', 'ac_test_buttons_2_enqueue_scripts');The Problem:
WordPress’ translation system injects the translation data into the webpage markup using
<script>tags. However, when working with ES6 modules, the translation script does not get injected into the page.This is due to our script tag being first modified from
type="module"totype="text/javascript". Then subsequently, thescript_loader_tagfilter is applied, which changes thetype="text/javascript"translation script back totype="module", effectively removing the translation data.
Investigation:We traced the issue to the
wp-includes/class-wp-scripts.php, specifically within thedo_item()function. At around line 605, you will find the following filter:$filtered_tag = apply_filters('script_loader_tag', $tag, $handle, $src);Before this filter is applied, the script tag contains the translation data with
type="text/javascript". After applying the filter, the tag is modified totype="module", and the translation data is dropped. Consequently, the translations are not echoed to the page.Below are the relevant log entries showing this behavior:
Log Entries:
[02-Oct-2024 17:11:54 UTC] do_item(): Built tag for handle: ac-test-buttons-2-script, value of $tag: <script type="text/javascript" id="ac-test-buttons-2-script-js-translations">
/* <![CDATA[ */
( function( domain, translations ) {
var localeData = translations.locale_data[ domain ] || translations.locale_data.messages;
localeData[""].domain = domain;
wp.i18n.setLocaleData( localeData, domain );
} )( "ac-test-buttons-2", {
"translation-revision-date": "2024-10-01 11:00-0000",
"domain": "ac-test-buttons-2",
"locale_data": {
"messages": {
"": {
"domain": "ac-test-buttons-2",
"lang": "de",
"plural-forms": "nplurals=2; plural=(n != 1);"
},
"You have clicked me!": [ "Du hast mich angeklickt!" ]
}
}
});
/* ]]> */
</script>
<script type="text/javascript" src="http://localhost:8100/wp-content/plugins/ac-test-buttons-2/dist/js/click-handlers.js" id="ac-test-buttons-2-script-js"></script>
[02-Oct-2024 17:11:54 UTC] do_item(): After applying script_loader_tag filter for handle: ac-test-buttons-2-script, value of $filtered_tag: <script type="module" src="http://localhost:8100/wp-content/plugins/ac-test-buttons-2/dist/js/click-handlers.js"></script>
[02-Oct-2024 17:11:54 UTC] do_item(): Echoing tag for handle: ac-test-buttons-2-script(Log show same handle with type changing and ID being dropped.)
Reproducing the Issue:
You can confirm this by adding the following logging within the core WordPress code in the
wp-includes/class-wp-scripts.phpfile inside thedo_item()function:$tag = $translations . $cond_before . $before_script;
$tag .= wp_get_script_tag($attr);
$tag .= $after_script . $cond_after;
error_log("do_item(): Built tag for handle: $handle, value of \$tag: $tag");
// Apply the script loader filter and log the result
$filtered_tag = apply_filters('script_loader_tag', $tag, $handle, $src);
error_log("do_item(): After applying script_loader_tag filter for handle: $handle, value of \$filtered_tag: $filtered_tag");Conclusion:
The translations are being stripped when the
script_loader_tagfilter is applied, resulting in the loss of translation functionality for ES6 module-based scripts. This raises a concern for plugin developers working with ES6 modules who rely on WordPress’ i18n system to handle translations. We would appreciate further guidance or clarification as to whether this behavior is intended, and if not, a potential fix for preserving translation data in this scenario.
The topic ‘JavaScript Translations Not Working with ES6 Modules in WordPress’ is closed to new replies.