Extract strings from Gutenberg blocks for translations

While developing my first more complex blocks I ran into different issues. One of them was extracting the strings for my translations. In my previous blog post I showed you how to get those strings for PHP files. Those methods also work for the JavaScript files as the use “the same functions”, or at least aliases that have the same name.

Translate strings in a Gutenberg block

Let’s start to look at an example of a string translation in a block. This example comes straight from the Create a Block Tutorial and shows an “Edit” component:

import { TextControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
 
export default function Edit( { attributes, className, setAttributes } ) {
    return (
        <div className={ className }>
            <TextControl
                label={ __( 'Message', 'gutenpride' ) }
                value={ attributes.message }
                onChange={ ( val ) => setAttributes( { message: val } ) }
            />
        </div>
    );
}

The __ function is imported from the @wordpress/i18n component. This code works perfectly fine for translating the string in line 8. It only fails when you try to extract this string into PO file.

Compiled JavaScript file

But why does this example not work when trying to extract the strings? When you work with components like this you usually split up your JavaScript code into multiple files. You then import all those files into a main JavaScript file and then you build the JavaScript file that is used in the browser with something like @wordpress/scripts like explained in the JavaScript Build Setup chapter. This will then create a file build/index.js and the string from the example above will look like this:

// ...
/* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n");
// ...
function Edit(_ref) {
  var attributes = _ref.attributes,
      className = _ref.className,
      setAttributes = _ref.setAttributes;
  return Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])("div", {
    className: className
  }, Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__["TextControl"], {
    label: Object(_wordpress_i18n__WEBPACK_IMPORTED_MODULE_2__["__"])('Message', 'block-i18n'),
    value: attributes.message,
    onChange: function onChange(val) {
      return setAttributes({
        message: val
      });
    }
  }));
}

In line 11 we will find the string again. But it’s not wrapped in a plain __ function. Instead the complied JavaScript files uses some weird function names from the components imported by webpack. As this function/syntax is not known to the wp i18n make-pot command or the X-Poedit-KeywordsList that Poedit is using, the string will not be found when parsing the files.

Solution: Use a different syntax to import components

There is an easy fix for that. You can import components in different ways. Simply replace the import of the i18n functions in line 2 with this “import”:

const { __ } = wp.i18n;

This will then result in the following complied JavaScript file which will use the plain __ function (in line 10) that is known to the parser:

// ...
var __ = wp.i18n.__;
function Edit(_ref) {
  var attributes = _ref.attributes,
      className = _ref.className,
      setAttributes = _ref.setAttributes;
  return Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])("div", {
    className: className
  }, Object(_wordpress_element__WEBPACK_IMPORTED_MODULE_0__["createElement"])(_wordpress_components__WEBPACK_IMPORTED_MODULE_1__["TextControl"], {
    label: __('Message', 'block-i18n'),
    value: attributes.message,
    onChange: function onChange(val) {
      return setAttributes({
        message: val
      });
    }
  }));
}

Interestingly, when I removed the import without replacing it, it worked as well. That might be due to the fact that the __ function was already imported by another import and was therefor available. But I would recommend to always define which external components and functions you use in your own JavaScript files. In the same way you can also replace the first line like this:

const { TextControl } = wp.components;

Other tutorials always use this method to import components from WordPress/Gutenberg, so I would highly recommend to do it like this as well. I haven’t had an issue with them and the result complied JavaScript files were even a little smaller in size.

Conclusion

Translating strings in a Gutenberg block (or similar JavaScript code for WordPress) is super easy, as you can simply use the same functions you already know from PHP. But if you do the imports “wrong”, extracting the strings for Poedit does not work.

As I have seen some plugins who do it this way and still have working translations there might be a way to extract them anyways. If you know how they do it, I would highly appreciate if you can leave a comment explaining us, how it works.

Posted by

Bernhard is a full time web developer who likes to write WordPress plugins in his free time and is an active member of the WP Meetups in Berlin and Potsdam.

Leave a Reply

Your email address will not be published. Required fields are marked *