I18N: Add an additional caching layer for `_load_textdomain_just_in_time()`.

Previously, if no translation files exist for a text domain, `_load_textdomain_just_in_time()` went through the entire process each time it was called. This results in an increased call to `get_locale()` and its `locale` filter.
This change splits the logic into `_get_path_to_translation()` and `_get_path_to_translation_from_lang_dir()`. The former, which is used by `_load_textdomain_just_in_time()`, caches the result of the latter. It also removes some non-working code from `WP_Locale_Switcher::load_translations()`.

Props jrf, swissspidy, sharkomatic, ocean90.
Fixes #37997.

git-svn-id: https://develop.svn.wordpress.org/trunk@39330 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Dominik Schilling (ocean90) 2016-11-21 16:06:38 +00:00
parent 0cbea5855e
commit e2f67203bb
4 changed files with 111 additions and 15 deletions

View File

@ -202,14 +202,7 @@ class WP_Locale_Switcher {
continue;
}
$mofile = $l10n[ $domain ]->get_filename();
unload_textdomain( $domain );
if ( $mofile ) {
load_textdomain( $domain, $mofile );
}
get_translations_for_domain( $domain );
}
}
@ -228,6 +221,9 @@ class WP_Locale_Switcher {
* @param string $locale The locale to change to.
*/
private function change_locale( $locale ) {
// Reset translation availability information.
_get_path_to_translation( null, true );
$this->load_translations( $locale );
$GLOBALS['wp_locale'] = new WP_Locale();

View File

@ -827,8 +827,6 @@ function load_child_theme_textdomain( $domain, $path = false ) {
* the translation file from `wp-content/languages`, removing the need
* to call load_plugin_texdomain() or load_theme_texdomain().
*
* Holds a cached list of available .mo files to improve performance.
*
* @since 4.6.0
* @access private
*
@ -843,13 +841,63 @@ function _load_textdomain_just_in_time( $domain ) {
$l10n_unloaded = (array) $l10n_unloaded;
static $cached_mofiles = null;
// Short-circuit if domain is 'default' which is reserved for core.
if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) {
return false;
}
$translation_path = _get_path_to_translation( $domain );
if ( false === $translation_path ) {
return false;
}
return load_textdomain( $domain, $translation_path );
}
/**
* Gets the path to a translation file for loading a textdomain just in time.
*
* Caches the retrieved results internally.
*
* @since 4.7.0
* @access private
*
* @see _load_textdomain_just_in_time()
*
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @param bool $reset Whether to reset the internal cache. Used by the switch to locale functionality.
* @return string|false The path to the translation file or false if no translation file was found.
*/
function _get_path_to_translation( $domain, $reset = false ) {
static $available_translations = array();
if ( true === $reset ) {
$available_translations = array();
}
if ( ! isset( $available_translations[ $domain ] ) ) {
$available_translations[ $domain ] = _get_path_to_translation_from_lang_dir( $domain );
}
return $available_translations[ $domain ];
}
/**
* Gets the path to a translation file in the languages directory for the current locale.
*
* Holds a cached list of available .mo files to improve performance.
*
* @since 4.7.0
* @access private
*
* @see _get_path_to_translation()
*
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @return string|false The path to the translation file or false if no translation file was found.
*/
function _get_path_to_translation_from_lang_dir( $domain ) {
static $cached_mofiles = null;
if ( null === $cached_mofiles ) {
$cached_mofiles = array();
@ -869,12 +917,14 @@ function _load_textdomain_just_in_time( $domain ) {
$locale = is_admin() ? get_user_locale() : get_locale();
$mofile = "{$domain}-{$locale}.mo";
if ( in_array( WP_LANG_DIR . '/plugins/' . $mofile, $cached_mofiles ) ) {
return load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile );
$path = WP_LANG_DIR . '/plugins/' . $mofile;
if ( in_array( $path, $cached_mofiles ) ) {
return $path;
}
if ( in_array( WP_LANG_DIR . '/themes/' . $mofile, $cached_mofiles ) ) {
return load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile );
$path = WP_LANG_DIR . '/themes/' . $mofile;
if ( in_array( $path, $cached_mofiles ) ) {
return $path;
}
return false;

View File

@ -8,6 +8,7 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase {
protected $orig_theme_dir;
protected $theme_root;
protected static $user_id;
private $locale_count;
public static function wpSetUpBeforeClass( $factory ) {
self::$user_id = $factory->user->create( array(
@ -21,6 +22,7 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase {
$this->theme_root = DIR_TESTDATA . '/themedir1';
$this->orig_theme_dir = $GLOBALS['wp_theme_directories'];
$this->locale_count = 0;
// /themes is necessary as theme.php functions assume /themes is the root if there is only one root.
$GLOBALS['wp_theme_directories'] = array( WP_CONTENT_DIR . '/themes', $this->theme_root );
@ -31,6 +33,7 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase {
unset( $GLOBALS['wp_themes'] );
unset( $GLOBALS['l10n'] );
unset( $GLOBALS['l10n_unloaded'] );
_get_path_to_translation( null, true );
}
public function tearDown() {
@ -42,6 +45,7 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase {
unset( $GLOBALS['wp_themes'] );
unset( $GLOBALS['l10n'] );
unset( $GLOBALS['l10n_unloaded'] );
_get_path_to_translation( null, true );
parent::tearDown();
}
@ -162,6 +166,24 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase {
$this->assertSame( 'Das ist ein Dummy Plugin', $expected );
}
/**
* @ticket 37997
*/
public function test_plugin_translation_after_switching_locale_twice() {
require_once DIR_TESTDATA . '/plugins/internationalized-plugin.php';
switch_to_locale( 'de_DE' );
$expected_de_DE = i18n_plugin_test();
switch_to_locale( 'es_ES' );
$expected_es_ES = i18n_plugin_test();
restore_current_locale();
$this->assertSame( 'Das ist ein Dummy Plugin', $expected_de_DE );
$this->assertSame( 'This is a dummy plugin', $expected_es_ES );
}
/**
* @ticket 26511
*/
@ -212,4 +234,30 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase {
$this->assertSame( 'Das ist ein Dummy Theme', $expected );
}
/**
* @ticket 37997
*/
public function test_get_locale_is_called_only_once_per_textdomain() {
$textdomain = 'foo-bar-baz';
add_filter( 'locale', array( $this, '_filter_locale_count' ) );
__( 'Foo', $textdomain );
__( 'Bar', $textdomain );
__( 'Baz', $textdomain );
__( 'Foo Bar', $textdomain );
__( 'Foo Bar Baz', $textdomain );
remove_filter( 'locale', array( $this, '_filter_locale_count' ) );
$this->assertFalse( is_textdomain_loaded( $textdomain ) );
$this->assertSame( 1, $this->locale_count );
}
public function _filter_locale_count( $locale ) {
++$this->locale_count;
return $locale;
}
}

View File

@ -24,11 +24,13 @@ class Tests_Locale_Switcher extends WP_UnitTestCase {
unset( $GLOBALS['l10n'] );
unset( $GLOBALS['l10n_unloaded'] );
_get_path_to_translation( null, true );
}
public function tearDown() {
unset( $GLOBALS['l10n'] );
unset( $GLOBALS['l10n_unloaded'] );
_get_path_to_translation( null, true );
parent::tearDown();
}