If you’re a thorough plugin developer you’re internationalizing (i18n) all your strings. WordPress includes several functions that allow the programmer to easily make his plugin usable natively worldwide:
In some older plugins you may find the function
_c() which is deprecated and replaced by
_x() since version 2.9. If you’re not familiar with i18n of your plugin you should take a look at the Codex.
All these functions translate a string to the language defined in
wp-config.php. So what’s the difference between them?
__() and _e() are the simplest functions: they return or echo the translated string. Their usage should be obvious: one string, one translation.
Not so obvious is the function of _x(). Suggest you have two strings in two different contexts in your plugin which are totally the same in your language. Are you sure they are also the same in the remaining 3000+ languages spoken on earth? Even Sebastian Heine is unlikely to know it so you shouldn’t be sure neither.
Fortunately the creators of WordPress have a solution in their bag: _x().This function contains an additional parameter:
string _x (string $text, string $context, [string $domain = 'default'])
By using the parameter
$context you can differentiate identical strings in different contexts. Simple, eh? The remaining problem is to define two different string in the
.po file. That’s not too difficult neither:
msgctxt "test1" msgid "testing" msgstr "context1" msgctxt "test2" msgid "testing" msgstr "context2"
The magic token ist
msgctxt which you might translate to “message context”. The code
echo 'Context: test1 -> ' . _x('testing', 'test1', 'test'); echo '<br>Context: test2 -> ' . _x('testing', 'test2', 'test');
would create the output
Context: test1 -> context1 Context: test2 -> context2
The remaining function
_ex is a combination of
_x: it echoes a translated string using a context.
If you’re using a visual editor for your
.pot files you should be aware that not every editor is capable of handling context definitions and might destroy your data.
Last but not least
_n() for retrieving the plural or single form based on the amount.
_n( $single, $plural, $number, $domain = 'default' )
If the domain is not set in the
$l10n list, then a comparison will be made and either
$single parameters returned. The function returned via the filter
ngettext and about this you can filter the returned strings.
Update (10 JUN 2011): The above explanation of
_n() seems to have confused some people. Maybe a few examples will clarify the usage of the function.
A simple example of
_n() would be:
$domain = 'test'; $comment_count = 1; echo _n('comment', 'comments', $comment_count, $domain) . '<br/>'; $comment_count = 2; echo _n('comment', 'comments', $comment_count, $domain);
the corresponding German (de_DE) language file entries are:
msgid "comment" msgid_plural "comments" msgstr "Kommentar" msgstr "Kommentare"
and the output:
which are the correct singular and plural translations.
If you’re planning to output the value of the numbers you have to use
sprintf(). Here’s an example:
$approved = 1; echo sprintf( _n( '%s comment approved', '%s comments approved', $approved, 'test' ), $approved); echo '<br/>'; $approved = 2; echo sprintf( _n( '%s comment approved', '%s comments approved', $approved, 'test' ), $approved );
The code might look a bit confusing so let’s rewrite it:
$approved = 1; $text = _n( '%s comment approved', '%s comments approved', $approved, 'test' ); echo sprintf($text, $approved); echo '<br/>'; $approved = 2; $text = _n( '%s comment approved', '%s comments approved', $approved, 'test' ); echo sprintf($text, $approved);
First a correctly translated singular or plural string is stored in
$text. Then this string is evaluated by
sprintf() which replaces the specifier “%s” with the value of
Using the following language file definitions
msgid "%s comment approved" msgid_plural "%s comments approved" msgstr "%s Kommentar genehmigt" msgstr "%s Kommentare genehmigt"
the output is
1 Kommentar genehmigt 2 Kommentare genehmigt
Of course there’s also a combination of
function _nx($single, $plural, $number, $context, $domain = 'default')
6 responses to “What’s the difference between __(), _e(), _x(), and _ex()?”
Still lost on the latter.
” .should be aware that not every editor is capable of handling context definitions and might destroy your data.” ..anyone know which are the Darth Vadors and which are Luke Skywalkers??!!..
I was interested in discovering the differences but this is still too technical ..like Frosty the last part without an example leaves me lost
Anyone seeing these functions for the first time should be aware that they aren’t the ONLY functions in this set:
_nx() – plural with context
esc_attr__() – return translated string escaped to be an attribute
esc_html__() – return translated string escaped to be HTML
esc_attr_e() – echo translated string escaped to be an attribute
esc_html_e() – echo translated string escaped to be HTML
esc_attr_x() – return translated string with context escaped to be an attribute
esc_html_x() – return translated string with context escaped to be HTML
The functions _n_noop(), _nx_noop(), and translate_nooped_plural() can also be used for dealing with translations.
For an explanation on the differences between functions, I find this article way too technical. Also the examples are anything but understandable and no, I am not a layman in this aspect. All my themes are localized with the proper calls, but the way you have described it, I find it impossible to understand, especially for something that I normally do without too many problems!
A far better explanation, tutorial including real examples, I find on WPML (http://wpml.org/2009/05/wordpress-theme-localization/)
You are right that this article is quite technical and it was written so intentionally. The mentioned article on wpml.org only describes the basics of localising a theme using __() and _e() but does not mention the other functions at all. The emphasis on this article is on _x() and _n() which are a bit more complex and the examples may not be too apparent at first view.
@Latz you are correct, the article over at wpml.org doesn’t mention the other calls. I still think however that such a technical article could benefit from some real world coding examples, but that’s just MHO…