diff --git a/src/wp-includes/l10n.php b/src/wp-includes/l10n.php index fa63b19b25..7ce5839b1c 100644 --- a/src/wp-includes/l10n.php +++ b/src/wp-includes/l10n.php @@ -509,14 +509,17 @@ function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) * * @since 1.5.0 * - * @global array $l10n + * @global array $l10n An array of all currently loaded text domains. + * @global array $l10n_unloaded An array of all text domains that have been unloaded again. * * @param string $domain Text domain. Unique identifier for retrieving translated strings. * @param string $mofile Path to the .mo file. * @return bool True on success, false on failure. */ function load_textdomain( $domain, $mofile ) { - global $l10n; + global $l10n, $l10n_unloaded; + + $l10n_unloaded = (array) $l10n_unloaded; /** * Filters whether to override the .mo file loading. @@ -530,6 +533,8 @@ function load_textdomain( $domain, $mofile ) { $plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile ); if ( true == $plugin_override ) { + unset( $l10n_unloaded[ $domain ] ); + return true; } @@ -561,6 +566,8 @@ function load_textdomain( $domain, $mofile ) { if ( isset( $l10n[$domain] ) ) $mo->merge_with( $l10n[$domain] ); + unset( $l10n_unloaded[ $domain ] ); + $l10n[$domain] = &$mo; return true; @@ -571,13 +578,16 @@ function load_textdomain( $domain, $mofile ) { * * @since 3.0.0 * - * @global array $l10n + * @global array $l10n An array of all currently loaded text domains. + * @global array $l10n_unloaded An array of all text domains that have been unloaded again. * * @param string $domain Text domain. Unique identifier for retrieving translated strings. * @return bool Whether textdomain was unloaded. */ function unload_textdomain( $domain ) { - global $l10n; + global $l10n, $l10n_unloaded; + + $l10n_unloaded = (array) $l10n_unloaded; /** * Filters whether to override the text domain unloading. @@ -589,8 +599,11 @@ function unload_textdomain( $domain ) { */ $plugin_override = apply_filters( 'override_unload_textdomain', false, $domain ); - if ( $plugin_override ) + if ( $plugin_override ) { + $l10n_unloaded[ $domain ] = true; + return true; + } /** * Fires before the text domain is unloaded. @@ -603,6 +616,9 @@ function unload_textdomain( $domain ) { if ( isset( $l10n[$domain] ) ) { unset( $l10n[$domain] ); + + $l10n_unloaded[ $domain ] = true; + return true; } @@ -793,15 +809,20 @@ function load_child_theme_textdomain( $domain, $path = false ) { * @access private * * @see get_translations_for_domain() + * @global array $l10n_unloaded An array of all text domains that have been unloaded again. * * @param string $domain Text domain. Unique identifier for retrieving translated strings. * @return bool True when the textdomain is successfully loaded, false otherwise. */ function _load_textdomain_just_in_time( $domain ) { + global $l10n_unloaded; + + $l10n_unloaded = (array) $l10n_unloaded; + static $cached_mofiles = null; // Short-circuit if domain is 'default' which is reserved for core. - if ( 'default' === $domain ) { + if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) { return false; } diff --git a/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php b/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php index 14a2b0d628..f73cfd5a90 100644 --- a/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php +++ b/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php @@ -22,6 +22,8 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { add_filter( 'template_root', array( $this, 'filter_theme_root' ) ); wp_clean_themes_cache(); unset( $GLOBALS['wp_themes'] ); + + unset( $GLOBALS['l10n_unloaded'] ); } function tearDown() { @@ -89,7 +91,7 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { } /** - * @ticket 341142 + * @ticket 34114 */ public function test_get_translations_for_domain_does_not_return_null_if_override_load_textdomain_is_used() { add_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) ); @@ -100,4 +102,43 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { $this->assertTrue( $translations instanceof NOOP_Translations ); } + + /** + * @ticket 37113 + */ + public function test_should_allow_unloading_of_text_domain() { + add_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) ); + + require_once DIR_TESTDATA . '/plugins/internationalized-plugin.php'; + + $expected_output_before = i18n_plugin_test(); + $is_textdomain_loaded_before = is_textdomain_loaded( 'internationalized-plugin' ); + + unload_textdomain( 'internationalized-plugin' ); + remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) ); + + $expected_output_after = i18n_plugin_test(); + $is_textdomain_loaded_after = is_textdomain_loaded( 'internationalized-plugin' ); + + add_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) ); + load_textdomain( 'internationalized-plugin', WP_LANG_DIR . '/plugins/internationalized-plugin-de_DE.mo' ); + + $expected_output_final = i18n_plugin_test(); + $is_textdomain_loaded_final = is_textdomain_loaded( 'internationalized-plugin' ); + + unload_textdomain( 'internationalized-plugin' ); + remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) ); + + // Text domain loaded just in time. + $this->assertSame( 'Das ist ein Dummy Plugin', $expected_output_before ); + $this->assertTrue( $is_textdomain_loaded_before ); + + // Text domain unloaded. + $this->assertSame( 'This is a dummy plugin', $expected_output_after ); + $this->assertFalse( $is_textdomain_loaded_after ); + + // Text domain loaded manually again. + $this->assertSame( 'Das ist ein Dummy Plugin', $expected_output_final ); + $this->assertTrue( $is_textdomain_loaded_final ); + } }