• Plugin version: 4.3.3 Summary: JS-side translations (via wp_set_script_translations()) don’t load anymore. Worked in an earlier version, broke at some point — likely when prestoComponentsTag() was introduced. Issue 1: script_loader_tag filter drops the translation <script> block

    In inc/Services/Scripts.php, Scripts::prestoComponentsTag() is hooked on script_loader_tag:

    public function prestoComponentsTag( $tag, $handle, $source ) {
        if ( 'presto-components' === $handle ) {
            $tag = '<script src="' . $source . '" type="module" defer></script>';
        }
        return $tag;
    }
    

    WordPress core builds $tag in WP_Scripts::do_item() by prepending the JS translation <script> block (generated from wp_set_script_translations( 'presto-components', 'presto-player' )) before calling the script_loader_tag filter. Because prestoComponentsTag() discards the incoming $tag and rebuilds it purely from $source, that prepended translation block is silently dropped for every request. Result: presto-components never gets translated in the browser, no matter what’s in the .po/.mo file.

    Suggested fix: modify $tag in place instead of rebuilding it, e.g.:

    public function prestoComponentsTag( $tag, $handle, $source ) {
        if ( 'presto-components' === $handle ) {
            $tag = str_replace( '<script ', '<script type="module" defer ', $tag );
            // (adjust as needed to avoid duplicate attributes if $tag already has some)
        }
        return $tag;
    }
    

    Note for whoever picks this up: $tag at this point already contains the translation <script> block prepended by WP_Scripts::do_item() and the actual <script src=...> tag. A naive str_replace('<script ', '<script type="module" defer ', $tag) would incorrectly add type="module" defer to the translations tag too — worth only targeting the actual source-bearing <script> (e.g. via a more specific regex on the tag that contains src=" matching $source). Issue 2: script handles containing / can never resolve their translation JSON

    Several handles registered with wp_set_script_translations( $handle, 'presto-player' ) (no explicit $path) contain slashes:

    • surecart/blocks/admin (dist/blocks.js)
    • presto/dashboard/admin (dist/dashboard.js)
    • surecart/divi/admin (dist/divi.js)

    WordPress core’s load_script_textdomain() builds the expected JSON filename as:

    $handle_filename = $file_base . '-' . $handle . '.json';
    

    with the raw, unsanitized handle. For surecart/blocks/admin this produces presto-player-<locale>-surecart/blocks/admin.json — a “filename” containing path separators, which no translation tool (Loco Translate, wp i18n make-json, GlotPress) can ever produce, since it would require literal nested directories named presto-player-<locale>-surecart/blocks/. This lookup can never succeed.

    WordPress then falls back to its older src-relative-path method (md5 of the enqueued script’s relative path, e.g. md5('dist/blocks.js'), looked up in wp-content/languages/plugins/) — but neither Loco Translate nor wp i18n make-json generate files under that name either, since both tools name JS translation JSON files after the original, pre-bundle source file referenced in the .pot comments (e.g. admin/blocks/blocks/hosted/HostedPlaceholder.js), not after the bundled dist/*.js output that’s actually enqueued. So the generated JSON never matches what core looks for at runtime, for either lookup path.

    Suggested fix: either (a) avoid / in script handles going forward, and/or (b) pass an explicit $path argument to wp_set_script_translations() for a directory laid out to match handle-based filenames without slashes (e.g. rename handles internally, or provide your own translation loading instead of relying on core’s automatic lookup), and (c) document/ship correctly-hashed JSON files (hashed against the actual dist/*.js relative paths) as part of the plugin’s own translation packaging, rather than relying on translators’ tools to derive the right filename from .pot source comments. Reproduction

    1. Set up JS strings for translation and get a translated .po/.mo for domain presto-player.
    2. View source of a page/admin screen enqueuing presto-components, surecart/blocks/admin, etc.
    3. Note the absence of any <script id="{handle}-js-translations"> block before the actual script tag, and/or that JS strings render untranslated in the browser despite a complete translation.

    Current workaround

    In the meantime we’re working around both issues via a small mu-plugin using script_loader_tag (to restore the translation block for presto-components) and Loco Translate’s loco_compile_single_json / WordPress core’s load_script_translation_file filters (to consolidate all of the domain’s JS strings into one predictably-named file, sidestepping the unresolvable slash-in-handle filenames). Happy to share it if useful as a reference for a proper upstream fix.

    Happy to provide more detail or test a patch.

    • This topic was modified 23 hours, 56 minutes ago by Heinrich Franz. Reason: clarify bug report

You must be logged in to reply to this topic.