I'm trying to localise my Gutenberg plugin and block, the PHP side is translated but zero luck on the js side.

I tried the official guide, few other blog posts, the solutions posted in this post enter link description here and this one enter link description here but nothing. Not even with the simplest block.

Maybe I'm missing something... Any idea? Thanks in advance.

WordPress version: 6.1.1 , PHP version: 8.0.28 , WP-CLI version: 2.7.1

EDITED as other answers recommendations: Still not working

My structure:

          - index.js
          - index.js.map
          - index.asset.php
          - index.js
          - my-block-es_ES.mo
          - my-block-es_ES.po
          - my-block-es_ES.pot
          - my-block-es_ES-1fdf421c05c1140f6d71444ea2b27638.json

       - block.json
       - my-block.php
       - package.json
       - ...

The main PHP my-block.php:

 * Plugin Name:       My Block
 * Requires at least: 6.1
 * Requires PHP:      7.0
 * Version:           1
 * Text Domain:       my-block

function create_block_my_block_block_init() {
    register_block_type( __DIR__ );

    // Load MO files for PHP.
    load_plugin_textdomain( 'my-block', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
add_action( 'init', 'create_block_my_block_block_init' );

function script_translations(){
    // Load JSON files for JS - this is necessary if using a custom languages path!!
    wp_set_script_translations( 'my-block-local-edit-script', 'my-block', plugin_dir_path( __FILE__ ) . '/languages' );
add_action( 'wp_enqueue_script', 'script_translations' );

The block.json

   "apiVersion": 2,
   "title": "Test Gutenberg Block Title",
   "name": "my-block/local",
   "category": "layout",
   "textdomain": "my-block",
   "icon": "universal-access-alt",
   "editorScript": "file:build/index.js"

And the src/index.js that compiles into build/index.js

 * WordPress dependencies
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

// Register the block
registerBlockType('my-block/local', {
   title: __('My Block Local', 'my-block'),
   edit: function () {
      return <p> {__('Hello world', 'my-block')} (from the editor)</p>;
   save: function () {
      return <p> {__('Hello world', 'my-block')} (from the frontend) </p>;
  • note that save components do not run on the frontend, their output is stored as static HTML in the posts content and then displayed, save components only run inside the editor, and their output is never shown in the browser. Additionally, the answer you linked to clearly states that init is far too early to call wp_set_script_translations, way way too early. It must happen after the block is registered and enqueued. register_block_type does not register and enqueue your blocks scripts, rather it adds hooks to do that in the future when the appropriate time occurs
    – Tom J Nowell
    Commented Mar 2, 2023 at 16:33
  • This means that for wp_set_script_translations and register_block_type to be called in the same function to work would require some form of Dr Who level time travel
    – Tom J Nowell
    Commented Mar 2, 2023 at 16:35
  • Changed the PHP to call wp_set_script_translation on wp_enqueue_script. Still not working :(
    – Jorge
    Commented Mar 2, 2023 at 18:19
  • are there any JS errors in the console, and can you confirm that the raw HTML of the block editor page has either a reference to your JSON or contains a string that can only be found inside your translation? How are you testing this? You said it isn't working, but didn't ellaborate on how you determined that, or explained how it is not working and the steps you took to test this.
    – Tom J Nowell
    Commented Mar 2, 2023 at 20:30
  • 2
    Thanks Tom for keep helping! Answering your comments: No js errors. I'm testing it using it on my local WP. If I don't register the block throw PHP it doesn't load. No .json loaded on the code. Uploaded to GitHub github.com/jrausell/wp-plugin-localization
    – Jorge
    Commented Mar 2, 2023 at 20:49

1 Answer 1


There are 2 main issues in your code:

  1. As stated in my answer, the script handle format is <block name with slashes replaced with hypens>-editor-script, so because your block name is my-block/local, then the script handle is my-block-local-editor-script and not my-block-local-edit-script.

  2. The correct action name is wp_enqueue_scripts (note the "s") and not wp_enqueue_script. However, wp_enqueue_scripts would not work because that's for the front-end (non-admin side). For admin use like the post editing screen at wp-admin/post.php, you can use either admin_enqueue_scripts or a hook specific to the block/Gutenberg editor like enqueue_block_editor_assets.

  3. Your JSON translation file should also be using dfbff627e6c248bcb3b61d7d06da9ca9 which is the value of md5( 'build/index.js' ) (no ./). So the file name should instead be my-block-es_ES-dfbff627e6c248bcb3b61d7d06da9ca9.json 🙂

    That value/hash is also what you'd get when you run this via WP-CLI: wp i18n make-json my-block-<locale>.po ./ --no-purge after doing a cd languages in your plugin directory.

How to fix the issues 1 and 2:

  1. Change the wp_set_script_translations() line (it's line 20 in your code) to:

        'my-block-local-editor-script',           // script handle
        'my-block',                               // text domain
        plugin_dir_path( __FILE__ ) . 'languages' // path to your translation files

    Or you can use generate_block_asset_handle() to generate the script handle:

    $script_handle = generate_block_asset_handle( 'my-block/local', 'editorScript' );
    wp_set_script_translations( $script_handle, 'my-block', plugin_dir_path( __FILE__ ) . 'languages' );
  2. Change the add_action( 'wp_enqueue_script', 'script_translations' ); (line 22 in your code) to:

    add_action( 'enqueue_block_editor_assets', 'script_translations' );
    // These also work:
    //add_action( 'admin_enqueue_scripts', 'script_translations' );
    //add_action( 'init', 'script_translations' );

    Note about using init: Calling register_block_type() will automatically and immediately register the block editor script — see register_block_script_handle(), so init can be used to set the script translations as long as it's called after calling register_block_type().

  • 1
    Thanks Sally!! now is working perfectly!
    – Jorge
    Commented Mar 3, 2023 at 11:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.