Try Tuts+ Premium, Get Cash Back!
Translating Your Theme

Translating Your Theme

Tutorial Details
  • Program: WordPress
  • Version: 2.1 and higher
  • Difficulty: Beginner
  • Estimated Completion Time: Varies

It’s very easy to turn a blind eye to other languages when developing your WordPress theme, but this is a very bad habit and immediately turns away a whole market of WordPress users and potentially thousands of dollars in lost revenue. Out of the top 10 countries that search Google for “WordPress themes”, only one is native English speaking (the USA) and that comes 9th. As of writing this, there are only 269 themes in WordPress’ theme database that are tagged as translation-ready out of more than 1,500 themes. That’s only 18% of the themes. I’m going to show you how to make yours one of them.


How It Works

When you usually make a theme, you will simply hardcode any theme text such as the 404 error message in the 404.php file, or labels such as “comments:” or “author:”. If the user’s WordPress is German for example, these snippets of text will still display in English. The solution to this is to return or echo these statements using one of four WordPress functions which are designed to reference a language file for the correct text. Once you have your text wrapped in these functions, you can create a file containing all the translations that is referenced every time the theme is loaded. There are three translation files that we use:

  • .pot (Portable Object Template) – This is the template file that contains a reference to each text string in your theme that needs translating. This file does not contain any translation. It is a plaintext file.
  • .po (Portable Object) – Made from the .pot file, the .po contains all your string references as well as their translations to one specific language. This is also a plaintext file that can be edited.
  • .mo (Machine Object) – A binary version of the .po file. By using machine code, the file can be used much faster than its plaintext alternative.

Step 1 The Four Functions

Each of the four functions requires at least one argument, which is the text that is to be translated. The functions are:

  • __()(two underscores) The basic function that you will use the majority of the time. It returns the text in the correct language.
  • _e() – The same as __() except it echoes the text instead of returning it.
  • _n() – Used when the text has the potential to be plural, so for example if you were to display how many comments have been made, you might want to output either “X comments” or “X comment” depending on how many comments you have.
  • _x() – Useful for when the translation of the word depends on the context. “Post” could mean “a post (noun)” or “to post (verb)” depending on context. It is important for the translator to know which you mean when translating to be accurate. _x() is mainly used where single words are used.

__() & _e()

These are the simplest translation functions that WordPress has to offer. Let’s take a look at an example of each:

<?php
if( is_single() ) { //If this is a "post"
	echo __( 'This is a post.' );
}
?>
<?php
if( is_single() ) { //If this is a "post"
	_e( 'This is a post.' );
}
?>

Both of these functions are doing exactly the same thing here. The statement “this is a post” is being checked against the .mo file if there is one, and returning the result. __() and _e() only require one argument to be passed to them, which is the text we want to be translated. A second optional argument is available and we’ll come to that later. The only difference between the two is that __() needs the echo statement here. Let’s look at an example where __() works better than _e():

<?php
the_content( __( 'Click here to read more' ) );
?>

Instead of passing a string to the the_content() function, we have used __() so that the text can be translated. If we had used _e() here instead, you would have the translation of “Click here to read more” echoed to the document instead of being passed to the_content() which would cause all sorts of unhelpful problems.

_n()

What if you have a situation where the text you output could potentially be a plural or a singular like the “X comments” example above? Instead of giving two different text strings for the translator, you can say that you have a single piece of text that needs a singular and plural translation. The following two examples both output the same result to the user:

<?php
if(get_comments_number() == 1) {
	_e( 'There is a comment' );
} else {
	_e( 'There are comments' );
}
?>
<?php
echo _n( 'There is a comment' , 'There are comments' , get_comments_number() );
?>

_n() requires three arguments. The first is the singular version of the text, the second is the plural, and the third is the number that it’s referencing. In this case, get_comments_number() is finding how many comments are on a post and then _n() is choosing the appropriate text to use.

_x() & _ex()

Let’s say you’re translating a .pot file, and you come across an entry “scroll”. Are you going to interpret that as “a piece of rolled paper” or “pan up or down the website”? You could really do with some context to describe what you need to translate it to. These functions give you that ability, by having a second required attribute which asks for a short description to describe the phrase or word. Check the example below:

