Internationalizing And Localizing Your WordPress Theme In 6 Steps

About The Author

Konstantinos Kouratoras is a software engineer based in Crete, Greece. WordPress lover and amateur photographer. You can contact him through personal website or … More about Konstantinos ↬

Email Newsletter

Weekly tips on front-end & UX.
Trusted by 200,000+ folks.

A very important part of WordPress theme development is preparing it so that users from every corner of the planet can translate its messages to any language.

This article covers the basics of internationalization, which is the process of designing a theme in such a way that the end user can adapt it to various languages without having to change the source code, and localization, which is the process of translating text messages to a particular language. Expanding the range of our theme’s users is a big deal, and WordPress provides a simple way to do that.

Overview of Process

Here is a brief overview of the process of internationalizing and localizing a WordPress theme:

  1. Load a text domain,
  2. Process text messages with WordPress functions,
  3. Extract these messages with the appropriate software,
  4. Provide a translation for each message,
  5. Create a language file for a particular locale,
  6. Instruct WordPress to enable localization and to load the language file.

Adding WordPress Functions

The first thing to do is load a text domain by adding the following line in the functions.php file of our theme:

load_theme_textdomain('mytheme', get_template_directory() . '/languages');

The first argument must be a unique identifier (a good practice is to use your theme’s name); it defines the theme’s domain, as the text for translation will not be in WordPress’ core translation files. The second argument defines the folder of the language files. To load these files, the function must be tied to the after_setup_theme action:

add_action('after_setup_theme', 'my_theme_setup');
function my_theme_setup(){
    load_theme_textdomain('mytheme', get_template_directory() . '/languages');
}

Processing Text Messages

After editing functions.php, the next step is to look through the source files, find the messages that need to be translated and process them with the appropriate WordPress function. The two most important and commonly used are _e($text_message) and __($text_message). The first function searches for the translation of $text_message and prints it. If the translation does not exist, then it prints $text_message. This function is used for text messages that are not in PHP functions, as it prints the result. Take the following line:

echo ‘Hello user’;

This should be transformed to:

_e(‘Hello user’,’mytheme’);

The second function searches for the translation of $text_message and returns it. If a translation does not exist, then it returns $text_message. It is used for text that is in PHP functions. For example:

the_content( ‘Read more’ );

This function call should be transformed to:

the_content( __(‘Read more’,’mytheme’) );

Sometimes, a text message includes dynamic data, such as a number from a PHP variable. In this case, we use the sprintf PHP function to produce the final message string:

$results_found = 12;
$message = sprintf( __(‘%s results found’ , ‘mytheme’) , $results_found );

Singular and Plural

WordPress provides a function for singular and plural translation of the same text message:

_n( $single, $plural, $number, $domain )

The first argument is the text that will be used for singular, and the second is the text that will be used for plural. The third argument is the number to compare in order to decide which to use.

Although the _n() function is built into WordPress, using it is discouraged because the translation software parses only the first parameter of a function, and so these two text messages would not be fetched. Instead, we can use the PHP if statement:

if($results_found == 1)
    $message = __(‘1 result found’ , ‘my-text-domain’);
else
    $message = sprintf( __(‘%s results found’ , ‘my-text-domain’) , $results_found );

Language Files

Once we ensure that we’ve processed every text message with the functions mentioned above, our theme is ready for translation. For this purpose, there are three types of language files:

  • The POT file contains a list of all translatable messages in our theme.
  • The .po file is created when we translate a POT file to a particular locale.
  • The .mo is a binary file that is created automatically by translation software and is not human-readable.

Messages List

The first thing to do is create a POT file, which contains all of the text messages of our source files and which will be the file that the translator uses to translate the messages to another locale. There are several tools for creating POT files. The most popular, and the one we will use in this article, is a cross-platform tool called Poedit.

  1. Open Poedit, and create a new catalog.
  2. Fill in the project’s information in the “Project info” tab: Project info tab of Poedit
  3. In the “Paths” tab, identify the folder for Poedit to search for source files that contain translatable text messages. These folders are relative to the folder of our language file, so if we save the file in a folder in our theme folder, then we should add ..: Paths info tab of Poedit
  4. In the “Keywords” tab, define the WordPress functions used to translate messages (keep in mind that Poedit is not only for WordPress). In our theme, the two keywords we used are __ and _e. Keywords info tab of Poedit
  5. After you click “OK,” Poedit will scan the folders you’ve provided in the Paths tab and will list the text messages in the source files. Messages list in Poedit
  6. Save the POT file in a folder named languages in your theme directory: Languages directory with POT file

Please note: WordPress does not need a POT file to load a particular translation. The file is just a template that contains all of the translatable message strings, which you can provide to the translator to translate and return to you as a .po file.

Providing Translation

Our POT file is now created! The next step is to translate the messages of this POT file to a particular locale and then save it as a .po file:

  1. Select the string you want from the list, and type the translation into the field at the bottom of the window. Type translation for a text message in Poedit
  2. Repeat this action until all messages have been translated.
  3. Save the file as a .po file in the same folder, setting the language code and country code as the file name (sometimes they are identical), as defined by ISO 639-1 and ISO 3166-1, respectively. For example, if the language of the translation is British English, then the name would be en_GB.po. Now, the languages folder will contain the .po and .mo files of our translation as well as the POT file: Languages directory with .po files

Please note: When saving a .po file, Poedit will automatically create an .mo file, which is a binary file and is not human-readable.

Updating the Configuration File

Once we’ve created the .po and .mo files, it’s time to instruct WordPress to enable the localization and to load the language files. Edit the wp-config.php file in WordPress’ root folder, and set the WPLANG variable to the relevant locale. For example:

define('WPLANG', ’);

If we’re using the British English locale, then we would change the line above to:

define('WPLANG', 'en_GB');

What About Plugins?

Although this article deals with WordPress themes, it’s worth mentioning that the differences in the process of internationalizing a plugin are minor. Similar to what we did, we tell WordPress where to find the language files by adding the following function in the plugin’s main file:

load_plugin_textdomain('myplugin', false, basename( dirname( __FILE__ ) ) . '/languages' );

The first parameter defines the text domain; using the plugin’s name is recommended, as it must be unique. The second parameter defines a path of a folder, where the .mo file resides. It corresponds to a deprecated function that was valid until WordPress 2.7, so we specify it as false. The third parameter is the folder where the language files reside (in this case, we assume they are located in a directory named languages).

To load the language files, we need to add a hook and tie this function into the init WordPress action:

function myplugin_internationalization()
{
    load_plugin_textdomain('myplugin', false, basename( dirname( __FILE__ ) ) . '/languages' );
}
add_action('init', 'myplugin_internationalization');

Finally, we process the text messages the same way as before, using the _e($text_message) and __($text_message) functions. After we’ve processed all of the text messages, our plugin is ready for localization.

Conclusion

WordPress’ user base is growing rapidly, making the CMS one of the most popular tools in the world of Web development. With people coming from all over the world and speaking different languages, WordPress offers a flexible platform and provides an easy method of internationalization, enabling users to translate with no modification to the source code.

Other Resources

This article covers the basics of internationalizing and localizing a WordPress theme. For more in-depth information, have a look at the following related resources, available in the WordPress Codex:

Smashing Editorial (al)