Solving Plugin Translation in WordPress 6.7
With the release of WordPress 6.7, developers were introduced to some changes regarding how translations are loaded.

WordPress 6.7 Translations
With the release of WordPress 6.7, developers were introduced to some changes regarding how translations are loaded for plugins. However, the guidance provided—especially the PHP warnings prompting developers to adjust their code—led to confusion. Following the recommended changes resulted in translations not being loaded correctly, especially for plugins with translation files stored locally within the plugin directory or for new plugins whose translations are not yet hosted in the WordPress repository.
In this post, I’ll walk you through the issue and the steps I took to resolve this issue for my plugin.
The Problem
Before WordPress 6.7, it was common practice to load translations using the load_plugin_textdomain
function within the init
action. For example:
add_action( 'init', 'load_textdomain' );
/**
* Load text domain for internalization.
*/
function load_textdomain() {
load_plugin_textdomain( 'my-textdomain', false, 'my-plugin-folder/langs/' );
}
This approach worked seamlessly for the following plugin structure:
my-plugin-folder/
├── my-plugin.php
├── langs/
├── my-textdomain-ro_RO.mo
├── my-textdomain-ro_RO.po
├── my-textdomain.pot
However, after WordPress 6.7, translations were no longer being picked up when the plugin was loaded. This was particularly problematic if:
- Your plugin’s text domain did not match the base name of the plugin folder.
- The translation files were stored locally within the plugin’s directory rather than the global
WP_LANG_DIR
. - You were developing a new plugin whose translations were not hosted in the WordPress repository.
Understanding the Changes
The changes in WordPress 6.7 adjusted the way translations are handled, emphasizing the use of translations hosted in the WordPress repository and making it more challenging to use local translations directly from the plugin folder. This behavior caused locally stored translation files to be overlooked, even when explicitly specified.
The Solution
To ensure translations are loaded correctly after WordPress 6.7, I made the following adjustments:
/**
* Load text domain for internalization.
*/
function load_textdomain() {
$locale = get_locale(); // Get the current locale.
$textdomain = 'my-textdomain';
$plugin_path = plugin_dir_path( __FILE__ ) . 'langs/' . $textdomain . '-' . $locale . '.mo';
$global_path = WP_LANG_DIR . '/plugins/' . $textdomain . '-' . $locale . '.mo';
// Attempt to load translations using load_plugin_textdomain.
load_plugin_textdomain( $textdomain, false, basename( __DIR__ ) . '/langs/' );
// Fallback to manually load local translations if not picked up.
if ( file_exists( $plugin_path ) && is_readable( $plugin_path ) ) {
load_textdomain( $textdomain, $plugin_path );
} elseif ( file_exists( $global_path ) && is_readable( $global_path ) ) {
load_textdomain( $textdomain, $global_path );
}
}
add_action( 'init', 'load_textdomain' );
Why This Works
- Explicit Locale Handling: By explicitly fetching the current locale with
get_locale()
, the solution ensures that the correct translation file (e.g.,my-textdomain-ro_RO.mo
) is targeted. - Fallback to Local Files: The use of
load_textdomain
as a fallback ensures that translations stored in the plugin’slangs
directory are loaded if they are not picked up byload_plugin_textdomain
. - Global Path Support: For plugins that rely on global translations stored in the
WP_LANG_DIR
, this solution checks and loads those files as well. - Backward Compatibility: This approach preserves compatibility with the existing plugin structure while addressing the changes introduced in WordPress 6.7.
Key Takeaways
- Test Local Translations: Always test your plugin’s translations when upgrading WordPress, especially for significant updates like 6.7.
- Understand the Text Domain Rules: Ensure your plugin’s text domain matches its declaration in the plugin header and translation files.
- Fallback Logic is Essential: Adding fallback logic with
load_textdomain
is a robust way to handle edge cases whereload_plugin_textdomain
fails.
By implementing this solution, I was able to ensure that translations were correctly loaded in my plugin, maintaining compatibility across WordPress versions and avoiding any disruption for users.
Click the heart.
The captivating image used in this article was generated by Adobe Firefly AI technology.
If you would like to support my work, consider making a donation, buy me a coffee, or share this on your feed.