<?php
echo _x( 'post link' , 'A link to the post' );
_ex( 'post link' , 'Submit a link' );
?>

The example shows you the difference between _x() and _ex(). It is the same e, as with _e, to make the function echo the output instead of returning it. For both, our first parameter is our text that needs translating, and the second is a comment or note about the translation text to make it clear what is meant.

Advanced Techniques

Let’s say that you have a situation where the text you want to generate is composed of a text string with the result of a function or the value of a variable put somewhere inside it. You might be tempted to right something like this:

<?php
$color = the_color();
_e( "You have chosen the $color theme" );
?>

When it comes to making your .pot file, POEdit will ignore this because it doesn’t want to use a variable in the middle of a sentence. The reason being is that it will submit the string You have chosen the $color theme to the .pot file, but when it comes to searching for the translation when the script is executed, it will search for the string You have chosen the blue theme which it won’t find. So what if we do this instead:

<?php
$color = the_color();
echo __( 'You have chosen the ' ) . $color . __( ' theme.' );
?>

The script will now be able to retrieve the translations, but now it’s become too difficult to translate because the sentence has been broken up. This sentence might not even be translatable in some languages that have largely different syntax, such as in German where their word for “chosen” would appear at the end of the sentence. You would need to go through the trouble of explaining that these two separate text strings are part of one, and that “theme” might not translate to “theme” at all.

The solution is to use a single text string that has single-quotation-friendly syntax. This is where the printf() or sprintf() functions become useful. Let’s take a look at what our code needs to look like:

<?php
echo sprintf( __( 'You have chosen the %s theme.' ) , the_color() );
printf( __( 'You have chosen the %s theme.' ) , the_color() );
?>

Not only does this solve all our problem we had before, but it’s a lot tidier and only uses one line of code. The printf() or sprintf() functions’ first arguments are the string to output which contains at least one placeholder, in this case %s (which means “string”), and any other arguments are variables that are to be placed inside the initial string. There are many different placeholders you can use inside your string and you can find a full list under sprintf in the PHP manual. Note that the different between printf() and sprintf() is similar to _e() and __() respectively.


Step 2 Introducing POEdit

Now that you have successfully tagged all your text output on your theme, you now need to collect this information into a .pot file. POEdit is a fantastic program that gives you the ability to create your .pot file, and also provides an easy to use GUI that can be used to make your .po and, more importantly, your .mo files too.

First, you will need to download POEdit, which you can find here for Windows, Mac and Linux:
http://www.poedit.net/download.php

Once POEdit is installed, you can create your .pot file. To do this, go to File > New Catalog. You will be presented with a dialog box where you need to enter some basic information. The essentials in the “Project Info” tab are the project name and your language/country. You also must enter the following in the “Plural Forms” box:

Plural Forms: nplurals=2; plural=n != 1;

POEdit project info

On the “paths” tab, enter the path where the files can be found relative to the save destination of this .pot file. For example, if you are putting the .pot file in the theme’s root folder, enter . (period). If you want to place the .pot file in a “language” folder inside the theme root, enter .. (two periods).

POEdit path

Next, you need to tell POEdit which keywords to look for when scanning our files. Enter the following:

  • __
  • _e
  • _n:1,2
  • _x:1,2c
  • _ex:1,2c

The :1,2 extension tell POEdit that these keywords have two parts to them. By default, the second argument is the plural unless you include the c which mean the second argument is a comment.

POEdit keywords

You’re good to go! Click “OK” and choose a place to save your .pot file. Remember that it has to relate to the path you defined earlier. POEdit will now scan through your files and find all the occurrences of your translation functions and save them without translations into your .pot file. If you only want to provide the bare minimum support for international translation you can ship your .pot file with your theme and stop here, however if you are able to translate your theme into another language yourself, you can ship your theme with a premade translation as described in step 3.


Step 3 Translating and Making Your .po File

POEdit translating singular
  1. A list of all the text strings to be translated
  2. The current string being translated
  3. Your translation of the string
