There are others, but this is most used: Poedit, a cross-platform gettext catalogs (.po files) editor.
.mo stands for Machine Object
-- compiled export of the .po file which is used by WordPress
.po stands for Portable Object
-- editable text file with the translations strings
-- based on the master .pot file, using Update from POT ...
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";
print("Welcome to my plugin");
/** Localization friendly */
_e('Welcome to my plugin', 'my-plugin');
$my_text = __('Welcome to my plugin', 'my-...
Here is how you can create a .pot file for your theme with Poedit (free edition, version 1.6.10) on OS X.
Best practise is to save language files in a folder named "languages" in your theme directory. If you haven't already, create it before you start.
In the "File" menu select "New"
Select the language that you used in your theme (probably ...
These are not any kind of WP's own format but rather just gettext file types which WP implements.
Translate Handbook has following definitions in its Glossary:
MO files: MO, or Machine Object is a binary data file that contains
object data referenced by a program. It is typically used to translate
program code, and may be loaded or imported into the ...
You can do this with the WordPress tools, without POEdit.
First, do an svn checkout of http://develop.svn.wordpress.org/trunk/:
svn co http://develop.svn.wordpress.org/trunk/ wpdev
Then, switch to the i18n tools directory in it:
Then just run the makepot.php over your theme's directory:
php makepot.php wp-theme /path/to/your/theme ...
I wouldn't try to localize your slugs. Instead, why not give your users the option to change them by adding another field to the permalink settings page?
Hook into load-options-permalink.php and set up some things to catch the $_POST data to save your slug. Also add a settings field to the page.
add_action( 'load-options-permalink.php', '...
You may try Eazy Po.
From file menu select “New from source code files..”.
In xgettext Command Manager window; Press “Browse folder” to select base source folder.
In Build pane press “Execute Command” button to generate Pot file.
When adding _x to the keywords, try it this way:
This tells the parser to watch out for _x and to take the first argument as msgid and the second argument as a comment, which will then be recognized as context by poEdit and inserted as msgctxt.
Oddly enough, my poEdit then shows me the msgid twice in the "new/old" messages window. However, in the ...
This is a very faceted issue. It combines inherent HTML content issues with whole new load of translation challenges, such as scanning for strings, translation process itself, and its verification.
So we have to combine:
Text (in translatable form)
HTML markup (in hard to break, but preferably flexible form)
URL destination (in secure and preferably ...
Never rely on core strings for translation, they may change or get a context parameter any time. Once that happens your users get a partially translated interface, and your translators have no way to fix that.
Also keep in mind the same string is not necessary translated everywhere with the same word. Even without a context parameter it might be useful to ...
Internationalization and localization (commonly abbreviated as i18n
and l10n respectively) are terms used to describe the effort to make
WordPress (and other such projects) available in languages other than
English, for people from different locales, who use different dialects
and local preferences.
__() is used when the message is passed as an ...
I'm trying to do a similiar thing, and the experts on the wp-hackers mailing list (Otto, Nacin) told me this:
Don't try to change WPLANG, you can't change a define'd constant.
Instead, change the global $locale, or put a filter on 'locale'.
So the best solution is to apply a filter on the 'locale' global variable. The only way to do that is by creating ...
__ (double underscore) is the base translate function. It translates a string and returns it as a string.
_e does the same as __, but echo's the result immediately.
_x is the contextual translate function. It has a second option to provide context to people doing the translation.
_ex is the same as _x, but echo's the result.
Example of using _x:
Use the fourth parameter for get_post_time():
$time = get_post_time(
'F j, Y', // format
TRUE, // GMT
get_the_ID(), // Post ID
TRUE // translate, use date_i18n()
get_post_time() calls mysql2date() internally, and it passes the $translate argument through. In mysql2date() we find this:
if ( $translate )
It's used for translate text.
The second argument is a kind of namespace (called domain here) to retrieve the translation (for example from a dedicated file or something else).
So Anyword here, should be the guy behind the template, or the company or what ever that can be a domain/namespace.
The doc from wordpress give more explanation on how to ...
(Here is an EXAMPLE of translation to DEUTSCH. CHANGE the customs to YOUR DESIRED ones.)
in every plugins head, there is an unique name.
Plugin Name: my-pluginname
then, in that plugin's folder, create a folder "languages";
then, into your plugin .php file (somewhere in the top), insert the initialization code:
In your theme, you enqueue the stylesheet usually like this:
add_action( 'wp_enqueue_scripts', 't5_enqueue_style' );
get_template_directory_uri() . '/css/default.min.css'
The extra RTL stylesheet is enqueued here too, listing the default as dependency:
Stylesheet Printing Order
WordPress does not load themes' alternative rtl.css files using wp_register_style() or wp_enqueue_style(). As such, the stylesheet does not get added to WordPress's style queue, and cannot be specified as a dependency when registering or enqueueing additional stylesheets.
Instead, this stylesheet's <link> element is added ...
Use the filter 'mce_external_languages'. From wp-includes/class-wp-editor.php:
The following filter loads external language files for TinyMCE plugins.
It takes an associative array 'plugin_name' => 'path', where path is the
include path to the file. The language file should follow the same format as
/tinymce/langs/wp-langs.php and should ...
This is not a problem if every string gets its own template for translation.
If you use the string You can include a %s in a childtheme. more than one time for different nouns it is not translatable.
An example, taken from a recent article: New %s is in German (yes, we have gendered nouns too) …
Neues Buch (for a book, neutral)
Neuer Film (for a movie, ...
If you're creating this theme or plugin for inclusion in the official plugin or theme directories on WordPress.org, then you need to use the plugin or theme's slug as the text-domain. You cannot have multiple text domains, and the text domain cannot be anything other than the slug of the plugin or theme.
This is due to the new language pack support coming ...
i18n resource ... the hide & seek game
Note up front: I'm not 100% sure about this, so please take the following with a grain of salt.
I'm 99% sure by now, that the following information is correct. (Still, it's confusing even after years with WordPress).
Non-Gettext translation for core
The 18n.wordpress.org resource is used by the Glotpress ...
__(), _e() and _x(), _ex()
__() and _e() are essentially both a wrapper of translate() (do not use directly) and almost the same.
The difference lies in that __() returns the translated string and _e() echoes it. Both need to be fed a string as a required parameter and usually, though optional, also a textdomain.
Analogously, there's _x() and _ex(), which ...
The second part is not required, it just loads a PHP file with language specific functions.
In some countries/regions/religions it is not allowed to use capital letters in a word for anything else than the name of some god. In these cases you probably want to remove the Wordpress to WordPress filter.
Some languages (Chinese) do not use spaces (in ...
For each translation file, WordPress has to unpack it, then each entry will be converted into an Translation_Entry object.
The short string "caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead. will need three times more memory when it is translated:
'"caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.' =>
No, it is not. Use esc_html__( 'string', 'text_domain' ) instead (two underscores).
Translated strings are unknown input. Unknown input is per default malicious.
You don’t know where the language file comes from. It doesn’t even have to be the one you provided, because the path can be filtered or changed with a symlink.
Even if it is your file: do you have ...
The issue is, there is no value for local_package in the URL.
At first I thought this might be a bug. Similar issues have been reported before (see here and here.
I then stumbled on comment in trac ticket 8729 where user nbachiyski explains how localization should work:
There are two ways to localize WordPress:
Drop some translation files.
These days I work with many multilanguages websites, and I have to say:
URLs of links often needs to be translatable.
Trust translation function output is bad. I pretty much never use __() but always esc_html__() / esc_attr__(). Which means that string to be translated can't contain HTML of any sort.
Writing in english we often don't realize that in other ...
You are loading the rtl.css using the WordPress automatic way, that is, having a rtl.css in the theme folder will be loaded by WordPress automatically if it presents and direction of current language ir rtl (you should add this information to the question, it has been difficult to figure it out how you are loading the file). This process defines ...