6 Tips for Localizing Your WordPress Plugin

Localizing (or internationalizing) your WordPress plugin means making its text capable of being translated into other languages, without having to change the plugin itself. That’s something any plugin author should want to do, considering the huge communities of non-English-speaking WordPress users and the relative ease with which internationalization can be done.

Here are my suggestions, proceeding from most commonly done to least often implemented.

Remember the basics

Include the text domain

Load the domain at the right time

Make good use of string formatting

Handle plurals correctly

Resolve ambiguities with comments

Remember the Basics

WordPress has two main localization functions: __ and _e. Wrap readable text in __ when you want just the text output (without printing it to the screen) and _e when you want to print, or echo, it. Examples:

<h2><?php _e('This is a printed header','my-plugin'); ?></h2>$variable = __('This string or its translation will be saved in the variable','my-plugin');

When you’re internationalizing your text, try to imagine how it will appear to a translator. Below is how the translation file for one of my plugins appears in Poedit, a popular .po files editor. As you can see, each localized line appears by itself, out of context. Keep that in mind as you localize.

Because localized strings of text can seem disconnected when viewed by a translator, plugin authors should try to keep discrete thoughts together. Disjointed strings of text can be difficult for a translator to put back together in another language.

Don’t let markup or style be overly dependent on the structure of English. For example, a number of languages read from right-to-left instead of left-to-right; an interface that assumes priority on the left, for example, could confuse international users.

Include the Text Domain

Throughout the core WordPress files, you’ll see that only one parameter is passed to the localization functions. In the example below, it’s the string of text “Log out of this account.” The second parameter, the text domain, is omitted, because core WordPress just uses the default domain.

<?php _e('Log out of this account') ?>

But your plugin needs to specify its own domain, as the text you’re translating isn’t likely to be in the core WordPress translation files. The plugin text domain is an arbitrary string unique to your plugin; most authors use the plugin file name minus the “.php” extension. The following line appears in the WP-DB-Backup plugin, which happens to use the file name “wp-db-backup.php.”

__('Backup Complete!','wp-db-backup')

Load the Domain at the Right Time

For plugin localization to work at all, a plugin must load the .mo file by calling load_plugin_textdomain at some point. However, many plugins load it too soon. It’s a good idea not to call load_plugin_textdomain any sooner than the WordPress “init” action event, so that the plugin will work with other internationalization plugins, plugins which might be doing things that need priority. In the following example, “myplugin” defines a function that is executed at the “init” event:

Make Good Use of String Formatting

It’s easy for native English speakers to forget that other languages don’t have the same syntax as English. Let’s say we want to internationalize output that in English has the form of the following:

“ERROR Code 102: username is a required field”

There is a bad way to do it (though not uncommon–this is a lightly modified example from an actual plugin):$error = __('ERROR Code ','my-plugin') . $code_number . ':' . $field_name . __('is a required field','my-plugin');

The first, bad, example chops the sentence into parts, which might not work independently in another language or might confuse the translator viewing a series of cryptic phrases. As much as possible, try to keep a distinct thought within one localized line.

To do this, the second, good, example above uses PHP’s formatting function, sprintf. Translators would see the line “ERROR Code %1$d: %2$s is a required field” and know that wherever in the sentence the numeric error code should appear, they should insert “%1$d,” and insert “%2$s” wherever the required field string should be.

Handle plurals correctly

Sometimes in the case of handling plurals, string formatting does not provide sufficient flexibility. Let’s say you need to be able to translate a string like this:

3 podcasts available for downloading

String formatting won’t allow you differentiate between the singular “podcast” and plural “podcasts.” Instead, you can use __ngettext. __ngettext accepts four parameters: the singular version of the string, the plural, the actual number, and the text domain. So we could localize the above example like so:

__ngettext('%s podcast available for downloading', '%s podcasts available for downloading', $podcast_count,'my-plugin');

Resolve Ambiguities with Comments

Sometimes an English word has different meanings depending on its context. In WordPress, for example, the English word “editor” can mean both the user role (someone who has editing capability) and the text-area where one writes a post. In other languages, those different meanings have different words, so localization needs a way of distinguishing them for a translator. WordPress’s _c function allows you to provide that context.

Use _c just as you would __, except that if you insert a pipe—i.e. “|” —everything including and following the pipe will be ignored in the output, allowing you to use the pipe to demarcate comments. The following two lines output the same in English, but the piped comments allow one to present context to the translators.