I'm struggling to get translations working on my custom blocks.

I have a plugin with multiple blocks, following this file structure:

  ..build files

Inside my index.php file I have a single init function:

function textdomain_register_blocks() {
    register_block_type( __DIR__ . '/build/block-one' );
    register_block_type( __DIR__ . '/build/block-two' );
add_action( 'init', 'textdomain_register_blocks' );

I've been trying to get translations working for my blocks, following the official documentation and these questions:

I have the .pot, .po and .json files created, apparently successfully, but can't seem to get the translations to apply.

I thought that the correct approach would be to add this to my textdomain_register_blocks function above

function textdomain_register_blocks() {
    register_block_type( __DIR__ . '/build/block-one' );
    register_block_type( __DIR__ . '/build/block-two' );
    $script_handle = generate_block_asset_handle( 'textdomain/block-one', 'editorScript' );
    wp_set_script_translations( $script_handle, 'textdomain', plugin_dir_path( __FILE__ ) . 'languages' );
add_action( 'init', 'textdomain_register_blocks' );

Then in my plugin/languages folder I have the .json files generated by wp i18n make-json, in the format <textdomain>-<locale>-<md5>.json



I've also tried renaming the translation files to the format <textdomain>-<locale>-<script handle>.json, which gives us:


However, this doesn't appear to work.

I have also tried moving the generated .json files directly to wp-content/languages/plugins, following the naming convention <textdomain>-<locale>-<md5>.json, but this doesn't work either.

I'm clearly missing something, so any help is much appreciated!

Edit: In case it's relevant, I have my plugin in the mu-plugins directory

1 Answer 1


/edit The question is very similar to Using wp_set_script_translations without manually registering the script and incidentally, my reply is very similar to https://wordpress.stackexchange.com/a/407513/197528


First, you indeed need to call wp_set_script_translations() so that your assets (eg from wp_enqueue_script) get a chance to be associated with a translation's path actually pointing to /languages. By default, the call to wp_set_script_translations made by register_block_type is passed a empty $path value.

Second, in order to set the the translation, you indeed need the right script handle for this to work. You could compute them the way register_block_type does by the mean of register_block_script_handle (like you did), or retrieve the handles from register_block_type itself.


    public const DOMAIN = 'foobar';
    private $handles = [];

    // add_action('init')
    public function init_blocks($blocks, $current_path)
        foreach ($blocks as $path) {
            $s = register_block_type($path);
            if ($s) {
                array_push($this->handles, ...$s->view_script_handles, ...$s->editor_script_handles);

    // add_action('wp_enqueue_scripts')
    // But don't forget wp admin script
    public function enqueue_assets()
        load_plugin_textdomain(self::DOMAIN, false, dirname(plugin_basename(__FILE__)) . '/languages');
        foreach ($this->handles as $handle) {
            wp_set_script_translations($handle, self::DOMAIN, plugin_dir_path(__FILE__) . 'languages');

Third: Translation applies the block is inserted within the Gutenberg editor (based on profile's language). If anything changed afterward (adding wp_set_script_translations or changing translation), the block must be removed and re-added because once saved, the markup is static (strings are fixed and will not change according to visitor's language)

I believe your error may be related to this last point (having added wp_set_script_translations later but not seeing the translation in your existing Gutenberg window because the blocks need to be removed and re-added)

A last though thing: i18n JSON file suffixes are based on the md5 of the build file name of your block, eg build/block-one/script.js or build/block-two/block.js and this path must exactly appear as-is in the PO's string source.

Since this won't happen because PO files are generated from source and not build files you need this map-file between sources and build files to be passed to wp i18n make-json languages --use-map.

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.