POEdit translating plural
  1. Singular and plural of current string
  2. Tabs to switch between singular and plural of your translation
  3. Your translation

Once you have translated all the strings in the .pot file, you can save this as your .po file. Any string that you haven’t provided a translation for will show in the original language when someone views your theme.

The filename of your .po is crucial. Gettext uses the ISO 639 standard for language abbreviations and ISO 3166 for locales. If your translation is written in American English for example, your file name will look like en-US.po. Capitalization is also important here. For a full list of language and country codes, check out these two links:

Once you save, POEdit by default automatically creates a .mo file alongside your .po file. It is recommended you include all three of your translation files with your theme so that people can create their own translations and edit your existing translations easily.


Step 4 Setting Up WordPress

Let’s recap what you have done so far. You have told WordPress all the text that you want to be translatable, and then you used POEdit to collect each string and place them into a .pot file which can be translated into a .po and .mo file. These files are then included in the theme files. The final step is to zip your theme, install it and let WordPress know which language .mo file you want it to use. This is a very straight forward procedure where you access your wp-config.php file found in your WordPress’ root folder.

/**
 * WordPress Localized Language, defaults to English.
 *
 * Change this to localize WordPress. A corresponding MO file for the chosen
 * language must be installed to wp-content/languages. For example, install
 * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German
 * language support.
 */
define('WPLANG', '');

Your file should already contain define('WPLANG', ''); but if it does not, you can add it in. You simply need to add your language and locale code into the define. If you were to translate your theme into German, you would have this:

define('WPLANG', 'de_DE');

