In this tutorial, you will learn how to make a WordPress plugin translatable.
With a translatable WordPress plugin, you can cover a more extensive user base for your plugin hosted on WordPress.org or sell more licenses in marketplaces like Envato Market.
Make a WordPress plugin hosted on WordPress.org translatable
This section will cover the method used to make a plugin hosted on the WordPress.org repository translatable.
Declare the text domain in the plugin header
The first step for making your plugin hosted on WordPress.org translatable is to declare the text domain in the plugin header.
More specifically, the text domain is an identifier used by WordPress to categorize the loaded translations. Its value should match the plugin slug, namely the unique portion of the plugin URL.
As an example, in a plugin available at https://wordpress.org/plugins/example-plugin/
the correct value of the text domain is example-plugin
.
The resulting plugin header with our example-plugin
text domain:
/*
* Plugin Name: Example Plugin
* Author: Plugin Author
* Text Domain: example-plugin
*/
An exception for plugins compatible with old WordPress versions
If your plugin supports WordPress versions older than 4.6 (you define this with the Requires at least
directive in the readme.txt file of the plugin) you should also declare the text domain and the relative path to the translation files with the load_plugin_textdomain()
WordPress function.
function initialize_plugin() { load_plugin_textdomain( 'example-plugin', false, 'example-plugin/lang/' ); } add_action( 'plugins_loaded', 'initialize_plugin' );
Note that with plugins hosted on WordPress.org a local translation in the example-plugin/lang/
folder is not required because the translation is defined on Translating WordPress.
Load a local translation with a plugin hosted on WordPress.org
If your plugin is hosted on WordPress.org, but you still want to load a local translation, there is the load_textdomain_mofile
filter.
This example demonstrates how to define the location of a local .mo file in a plugin associated with the example-plugin
text domain.
function change_translation_file_location( $mofile, $domain ) { if ( 'example-plugin' === $domain ) { $mo_file_location = WP_LANG_DIR . '/textdomain/yourtranslationfile-' . get_locale() . '.mo'; } return $mo_file_location; } add_filter( 'load_textdomain_mofile', 'change_translation_file_location', 10, 2 );
Make a plugin not hosted on WordPress.org translatable
Suppose you are developing a custom WordPress plugin for a client or planning to sell your plugin online on marketplaces like Envato Market. In that case, the declaration of the text domain in the plugin header is not necessary.
Instead, use the load_plugin_textdomain()
function to declare the text domain and the translation file location. Then create the translation files for each combination of language and locale.
Declare text domain and file location
Use load_plugin_text_domain()
to define the text domain and the translation file location like you did in the previous section.
function initialize_plugin() { load_plugin_textdomain( 'example-plugin', false, 'example-plugin/lang/' ); } add_action( 'plugins_loaded', 'initialize_plugin' );
Create a translation file with a proper name
The translation file should start with the text domain and be followed by the ISO_639-1 code of the language and then the ISO 3166-1 alpha-2 code of the locale.
As an example, the translation file for the Italian version of a plugin with the example-plugin
text domain has the following name:
example-plugin-it_IT.po
Translation functions
All the text strings used in the WordPress plugin should be added as arguments in the translation functions provided by WordPress.
A simple example
If a button in your plugin contains a string that you want to make translatable replace your current button HTML:
<input class="button" type="submit" value="Add Item">
with:
<input class="button" type="submit" value="<?php esc_attr_e('Add Connection', 'dahm'); ?>" >
In this example, I’ve used the esc_attr_e()
function to make the “Add Connection” string translatable, however other translation functions are available.
In this regard, it’s worth mentioning that you should select the translation function based on the context. To this end, I recommend you to read the next section, which includes an overview of all the translation functions.
The complete list of WordPress translation functions
In this section, I’ve included a complete list of the translation functions provided by WordPress, and each translation function comes with a short explanation and an example.
_e()
The _e()
translation function echoes the content of a translatable string.
_e('Hello World', 'example-plugin');
__()
The __()
translation function returns the content of a translatable string.
echo __('Hello World', 'example-plugin');
esc_attr__()
The esc_attr__()
function is the same as __()
, but the resulting string is escaped for HTML attributes.
echo esc_attr__('Hello World', 'example-plugin');
esc_html__()
The esc_html__()
function is the same as __()
, but the resulting string is escaped for HTML content.
echo esc_html__('Hello World', 'example-plugin');
esc_attr_e()
This esc_attr_e()
function is the same as _e()
, but the resulting string is escaped for HTML attributes.
esc_attr_e('Hello World', 'example-plugin');
esc_html_e()
The esc_html_e()
function is the same as _e()
, but the resulting string is escaped for HTML content.
esc_html_e('Hello World', 'example-plugin')
_n()
With the _n()
function, you can display two alternative strings based on the value of a numeric variable.
The first string is display when the numeric variable value is equal to 1. The second string is displayed when the numeric variable value is different from 1.
echo _n('item', 'items', $count, 'example-plugin');
_x()
Use the _x()
function to create multiple contexts for the same string.
For instance, the word ship is both a noun that means “A large vessel” and a verb that means “To send or transport”.
The first occurrence of the string ship:
$result = _x('ship', 'A large vessel.', 'example-plugin');
Another occurrence of the string ship but with a different context:
$result = _x('ship', 'To send or transport.', 'example-plugin');
Note that with _x()
, the translation editor software will produce two entries for the string ship
. As a consequence, you will be able to assign the two different translations of the string.
_ex()
The _ex()
function is like _x()
, but with the result echoed instead of returned.
_ex('country', 'A state or nation.', 'example-plugin');
_nx()
The _nx()
function considers both the value of a number and the context.
echo _nx( 'record', 'records', $animals, 'Achievement in sport.', 'text-domain' );
_n_noop() and translate_nooped_plural()
The _n_noop()
and translate_nooped_plural()
functions work together to achieve the same result of _n()
. However, in this case, two steps are required.
In the first step, you register the two strings without providing the numeric variable used to select the considered string:
$nooped_plural =_n_noop( 'item', 'items') );
Later in your code, you can use the $nooped_plural
array with a numeric variable:
echo translate_nooped_plural( $nooped_plural, $count );
These two functions are necessary if you are in a situation where you have to pass only the singular and plural forms of a string (without the numeric variable) to a function.
How to verify if the plugin is translatable
To verify if a plugin is translatable, visit the page of your plugin on the Translating WordPress website.
If the plugin is prepared correctly, you will find a table with all the languages and the translation statistics.
Translate the strings on the Translating WordPress website
First, visit the translation page of the plugin and click on the language for which you want to create a translation.
Then select the sub-project that you want to translate. The Stable (latest release) project includes all the translatable strings of the plugin, while the Stable Readme (latest release) project includes all the translatable strings of the plugin readme file.
Consider that a user of an authorized role should approve the translation submitted in Translating WordPress. However, you can approve your own submissions by becoming a Project Translation Editor (PTE).
For more details on the roles of the Polyglots Team, see Roles and Capabilities.
Translate the local strings
The local translations are stored in .po files, usually placed in a dedicated folder. This dedicated folder is typically named lang or languages.
The best tool to create .po and .pot files for a WordPress plugin is the Poedit translation editor, a free program available in Windows, Linux, and Mac.
This translation editor automatically finds the translatable string in your plugin code and provides you an interface to create and modify the translations.
How to use Poedit with a WordPress plugin
Let’s see how to use Poedit to translate the strings of your WordPress plugin.
Create a localized translation file with Poedit
This section describes the steps to create a translation file with Poedit.
Download and install the Poedit translation editor from the official website.
Create a new translation by selecting New… in the File menu of the application.
Select the language of the translation and then save your new and empty .po file with a name that follows this structure:
[slug]-[languge-code]_[locale-code].po
Below you can find the resulting translation file name of a plugin with the example-plugin
slug, Italian as a language, and Italy as a geographic target.
example-plugin-it_IT.po
Now we have to add general information to the translation and also configure Poedit so that it will be able to extract the translatable strings from the plugin.
Open the Properties… menu of the Catalog submenu. In this tab, assign a name to the project, then define the language and the charset in the Translation Properties tab.
In the Source paths tab, use the Paths section to set the path where Poedit should search the translatable strings.
In the Excluded paths section, define the folders where you don’t want to search for translatable strings. For example, you can include folders with PHP libraries.
Add in the Source keywords section the WordPress translation function (covered in the translation functions section) used in the plugin.
Click the Ok button to complete the configuration of the project and start the parsing process by clicking the Update from code button.
If the project has been properly configured, a list of strings with the related translations is displayed. Now you have to click on a specific string and enter its translation.
Translate the JavaScript files of a WordPress plugin
It’s possible with WordPress 5.0 and later versions to translate the strings available in the JavaScript files of the plugin. More precisely, you can use translation functions with the same names and behavior as their PHP counterparts.
To make specific translations function available, import them from the wp.i18n
object:
//Dependencies const {__} = wp.i18n;
You can use the JavaScript translation functions in any context of your JavaScript file. For instance, here __()
is used to define the value of a constant.
const title = __('My title', 'example-plugin');
How to store the translation of the strings
For plugins distributed in WordPress.org the translatable strings defined in a JavaScript file are automatically added by WordPress in the translatable string of the Translating WordPress interface.
Instead, if the plugin is distributed outside WordPress.org, you have to manually generate a JED file with the translation and define its location with the wp_set_script_translations() function.
Note that a JED file should be created based on an existing .po file with tools like GlotPress or po2json.
In the case of po2json you can install the tool with npm:
npm install po2json
And then use this command to generate a JED file:
po2json example-plugin-it_IT.po example-plugin-it_IT.json -f jed