In order to run multilingual WordPress sites both contents and the theme need to be localized. In this post, I’ll describe what we did in order to fully localize our own theme for

The entire process for theme localization includes:

  1. Identifying and marking texts that need to be translated.
  2. Collecting all the texts for translation.
  3. Translating the texts.
  4. Using the translation when displaying the theme in different languages.

WordPress uses GetText for its own localization, so it’s pretty natural to use the same solution to localize the theme.

Making the theme texts translatable

Normally, WordPress themes include some texts. For example, let’s look at comments.php. The form for leaving new comments asks for the visitor’s name, email and website and includes a submit button.

Translation plus echo

Here is a very simplified version of the field requesting the first name:

<input type="text" name="author" id="author" value="<?php echo $comment_author; ?>" />
Name <?php if ($req) echo ('(required)'); ?>

The string ‘Name‘ needs to be translated and so is the string ‘required‘ (which is optional). To allow GetText to provide translations for these strings, we’ll wrap them in the GetText echo call: _e().

<input type="text" name="author" id="author" value="<?php echo $comment_author; ?>" />
<?php _e('Name', 'wpml_theme'); ?> <?php if ($req) _e('(required)', '
wpml_theme'); ?>

Can you see the difference?

Translation without echo

When you don’t need to echo the string (for example, when it’s the argument of a function), you should use the __() call. This is similar to _e(), but doesn’t echo the translation. For example, in the comment number display, we use:


<?php comments_number('No Responses', 'One Response', '% Responses');?>

After using the GetText call:

<?php comments_number(__( 'No Responses', '
wpml_theme'), __('One Response', 'wpml_theme'), __('% Responses', 'wpml_theme'));?>

The second argument in both these calls is the text domain. This allows texts to be translated in their correct context. If plugins or even WordPress itself includes the same strings, used in a different context, GetText will still provide the correct translation, because we’ve provided our own text domain (wpml_theme).

Translation with parameters

Sometimes, texts have parameters. For instance, the text that says who wrote a post:

by <?php echo(ucwords(the_author('', false)) ); ?>

We can’t translate the word ‘by’ on its own. Translation should be for complete sentences, or at least, phrases. The translator needs to translate ‘by SOMEONE‘ (and we’ll fill in who’s that someone later). For that, we use a parameter.

<?php printf(__('by %s', '
wpml_theme'), ucwords(the_author('', false))); ?>

Now, the translator will translate ‘by %s’ as an entire phrase. We use the __() function to translate the string and the PHP printf instruction to insert the name of the author back to the string.

Collecting the texts for translation

Once all the texts in your theme are wrapped with GetText calls, it’s time to collect them into a single file, which we’ll later translate.

Allow me to introduce poedit. It’s a program that can create and translate .po (Portable Oject) files and then turn them into .mo (Machine Object) files, which WordPress can import and use to translate the theme.

poedit can scan many different types of files, including C, CPP, PHP and others. But, instead of using poedit, we’ll do something a bit different – and a lot easier.

In order to localize our own theme, we’ve used our own PHP to .po file converter. It’s free tool which allows you to upload a ZIP file containing your theme. The converter will instantly create a .po file for you to download. This is the file that you need to start the translation.

Translating the texts

Now that you have a .po (or .pot – Portable Object Template), it’s time to get it translated. Each .po file includes strings and their translation to a single language, so you’ll need as many .po files as the languages you’re translating the theme to. Then, from each .po file, you’ll be able to create the corresponding .mo file (which WordPress needs).

If you’re working with translators, just send them the .po files. Each translator would translate it and return to you.

We’ve done the translation to all languages at once. Again, this was done using our own translation service.

Here is how it works:

  1. Create an account at ICanLocalize (that’s free).
  2. Create a new text resource project (still free).
  3. Upload the .po file and select which languages to translate to.
  4. The system counts the words in the file and asks for payment. Payment is calculated as 0.09 USD * words * languages. For instance, translating our own theme to both Spanish and German cost us $30 (together).
  5. Translators do the translation.
  6. You download all the translated .po files (one .po file per language), ready to be used by WordPress.

Using the translation in WordPress

Now that you have a .po file, per language, you need to create the corresponding .mo files, which WordPress can use.

Open each .po file in poedit and just click on Save. poedit will create the .mo file for each .po file you save. It happens instantly.

The names of the .mo files are important. All .mo files will go to the theme’s folder and their names indicate which language they translate to. You can choose any name you like, but you should really follow the standard locale naming convention. Normally, it’s language_COUNTRY (each in two letters). For example, to provide the German (Germany) translation, you’ll name it

For reference, you can see the locale names used by WordPress in the WordPress i18n project. Remember that some of the translations need to be provided directly by WordPress, so keeping to the same names is crucial.

Where to place the .mo files

Two sets of .mo files are required to get full translation of your theme:

  • Your theme’s .mo files.
  • WordPress .mo files.

Up to now, all we discussed was related to your theme’s .mo files. You need to place them in the same folder as your theme.

To get the WordPress .mo files, follow this:

  1. Go to the WordPress i18n project.
  2. Navigate to the language you need.
  3. In that language folder, navigate to tags/WP_VERSION/messages.
  4. You’ll find both .mo and .po files. Download the .mo file and save it in WordPress’ languages directory. Normally, it’s in wp-includes/languages. If that directory doesn’t exist, you’ll need to create it.

Choose the locale name for each language

Last, you need to tell WPML what’s the name of the locale for each language.

WPML theme localization
WPML theme localization
  1. Log in to WordPress.
  2. Click on the WPML admin section.
  3. Scroll down to where it says ‘Theme localization‘ and expand it.
  4. For each language, enter the locale name (like de_DE for German).

When you save WPML will verify that the .mo files exist in both the theme directory and in WordPress’ language directory. If any of these files are missing, you’ll see a warning, but you can still save.

Now, visit your site in different languages and you’ll see that it displays correctly. Not only the posts and pages, but everything in the theme should be fully localized.

Tell WordPress to load this textdomain

WordPress needs to load your .mo file and associate it with a text-domain. To do this, you need to include this call in your theme (normally, in header.php).

<?php load_theme_textdomain('YOUR_TEXT_DOMAIN'); ?>


This has been a pretty long article, so it’s great to see you’ve made it all the way down here.

Although it seems like a complex process, creating multilingual themes is really simple. It’s a good idea to create all your themes translation-ready. Not only is it a powerful feature to advertise, but it’s a real time saver for your clients. They’ll more than appreciate it when they start translating their site’s contents.

A premium theme’s value can increase dramatically if it already comes translated to several languages, and with a .pot file, making it easy to translate to other languages. Most of the texts are shared between different themes, so it’s just a tiny one time investment, that can later be reused over and over.