So I've found absolutely nothing about this subject online.

What I've done: I successfully programmed a custom admin menu in english for my wordpress backend, according to https://webkul.com/blog/how-to-add-menu-in-wordpress-admin-panel/, so that's all good.

What I need: If I change the language of the backend (via the user settings in the wordpress backend), every admin menu gets translated to the new (selected) language, except from my custom admin menu, which of course still appears in English. My question is: How / Where do I need to store custom admin menus in other languages, such that they also get their language changed according to the language selected for the backend ??

Update: Ok meanwhile I developed a plugin as it should be done, and learned all the stuff about .pot, .po and .mo files. The only thing missing now is that the internationalization only works if I put the .mo and the .po files into the root wp_content/languages/plugins directory, although I used:

if ( ! class_exists( 'MyPlugin' ) ) {

  // Used class for plugin configuration to avoid naming collision
  class MyPlugin {

    // Used hooking functions on class constructor
    public function __construct() {

      // Hook Admin Menu Creation callback onto admin_menu action hook
      add_action( 'admin_menu', array( $this, 'create_admin_menus' ) );

      // Load Plugins Text Domain
        array( $this, 'my_plugin_load_plugin_textdomain' )

    } // end of constructor function

    // Define corresponding callback functions

    public function create_admin_menus() {
      // Admin Menu code, which worked successfully

    } // end of create_admin_menus callback definition

    public function my_plugin_load_plugin_textdomain() {

    } // end of my_plugin_load_plugin_textdomain function definition

  } // end of class MyPlugin definition

} // end of check if MyPlugin class exists

// Initiate class object
new MyPlugin;

What am I missing out here? Is thiy may due to the polylang plugin (the only one I use atm..). I double-checked all the text domains etc. they're all good, and the specified path should also be good, so how I can I make sure that the internationalization of the MyPlugin works with the .mo files inside the wp-content/plugins/my-plugin/languages/ directory, and not in the wp-content/languages/plugins/ directory?

What happens currently is that the localized strings appear in English (so translations not found), but are successfully and perfectly translated when I copy the same .po and .mo files into the wp-content/languages/plugins/ directory.

P.S.: Thanks a lot Tom for your hints already, was completely worth it learning the stuff you've told me!

  • 1
    Do you know about the __ family of functions?
    – Tom J Nowell
    Apr 5, 2020 at 22:39
  • Nope, don't really get what you mean? Sth to do with this developer.wordpress.org/reference/functions/__ ?? Still, could you may explain how to do it? Thanks in advance for your help!
    – Joe
    Apr 5, 2020 at 22:43
  • Actually, when I programmed the custom admin menu in English, I defined its page content via a php page, all in English. Guess it would be the easiest to be able to simply call another php page (same functions etc. but other language) in function of the currently selected backend language. There's no solution like this? Something like creating a page template in wordpress for each language; you get what I mean?
    – Joe
    Apr 5, 2020 at 22:47

1 Answer 1


You need to use the internationalisation APIs, these let you swap out hardcoded strings for localised versions, e.g.

<p>Hello world</p>


<p><?php _e( 'Hello world', 'joes_plugin' ); ?></p>

Then, you can use .po/.mo/.pot files to provide alternatives, e.g. a file with french translations, a file with russian etc.

You'll need to declare your translation text domain in your theme/plugin ( joes_plugin in the example above ), as well as the domain path so WP knows the folder to look in for translation files. You'll also need to call load_plugin_textdomain on the plugins_loaded hook

Here's the handbook for the Internationalisation API:


And the page for plugins:


And for generating the localisation files themselves:


Each of these is a huge subject in of themselves, so I recommend asking multiple new follow up questions about specific parts

Note that this API cannot be used to translate things in the database, and you should never pass dynamic variables into these APIs. For multilingual frontends, you will need a plugin

  • Thanks a lot for this Tom, really! Still one question; I figured out a way to do it meanwhile; and wonder if you'd still recommend your solution and / or see any drawbacks in my way of doing it: 1) I created one php - file, containing all the translations in associative arrays. 2) I created one php page, linked to the corresponding custom admin page, to get the content for that custom admin page. 3) When loading that custom admin page, I access the currently into the backend logged user, then his language, and load the page content in function of it. May I ask about your opinion?
    – Joe
    Apr 6, 2020 at 15:14
  • I would not do that, it means that your plugin won't pass the .org plugin review if you ever tried to share it. It also means that multilingual plugins would be incompatible with your code, and, it means if you ever have to change markup then you'd be modifying every single file manually. Just use a single PHP file than use the official string translation API
    – Tom J Nowell
    Apr 6, 2020 at 15:39
  • And that single PHP file has to be inside a custom plugin which I would need to create on my own, true? I'm not at all experienced with that; so when I develop a plugin, there's no way that it gets publicly available right? Just to make sure that I can try some stuff without needing to worry about that...
    – Joe
    Apr 6, 2020 at 16:09
  • Actually, my only fear is the following: For my admin menu, I will need to update the translations available in the PO MO files continuously. Before I start over with your strategy (my online research was not successful for this concern); is there a way to update PO / MO files programmatically? Because, if I can choose in between writing into an associative array via PHP, or updating a POT file, converting that one to PO, and that one to MO, etc..... You see what I mean?
    – Joe
    Apr 6, 2020 at 19:18
  • You have to update the translations regardless of wether they're in those files, or in PHP files, and using an associative array eliminates all the tooling surrounding po/mo files, as well as all the APIs and integrations. Use the official APIs.
    – Tom J Nowell
    Apr 6, 2020 at 19:21

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.