Your internationalization is complete! Remember to include your .pot file with your theme, and if you were able to translate your theme to another language, to include the .po and .mo files too.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://pippinsplugins.com Pippin

    Great tutorial, but you missed the part about loading the theme’s text domain. Strings that are already translated in the core WordPress language files will translate fine, but none of your custom strings will translate unless you have the theme text domain loaded.

  • Pingback: Translating Your Theme | Shadowtek | Hosting and Design Solutions

  • http://deckerweb.de David Decker

    Thanx for writing something about internationalization – very important topic!

    But appearantly you are missing some important things:
    1) Like Pippin mentioned, loading of textdomain is very often forgotten” by theme developers – also point out the existence/ difference of “load_theme_textdomain” and “load_child_theme_textdomain”

    2) There’s no “de-DE”, almost all locales are defined with underscores, so there’s only “de_DE” or “nl_NL” or “fr_FR”

    3) There’s not only “Poedit” editor which tends to confuse a lot of users! You should also mention an awesome translation plugin for end users and developers (testing, debugging…) alike: “Codestyling Localization” — http://wordpress.org/extend/plugins/codestyling-localization/

    I am specializing in translation of plugins and themes and also to make them translateable so I strongly suggest to update your post because there’s already to many wrong stuff out there regarding this topic!

    Thank you!!

    -David from Germany :)

  • http://www.themeprince.com ThemePrince

    WordPress should come up with something waaaay better and easier solution for translation handling.

  • http://wpti.ps Piet

    Almost a very complete tutorial indeed.

    But, not only are you missing the part about loading the theme’s text domain, you also don’t include it in the strings, so people have to figure that all out by themselves?

    • http://www.sutanaryan.com/ Ryan S

      The code above simply don’t work if you didn’t add text_domain, or there is a solution translating your theme without text_domain?

  • http://www.wpfix.org Wpfix

    Very useful tutorial on translating themes.

  • Sami Keijonen

    Good points from Pippin and David. Other than that this pretty good stuff. Couple of questions.

    What is the purpose of nplurals=2; plural=n != 1;. Why it needs to be in Poedit?

    I forget the other one:) But anyway you should read also Otto’s article.

    http://ottopress.com/2012/internationalization-youre-probably-doing-it-wrong/

  • http://wppot.com Ajay Patel

    Grate article ! I have learn lot about language translation in WP.

    Thx !

  • http://jamesbanks.me James

    Great post. Few requests:

    1. Can you please list the top 10 countries that you found in google under the search query “wordpress themes’
    2. I’m not sure if I missed it, but were do you save these .mo and .pot once you are finished with them? Do you create a new languages folder inside your wordpress theme or do they require a specific folder path that you must follow?

  • http://www.mehmetsali.com Mehmet Sali

    Very useful tutorial, thanks.

  • Pingback: some cool links which helps you to make you full programmer | myjunk.in

  • keha76

    POedit on OSX is really buggy IMHO, that’s why I want to share an alternative plugin solution for translation http://wordpress.org/extend/plugins/codestyling-localization/ it works quite well and it also informs you about some common errors, if there are any.

  • http://kathyisawesome.com kathy

    i see the purpose of _x() but for the life of me i can’t get those comments to appear in poedit, so what good are they? are they not supposed to? do translators have to go searching through the code for every string’s comments? seems wildly inefficient, so i hope i am missing something.

  • Pingback: 10 posts de WordPress que no debes perderte « Silvercorp

  • Pingback: Skeleton to WordPress: Finishing Off | How to Web

  • http://www.vandenwinkel.com Stork on the Roof

    The part about POEdit was helpfull

    I’m wondering though, why the context specified in _x or _nx don’t show in POEdit.
    When you open the po file in a plain text editor, you can see the context, but not in POEdit itself.
    Any ideas for another program that does?

    Best!

  • Carina

    May be I’m stupid, may be I’m missing something… I’ve already have my WP in spanish.
    If I have a theme in english with it’s own .po file (on theme/lenguage folder), how do I supose to mix it with my spanish one?

    • Luis

      Hola Carina. Lograste que funcione la traducción? Por favor, si es así te agradecería me indiques como hiciste. Estoy igual.

  • Pingback: Globex - Responsive Business WordPress Theme - XavorTM

  • Pingback: WordPress - Poedit: Translation Secrets - cssigniter.com

  • http://ivatanackovic.com Iva

    “You might be tempted to right something like this” does not mean anything.

    Thanks for the tutorial. I’m still having problems with printf and sprintf, but I have learnt something new.

  • Pingback: Iva on "Comments title won’t localize on my custom theme" | Upgrade Wordpress

  • Pingback: How to translate theme in another language? – Support Center

  • chadw

    WOW! Thanks for your awesome explanation. This is one of those things I knew I should be doing, but kept putting off figuring out. Now that I am rebuilding my theme development framework I felt it was the time to put it into action.

  • Talton

    I really like how they go in-depth into the creation of the pot file. It adds a lot of context as to how translations work in general.

  • Pingback: 25 WordPress Theme Development Tutorials to Get Started - Rockable Themes

  • Pingback: 25 WordPress Theme Development Tutorials to Get Started - Daily Design Hub

  • Pingback: 20 Useful WordPress Theme Tutorials and Resources - Streetsmash

  • Pingback: Top 8 Best Wordpress Tutorial Sites | The Geek Connection

  • Gerhard

    Great article, thanks.
    There are the functions esc_attr__ and esc_attr_e you need to add to the POEdit keywords.

  • Peter

    Danke sehr. Es hat gut geklappt. (Lokalisierung eines gekauften Themes.)

  • Pingback: catch everest 主题翻译(theme translation) | zciii的博客

  • Pingback: Why you should Translate your Wordpress Theme & Plugins | DollarFry

  • VanessaT

    You can also try this plugin: http://wordpress.org/extend/plugins/poeditor/. It’s a very good plugin that works with poeditor.com via API. Using this plugin along with this localization software will ease your work a lot, not needing to create as many po and mo files as usually.

  • Pingback: 25 บทความสอนการทำ theme wordpress ตั้งแต่เริ่มต้น!! | Mister sTA

  • http://www.facebook.com/jojojoson Jojo Joson

    Translating your theme is an important business decision. It can help you to reach maximum customers across different continents. But translating a theme to each & every language would be a dumb decision because its a waste of time. In my opinion, you need to translate it only to languages in which WordPress is widely used. This is an interesting article which looks deep into such data – which all countries and languages use WordPress:- http://www.dollarfry.com/which-all-countries-and-languages-use-wordpress/