How to internationalise and translate your WordPress Plugin

Today I got a lovely request from Andrew over at who asked if he could translate my P2 Header Ad plugin into Spanish. “Of course”, I thought – and then I realised that I knew not much about how to get a plugin translation ready. I knew POEdit of course, but how to make my plugin speak another language wasn’t really clear to me.

An online search didn’t really reveal all the answers – snippets here and there, but not the whole picture. So here it is – step by step – as of December 2013.

In a nutshell:

  • add a text domain
  • replace all strings with compatible PHP calls
  • generate a .pot file
  • open it it POEdit and translate your strings
  • switch WordPress to another language to see if it actually works

Adding a Text Domain

First the plugin needs to know where to go for those additional foreign strings. The Text Domain does this, and it needs to be the same as the slug used for your plugin. I’ll stick with my P2 Header Ad example whose slug is p2-header-ad (no underscores).

The Text Domain is declared in the commend block like so:

 * Plugin Name: P2 Header Ad
 * Plugin URI:
 * Description: inserts a block of ad code into the P2 Theme's Header
 * Version: 1.3
 * Author: Jay Versluis
 * Author URI:
 * License: GPL2
 * Text Domain: p2-header-ad
 * Domain Path: /languages

The parameter underneath it is a sub folder to keep all your language files organised. It’s optional, but recommended – if you use it, create a folder in your plugin by that name.

You also need to call the load_plugin_textdomain() function for those strings to be loaded. We can do this by hooking into plugins_loaded:

function p2HeaderAd_textdomain()
	load_plugin_textdomain('p2-header-ad', false, dirname(plugin_basename(__FILE__)) . '/languages/');
add_action('plugins_loaded', 'p2HeaderAd_textdomain');

Replace your strings

Plain strings need to be wrapped in special PHP function calls to be translatable. For example:

echo 'Hello';
// would become
_e('Hello', 'p2-header-ad');

Notice the text domain inside the _e function. It’s a tad tedious to replace every string occurrence, but once you’re on a roll not as painful as I thought.

Creating Translations with .pot/.po/.mo files

Here’s where I was confused, and I bet most people are. What’s a .pot / .po / .mo file, and where do we get them? Let’s start by what they are:

– .pot files are “templates” without a translation, from which a .po and .mo file can be created. They contain all “generic base” strings.
– .po files are the same as .pot files, but include a translation. These are what translators edit.
– .mo files are compressed / binary versions of .po files. They have a smaller size, do not contain comments and will be loaded by a user’s browser. .mo files are generated from .pot files by tools like POEdit.

Right now we have none of those, and we have several options on how to get one.

Create a .pot file via

If your plugin is already hosted on you can use the excellent service that gives you a .pot template from your trunk. Login to, navigate to your plugin, then hit Admin and find the Generate .pot file option:

Screen Shot 2013-12-09 at 20.07.48

This requires though that you upload your plugin files with replaced string values to the SVN trunk. Hit that button and WordPress will give you a .pot file.

You can also create a .pot file with POEdit (see below).

Start translating with POEdit

POEdit has a “Pro” version which can scan your plugin and extract the translatable strings right away. It’s a one-click operation (File – New WordPress Translation) and worth the current asking price of $20.

If you’re strapped for cash you can use POEdit for free, create a new file, then define __ and _e manually in Catalogue – Properties – Source Paths. This may also result in a list of translatable strings.

When you save your creation, POEdit will generate a .po and .mo file for you, it will not generate a .pot file. However, saving out an untranslated POEdit file with the extension .pot also works.

If you have a .pot file, open it in POEdit and start translating each string – it’s pretty straight forward.

Saving localised files

When you’re done translating, hit File – Save As and POEdit will suggest a file name and location for your project. In my case, it correctly suggested the /languages folder in my plugin’s directory with a name of my text domain (p2-header-ad.po).

What it did not do – and this is extremely important – was to amend the correct international “language code”. For example, the German language code is de_DE, and for my German .po files to be recognised my filename needs to be p2-header-ad-de_DE.po and .mo respectively.

You can find the code for your language here:

Switch WordPress to another language for testing

Finally, to see those translations in action you need to switch WordPress to the language you’ve created at least a test translation for. Don’t worry if you don’t speak another language, just pick one you like, “translate” some strings into words you choose and see if they work as expected.

First, download the language files for the local WordPress version (say and and add them to wp-content/languages – not in a subdirectory. You can find the relevant links above.

Next, open your wp-config.php file and tweak the following line:

define('WPLANG', '');

and change it to

define('WPLANG', 'de_DE');

The comment block above that line explains this better than I can.

Now refresh your browser, and if all went well, both WordPress and your Plugin should now display translated strings where there once was English.

Don’t forget to distribute the .pot file with the next version of your plugin (leave it in the languages folder) 😉

Further Reading

Jay is the CEO and founder of WP Hosting, a boutique style managed WordPress hosting and support service. He has been working with Plesk since version 9 and is a qualified Parallels Automation Professional. In his spare time he likes to develop iOS apps and WordPress plugins, or draw on tablet devices. He blogs about his coding journey at and