In this section, we internationalize the plugin GCMovie to make it can be translated into other languages.
The theory of internationalization is not complex. To use a translated string, WordPress provides a set of special functions (the gettext libraries). Therefore we should use these functions to get strings rather than using the literal text directly when we want them to be translatable.
Because there are normally many plugins in a WordPress site, each one may provide one or several translation files for different languages, it needs a way to tell WordPress where to load the translation and how to distinguish them. That why text domain
and domain-path
come. They are two header fields (you’v seen some header fileds in the main plugin file) serverd for internationalization. WordPress use a text-domain
to denote all text belonging to your plugin and a domain path
to define the location for a plugin’s translation.
Now let’s add our internationalization.
Add header fields in main plugin file
Add text domain
and domain path
to our main plugin file gcmovie.php
, now it looks like:
<?php
/*
* Plugin Name: GCMovie
* Plugin URI: https://www.gloomycorner.com/gcmovie/
* Description: A plugin example with custom post type, shortcode, widget, etc.
* Author: Gloomic
* Version: 0.1
* Author URI: https://gloomycorner.com
* License: GPL2+
* Text Domain: gcmovie
* Domain Path: /languages
*/
text domain
The text domain need to be a unique identifier for WordPress to distinguish between all loaded translations. In format, it match the slug of the plugin. And the text domain name must use dashes instead of underscores, be lower case, and have no spaces.
domain path
Normally the translation is located in a folder named languages
within your plugin. It must be written with the first slash in the header field.
Use strings with gettext functions
There are kinds of gettext functions for different needs. __()
and _e() are two most used ones.
-
__()
, retrieve the translation of a text.__( $text, $domain );
Examples:
echo __( 'Search Movies', 'gcmovie' );
- _e(), display translated text. Its effect equals
echo __(...);
.
See How to internationalize your plugin for more usages of these functions.
Now replace string literals with such function in all your code. Below are dome code that enables translations:
add_meta_box(
'gcmovie_meta_box_information', // id
__( 'Information', 'gcmovie' ), // name
array( $this, 'display_meta_box_information' ), // display function
'gcmovie' // post type
);
Adding a text domain for every such a function can be burden if not done continuously when writing code. How to internationalize your plugin mentions a way to do it automatically. The method is downloading a tool add-textdomain.php (a php file) and run it to create a new file with the text domain added.
Create translation files
Now we can extract the strings that need translations from the code.
There are three kinds of translation files: POT (the template file) , PO (files with real translations) and MO (Compiled PO files).
- POT (Portable Object Template) This file contains the original strings (in English) in your plugin.
- PO (Portable Object) files Take the POT file and translate the
msgstr
sections into some language, it will become a PO file. - MO (Machine Object) files This a kind of machine-readable, binary files that are compiled from PO files.
There are several ways to generate a POT file, you can run a WP-CLI command or use a separate tool.
Generate the POT file
Here we use Poedit (a small GUI tool). Download and install it.
- Download a Blank POT file and put the
Blank-WordPress.pot
file to thelanguages
folder under our gcmovie plugin. Rename it asgcmovie.pot
, now we use it as the base of our own POT file. - Open Poedit > Open > Choose our
gcmovie.pot
file > Click “Update from the code” button in the tool bar > Save.
Now we can create a translation file of some language from the pot file. Copy the pot file and rename it as gcvmovie-{local}.po
. The locale is the language code and/or country code. such as de_DE for German, zh_CN for Chinese.
Below is a part of a Chinese translation filegcmovie-zh_CN.po
. In the file add our translated strings in the “msgstr” section of the string indicated by “msgid”. You may also use the “Pretranslation” feature supplied by Poedit ( pro version provides online translation) and then correct the result instead translate one by one.
#: gcmovie.php:137
#: gcmovie.php:221
#: inc/class-gcmovie-admin.php:32
msgid "Director"
msgstr "导演"
Compile PO file to MO file
Open Poedit > Open > Choose gcmovie-zh_CN.po
> Select “Compile to MO” from the file menu > Choose the default name.
In the langeuages folder there will be a gcmovie-zh_CN.mo
file.
Load text domain
We need to load the MO file when our plugin is loaded.
As loading text domain said, since WordPress 4.6 translations now take translate.wordpress.org as priority and so plugins that are translated via translate.wordpress.org do not necessary require
load_plugin_textdomain()
anymore.If you don’t want to add a
load_plugin_textdomain()
call to your plugin you have to set theRequires at least:
field in your readme.txt to 4.6.
Here we still show how to that with code (not the preferred way) by calling the load_plugin_textdomain()
( and load_muplugin_textdomain() if your plugin will be used as a must-use plugin). This call loads the corresponding mo according the site language settings from the plugin’s base directory.
Add below to the constructor of class GCMovie in gcmovie.php
add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
Implement load_textdomain()
method inside GCMovie
calss by calling load_plugin_textdomain()
:
function load_textdomain() {
load_plugin_textdomain( 'gcmovie', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
}
Resources
- WordPress plugin development: Internationalization
- How to Internationalize Your Plugin
- Internationalization Security
Gettext Functions
- How to internationalize your plugin
Basic functions
Translate & Escape functions
Strings that require translation and is used in attributes of html tags must be escaped.
Date and number functions #Date and number functions