Grunt & WordPress development III: Tasks for internationalisation


This is part 3 in a series looking at using Grunt in WordPress plug-in/theme development.

  1. Grunt & WordPress development
  2. Grunt & WordPress development II: Installing Grunt
  3. Grunt & WordPress development III: Tasks for internationalisation
  4. Grunt & WordPress development IV: Another task for internationalisation

Internationalisation Tasks

One aspect of WordPress plug-in development that involves a lot of mundane work is that of internalisation: ensuring WordPress’ localisation functions are used correctly, generating a .pot file, compiling submitted .po files to .mo files. The latter two you can do with Poedit – but this still involves manually opening the .po/.pot file. These tasks can be completely automated so let’s do that:

po2mo – Compiling to .po files to .mo

The po2mo plug-in automatically compiles given .po files and produces a .mo file of the same name.

To install:

npm install grunt-po2mo --save-dev

<em>Please not an earlier version of this article executed the above as a super user (`sudo npm`). As pointed out by Lacy in the comments, this necessary and can cause permission issues with the npm cache.</em>

The following set up looks in the languages directory for any .po files and compiles them, creating the corresponding .mo in the same directory:

po2mo: {
    files: {
        src: 'languages/*.po',
        expand: true,

Finally load the task by adding grunt.loadNpmTasks('grunt-po2mo'); at the bottom of your Gruntfile.js, just after grunt.loadTasks('tasks');. Then whenever you add or change a .po file:

grunt po2mo

(You can see a live example of this task, and the others listed below, here.

pot – Create a .pot template file

For users to be able to translate your plug-in you’ll need to create a .po template file ( a .pot file). The pot plug-in does exactly that.

You just need to provide it with:

  • The files to search in,
  • The keywords to search for (and indicate which arguments are translatable strings, and which are context specifiers)
  • A text domain (used only for naming the the .pot file)
  • The directory where you wish to output the .pot file.

To install:

npm install grunt-pot --save-dev


pot: {
          text_domain: 'my-plugin', //Your text domain. Produces my-text-domain.pot
          dest: 'languages/', //directory to place the pot file
          keywords: [ //WordPress localisation functions
          src:  [ '**/*.php' ], //Parse all php files
          expand: true,

Finally load the task by adding grunt.loadNpmTasks('grunt-pot'); to the bottom. Then to generate your .pot file:

grunt pot

checktextdomain – Verify localisation functions have been used correctly

Having generated a .pot file, gathered translations for your plug-in and then compiled them – it would be entirely wasted if you haven’t used the WordPress localisations functions properly. In particular, if you had failed to specify the correct domain, your efforts would have been wasted.

When coding it’s easy to forget to specify a text domain, or to mistype it. Or perhaps you’ve been using a variable for the domain, and now want to switch to a literal string.

The checktextdomain – not only checks if you’ve used the correct textdomain in the localisation function it can also correct it for you.

Simply provide it with:

  • Files to look in,
  • Keywords to look for (important: you must provide a domain argument specifier)
  • A text-domain to check against
  • Whether you want mistakes corrected (it will not add missing domains… yet).

The plug-in will then

  • Warn you if some keywords have been used without a text domain
  • Warn you if some keywords have been used with an incorrect text domain (optionally correct it for you)
  • Warn you if some keywords have been used with a variable text domain (optionally correct it for you)

There are various options for this plug-in to enable you to check (and correct) the things you want to. You can see all the available options for this Grunt plug-in on its Github page.

To install:

npm install grunt-checktextdomain --save-dev

You’ll notice that the keywords option is very similar to grunt-pot. There is an important distinction. For this plug-in to work you must extend the keyword specifier and indicate where the domain should be.

E.g. 2d indicates that the domain should be passed as the second argument of the localisation function

checktextdomain: {
      text_domain: 'my-plugin',
      correct_domain: true, //Will correct missing/variable domains
      keywords: [ //WordPress localisation functions
   files: {
       src:  [ '**/*.php', ], //All php files
       expand: true,

Finally load the task by adding grunt.loadNpmTasks('grunt-checktextdomain'); to the bottom. Then to check your files:

grunt checktextdomain

I’m planning on improving this further to warn you of missing contexts which using functions that expect one.

Final remarks

Remembering to add grunt.loadNpmTasks(...); at the bottom of your Gruntfile.js, just after grunt.loadTasks('tasks'); is easily forgotten. But there’s a way around this which I’ll discuss in my next post.

Just before publishing Brady Vercher announced his Grunt plug-in, which allows you to utilize the internationalisation tools that WordPress uses. There’s a bit more set-up involved, but a notable advantage over grunt-pot is that it recognises theme template headers as translatable.

7 thoughts on “Grunt & WordPress development III: Tasks for internationalisation

  1. Hi Stephen,

    This serious has been invaluable. As has reading the full Gruntfile.js you have up in your github repos. I should actually be able to get this implemented in my own plugins soon.


  2. A Bundle of Links about I18N in WordPress Development | mgiulio

    • You’re welcome :). Yes, they do the same thing (generate a `.pot` file from the parsed folders). `grunt-wp-i18n` is slightly better in the context of theme development as it also parses the template header comments (e.g template name).

  3. Hi there,
    Just wanted to point out though that you should not be running npm as a superuser (sudo npm). It can cause even further permissions issues with you npm cache.

    Thanks for the great article!

    • Duly noted! In deed having done it once you have to keep doing it (or chmod npm cache), and I’m afraid my laziness has been ingrained :/. I’ve just updated the post.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>