How To Internationalize TinyMCE Plugins in WordPress Plugins

To internationalize a TinyMCE button/plugin within a WordPress plugin, you have to interface with the TinyMCE API as well as the normal methods for i18n in WordPress. I didn’t find much help in figuring it out, so I decided to document my findings.

For the purposes of this tutorial, we are working with my Better Click To Tweet WordPress Plugin, which adds a button to the visual editor for users to add a Tweetable Quote to their posts.

Swap out hard-coded strings in the .js file

In the original js file, I have 5 strings that are in need of being translated. Let’s look at the first one: the ToolTip (line 8 of the file). Instead of hard-coding ‘Better Click To Tweet Shortcode Generator’ as in the original js file, I need to substitute

editor.getLang( 'bctt.toolTip', 'Better Click To Tweet Shortcode Generator' ),

Which tells the machine “Find ‘bctt.toolTip’ within the list of translatable strings loaded in TinyMCE, and echo that here.”

The optional (included) second parameter in the getLang() function gives a default text to fall back to, in this case “if you can’t find anything, echo ‘Better Click To Tweet Shortcode Generator'”

Repeat that process for all translatable strings in the .js file, giving them unique names.

Put the translatable strings into the php

Now we’ve told it to translate them within the js file, but there are two problems we need to solve:

  1. Put the translatable strings in the php somewhere, so that our .po and .mo files can get to them to translate them.
  2. Add the translatable strings to TinyMCE.

To solve problem one, create a file to store the strings in. In our case, I made a file named bctt-mce-locale.php.

Here’s the content of that file:

$strings =
		"' . $mce_locale .'.bctt", 
			toolTip : "' . esc_js( _x( 'Better Click To Tweet Shortcode Generator', 'Text that shows on mouseover for visual editor button', 'better-click-to-tweet' ) ) . '",
			windowTitle : "' . esc_js( _x( 'Better Click To Tweet Shortcode Generator', 'Text for title of the popup box when creating tweetable quote in the visual editor', 'better-click-to-tweet' ) ) . '",
			tweetableQuote : "' . esc_js( _x( 'Tweetable Quote', 'Text for label on input box on popup box in visual editor', 'better-click-to-tweet' ) ) . '",
			viaExplainer : "' . esc_js( _x( 'Add \"via @YourTwitterName\" to this tweet', 'Text explaining the checkbox on the visual editor', 'better-click-to-tweet' ) ) . '",
			viaPrompt : "' . esc_js( _x( 'Include "via"?', 'Checkbox label in visual editor', 'better-click-to-tweet' ) ) . '",

This file is using the tinyMCE function addI18n() and making an associative array containing the translatable strings. The _x() allows me to add an explanation as the second parameter, to give translators some context for where this text appears in the plugin.

Each new .mo/.po file included in the main plugin’s language folder adds a new mce locale thanks to the $mce_locale variable in the third line.

Load the strings into TinyMCE

Now we are almost there. Our strings can be translated by .po and .mo files, but they are still not being added as external languages to TinyMCE. Luckily, there’s a filter for that.

In the same file that registers the TinyMCE plugin, we need to hook into the filter at mce_external_languages with a function that returns the location of our new file. That looks like this:

public function tinymce_loader() {
add_filter( 'mce_external_languages', array( __class__, 'bctt_tinymce_languages' ) );

public static function bctt_tinymce_languages( $bctt_locales) {
    	$bctt_locales[ 'bctt' ] = plugin_dir_path( __FILE__ ) . '/languages/bctt-mce-locale.php';
  		return $bctt_locales;

That’s it! Make sure that the path to the newly created file is correct, and you are good to go!

I have disabled comments, but if you have comments or questions, the contact form below will get to me. Thanks!