• Internationalizing and localizing block based plugins

    Internationalizing and localizing block based plugins

    Internationalizing and localizing block based plugins is an important stage in the creation of WordPress blocks that can be used worldwide. Once it’s been internationalized a plugin can be delivered in any locale that WordPress supports; over 200 at the last count.

    In this post I summarize the process I use to automatically perform internationalization ( i18n ), translation and localization ( l10n ) of my block based WordPress plugins from US English to UK English and the bbboing language.

    Using easy to use translation tools, internationalized plugins can be made available in many other languages.


    The overall process for internationalization, translation and localization of translatable strings in a WordPress plugin is as follows:

    • Write the code so that the translatable strings can be extracted from the relevant files
    • Extract the strings using makepot into a .pot file
    • Translate the strings into each required locale, producing one .po file per locale
    • Convert the translated .po files into .mo files, using msgfmt if not already done by poedit.
    • Extract the strings required in the JavaScript routines into .json files
    • Ensure the localized files are loaded by the plugin.

    These steps will be explained in the following sections.

    There are two other sections

    Install tools

    Prerequisite to performing these tasks you need to install the required tools.

    • npm – used to build the JavaScript blocks using wp-scripts.
    • WP-CLI – used to run the internationalization and localization.
    • l10n – used to run the automated translation into the target locales.

    npm – Node Package Manager

    This is used to control the build of the blocks. See Block Editor Handbook: @wordpress/scripts

    WP-CLI – Command line interface for WordPress

    The WP-CLI command line interface is required to run the internationalization and localization routines. Download from wp-cli.org

    To get the routine to extract strings from the block.json files you need to install the latest version of the i18n-command.

    wp package install git@github.com:wp-cli/i18n-command.git

    l10n – automatic translation to en_GB and bb_BB

    Download the oik-i18n plugin from bobbingwide/oik-i18n. It requires oik-batch to run it.

    Internationalization ( i18n )

    A major part of internationalization is the process of ensuring that the translatable strings in your code are extractable and include enough context to enable translators to perform their role.

    The translatable strings should be written in US English. Examples below for a plugin with a text domain of text-domain. The __() function returns the translated string. For more information see How to internationalize your plugin.


    __( 'Color', 'text-domain' );


    import { __ } from @wordpress/i18n;
    __('Color', 'text-domain' );


    { "title": "Color",
    "description": "Color",
    "textdomain": "text-domain"

    Extract strings

    All of the translatable strings need to be extracted into a single .pot file.

    For block based plugins this is done using npm run makepot, where the makepot command is defined in package.json.

    "makepot": "wp i18n make-pot . languages/sb-starting-block.pot --exclude=node_modules,vendor,src/*.js",

    The npm command invokes WP-CLI‘s i18n command to run make-pot against the current directory, producing the sb-starting-block.pot output file in the languages folder.

    • Makepot extracts strings from .php files, .js files and certain .json files.
    • The --exclude parameter indicates which files to ignore.
    • Note: the only JavaScript file that we actually want processed is in the build folder; build/index.js.
    • But since the block.json files are in the src folder we have to exclude src/*.js.

    For some plugins additional parameters are required.

    "makepot": "wp i18n make-pot . languages/oik.pot --ignore-domain --domain=oik --exclude=node_modules,vendor,src/*.js,tests",

    For the oik plugin, for example, we need --ignore-domain to enable makepot to extract strings regardless of the value of the text-domain literal used in the (PHP) source. We therefore need to use --domain=oik to indicate the text-domain to use. This is required to enable makepot to extract translatable strings from PHP shared libraries, where the text-domain is null.

    Additionally, when using --ignore-domain, due to a limitation of the current string extraction process, it is necessary to omit the textdomain attribute from the block.json files and provide the value at run time.

    This is achieved using a block_type_metadata filter hook, which sets the textdomain for each block, if it’s not set and the block prefix matches the expected value for the plugin.

    add_filter( 'block_type_metadata', 'oik_block_type_metadata', 10 );
    function oik_block_type_metadata( $metadata ) {
        if ( !isset( $metadata['textdomain']) ) {
            $name = $metadata['name'];
            $name_parts = explode( '/', $name );
            $textdomain = $name_parts[0];
            if ( 'oik' === $textdomain ) {
                $metadata['textdomain'] = $textdomain;
        return $metadata;


    Translation – automated

    For my plugins I automatically translate the US English strings into UK English ( locale en_GB ) and the obfuscated bbboing language ( locale bb_BB ). The process is fully automated and is performed by npm run l10n.

    "l10n": "l10n sb-starting-block",

    For each target locale l10n produces a .po file, then this is formatted using msgfmt into the .mo file.

    The translation into UK English is performed for two reasons.

    1. To deliver the translations with correct spelling for the UK English community.
    2. To check that the original spellings are US English.

    I can test that my plugins have been correctly internationalized and localized into the bbboing language using PHPUnit.

    Sample translations

    US English ( en_US ) UK English ( en_GB ) bbboing ( bb_BB )
    Color Colour Cloor
    Check – context banking Cheque Cehck
    Starting block Starting block Sattrnig bolck
    Sample translations from US English to UK English and bbboing.

    Translation – manual

    For other languages the translation has to be performed manually. This can be done using a tool such as poedit. Using poedit, when the .po file is saved the .mo file is generated automatically.

    Localization ( l10n )

    For strings which need to be translated in the block editor a further step is required. The strings from the relevant .js files needs to be localized into a locale specific .json file. This is performed using npm run makejson.

    • This command creates a locale specific file, called locale-MD5.json, for each JavaScript file found in the .po file.
    • The MD5 part is the string returned by md5() for the file name
    • md5 for build/index.js is dfbff627e6c248bcb3b61d7d06da9ca9.

    The final part of the localization is performed by the routines that enable the run time string translation. For strings in .php files this is achieved by loading the required locale’s text domain, the .mo file.

    load_plugin_textdomain( 'sb-starting-block', false, 'sb-starting-block/languages' );

    load_plugin_textdomain() needs to be run before the blocks are registered in the server, as the translation of strings in block.json is performed when each block is registered.

    $args = [ 'render_callback' => 'oik_sb_sb_starting_block_dynamic_block'];
    register_block_type_from_metadata( __DIR__ . '/src/starting-block', $args );
    register_block_type_from_metadata( __DIR__ . '/src/second-block' );

    For the JavaScript strings to be loaded we use wp_set_script_translations(). The translations are associated with the script handle that’s generated for the editor script.

     * Localise the script by loading the required strings for the build/index.js file
     * from the locale specific .json file in the languages folder.
     * oik-sb/sb-starting-block

    $ok = wp_set_script_translations( 'oik-sb-sb-starting-block-editor-script', 'sb-starting-block' , __DIR__ .'/languages' );

    For multi-block plugins where the block.json file refers to the build/index.js file using a relative path that’s not ./build/index.js, we have to implement a special filter hook. This adjusts the relative path to match the one that was used to create the locale-MD5.json file generated by makejson. See https://github.com/bobbingwide/sb-post-edit-block/issues/5#issuecomment-899015787.

    add_filter( 'load_script_textdomain_relative_path', 'oik_sb_sb_starting_block_load_script_textdomain_relative_path', 10, 2);
    function oik_sb_sb_starting_block_load_script_textdomain_relative_path( $relative, $src ) {
            if ( false !== strrpos( $relative, './build/index.js' )) {
                    $relative = 'build/index.js';
            return $relative;

    Finally, since multiple blocks are delivered in the single build/index.js file we only need to specify the following attributes in one of the block.json files.

    "editorScript": "file:../../build/index.js",
    "editorStyle": "file:../../build/index.css",
    "style": "file:../../build/style-index.css"

    This ensures that the JavaScript for all the blocks delivered by the plugin is only enqueued once.

    Further work?

    I feel I need to investigate whether or not my block based plugins can be successfully translated into other popular languages.

    • I’ve used this process doucmented above to internationalize and localize nearly all of my block based plugins.
    • I’ve manually tested the translation to bbboing in the block editor.
    • A couple of the plugins are available from wordpress.org: eg oik, uk-tides

    But I don’t yet know if the translation files created using the WordPress translation tools will produce satisfactory results for these plugins.

    • I don’t understand how wordpress.org knows which files to use as the input to makepot and makejson.
    • I also don’t know what process wordpress.org uses to produce the .pot file for the readme.txt file

    My process for multiple block plugins seems rather complex. This could be due to some current limitations of the tools. Should I consider raising some feature requests/issues against these tools? Or should I look at how other plugins support internationalization and localization?



    Last updated:

    October 16, 2021

Today’s word is this:







Tide times from tidetimes.org.uk

Tide Times & Heights for Langstone Harbour on
18th July 2024
02:42 Low Tide ( 1.9m )
10:11 High Tide ( 4.1m )
15:09 Low Tide ( 1.94m )
22:26 High Tide ( 4.34m )

Tide times from tidetimes.org.uk

Tide Times & Heights for Northney on
18th July 2024
02:50 Low Tide ( 1.56m )
10:08 High Tide ( 3.75m )
15:04 Low Tide ( 1.62m )
22:22 High Tide ( 4m )