Using wp_set_script_translations without manually registering the script

@drskullster already posted a good answer, but I thought I should share the following which explains why wp_set_script_translations() needs to be called manually:

  1. Yes it’s true that WordPress will automatically register and enqueue the block editor script. So we do not need to manually register/enqueue that script!

  2. WordPress will also automatically set the script’s translations, but only if the block metadata file (i.e. block.json) specifies a valid text domain (e.g. "textdomain": "gutenpride") and that the script has wp-i18n as one of its dependencies. See register_block_script_handle().

  3. WordPress uses wp_set_script_translations( $script_handle, $metadata['textdomain'] ) to register/set the translations for the script, which means the 3rd parameter (the file path) is not specified and therefore, WordPress will try to load the translation files from the wp-content/languages/plugins folder.

    So for example, if my-block-fr_BE-dfbff627e6c248bcb3b61d7d06da9ca9.json was the JSON file name, then WordPress would attempt to load wp-content/languages/plugins/my-block-fr_BE-dfbff627e6c248bcb3b61d7d06da9ca9.json.

    And thus, you should copy that file to the wp-content/languages/plugins folder. That way, your main plugin file would only need to call register_block_type() and that’s it — no need to worry about the JSON file name or MD5 hash, and you also would not need to manually call wp_set_script_translations().

But if you don’t want to having to copy the files, then yes, you will need to manually call wp_set_script_translations(), but remember that the script handle is in the form of <block name>-editor-script where <block name> is the block name (which is the name property in block.json), but with slashes (/) replaced with hypens (-).

  • So if the block name is my-block, then the script handle would be my-block-editor-script. Or if the name is create-block/gutenpride, then the handle would be create-block-gutenpride-editor-script. See generate_block_asset_handle() for more details.

So I hope that helps, and FYI, the following is what I had in my main plugin file (wp-content/plugins/gutenpride/gutenpride.php):

function create_block_gutenpride_block_init() {
    register_block_type( __DIR__ . '/build' );

    // Load MO files for PHP.
    load_plugin_textdomain( 'gutenpride', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );

    // Load JSON files for JS - this is necessary if using a custom languages path!!
    $script_handle = generate_block_asset_handle( 'create-block/gutenpride', 'editorScript' );
    wp_set_script_translations( $script_handle, 'gutenpride', plugin_dir_path( __FILE__ ) . 'languages' );
}
add_action( 'init', 'create_block_gutenpride_block_init' );
  • Note: I followed the same steps as in your procedure, but I got an extra step — I created an MO file for use in standard PHP translations, e.g. <?php _e( 'text', 'gutenpride' ); ?>.

Additional Notes

  1. If the 3rd parameter for wp_set_script_translations() is specified and the path/folder contains a JSON translations file named <text domain>-<locale>-<script handle>.json, e.g. gutenpride-fr_BE-create-block-gutenpride-editor-script.json, then WordPress will attempt to load that first.

    So if the file doesn’t exist, then WordPress will attempt to load the default one with the MD5 hash, e.g. gutenpride-fr_BE-dfbff627e6c248bcb3b61d7d06da9ca9.json.

  2. load_script_translations() is the function used to load translations from script translations files, i.e. that function opens the file and reads its content; and the function applies filters like load_script_translation_file which you may find useful when debugging.. 🙂

  3. My “Gutenpride” block was tried & tested with WordPress v6.0, and the latest version of the @wordpress/create-block package at the time of writing.