Main menu

Help for authors

Making your bundle translatable with Loco

This page is intended for WordPress developers. The word bundle here refers to a theme or a plugin.

If you're having trouble translating a bundle then most likely it's either incompatible with Loco, or isn't set up for translation at all. We cannot provide personal help to translators experiencing this kind of issue, but we will work with developers to ensure their work is compatible with our plugin.

Why be compatible with Loco?

It's entirely up to you whether you want your theme or plugin to "just work" with Loco. You're under no obligation to implement any of the suggestions on this page. Most of these things are not required by WordPress for your bundle to work. They're just required by Loco Translate.

But consider that Loco Translate is installed on over a million websites. Many people out there want to translate themes and plugins into their own language, or simply customize the strings you've provided. Not all of these people are familiar with the technicalities of WordPress localization and the conventions of Gettext. Following a few simple rules will enable more people to translate your work.

How to be compatible with Loco?

If your bundle has a single text domain it's very easy to be compatible just by following a few WordPress conventions. Start by adding the following two declarations in your bundle's file header.

/*
...
Text Domain: my-domain
Domain Path: /languages/
*/

Additionally:

  • Provide a correctly named template file under the domain path, e.g. languages/my-domain.pot
  • Keep your PO/MO files together in the same directory. They should always be in pairs as <name>.po and <name>.mo.
  • Name PO files with valid locale codes and POT files only by their text domain. Avoid incorrect names like default.po and en_EN.po
  • Load MO files correctly at runtime using load_theme_textdomain or load_plugin_textdomain

That's about it. Loco will understand a single domain bundle if these things are in place.

Multiple text domains

The WordPress convention above can only express a single text domain, but Loco Translate is not limited this way. Through custom configuration Loco Translate can understand bundles with multiple text domains, and even split them across multiple files if required.

This kind of configuration cannot happen automatically because WordPress provides no mechanism to express it. Users of your bundle will have to manually configure Loco Translate to make sense of all your files. This can be a complex task. You will see many people on our support forum asking why they can't translate a theme or plugin they've just bought.

By placing a loco.xml file in the root of your bundle, Loco users won't have to do any configuration and Loco Translate will "just work" with your bundle. See the XML schema for more information, and our sample repository for examples of open source bundle configurations.

POT Templates

We urge authors to ship a POT file for every text domain. This is critical for translators.

Either name your template <text-domain>.pot or define an alternative in the loco.xml configuration. Place the POT file in the Domain Path folder, even if you're not shipping any actual translations.

Without a POT file Loco Translate will attempt to do string extraction directly from source code every time it needs to know what strings are translatable. Translators should not be concerned with string extraction at all. It is a development task and there are many nuances that cause it to go wrong. The only bullet proof way to declare your translatable strings is via a canonical template file.

Every time you ship a new version of your bundle, please ensure your POT files are up to date with the source code. We see a lot of published code with out-of-sync files. This confuses translators when they can't find the strings they want to translate, or strings they've translated don't show on their site.

See more on working with templates.

Source code

When it comes to extracting your source strings, you're not obliged to use Loco Translate in order that your files are compatible. Feel free to extract strings from your sources any way you see fit. Any valid POT will be compatible with our software.

If you've provided translators with a valid template then there's no reason for them to be concerned with how strings are used in your code. That said, we often see mistakes in source code that lead to translations not showing up. Here are a few common errors that are easily fixed:

  • Check translation functions always reference the text domain and it is spelled correctly.
  • Check translation functions aren't called too early. i.e. before translation files are actually loaded.
  • A string only has to be translated once to be extracted, but that doesn't mean every instance of it has been localized.
  • Check for accidental use of "context". e.g. _x("Foo","my-domain") and __("Foo","Bar","my-domain") are both errors.

JavaScript

If your bundle has localized JavaScript strings (and you want them to be editable via Loco Translate) please ensure you are using one of the following methods:

  1. Loading from JSON files via wp_set_script_translations.
  2. Loading from MO files and passing into JavaScript using wp_localize_script or equivalent.

Whichever method you use, ensure the strings required by JavaScript are available in your POT file. When using wp_set_script_translations the extracted file references in your POT must point to a valid JavaScript file. See JSON language packs for more detail.

Get more help

If you're a developer looking to make your work more compatible with our plugin, please talk to us in the support forum. We're keen to help bundle authors if it helps translators using our software, but we don't provide private consultancy on general coding problems.

If you're having problems translating somebody else's work, we cannot provide technical support unless their work is open source. Please contact commercial developers and direct them to this page. We will try to help them make their next release more compatible with Loco.

Last updated by