How To Internationalize WordPress Themes and Plugins


In 5 Cardinal Sins of WordPress Theme Development, we briefly spoke about the significance of internationalizing themes and plugins but we didn't actually discuss how to do it. 

If you're in the commercial theme or plugin space, then it's almost expected that your work will support multiple languages. In the this article, we'll take a look at understanding what internationalization really is, why it's important, and what steps are necessary to internationalize your project.

Understanding Internationalization

When it comes to internationalizing WordPress projects, perhaps the most difficult aspect is actually understanding how to do it - internationalizing a WordPress project is actually really easy to do.

Before looking at how to do it, it's important to take a look at the significance of internationalization and why we, as developers, should even bother doing it.

Internationalization Defined

Simply put, internationalization is the process by which we prepare our theme for translation. This means that no matter what [spoken] language was used to develop our work, future users (or even developers) can easily translate the project for whatever language required. Internationalization doesn't actually require that we provide the translations (although the multi-lingual among us could easily do so), just that we take the steps necessary for future translators to do so.

Why Bother?

Years ago, I would've said that internationalization should only be done if the target market for your work was something different than your native language, but that's no longer the case.Thanks to the Internet, we're able to converse, collaborate, and communicate with people from all over the world. The potential audience for any given project is wider than its ever been before.

Even more so, WordPress powers a significant number of modern websites. To that end, we should think globally about our work.I'd argue that internationalizing commercial themes or plugins is a no longer negotiable. If the platform on which your work is built is used by a variety of languages - and WordPress is - and said platform provides a clean and simple way of internationalizing a theme - and WordPress does - then it's more of a question of why am I not internationalizing my work.

How To Internationalize

As previously mentioned, actually internationalizing a theme is more of an effort in understanding the key functions in the WordPress API than the actual process of preparing the text. So before taking a look at a concrete example, let's define a few important terms and functions:- Internationalization Key. You can think of this as a context, domain, or unique identifier for your strings.

Regardless, this is a single, unique value that WordPress will use to internationalize the text throughout your theme.- __($text, $key) is a function that returns a translated string. This function does not echo, print, or display the string. It's often used when needing to perform another operation on the translated string (such as passing it into another function). It accepts two arguments - the string to translate and the internationalization key.- _e($text, $key) is a function that actually echoes the translated string.

This is best used when you need to retrieve a translated value and display it somewhere in your theme or plugin.- load_theme_textdomain($domain, $translation_directory), load_plugin_textdomain($domain, $translation_directory) are two functions that tell WordPress where to locate your translations. We'll take a look at these functions a little bit more in detail momentarily.

For now, just know that each function serves the same purpose though one is for themes, one is for plugins.For the most part, this is all there is to understanding how to internationalize your theme. From here, we'll take a look as exactly what's entailed in putting these functions into practice.

Internationalizing Your Work

Displaying Translated Text

Before internationalizing a theme, let's take a look at how a standard piece of markup looks like:

<h1>My WordPress Blog</h1>
<h2>Just one of the best sites on the Internet</h2>
<p>This paragraph is only the best paragraph that exists in all of the WordPress blogs on the Internet. Read it and enjoy.</p>

Nothing spectacular, right? Looks like a standard piece of HTML (which is all that it is). Granted, this is a simple example but it's all that's required to demonstrate how to internationalize a theme.

To internationalize this text above, we need to determine what unique identifier we're going to use to internationalize our text - I'm going to go with 'tutsplus.' Secondly, since all of the above text is displayed on the screen, we'll use the __e() function. The internationalized code should be:

<h1><?php _e('My WordPress Blog', 'tutsplus'); ?></h1>
<h2><?php _e('Just one of the best sites on the Internet', 'tutsplus'); ?></h2>
<p><?php _e('This paragraph is only the best paragraph that exists in all of the WordPress blogs on the Internet. Read it and enjoy.', 'tutsplus'); ?></p>

But what about text that needs to be translated before being displayed on the screen? It's not much different but let's take a look at how we can internationalize sidebars.

