What makes Wordpress.org make an internationalization of a plugin approved?

I've created my first plugin and here's the main code:


I am using a constant for the text domain:

class mastercurrencywp {
    const plugin_textdomain = 'mcwpww';

And later in the same class I use it like this:

$curr_desc['EUR'] = __('Euro', self::plugin_textdomain);

I've tested this locally and then internationalization of the plugin worked, I've also added a Swedish translation (that works on my local server) but wordpress.org states:

This plugin is not properly prepared 
  for localization. If you would like to 
  translate this plugin, please contact the author.

( https://translate.wordpress.org/projects/wp-plugins/mastercurrency-wp )

Why? (What is missing?)

I've just updated the plugin, so it might take some time before wordpress.org updates it statement?

  • 1
    self::plugin_textdomain is readable for a PHP parser only, not for the translation tool. Use a string. And the error messages aren't translated at all.
    – fuxia
    Mar 19, 2016 at 7:58
  • But the translation does work? With the translation tool you mean wordpress.org's translation tool? The error messages .. yes thanks I did miss those. Mar 19, 2016 at 8:05
  • @toscho - I've updated, but it still get the same statement from wordpress.org Mar 19, 2016 at 8:39
  • 1
    I think I've understand the actual issue now! I don't understand how I could miss this: "Do not use variable names for the text domain portion of a gettext function. Do not do this as a shortcut: __( ‘Translate me.’ , $text_domain );". Mar 19, 2016 at 8:50
  • @toscho - sorry. Somehow I managed to misunderstand your answer. Please put that as an answer and I will accept. Mar 19, 2016 at 9:34

1 Answer 1


The value of a constant or variable can be evaluated by a PHP parser only. The tool that is used to extract the translatable strings is written in PHP, but is just a string parser. It doesn't run your code, because that would be too slow and error prone.

Here is an example for how complex that could be:

interface FooTranslate
    const TEXT_DOMAIN = 'foo';
interface BarTranslate extends FooTranslate {}

class FooBar implements BarTranslate
    public function greeting()
        _e( 'hello!', self::TEXT_DOMAIN );

(new FooBar)->greeting();

Now find the correct string value for the text domain without executing PHP. Difficult.

You have to use a simple string for all calls to the translation functions.

The developer handbook is telling us that very clearly, unfortunately in the style of an error message and with wrong quotation marks:

Do not use variable names for the text domain portion of a gettext function. Do not do this as a shortcut: __( ‘Translate me.’ , $text_domain );

On a second note: Please do not load your translation files on init. This is expensive: These files are now loaded on every call to AJAX requests, comment submissions and every other file that might not even be related to your plugin. Check the current request context before you are asking WordPress to include a file.

  • Thanks a lot! There were actually one more issue. The textdomain should be the slug of the plugin. It didn't work to place the name of the file (mastercurrency.php) as the documentation stated (developer.wordpress.org/plugins/internationalization/… ). I had to change the textdomain to mastercurrency-wp for the translation tool to work. Mar 19, 2016 at 23:18
  • I've read around and seeing lot of sites that says I should load translation files on init.Here's an example: geertdedeckere.be/article/… . Here's another one:ulrich.pogson.ch/load-theme-plugin-translations Are they they incorrect? Mar 19, 2016 at 23:20
  • Yes, if they are recommending to load those files without respect to the request context, they are wrong.
    – fuxia
    Mar 20, 2016 at 8:41
  • Should I use a hook at or just load it at construct() ? Mar 20, 2016 at 10:17
  • Always wait for the proper hook. You can invoke a constructor on a hook too, so this not really mutually exclusive choice.
    – fuxia
    Mar 20, 2016 at 11:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.