Internationalization (i18n) for WordPress Plugins: A Complete Guide

A comprehensive guide to preparing your WordPress plugin for translation, covering PHP string functions, JavaScript i18n, and the WordPress translation pipeline.

If you’re building a WordPress plugin for the public repository, internationalization — commonly called i18n — is not optional. WordPress is used in over 200 countries, and over 50% of installations are in languages other than English. A plugin that isn’t translation-ready excludes more than half its potential audience.

Fortunately, WordPress provides a comprehensive i18n system that makes preparing your plugin for translation straightforward. This guide covers everything you need to know, from the basic PHP functions to JavaScript i18n to the GlotPress translation workflow.

The Basics: __() and _e()

At the core of WordPress i18n are two functions that mark strings for translation. The __() function returns the translated string, while _e() echoes it directly. Both take two parameters: the string to translate and the text domain — a unique identifier for your plugin’s translations.

Every string that appears in your plugin’s user interface should be wrapped in one of these functions. This includes button text, labels, error messages, admin page titles, and settings descriptions. If a user can see it, it should be translatable.

The Text Domain: Your Plugin’s Translation Key

The text domain is a unique slug that identifies your plugin in the translation system. It should match your plugin’s slug in the WordPress.org directory. You declare it in the plugin header and load it with the load_plugin_textdomain() function, typically in a hook attached to plugins_loaded.

If you change your text domain after plugins have been translated, all existing translations break. Choose your text domain carefully and never change it.

Plurals and Context

English has simple plural rules, but many languages have complex plural forms. Use _n() for strings that need singular/plural handling. It takes four parameters: the singular form, the plural form, the number to determine which form to use, and the text domain.

For strings that need additional context — like “post” in the editorial sense versus “post” as in mail — use _x() and _ex(). These functions add a context parameter that helps translators understand the correct meaning.

Variables in Translated Strings

Never concatenate translated strings with variables. The order of words changes between languages, and hardcoded variables break translations. Use sprintf() with placeholder syntax to insert variables into translated strings.

Use %s for strings, %d for integers, and %f for floats. Add numbered placeholders like %1$s when you need to reference the same variable multiple times or change the order of variables in a translation.

JavaScript i18n with wp.i18n

For JavaScript code in your plugin — particularly custom Gutenberg blocks and admin interfaces — use the wp.i18n package provided by WordPress. It provides __(), _n(), _x(), and sprintf() equivalents that work client-side.

To use wp.i18n, enqueue the wp-i18n script as a dependency for your JavaScript file. Then use the functions directly in your code. The WordPress build process extracts strings from your JavaScript files and generates translation files automatically.

Generating POT Files

The POT (Portable Object Template) file is the master template that translators use to create translations for specific languages. It contains all the translatable strings from your plugin. Generate it using a tool like WP-CLI’s i18n command or a plugin like Loco Translate.

Run wp i18n make-pot . languages/my-plugin.pot from your plugin directory. This scans your PHP and JavaScript files, extracts all translatable strings, and generates the POT file. Include this file in your plugin’s languages directory.

WordPress.org Translation Platform

When your plugin is on WordPress.org, translators can contribute translations through translate.wordpress.org. The platform automatically detects your plugin’s POT file and makes it available for translation. Community translators can submit translations for their language, and users automatically receive translations for their locale.

To get the most out of this platform, keep your POT file up to date with each release. Add clear comments to your i18n functions to help translators understand context. Review submitted translations before they go live.

The Bottom Line

Internationalization is not difficult, but it requires discipline. Wrap every user-facing string in __() or _e(). Use sprintf() for variables. Generate your POT file with each release. Keep your text domain consistent. These practices open your plugin to a global audience and are required for the WordPress.org directory.

Leave a Reply

Your email address will not be published. Required fields are marked *