Processing Translated Text

First, let's setup the sidebar:

		'name' => 'Custom Sidebar',
		'id' => 'sidebar'

For reference, I'm using the register_sidebar function available via the WordPress API. Note that the name of the sidebar is rendered on the Widgets screen. As such, we need to internationalize it; however, an array doesn't accept an echoed string - it accepts a string value.

In this case, we'll take advantage of the __() function:

		'name' => __('Custom Sidebar', 'tutsplus'),
		'id' => 'sidebar'

Easy enough, huh?

Remember, internationalization should only apply to static text. It's not the developer's responsibility to provide internationalization of page content, post content, and so on.

Preparing the Theme and/or Plugin For Internationalization

After you've gone through your theme and properly addressed the text that needs to be internationalized, you have to tell the theme or plugin where to find the internationalization files. We'll take a look at this in more depth in just a moment, but first I always recommend creating a 'lang' directory in the root of the theme or plugin directory to store internationalization files.

Remember the functions load_theme_text_domain and the load_plugin_text_domain functions from earlier? This is where we use them. If you're working with a theme, we'll need to define a custom function that is called in the after_setup_theme hook:

function custom_theme_setup() {

} // end custom_theme_setup
add_action('after_setup_theme', 'custom_theme_setup');

Next, we'll tell the function where to locate the translations. To do this, add the following to lines to your theme (note the comments that explain what each line does):

function custom_theme_setup() {

	// Retrieve the directory for the internationalization files
	$lang_dir = get_template_directory() . '/lang');
	// Set the theme's text domain using the unique identifier from above
	load_theme_textdomain('tutsplus', $lang_dir);

} // end custom_theme_setup
add_action('after_setup_theme', 'custom_theme_setup');

Relatively simple, right? It's not much different for plugins either. Similar with themes, I always place my plugin internationalization files in a 'lang' subdirectory. First, we have to tell WordPress where the internationalization files are located. Assuming that yours are located in a 'lang' directory:

load_plugin_textdomain('tutsplus', false, dirname(plugin_basename(__FILE__)) . '/lang/');

The second parameter - where we've specified 'false' - is necessary but corresponds to a deprecated function in WordPress.

Finally, we have to determine where to call the load_plugin_textdomain function. If we're writing a Widget, then I typically place this function call in the constructor:

class My_Custom_Widget {

	function My_Custom_Widget() {
		load_plugin_textdomain('tutsplus', false, dirname(plugin_basename(__FILE__)) . '/lang/');
	} // end constructor
} // end My_Custom_Widget

If we're writing a vanilla plugin, then there are a variety of ways that you can tell WordPress where the translation files are located, but you have flexibility to hook into the after_setup_theme function. Similar to the theme code above, you can place this in your plugin:

function custom_plugin_setup() {
	load_plugin_textdomain('tutsplus', false, dirname(plugin_basename(__FILE__)) . '/lang/');
} // end custom_theme_setup
add_action('after_setup_theme', 'custom_plugin_setup');

At this point, your theme or plugin are ready for internationalization.

Two More Considerations

At this point, you're actually done but it's always worth knowing what's required to take your work and move forward. Here are the two outstanding tasks that translators will normally perform to translate your theme

  • Translate The Text. Translators will process your theme through a translation application (such as POEdit) that will generate files that are stored in your 'lang' directory which is where WordPress will retrieve the files.
  • Updates to WP-Config.php. At this point, translators will have to instruct WordPress to enable internationalization and specify which language they're using. This is beyond the scope of this article, but you can read more about it in the Codex.

In contrast to some of the other development environments that are available, WordPress makes it incredibly easy to internationalize your work. Arguably, the most challenging part is understanding the key functions necessary to prepare your strings for internationalization.

Additionally, refactoring existing work can always be a time consuming process. In the context of WordPress, it may be tedious but it's relatively easy to do. If you've got any additional suggestions or questions regarding internationalization, feel free to leave them in the comments!