Make WordPress Core

Changeset 59430


Ignore:
Timestamp:
11/20/2024 02:48:40 AM (12 days ago)
Author:
desrosj
Message:

i18n: Account for load_*_textdomain() after JIT loading.

When load_*_textdomain() functions are called after WordPress has already attempted just-in-time loading of translations, nothing happens.

This updates the related logic to retry translation loading when a custom path is set to ensure all translations are available.

Additionally, this also fixes cases where an en_US.mo file is provided with non-English strings to override the default language.

Follow up to [59157].

Props swissspidy, peterwilsoncc, desrosj, apermo, sergeybiryukov, wildworks, tigriweb, twvania, looswebstudio, stimul, audrasjb, finntown, bluantinoo, timwhitlock, albigdd.
See #62337.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-textdomain-registry.php

    r58591 r59430  
    154154     */
    155155    public function set_custom_path( $domain, $path ) {
     156        // If just-in-time loading was triggered before, reset the entry so it can be tried again.
     157
     158        if ( isset( $this->all[ $domain ] ) ) {
     159            $this->all[ $domain ] = array_filter( $this->all[ $domain ] );
     160        }
     161
     162        if ( empty( $this->current[ $domain ] ) ) {
     163            unset( $this->current[ $domain ] );
     164        }
     165
    156166        $this->custom_paths[ $domain ] = rtrim( $path, '/' );
    157167    }
     
    337347         * using load_plugin_textdomain/load_theme_textdomain, use that one.
    338348         */
    339         if ( 'en_US' !== $locale && isset( $this->custom_paths[ $domain ] ) ) {
     349        if ( isset( $this->custom_paths[ $domain ] ) ) {
    340350            $fallback_location = rtrim( $this->custom_paths[ $domain ], '/' ) . '/';
    341351            $this->set( $domain, $locale, $fallback_location );
  • trunk/src/wp-includes/l10n.php

    r59264 r59430  
    986986 * @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
    987987 *
     988 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
     989 * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
     990 *
    988991 * @param string       $domain          Unique identifier for retrieving translated strings
    989992 * @param string|false $deprecated      Optional. Deprecated. Use the $plugin_rel_path parameter instead.
     
    995998function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
    996999    /** @var WP_Textdomain_Registry $wp_textdomain_registry */
    997     global $wp_textdomain_registry;
     1000    /** @var array<string, WP_Translations|NOOP_Translations> $l10n */
     1001    global $wp_textdomain_registry, $l10n;
    9981002
    9991003    if ( ! is_string( $domain ) ) {
     
    10121016    $wp_textdomain_registry->set_custom_path( $domain, $path );
    10131017
     1018    // If just-in-time loading was triggered before, reset the entry so it can be tried again.
     1019    if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
     1020        unset( $l10n[ $domain ] );
     1021    }
     1022
    10141023    return true;
    10151024}
     
    10231032 *
    10241033 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
     1034 * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
    10251035 *
    10261036 * @param string $domain             Text domain. Unique identifier for retrieving translated strings.
     
    10311041function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
    10321042    /** @var WP_Textdomain_Registry $wp_textdomain_registry */
    1033     global $wp_textdomain_registry;
     1043    /** @var array<string, WP_Translations|NOOP_Translations> $l10n */
     1044    global $wp_textdomain_registry, $l10n;
    10341045
    10351046    if ( ! is_string( $domain ) ) {
     
    10401051
    10411052    $wp_textdomain_registry->set_custom_path( $domain, $path );
     1053
     1054    // If just-in-time loading was triggered before, reset the entry so it can be tried again.
     1055    if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
     1056        unset( $l10n[ $domain ] );
     1057    }
    10421058
    10431059    return true;
     
    10571073 *
    10581074 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
     1075 * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
    10591076 *
    10601077 * @param string       $domain Text domain. Unique identifier for retrieving translated strings.
     
    10651082function load_theme_textdomain( $domain, $path = false ) {
    10661083    /** @var WP_Textdomain_Registry $wp_textdomain_registry */
    1067     global $wp_textdomain_registry;
     1084    /** @var array<string, WP_Translations|NOOP_Translations> $l10n */
     1085    global $wp_textdomain_registry, $l10n;
    10681086
    10691087    if ( ! is_string( $domain ) ) {
     
    10761094
    10771095    $wp_textdomain_registry->set_custom_path( $domain, $path );
     1096
     1097    // If just-in-time loading was triggered before, reset the entry so it can be tried again.
     1098    if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
     1099        unset( $l10n[ $domain ] );
     1100    }
    10781101
    10791102    return true;
  • trunk/tests/phpunit/data/plugins/custom-internationalized-plugin/custom-internationalized-plugin.php

    r53874 r59430  
    88*/
    99
    10 load_plugin_textdomain( 'custom-internationalized-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
     10function custom_i18n_load_textdomain() {
     11    load_plugin_textdomain( 'custom-internationalized-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
     12}
     13
     14add_action( 'init', 'custom_i18n_load_textdomain' );
    1115
    1216function custom_i18n_plugin_test() {
  • trunk/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php

    r57516 r59430  
    343343        $this->assertSame( 1, $filter->get_call_count() );
    344344    }
     345
     346    /**
     347     * @ticket 44937
     348     * @ticket 62337
     349     *
     350     * @covers ::load_plugin_textdomain
     351     * @covers ::is_textdomain_loaded
     352     * @covers WP_Textdomain_Registry::set_custom_path
     353     */
     354    public function test_plugin_translation_should_be_translated_when_calling_load_plugin_textdomain_too_late() {
     355        require_once DIR_TESTDATA . '/plugins/custom-internationalized-plugin/custom-internationalized-plugin.php';
     356
     357        add_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
     358
     359        $is_textdomain_loaded_before = is_textdomain_loaded( 'custom-internationalized-plugin' );
     360        $output_before               = custom_i18n_plugin_test();
     361
     362        $is_textdomain_loaded_middle = is_textdomain_loaded( 'custom-internationalized-plugin' );
     363
     364        custom_i18n_load_textdomain();
     365
     366        $output_after               = custom_i18n_plugin_test();
     367        $is_textdomain_loaded_after = is_textdomain_loaded( 'custom-internationalized-plugin' );
     368
     369        $this->assertFalse( $is_textdomain_loaded_before );
     370        $this->assertFalse( $is_textdomain_loaded_middle );
     371        $this->assertSame( 'This is a dummy plugin', $output_before );
     372        $this->assertSame( 'Das ist ein Dummy Plugin', $output_after );
     373        $this->assertTrue( $is_textdomain_loaded_after );
     374    }
    345375}
  • trunk/tests/phpunit/tests/l10n/wpLocaleSwitcher.php

    r57337 r59430  
    494494        require_once DIR_TESTDATA . '/plugins/custom-internationalized-plugin/custom-internationalized-plugin.php';
    495495
     496        custom_i18n_load_textdomain();
     497
    496498        $actual = custom_i18n_plugin_test();
    497499
  • trunk/tests/phpunit/tests/l10n/wpTextdomainRegistry.php

    r57831 r59430  
    4040            'Incorrect availability status for textdomain with custom path'
    4141        );
    42         $this->assertFalse(
     42        $this->assertSame(
     43            WP_LANG_DIR . '/bar/',
    4344            $this->instance->get( 'foo', 'en_US' ),
    44             'Should not return custom path for textdomain and en_US locale'
     45            'Should return custom path for textdomain and en_US locale'
    4546        );
    4647        $this->assertSame(
Note: See TracChangeset for help on using the changeset viewer.