How to make a WordPress plugin translation ready?

What is the best way create a plugin that is translation ready?

It doesn’t have to be translated from the beginning but it has to be easily translatable so fellow developers from different cultures can participate to the localization process of the plugin.


1. Write with localization in mind

Don’t use echo or print() to produce text output, instead use the WordPress functions __() and _e():

/** Not localization friendly */
echo "Welcome to my plugin";    
// OR
print("Welcome to my plugin");

/** Localization friendly */
_e('Welcome to my plugin', 'my-plugin');
// OR
$my_text = __('Welcome to my plugin', 'my-plugin');
echo $my_text;

_e() and __() will provide the translation — in the current language — of the text provided as the first parameter. _e() will output the text whereas __() will return it.

The second parameter is the text domain, you will be using it to tell WordPress that the text provided as the first parameter belongs to this plugin, you can use any name you want but I prefer to use the same name as I used for the plugin file of directory, I find it more intuitive.

How to output dynamic text like: “Hello <username>”?

With __() and sprintf():

/** Get the username */

/** Not localization friendly */
echo "Hello $username";     

/** Localization friendly */
printf(__('Hello %s', 'my-plugin'), $username);
// OR 
$my_text = sprintf(__('Hello %s', 'my-plugin'), $username);
echo $my_text;

2. Prepare the .pot/.po/.mo files


  • The .pot file: is put at your disposal by the plugin developer and it’s used as a starting point to create new translations, WordPress doesn’t use it.
  • A .po file: is a translation file you or someone else started, and maybe completed, WordPress doesn’t use it.
  • file: is automatically created by Poedit whenever you save a .po file, all you can do with these files is to upload or re-upload them whenever you create or update a .po file. WordPress gets translations from .mo files.

Open Poedit and create a new catalog (File › New Catallog…) with these settings:

  • Project info: Use your (or your team) information, the language and country should match your plugin default language
  • Paths:
    • Base path: .
    • Paths : remove all & add .., (we will store language file in a plugin subdirectory called languages)
  • Keywords : remove all & add __ and _e

Save the catalog as /my_wordpress_blog/wp-content/plugins/my-plugin/languages/my-plugin.pot and scan your plugin files for translatable text by pressing the update button. When the update is finished close that catalog, you won’t need to update that file unless you add new translatable strings (i.e enclosed in __() or _e()) to your plugin.

Now let’s create the first translation (I will use fr_FR):

Using Podeit, create a catalog from a POT file
(File › New catalog from POT file…):

  • Project info: Use your (or your team) information, change the language and country, I will use French and France
  • Paths:Don’t change
  • Keywords : Don’t chage

Save the catalog as /my_wordpress_blog/wp-content/plugins/my-plugin/languages/my-plugin-fr_FR.po. Translate some or all the of the strings, save the .po file again, upload both the .po and .mo files.

Note that whenever you save a .po file a .mo file is generated with the same name, the filename of the .po file is crucial, it’s composed of the concatenation of the plugin text domain (my-plugin) and the language locale (fr_FR), always name your .po files for plugins like this: [textdomain]-[locale].po, here are some examples:

  • Italian/Italy: wpcf7-it_IT.po
  • Portuguese/Brazil: wpcf7-pt_BR.po
  • Arabic: wpcf7-ar.po… Yes!

Whenever the plugin is updated with new text, update the po file, translate new strings and reupload the .po and .mo files

3. Instruct the plugin to load translated text for the current language

Somewhere in your plugin, you must tell WordPress to use your .mo file, you can do it by using this code in the beginning of your plugin file:

function my_plugin_init() {
  load_plugin_textdomain( 'my-plugin', false, 'my-plugin/languages' );
add_action('init', 'my_plugin_init');

Replace my-plugin with your plugin name in the 1st and 3rd parameter of the load_plugin_textdomain function.

4. Test and troubleshoot

Some reasons it may not work:

  • Strings are not imported into the .pot or .po file
    • → Wrong catalog settings (path or keywords or both)
  • Text is not translated on the WordPress site
    • → .mo file for that language missing or has a wrong file name
    • → Text domain not used (replace _e('my text') with _e('my text', 'my-plugin'))
    • → Text domain not loaded (use example above with the right parameters, WP will not warn you about mistakes)

Leave a Comment