Translating Plugins

Continuing discussion from Translate your plugin into Russian:

Hi @norske, would you mind sharing a bit about the tools you use here?

  • How to create and update the .pot file for a plugin
  • Your preferred solution for translating this into .po and .mo files
  • Whether there is anything else that needs to be done in order to get the translations to show up in the admin interface
  • Anything else?

Hi @james!

I’ll try to give a detailed answer (maybe someone could use it as a kinda draft for a tutorial).

I assume that:

  • plugin source files are properly localized, translatable strings are wrapped with _(), e(), esc_html() or esc_html_e().
  • plugin uses a single text-domain (see notes in the Issues section).

How to create and update the .pot file for a plugin

There are two typical ways to generate a .pot file from the source code.

  • Paid and lazy is Poedit PRO, which has a special option “Translate Wordpress theme or plug-in”. It parses the code files and extracts localized strings (GNU gettext, twig templates) into a .pot automatically. Any version of the Poedit (even free) (re)creates .po and .mo files when saving a translation and can update strings from the source/pot files.

  • Free and flexible is making a .pot file directly from the command line which requires WP-CLI or gettext utilities (see below). Typically I switch to a plugin folder and run:
    wp i18n make-pot . languages/text-domain.pot --domain="text-domain".
    This looks for localized strings in a current directory and its subdirectories, checks if they belong to the common text domain and puts them into a valid .pot file in languages directory. Assuming text-domain is a proper value of the “Text Domain” in a plugin meta and is used in all localized strings. The make-pot utility is documented here. It also extracts some plugin meta (author, version, link, description etc.) and includes into translation files. Those strings can be translated, too. They are shown in plugins list etc.

The simplest way to update the .pot file is usually to recreate it. This guarantees that there are no lost or outdated strings from previous builds.

I’ve used Poedior Pro version some time ago for that, but now I opt out in favor of Free version + command line tools.

Preferred solution for translating into .po and .mo files

This depends on a project type and environment.

  • GlotPress native interface is used for projects hosted on and similar.

    This is probably the best tool ever for collaborative translation within WP ecosystem. It’s deeply integrated with plugin/theme directories (which allows authors to request translations for meta data - readme files etc.), supports user roles and many other things. And all the updates are delivered to the end users automatically through the WP upgrade system.

    I haven’t configured Glotpress serverside yet myself, but if I understand it right, Glotpress manages the local packages and rebuilds .po and .mo when a certain % of strings gets translated (approved). This triggers the update system, all users get a notification “New translation for %plugin_name% is available” in their dashboards.

    But there is also the reverse side of the coin. All strings should be approved by PTE (Project Translation Editor) or global editors. And if your project has no editor for your locale, all translated strings can hang in “Waiting” status for years.

    The good news is that anyone can request PTE status for a certain project. Personally, I’m now building relations with local WP Team and its Locale Manager. Which means I ask for PTE rights in Slack and (probably) get it in some days. This allows to approve strings and release translations immediately (if > 95% of strings are ready). BTW, I openly declare that I’m a member of ClassicPress community and this doesn’t make any harm.

  • Poedit

    The most well-known tool and my favorite. I use Free version now, but it covers almost all my needs.


    • Automatically (re)builds .po and .mo on save
    • Highlights links, expressions.
    • Has a simple build-in validator, which often helps avoid loosing expressions, whitespaces and punctuation marks at the beginning/end of lines.
    • Allows to update the list of strings form .pot files (even in free version)
    • Supports comments (/* translators: … */) and suggestions.

    To my mind this is the most suitable tool for a non-techie translator, who works with autonomous files. It’s simple and handy. Pro version allows to do the whole job with no technical knowledge at all.

  • Poedit-alike alternatives (GUI)

    Plenty of them. Probably the most similar free analog for Win is Virtaal. It’s a bit less functional, but quite simple and free. *nix have their own tools. I’ve tried gTranslator for Windows, but it crashed when loading huge .pots several times and I deleted it. Anyway, all those tools are very similar and to be honest I don’t see any meaningful difference. They all can do the job.

    An interesting alternative is Unlike others, this tool is a web-based online service. It’s very similar to poedit-alike tools but also implements some advantages of Glotpress (collaboration, user roles). I’ve tested it on a free plan for several hours and it seemed nice. Free version has a limit of 1000 strings. (But they also offer a free plan for open source projects by direct request). I still prefer Poedit for local projects because local sowtware is a bit faster in use (less clicks/ajax loads).

  • Hardcore :slight_smile:

    Certainly, any .pot can be also translated using pure notepad or other text editor (technically .pot is a structured plaintext file and .po is just its advanced copy). But this is not really useful, when there are hundreds of strings to translate.

