WordPress theme localization
May 31st, 2009 by AmirIn 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 wpml.org.
The entire process for theme localization includes:
- Identifying and marking texts that need to be translated.
- Collecting all the texts for translation.
- Translating the texts.
- 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:
Original:
<?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:
- Create an account at ICanLocalize (that’s free).
- Create a new text resource project (still free).
- Upload the .po file and select which languages to translate to.
- The system counts the words in the file and asks for payment. Payment is calculated as 0.07 USD * words * languages. For instance, translating our own theme to both Spanish and German cost us $30 (together).
- Translators do the translation.
- 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 de_DE.mo.
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:
- Go to the WordPress i18n project.
- Navigate to the language you need.
- In that language folder, navigate to tags/WP_VERSION/messages.
- 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.
- Log in to WordPress.
- Click on the WPML admin section.
- Scroll down to where it says ‘Theme localization‘ and expand it.
- 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'); ?>
Summary
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.

English
Deutsch
Español
I just want to say a HUGE thanks for this clean, clear explanation. I was a little daunted when I started reading your instructions to localize my theme but I flew through them and now I have a multi-lingual site.
This plug-in is brilliant and adds alot of value to my site.
Many thanks again!!!
[...] page de WPML WordPress theme localization décrit bien les étapes nécessaires (il manque bizarrement un morceau que j’ai du chercher [...]
Ok. I have a problem with WPML and _e() function.
My site is in polish. And polish is my default language in WPML.
I added english as my second language.
Using _e(‘Categories’) f.e. always translate it to polish even if on english version of the blog (http://myblog.com/en/).
Can you give me any cues?
Just Amazing explanation dude!! big thanks!
I want to add my thanks to the list. This WP plugin is absolutely excellent. I’ve been using Dotclear for some time now (and still do), and there’s a very good internationalisation plugin for dotclear called DCtranslations, which goes beyond what is usually available to blogs.
I never before went the wordpress way, because this platform lacked a true internationalization plugin. Now that we have WPML, things will change
As I’m developing themes which rely heavily on images and have text in them, I need to internationalize them as well. So far, I’ve added (‘bloglang’ ‘en’) pair in my themes ‘locale’ files ( ie English : bloglang=en ; French : bloglang=fr ; …) then I name the images accordingly, and refer to them in the theme by :
<img src="image1_”/>
Is this the best way to do this, or is there another, smarter ?
(and sorry for my first comment, accidentally hit ‘enter’ while typing)
Thanks for the kind feedback.
What you’re doing with images makes good sense. It’s easy to manage and makes the ‘multilingual’ images stand out.
When you have something, add it to the showcase section in our forum. It will be fun to discuss the way you implemented various things.
We’ll add you new site to the showcase soon.
By the way, if ever you’d like a French translation of the WPML interface, let me know. I’d be glad to contribute.
read “our new site”. Sorry for the typo.
Beautifully explained! I had been balking at the notion of building localization support for my theme, particularly since WP’s documentation page for this is quite big, but I have managed to get it done.
thanks for this explanation, i think i have this working 95% but i have one small problem that i have posted on the forum.
how do you wrap a value in a search form with gettext, like the term ‘search’ below:
<input type="image" id="searchsubmit" value="Search" src="/images/search-btn.gif” />
It should be:
<input type=”image” id=”searchsubmit” value=”<?php _e(‘Search’); ?>” src=”/images/search-btn.gif” /&>
This plugin is quite ok, but there is a huge error :
I can’t work when english is not the default language!
too bad…
Sure you can. You need to set the locale correctly and it will work just fine.
If you need technical support, try our support forum:
http://forum.wpml.org
Hi – I posted a forum post here http://forum.wpml.org/topic.php?id=822 – re: the example you gave above in this article, for translating template tags that have parameters, I can’t seem to get it to work. Details on my forum post. I appreciate any thoughts/help you can offer. Thanks!
Hi,
I´v used this tutorial to wrap all my strings,and it works great. Thanks for that. The only one I´m having a problem with is :
<?php else :
if ( is_category() ) { // If this is a category archive
printf("Sorry, maar er zijn nog geen berichten in de %s categorie.”, single_cat_title(”,false));
It´s the printf line I just don´t seem to get working.
[...] Tõlkida WordPressi teema erinevatesse keeltesse – selleks tuleb ümbritseda teema failides tõlgitavad elemendid PHP koodiga. Näide: <?php _e('Tekst', 'wpml_theme'); ?> Peale teema kohandamist tõlkimiseks saab tõlkida otse WordPressi adminipaneelist. Rohkem juttu sellest siin. [...]
I tried this plugin a few minutes ago and just love it!. I used Gengo for a long time and I haven’t been able to updated my wordpress because that plugin is outdated now. I looked for something similar (xili-language) and was so difficult to use… this one is so easy…
I haven’t had problem at all.
Thanks for this plugin!!!
Hi Amir
here is what I ve done so far. I localized a theme using poedit. So far I am using the 3rd option that directs where the .mo files are located. However I thought I should use the “scanner” for the theme as I have some text which I cannot “read” with poedit.
So I did >> 81 strings are found.
issue 1: eventhough I have set Greek (el) as the default language, the “translations” fields appear as Default = english text, strings and when I click to translate i am asked to enter the English translation.
Issue 2: If I set the default language to English then I GET as a result “NO found” to translate
Issue 3: in any case, I translated 2 strings for test reasons but the theme did not change. Do I need to do anything else apart from translating >> clicking on Complete >> save. ??
Hope the above make sense!
I’m having the same problem as the one reported by Marja above. Anyone found a solution yet?
Ok, this seems to be the perfect solution for my theme !
But one question. Does it work for text administrable into the theme option ? WPML didn’t found me any strings.
Then, what is the correct way to translate (with gettext) the text directly in the code ?
For example : Search Property ?
Is it __(Search Property)
Thanks for your help !
Hi, why, in line:
Nameyou can use:
But there is no echo…
Please help.
I am really curious if this would work as well with the new WordPress 3.0 that is going to be released this month. Have you tried it with the latest release candidate or do you have any info on that? Thank you.