Skip to content

Extensible Site Editor (v2): wp_set_script_translations() data never reaches wp.i18n – script translations missing for all plugin editor scripts #83769

Open

Description

@Gierand

Description

The Site Editor v2 (admin.php?page=site-editor-v2, extensible site editor / lazy-editor) loads editor assets via the REST endpoint GET /wp-block-editor/v1/assets and injects <script>/<style> tags client-side. The server-side collector, WP_REST_Block_Editor_Settings_Controller::process_assets() (lib/experimental/class-wp-rest-block-editor-settings-controller.php), serializes each script as {src, deps, version, in_footer} plus inline_scripts (before/after + print_extra_script() data), but it never calls WP_Scripts::print_translations().

As a result, no wp.i18n.setLocaleData() payload is emitted for any script that has a text domain registered via wp_set_script_translations() – which is what register_block_script_handle() does automatically for every editorScript declared in block.json (wp-includes/blocks.php). wp.i18n.getLocaleData( $domain ) is empty and all __()/_x()/sprintf() calls in plugin block editor code return the English originals, even though the Jed JSON translation file exists and is correctly resolved by load_script_textdomain().

This affects every plugin block editor script – not just one plugin. The same gap presumably applies to script modules (load_script_module_textdomain is likewise never invoked for the script_modules import map).

Step-by-step reproduction instructions

  1. Enable the "Extensible Site Editor" experiment (or open admin.php?page=site-editor-v2 directly – the page is registered unconditionally).

  2. Register a block whose editor script has translations:

    add_action( 'init', function () {
        register_block_type( 'my-plugin/demo', array(
            'api_version'   => 3,
            'editor_script' => 'my-plugin-demo',
        ) );
        wp_register_script(
            'my-plugin-demo',
            plugins_url( 'demo.js', __FILE__ ),
            array( 'wp-blocks', 'wp-element', 'wp-i18n' )
        );
        wp_set_script_translations( 'my-plugin-demo', 'my-plugin' );
    } );

    …with a Jed JSON file present at wp-content/languages/plugins/my-plugin-{locale}-{md5(src-rel-path)}.json (or in the plugin's languages/ dir registered via load_plugin_textdomain()).

  3. Open the v2 site editor and run in the console:

    wp.i18n.getLocaleData( 'my-plugin' )
    // => undefined / {} – no messages
    
    document.getElementById( 'my-plugin-demo-js-translations' )
    // => null – the -js-translations inline script is never emitted

    …while the script itself IS injected (document.getElementById( 'my-plugin-demo-js' ) exists).

  4. Compare with post.php (post editor) or the v1 site editor (site-editor.php): my-plugin-demo-js-translations IS printed and getLocaleData( 'my-plugin' ) returns the translated messages.

Expected behavior

Script translations are resolved and emitted for editor scripts loaded via /wp-block-editor/v1/assets, identically to WP_Scripts::do_item() calling print_translations() in the classic editors.

Root cause

  • get_assets() fires admin_enqueue_scripts, admin_print_scripts, wp_print_footer_scripts etc. inside ob_start() (lines ~419–431), but only text/html script templates are extracted from that output – everything else is discarded.
  • process_assets() then walks $wp_scripts->queue + dependencies and collects src/deps/version, get_inline_script_data() (before/after) and print_extra_script() – but never print_translations(), so the ( function( domain, translations ) { …wp.i18n.setLocaleData… } ) payload is neither collected nor sent to the client.
  • Client-side, packages/lazy-editor (loadAssets) injects inlineScripts.before[handle] → src → inlineScripts.after[handle] via injectInlineScript()/loadScript() – the injection channel for translations exists; only the server never fills it.

Suggested fix direction

In process_assets() (or get_assets()), include WP_Scripts::print_translations( $handle, false ) output per script – e.g. appended to inline_scripts.before[$handle], which is the same channel #83762 already uses to deliver wp.blocks.setCategories() before block scripts run, so ordering before src execution is guaranteed. For script modules the equivalent is load_script_module_textdomain() + wp.i18n.setLocaleData injection alongside the script_modules map.

Environment

  • Gutenberg plugin 24.0.0 (experiment "Extensible Site Editor" enabled)
  • WordPress 7.1.2 / 7.2-alpha
  • Theme: block theme (FSE)

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions