Skip to content

Commit

Permalink
I18N: Do not load translations directly in load_*_textdomain.
Browse files Browse the repository at this point in the history
In [59127], `_doing_it_wrong` warnings were added if plugins or themes load translations too early, either through a manual function call or just-in-time loading.

Because many plugins and themes still manually call `load_plugin_textdomain()`, `load_theme_textdomain()` or `load_muplugin_textdomain()`, even though they don't have to anymore, that caused a lot of warnings.

With this new approach, these functions merely register the translations path in the existing `WP_Textdomain_Registry` and do not immediately try to load the translations anymore. The loading is all handled by the just-in-time functionality.

This way, warnings will only be emitted if triggering the just-in-time loading too early, greatly improving the developer experience and to a degree also performance.

Props swissspidy, sergeybiryukov, mukesh27.
See #44937.



git-svn-id: https://develop.svn.wordpress.org/trunk@59157 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
swissspidy committed Oct 2, 2024
1 parent 1ec0abb commit d42d958
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 172 deletions.
99 changes: 10 additions & 89 deletions src/wp-includes/l10n.php
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,7 @@ function load_default_textdomain( $locale = null ) {
*
* @since 1.5.0
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
* @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
*
* @param string $domain Unique identifier for retrieving translated strings
* @param string|false $deprecated Optional. Deprecated. Use the $plugin_rel_path parameter instead.
Expand All @@ -999,36 +1000,6 @@ function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path
return false;
}

if ( ! doing_action( 'after_setup_theme' ) && ! did_action( 'after_setup_theme' ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: The text domain. 2: 'after_setup_theme'. */
__( 'Attempted to load translations for the %1$s domain too early. Translations should be loaded after the %2$s action has fired, to ensure that the current user is already set up.' ),
'<code>' . $domain . '</code>',
'<code>after_setup_theme</code>'
),
'6.7.0'
);
}

/**
* Filters a plugin's locale.
*
* @since 3.0.0
*
* @param string $locale The plugin's current locale.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
*/
$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );

$mofile = $domain . '-' . $locale . '.mo';

// Try to load from the languages directory first.
if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) {
return true;
}

if ( false !== $plugin_rel_path ) {
$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
} elseif ( false !== $deprecated ) {
Expand All @@ -1040,14 +1011,15 @@ function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path

$wp_textdomain_registry->set_custom_path( $domain, $path );

return load_textdomain( $domain, $path . '/' . $mofile, $locale );
return true;
}

/**
* Loads the translated strings for a plugin residing in the mu-plugins directory.
*
* @since 3.0.0
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
* @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
*
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
*
Expand All @@ -1064,34 +1036,11 @@ function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
return false;
}

if ( ! doing_action( 'after_setup_theme' ) && ! did_action( 'after_setup_theme' ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: The text domain. 2: 'after_setup_theme'. */
__( 'Attempted to load translations for the %1$s domain too early. Translations should be loaded after the %2$s action has fired, to ensure that the current user is already set up.' ),
'<code>' . $domain . '</code>',
'<code>after_setup_theme</code>'
),
'6.7.0'
);
}

/** This filter is documented in wp-includes/l10n.php */
$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );

$mofile = $domain . '-' . $locale . '.mo';

// Try to load from the languages directory first.
if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) {
return true;
}

$path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' );

$wp_textdomain_registry->set_custom_path( $domain, $path );

return load_textdomain( $domain, $path . '/' . $mofile, $locale );
return true;
}

/**
Expand All @@ -1104,6 +1053,7 @@ function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
*
* @since 1.5.0
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
* @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
*
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
*
Expand All @@ -1120,43 +1070,13 @@ function load_theme_textdomain( $domain, $path = false ) {
return false;
}

if ( ! doing_action( 'after_setup_theme' ) && ! did_action( 'after_setup_theme' ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: The text domain. 2: 'after_setup_theme'. */
__( 'Attempted to load translations for the %1$s domain too early. Translations should be loaded after the %2$s action has fired, to ensure that the current user is already set up.' ),
'<code>' . $domain . '</code>',
'<code>after_setup_theme</code>'
),
'6.7.0'
);
}

/**
* Filters a theme's locale.
*
* @since 3.0.0
*
* @param string $locale The theme's current locale.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
*/
$locale = apply_filters( 'theme_locale', determine_locale(), $domain );

$mofile = $domain . '-' . $locale . '.mo';

// Try to load from the languages directory first.
if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile, $locale ) ) {
return true;
}

if ( ! $path ) {
$path = get_template_directory();
}

$wp_textdomain_registry->set_custom_path( $domain, $path );

return load_textdomain( $domain, $path . '/' . $locale . '.mo', $locale );
return true;
}

/**
Expand Down Expand Up @@ -1425,9 +1345,10 @@ function _load_textdomain_just_in_time( $domain ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: %s: The text domain. */
__( 'Translation loading for the %s domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early.' ),
'<code>' . $domain . '</code>'
/* translators: 1: The text domain. 2: 'init'. */
__( 'Translation loading for the %1$s domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the %2$s action or later.' ),
'<code>' . $domain . '</code>',
'<code>init</code>'
),
'6.7.0'
);
Expand Down
81 changes: 0 additions & 81 deletions tests/phpunit/tests/l10n/loadTextdomain.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* @group i18n
*/
class Tests_L10n_LoadTextdomain extends WP_UnitTestCase {
protected $locale;
protected static $user_id;

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
Expand All @@ -20,11 +19,6 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
public function set_up() {
parent::set_up();

$this->locale = '';

add_filter( 'plugin_locale', array( $this, 'store_locale' ) );
add_filter( 'theme_locale', array( $this, 'store_locale' ) );

/** @var WP_Textdomain_Registry $wp_textdomain_registry */
global $wp_textdomain_registry;

Expand All @@ -41,12 +35,6 @@ public function tear_down() {
parent::tear_down();
}

public function store_locale( $locale ) {
$this->locale = $locale;

return $locale;
}

/**
* @covers ::is_textdomain_loaded
*/
Expand Down Expand Up @@ -232,75 +220,6 @@ public function override_load_textdomain_filter( $override, $domain, $file ) {
return true;
}

/**
* @covers ::load_muplugin_textdomain
*/
public function test_load_muplugin_textdomain_site_locale() {
load_muplugin_textdomain( 'wp-tests-domain' );

$this->assertSame( get_locale(), $this->locale );
}

/**
* @ticket 38485
*
* @covers ::load_muplugin_textdomain
*/
public function test_load_muplugin_textdomain_user_locale() {
set_current_screen( 'dashboard' );
wp_set_current_user( self::$user_id );

load_muplugin_textdomain( 'wp-tests-domain' );

$this->assertSame( get_user_locale(), $this->locale );
}

/**
* @covers ::load_plugin_textdomain
*/
public function test_load_plugin_textdomain_site_locale() {
load_plugin_textdomain( 'wp-tests-domain' );

$this->assertSame( get_locale(), $this->locale );
}

/**
* @ticket 38485
*
* @covers ::load_plugin_textdomain
*/
public function test_load_plugin_textdomain_user_locale() {
set_current_screen( 'dashboard' );
wp_set_current_user( self::$user_id );

load_plugin_textdomain( 'wp-tests-domain' );

$this->assertSame( get_user_locale(), $this->locale );
}

/**
* @covers ::load_theme_textdomain
*/
public function test_load_theme_textdomain_site_locale() {
load_theme_textdomain( 'wp-tests-domain' );

$this->assertSame( get_locale(), $this->locale );
}

/**
* @ticket 38485
*
* @covers ::load_theme_textdomain
*/
public function test_load_theme_textdomain_user_locale() {
set_current_screen( 'dashboard' );
wp_set_current_user( self::$user_id );

load_theme_textdomain( 'wp-tests-domain' );

$this->assertSame( get_user_locale(), $this->locale );
}

/**
* @ticket 58035
*
Expand Down
4 changes: 2 additions & 2 deletions tests/phpunit/tests/rest-api/rest-themes-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -582,8 +582,8 @@ public function test_theme_tags() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'tags', $result[0] );
$this->assertSame( array( 'holiday', 'custom-menu' ), $result[0]['tags']['raw'] );
$this->assertSame( 'holiday, custom-menu', $result[0]['tags']['rendered'] );
$this->assertSame( array( 'Holiday', 'custom-menu' ), $result[0]['tags']['raw'] );
$this->assertSame( 'Holiday, custom-menu', $result[0]['tags']['rendered'] );
}

/**
Expand Down

0 comments on commit d42d958

Please sign in to comment.