Updating .po and .mo

This is a built-in feature for almost any GUI tool (Poedit, Virtaal and others). They all have an option kinda “Update strings from .pot/template”, which merges existing .po file with a new .pot. And .mo files are regenerated on save.

But for techies there is a “hardcore” method to do this from the command line. It requires gettext tools (here are compiled versions for Windows).

To merge existing .po file with a new .pot:
$ msgmerge my-existing-locale.po new.pot

and then to produce a relevant .mo file:
$ msgfmt my-existing-locale.po

(Full docs are here)

What needs to be done in order to get the translations to show up in the admin interface

  • If a plugin/theme uses, all translations are loaded automatically after being approved. To get an update user has to go to the Dashboard and click “Update translations” there. (Assuming his site uses a relevant locale).

  • If a plugin/theme is installed manually, localized files (.po and .mo) should be placed under wp-content/languages/plugins/ (or .../themes/).
    Filename format: {text-domain}-{locale}.{ext}, where {locale} is kinda ‘ru_RU’ and {ext} is po or mo. E.g. russian localization files for text-domain ‘classicpress’ would be classicpress-ru_RU.po and

Typical issues and difficulties
(to help developers to improve the localization of their products).

  • Inconsistent strings in similar parts of the plugin.
  • Insufficient space. English strings are usually shorter than their translations. This is sometimes critical when translating UI elements.
  • Partial localization. Top losties are value attributes for buttons and inputs, labels. The worst (and common) situation is when localized parts (hints, descriptions etc.) mention names of UI elements which are not yet localized. Or vice versa. This is a potential threat. E.g. you have a readable button “Do it!” but a related warning “This button will delete all your data” is in another language and unreadable for users :slight_smile:
  • One-word strings for different types of speech. E.g. when “Post” is both verb and noun. In English both strings have exactly the same spelling, but in Russian (and other languages as well) they should be translated separately (2 different words: “Запись” и “Опубликовать”). But since the English string is also the unique id (msgid) in the .pot file, there is no way to translate both cases separately. All occurrences are merged into a single line.
  • Multiple text domains in a single plugin. WP automatitially loads only one text-domain per plugin. But developers often create a “branded” menu page which unites several products. This page doesn’t belong to a certain plugin and devs sometimes use a different text domain for it. In this case English version looks ok and our tools even successfully include all strings into a .pot file. But WP doesn’t load the second text-domain by default. This leads to a ‘language mix’ when ‘brand’ pages (or some parts of the output) are still shown in English (even when all strings are actually translated!). To fix it, plugin should probably make a separate .pot (e.g. my-brand-text-domain.pot), then build separate translation files (e.g. and for each supported locale and then place them under wp-content/languages/plugins/ or use load_text_domain() functions. I didn’t tested any fixes yet, but logically it should work.
  • Hardcoded local links. E.g. “” instead of “”.
  • Javascript / ajax data. This is a real problem, because .pot files are used to localize PHP/html files only. But a huge part of content is dynamic now (messages, notification, elem lists). Some strings are often hardcoded into JS. However, WP 5.0 introduced JavaScript i18n support (similar way: wp i18 make-json ...). I haven’t used this yet.

Translator’s guides and tools

By the way, talking about Russian language in particular, I recommend using Yandex.Translate. Being the native russian search engine and one of the most famous russian IT-companies, they have very strong algorythms for this language. Yandex translates is much more accurate in EN->RU direction than Google. I guess, there are similar native translation services for other worldwide languages.


If that isn’t a tutorial, I don’t know what is! That’s a fantastic reference!


I’m not a native speaker and I’m writing all this half-asleep :slight_smile: This text obviously needs a deep correction and simplification to become a tutorial. But your post inspires me greatly, thank you!


I’ve used this plugin which now says it’s not available for download. You can still get it from the SVN link.
It does it all, without need for Poedit or those other tools.

You can test with the plugin to make sure you didn’t miss using translation functions on any strings.

And the functions for localizing scripts works great for any strings needed for javascript, without having to use the new JS i18n stuff, which is harder to test and just more unneeded code.

1 Like

Excellent info @norske, thank you :slight_smile:

The _x() function (and friends) solve this problem by accepting a context argument which is then used as part of the unique ID.

This wasn’t mentioned specifically but the correct way to handle this is to translate the links too, whenever you expect that a destination page might be translated into different languages. Arguably links to could be translated too, because this is something we’ll need to do one day…

This extra step is unfortunate…

and this is something we’ll need to handle one way or another in our directory also.


I recently did series on translating plugins using POEdit and GlotPress.


You did, and I’ve got it bookmarked. Another very good source of info. :+1:

1 Like