How to Customize Localized Theme Text Domains and Translations in Multi-Language Site Networks
Understanding WordPress Text Domains
In WordPress, internationalization (i18n) and localization (l10n) are crucial for creating themes and plugins that can be translated into multiple languages. The core mechanism for this is the “text domain.” A text domain is a unique string identifier used by WordPress to load the correct translation files (.po/.mo) for a specific theme or plugin. When you use translation functions like __('Text to translate', 'my-text-domain'), WordPress looks for a translation file associated with my-text-domain to find the translated string. For themes, this text domain is typically set in the style.css file’s header. For plugins, it’s defined in the main plugin file’s header.
Customizing Text Domains in Theme Development
When developing a custom theme, it’s best practice to use a unique text domain that reflects your theme’s slug. This prevents conflicts with WordPress core, other themes, and plugins. The text domain is declared in the theme’s style.css file.
Here’s an example of the header in a theme’s style.css file:
/* Theme Name: My Awesome Theme Theme URI: https://example.com/my-awesome-theme/ Author: Your Name Author URI: https://example.com/ Description: A custom theme with internationalization support. Version: 1.0.0 License: GNU General Public License v2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html Text Domain: my-awesome-theme Domain Path: /languages Tags: custom-background, custom-menu, featured-images, theme-options */
In this example, Text Domain: my-awesome-theme tells WordPress that all translatable strings within this theme will use my-awesome-theme as their identifier. The Domain Path: /languages directive specifies that translation files (e.g., my-awesome-theme-fr_FR.mo) will be located in a subdirectory named languages within the theme’s root directory.
Handling Translations in a Multi-Language Site Network (Multisite)
WordPress Multisite allows you to manage multiple sites from a single WordPress installation. When dealing with translations in a multisite environment, especially when using a theme that might be used across different sites with different language requirements, careful consideration of text domains and translation file management is necessary. The core WordPress translation system generally works as expected, but the organization and loading of translation files can become more complex.
Global vs. Site-Specific Translations
By default, WordPress loads translation files based on the site’s language setting. For themes and plugins, it checks specific directories. In a multisite setup, translation files can be managed in a few ways:
- Core WordPress Languages Directory:
wp-content/languages/. This is where WordPress itself stores core, theme, and plugin translations. It’s generally recommended to keep your custom theme/plugin translations here for global availability across all sites in the network. - Theme’s
languagesDirectory: As specified by theDomain Pathin the theme’s header (e.g.,wp-content/themes/my-awesome-theme/languages/). Translations placed here are specific to that theme. - Plugin’s
languagesDirectory: Similar to themes, plugins can have their ownlanguagesdirectory.
For a theme to be consistently translated across all sites in a network, placing its translation files in the wp-content/languages/themes/ directory is the most robust approach. WordPress will automatically look for files named [text-domain]-[locale].mo (e.g., my-awesome-theme-fr_FR.mo) in this location.
Generating Translation Files (.po and .mo)
To create translation files, you first need to extract translatable strings from your theme’s PHP files into a .pot (Portable Object Template) file. This file acts as a blueprint for translators. Tools like Poedit or command-line utilities like xgettext (part of the GNU gettext utilities) are commonly used.
Using xgettext (Command Line):
Navigate to your theme’s directory in your terminal and run the following command. Ensure you have gettext installed on your system.
cd /path/to/your/wordpress/wp-content/themes/my-awesome-theme xgettext --keyword=__ --keyword=_e --package-name="My Awesome Theme" --package-version="1.0.0" --msgid-bugs-address="[email protected]" --copyright-holder="Your Name" --output="my-awesome-theme.pot" *.php
This command scans all .php files in the current directory for strings marked with the __ and _e translation functions and outputs them to my-awesome-theme.pot. You can add more keywords if your theme uses other translation functions (e.g., _n for plurals).
Once you have the .pot file, you can use Poedit to open it and create language-specific .po files (e.g., fr_FR.po for French). After translators fill in the translations in the .po file, you compile it into a .mo (Machine Object) file, which WordPress actually uses.
Using Poedit:
- Download and install
Poedit. - Open your
my-awesome-theme.potfile. - Go to File > Save as… and name your translation file (e.g.,
fr_FR.po). - Translate the strings.
- Save the
.pofile.Poeditwill automatically generate the corresponding.mofile in the same directory.
Deploying Translation Files in Multisite
For a theme’s translations to be available across your entire WordPress multisite network, you should place the compiled .mo files in the global languages directory. The naming convention is critical: [text-domain]-[locale].mo.
For our example theme, My Awesome Theme with the text domain my-awesome-theme, the French translation file would be named my-awesome-theme-fr_FR.mo.
The target directory would be:
/path/to/your/wordpress/wp-content/languages/themes/my-awesome-theme-fr_FR.mo
If you are developing a plugin, the path would be:
/path/to/your/wordpress/wp-content/languages/plugins/my-awesome-plugin-fr_FR.mo
WordPress automatically scans these directories. When a site in the network is set to French (fr_FR), and its theme or plugin uses the corresponding text domain, WordPress will attempt to load the translation from this location.
Programmatically Loading Translations (Advanced)
While the Domain Path in the theme header is the standard way, you can also programmatically load translation files using the load_theme_textdomain() function in your theme’s functions.php file or load_plugin_textdomain() for plugins. This offers more control, especially in complex multisite scenarios or when you need to load translations from non-standard locations.
Example for a Theme:
/**
* Load theme textdomain for translation.
*/
function my_awesome_theme_load_textdomain() {
load_theme_textdomain(
'my-awesome-theme', // The text domain
get_template_directory() . '/languages' // The path to the languages directory
);
}
add_action( 'after_setup_theme', 'my_awesome_theme_load_textdomain' );
The load_theme_textdomain() function takes the text domain and the absolute path to the directory containing the translation files. The after_setup_theme hook is the appropriate place to call this function.
For plugins, you would use:
/**
* Load plugin textdomain for translation.
*/
function my_awesome_plugin_load_textdomain() {
load_plugin_textdomain(
'my-awesome-plugin', // The text domain
false, // Deprecated, set to false
dirname( plugin_basename( __FILE__ ) ) . '/languages' // Relative path to the languages directory
);
}
add_action( 'plugins_loaded', 'my_awesome_plugin_load_textdomain' );
The dirname( plugin_basename( __FILE__ ) ) part dynamically calculates the plugin’s directory path, making the code portable. The plugins_loaded hook is generally recommended for plugin text domain loading.
Troubleshooting Translation Issues in Multisite
If translations aren’t loading correctly in your multisite network, consider these common pitfalls:
- Incorrect Text Domain: Ensure the text domain used in your PHP code (e.g.,
__('Hello', 'my-awesome-theme')) exactly matches the text domain declared in the theme/plugin header and the name of your translation files. - Incorrect File Naming: Translation files must follow the pattern
[text-domain]-[locale].mo. For example,my-awesome-theme-es_ES.mofor Spanish. - Incorrect File Location: Verify that the
.mofiles are placed in the correct directory (wp-content/languages/themes/orwp-content/languages/plugins/for global availability, or within the theme/plugin’s ownlanguagesdirectory if usingDomain Path). - Site Language Mismatch: Check that the language set for the specific site in the WordPress admin (Settings > Site Language) matches the locale of your translation file (e.g.,
es_ESfor Spanish). - Caching: WordPress and server-level caching can sometimes prevent newly uploaded translation files from being recognized. Clear all caches (WordPress plugins, server cache, CDN) after uploading new translation files.
- Theme/Plugin Activation: Ensure the theme or plugin is active on the site where you expect translations to appear.
- Syntax Errors in PHP: A fatal PHP error can prevent WordPress from loading text domains or even executing the translation functions. Check your server’s error logs.
By meticulously managing your text domains and ensuring translation files are correctly named, located, and deployed, you can effectively create and manage multi-language WordPress sites, even within a complex multisite network.