How to Internationalize and Translate WordPress Themes and Plugins

Learn to translate WordPress themes and plugins and integrate these translations into your projects with ease.

Instead of explaining the theory behind WordPress internationalization (i18n) and localization (l10n), this guide uses a demo plugin to show you:

  • How to make a WordPress plugin translation-ready
  • How to translate the text strings and integrate these translations into your plugin

Each step of this tutorial is demonstrated with code changes. Check the demo plugin’s repository to review them via Git commits.

The Goal for Our Demo Plugin: Making it Multilingual

Our demo plugin, OTGS Foo Banner, displays a banner with a customizable message on the front-end.

Message displayed by the demo plugin on the front-end

Users with access to the site’s backend also see:

An admin page to manage message status and content

A confirmation pop-up That Appears After saving changes


Our goal is to make all strings translatable and add Spanish translations. This way, users who switch WordPress to Spanish can use the plugin in their language.

Step-by-Step Guide to WordPress Plugin Internationalization (i18n) and Localization (l10n)

1. Initialize Composer and Install WP-CLI as a Dev Dependency

If you’re not using Composer in your projects yet, initialize it by running composer init. Then, follow the command-line wizard.

Commit Reference: See commit 6f7a13f on GitHub

To run WP-CLI commands, install WP-CLI via Composer by running:

composer require --dev wp-cli/wp-cli-bundle

Commit Reference: See commit 7a8a68c in GitHub

2. Wrap All Texts in GetText Calls

Adding GetText Calls to PHP Code

In PHP, wrap all the hard-coded strings in gettext WordPress localization functions like __() and _e(). Specify a text domain to uniquely identify translations for your theme or plugin.

  • The __() function returns the strings
__('Hello, world!', 'your-text-domain');
  • The _e() function echoes a translatable string
_e('Hello, world!', 'your-text-domain');

These functions find the correct translation in the specified locale and domain. If no translation is available, the original string will remain unchanged.

Commit Reference: See commit cae0a31 in GitHub

Adding GetText Calls to JavaScript (JS) Code

Just like in PHP, make sure that all text in your JavaScript code can be translated into different languages.

WordPress provides the wp-i18n dependency to retrieve translations of text strings.

Specify a text domain for translations to be correctly matched and displayed based on the current language set in WordPress.

Commit Reference: See commit 7e73eaf in GitHub

3. Generate the Portable Object Template (POT) Files

To translate your code, you will need to generate POT files that include the original texts. You don’t need to create these files manually – below, you’ll find the WordPress commands you need to run to generate the POT files.

Here’s what the end result will look like:

An example of a POT file

While you can combine PHP and JavaScript strings into a single POT file, our demo maintains separate POT files.

Generating the POT File for PHP Strings

You need to run a Composer script that scans all the PHP files in your project, looks for GetText calls (which you previously added), and creates a .pot file that includes all the translatable strings in the project.

To do this:

  1. Add the Composer script make-php-pot to your project to avoid executing the full command manually each time you update the POT file.

Commit Reference: See commit 88a9323 in GitHub

  1. Run the make-pot command: composer make-php-pot

Commit Reference: See commit c9767f1 in GitHub

Generating the POT File for JS Strings

Next, run a script that scans the JS files for GetText function calls and generates a POT file with all the translatable strings it finds.

  1. Add the Composer script make-js-pot to create the JS POT file with the correct configuration.

Commit Reference: See commit e2da741 in GitHub

  1. Run the command: composer make-js-pot

Commit Reference: See commit 2c31ed3 in GitHub

If your project includes bundled JavaScript scripts (for example, via Webpack), use @wordpress/babel-plugin-makepot instead. 

4. Create the Translations

You need to provide specific files to GetText for it to return translations. Here’s a general overview of the process:

  1. First, translate the content of your .pot files and save each translation in a .po file (Portable Object file).
  2. Next, from the .po file, generate an .mo file (Machine Object file), which is the machine-readable version of the translations.
  3. Place the .mo files in the folder where GetText expects them to be, typically under a directory like /languages in your plugin’s repository.

You don’t have to complete the steps above manually. PTC (Private Translation Cloud) can do it for you in just a few clicks.

Using PTC to Create Translations

PTC (Private Translation Cloud) is a software translation tool that provides high-quality automatic translations for .po, .mo, and .json files.

With PTC, you get…

Instant, Better Than Human Translations

Integratation with your software repository and translations sent as merge requests

Unlimited translation rounds, enhanced by AI and machine learning

Continuous localization

To get started:

  1. Set up up your project in PTC and link it to your repository. PTC will automatically detect your resource files.
  2. Choose the target languages.
  3. Wait for PTC to generate AI-powered translations, delivered directly to your repository as a merge request.

The translation files will be stored in a specific folder in your plugin’s repository. In our example, the translation files are in the languages/php folder. 

PHP PO/MO File Commit Reference: See commit c1c17bf in GitHub

JS PO/MO File Commit Reference: See commit 7dc8463 in GitHub

5. Configure and Load Translation Files in WordPress

Lastly, configure WordPress to recognize and load the translation files for both PHP and JavaScript components of the plugin or theme.

Load the Plugin’s Text Domain for PHP Files

Tell WordPress where it can find the translation files for your PHP code. 

Commit Reference: See commit c36688c in GitHub


The PHP strings show as translated on the admin page. We left the “Foo Banner” string untranslated as it’s a brand.

Translated plugin strings on the admin page

Generate the JSON (JED) Translation File and Load Script Translations for JS Files

When translating JavaScript files in WordPress, you will use JED (JSON Extended Description) files. These JSON files are generated from MO files and contain the translations needed for your JavaScript scripts. 

For optimal performance, WordPress loads JS translations only for the scripts currently in use. Each JSON translation file ends with a hash representing the relative path to the corresponding JS script, in order to accurately map the translations.

To generate and load JED files:

  1. Add the Composer script make-js-json.

Commit Reference: See commit 5cc9548 on GitHub

  1. Run the command composer make-js-json to convert the MO file into a JSON file for JS scripts.

Commit Reference: See commit f172167 on GitHub

  1. Load the script translations for your JavaScript files by telling WordPress where to find the JSON translation files. In our example, we use a file named confirm.js.

Commit Reference: See commit 49b3069 in GitHub

In our demo plugin, the strings from the JS file in the confirmation pop-up now appear translated.

Translated confirmation pop-up

Make Your WordPress Projects Multilingual

By translating your WordPress themes and plugins, you can reach a broader, global audience. WordPress itself supports numerous languages, and your themes and plugins should too.

Take your WordPress projects global

Try PTC free for 30 days and experience fast, accurate translations for your WordPress plugins and themes.

Scroll to Top