Home » Blog » Multilingual » WordPress theme localization

WordPress theme localization

May 31st, 2009 by

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 wpml.org.

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:

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:

  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.07 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 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:

  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'); ?>

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.

34 Responses to “WordPress theme localization”

  1. Andrea says:

    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!!!

  2. [...] page de WPML WordPress theme localization décrit bien les étapes nécessaires (il manque bizarrement un morceau que j’ai du chercher [...]

  3. Maciej M says:

    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?

  4. Juan says:

    Just Amazing explanation dude!! big thanks!

  5. babel comics says:

    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)

  6. Sayontan says:

    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.

  7. Estate says:

    thanks for this explanation, i think i have this working 95% but i have one small problem that i have posted on the forum.

  8. justin style says:

    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” />

    • amir says:

      It should be:
      <input type=”image” id=”searchsubmit” value=”<?php _e(‘Search’); ?>” src=”/images/search-btn.gif” /&>

  9. DontWork says:

    This plugin is quite ok, but there is a huge error :
    I can’t work when english is not the default language!

    too bad…

  10. luispunchy says:

    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!

  11. Marja says:

    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.

  12. [...] 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. [...]

  13. Yunne says:

    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!!!

  14. Jason says:

    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! :)

  15. Halibutt says:

    I’m having the same problem as the one reported by Marja above. Anyone found a solution yet?

  16. Matt says:

    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 !

  17. Pablo says:

    Hi, why, in line:
    Name
    you can use:

    But there is no echo…
    Please help.

  18. 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.

  19. Pi-C says:

    I have a major problem with the approach to translating texts with parameters:

    by

    This works alright for some functions. However, other functions place their output in front of the whole string, not at the position of the “%”. For example,

    <?php printf(__('You have to log in to post a comment.', 'wpml_theme'), get_option('siteurl'), the_permalink()); ?>

    results in something like this:

    http://URL/?p=676You have to log in to post a comment.

    Do you know what to do in such a case?

    • Pi-C says:

      Darn it… I just see that somehow the string placeholders got swallowed in the previous posting! However, I just found another — more simple — example for the same mistake:

      This should print

      Posted in General

      but what I get is

      GeneralPosted in

      So, any ideas anybody? :-)

  20. Rick says:

    How can I add translation to this:

    ??

  21. Louise says:

    I was just having a problem but I found the answer myself while writing the question so I thought I’d share anyway.

    I was following the steps above which are quite clear and well written.
    Number (1) using echo seemed like a good way to go, and using the hybrid theme as a base for my custom theme there are already examples of how to code this, so I copied the code already in hybrid theme which was:

    This string ‘Apologies, but no results were found.’ was already showing up in the WPML plugin management screen so I knew it was working correctly.
    I then copied, pasted, and changed it

    Then I searched the “string translation” tab in the WPML plugin management screen for ‘this is some test text’ but it didn’t show up, nor did it show up when I tried to export a .po file.

    The answer was, I needed to get the plugin to rescan the files to pick up the new string ‘this is some test text’.

    The rescan button is not in the “String Translation” tab. You need to go to the “Theme and Plugins Localization” tab and press “scan the theme for strings” after you have written all the _e calls into your custom theme. I hope this helps someone else. It might be kind to put it in the main article for others who might be at a similar low skill level as I.

    My thanks to you :)

  22. Jason says:

    Hi,
    What values I need to put in the textdomain value.any value or specific.please guide me .I recieved messages file not found infront of all my all translations.

  23. Davy says:

    Hi, wpml is working great so far on all my content, great plugin. worth every cent. but the only thing is i cant get my theme itself translated properly.. am hoping to run theme auto translation using wpml instead of using another plugin like wp native dashboard…

    i’m on wordpress 3.3.1 running on a themeshift theme.

    what i’ve done so far:
    i’ve copied both the .po and .mo file into wordpress/wp-content/languages and also into the theme root directory, and to overkill it i put it into the theme/lang folder as well. just for good measure..

    but i still get the red “file not found” error at the themes and plugins localisation screen.

    and i can’t seem to understand what is and where can i find the textdomain value:??

    thanks so much :)

    • Amir says:

      You only need the theme .mo files. Ask the theme author where to place them. The theme loads these .mo files by itself and not WPML. WPML sets the locale (language code) and the theme loads the .mo files.

      If you place the .mo files in their correct location and the translations are still not showing, it means that the theme is loading these files too early – before the WordPress initialization sequence completes. Please use our technical forum to follow up on this.

    • Davy says:

      Hi Amir,

      thanks for the explanation…, i think you are correct, because basically i placed the .mo files almost everywhere i think i it could help… but its still not running. although i’ve sent an email to the theme author to confirm where the .mo files should go however..

      by if the theme is loading the file too early.. what could i do? could you point me in the right direction in the technical forums? i only just signed up to wpml today,so very new to all this, thanks again. :)

      • Amir says:

        We’ll need the theme files to suggest where and how to fix. The absolute best thing is to get the authors to contact us and we’ll explain this in 2 seconds. This is one of the more common mistakes that theme authors do and is very easy to fix. Can you please move this to our technical forum, so that our support people can tell exactly what to change?

Leave a Reply

Please leave here comments about this page only.
For technical support and feature suggestions, head to our forum. We are waiting there!

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