Make WordPress Core


Ignore:
Timestamp:
10/20/2020 04:03:58 PM (4 years ago)
Author:
ocean90
Message:

I18N: Introduce WP_Textdomain_Registry to store text domains and their language directory paths.

Previously, when using switch_to_locale() all current loaded text domains were unloaded and added to the $l10n_unloaded global. This prevented the just-in-time loading for text domains after a switch. The just-in-time loading was also only possible if the translations were stored in WP_LANG_DIR. Both issues have been fixed.

  • Adds WP_Textdomain_Registry to keep track of the language directory paths for all plugins and themes.
  • Updates all load_*_textdomain() functions to store the path in WP_Textdomain_Registry.
  • Adds $reloadable parameter to unload_textdomain() to define whether a text domain can be loaded just-in-time again. This is used by WP_Locale_Switcher::load_translations().
  • Extends _load_textdomain_just_in_time() to also support text domains of plugins and themes with custom language directories.
  • Fixes the incorrect test_plugin_translation_after_switching_locale_twice() test which should have catch this issue earlier.
  • Adds a new test plugin/theme to test the loading of translations with a custom language directory.
  • Deprecates the now unused and private _get_path_to_translation() and _get_path_to_translation_from_lang_dir() functions.

Props yoavf, swissspidy, dd32, ocean90.
See #26511.
Fixes #39210.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/l10n.php

    r49193 r49236  
    690690 * @since 1.5.0
    691691 *
    692  * @global MO[] $l10n          An array of all currently loaded text domains.
    693  * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
     692 * @global MO[]                   $l10n                   An array of all currently loaded text domains.
     693 * @global MO[]                   $l10n_unloaded          An array of all text domains that have been unloaded again.
     694 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
    694695 *
    695696 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
     
    698699 */
    699700function load_textdomain( $domain, $mofile ) {
    700     global $l10n, $l10n_unloaded;
     701    global $l10n, $l10n_unloaded, $wp_textdomain_registry;
    701702
    702703    $l10n_unloaded = (array) $l10n_unloaded;
     
    756757    $l10n[ $domain ] = &$mo;
    757758
     759    /** @var WP_Textdomain_Registry $wp_textdomain_registry */
     760    $wp_textdomain_registry->set( $domain, dirname( $mofile ) );
     761
    758762    return true;
    759763}
     
    763767 *
    764768 * @since 3.0.0
     769 * @since 5.6.0 Added the `$reloadable` parameter.
    765770 *
    766771 * @global MO[] $l10n          An array of all currently loaded text domains.
    767772 * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
    768773 *
    769  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
     774 * @param string $domain     Text domain. Unique identifier for retrieving translated strings.
     775 * @param bool   $reloadable Whether the text domain can be loaded just-in-time again.
    770776 * @return bool Whether textdomain was unloaded.
    771777 */
    772 function unload_textdomain( $domain ) {
     778function unload_textdomain( $domain, $reloadable = false ) {
    773779    global $l10n, $l10n_unloaded;
    774780
     
    779785     *
    780786     * @since 3.0.0
    781      *
    782      * @param bool   $override Whether to override the text domain unloading. Default false.
    783      * @param string $domain   Text domain. Unique identifier for retrieving translated strings.
    784      */
    785     $plugin_override = apply_filters( 'override_unload_textdomain', false, $domain );
     787     * @since 5.6.0 Added the `$reloadable` parameter.
     788     *
     789     * @param bool   $override   Whether to override the text domain unloading. Default false.
     790     * @param string $domain     Text domain. Unique identifier for retrieving translated strings.
     791     * @param bool   $reloadable Whether the text domain can be loaded just-in-time again.
     792     */
     793    $plugin_override = apply_filters( 'override_unload_textdomain', false, $domain, $reloadable );
    786794
    787795    if ( $plugin_override ) {
    788         $l10n_unloaded[ $domain ] = true;
     796        if ( ! $reloadable ) {
     797            $l10n_unloaded[ $domain ] = true;
     798        }
    789799
    790800        return true;
     
    795805     *
    796806     * @since 3.0.0
    797      *
    798      * @param string $domain Text domain. Unique identifier for retrieving translated strings.
    799      */
    800     do_action( 'unload_textdomain', $domain );
     807     * @since 5.6.0 Added the `$reloadable` parameter.
     808     *
     809     * @param string $domain     Text domain. Unique identifier for retrieving translated strings.
     810     * @param bool   $reloadable Whether the text domain can be loaded just-in-time again.
     811     */
     812    do_action( 'unload_textdomain', $domain, $reloadable );
    801813
    802814    if ( isset( $l10n[ $domain ] ) ) {
    803815        unset( $l10n[ $domain ] );
    804816
    805         $l10n_unloaded[ $domain ] = true;
     817        if ( ! $reloadable ) {
     818            $l10n_unloaded[ $domain ] = true;
     819        }
    806820
    807821        return true;
     
    868882 */
    869883function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
     884    global $wp_textdomain_registry;
     885
    870886    /**
    871887     * Filters a plugin's locale.
     
    894910    }
    895911
     912    /* @var WP_Textdomain_Registry $wp_textdomain_registry */
     913    $wp_textdomain_registry->set( $domain, $path );
     914
    896915    return load_textdomain( $domain, $path . '/' . $mofile );
    897916}
     
    902921 * @since 3.0.0
    903922 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
     923 *
     924 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
    904925 *
    905926 * @param string $domain             Text domain. Unique identifier for retrieving translated strings.
     
    909930 */
    910931function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
     932    global $wp_textdomain_registry;
     933
    911934    /** This filter is documented in wp-includes/l10n.php */
    912935    $locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
     
    921944    $path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' );
    922945
     946    /* @var WP_Textdomain_Registry $wp_textdomain_registry */
     947    $wp_textdomain_registry->set( $domain, $path );
     948
    923949    return load_textdomain( $domain, $path . '/' . $mofile );
    924950}
     
    934960 * @since 1.5.0
    935961 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
     962 *
     963 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
    936964 *
    937965 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
     
    941969 */
    942970function load_theme_textdomain( $domain, $path = false ) {
     971    global $wp_textdomain_registry;
     972
    943973    /**
    944974     * Filters a theme's locale.
     
    961991        $path = get_template_directory();
    962992    }
     993
     994    /* @var WP_Textdomain_Registry $wp_textdomain_registry */
     995    $wp_textdomain_registry->set( $domain, $path );
    963996
    964997    return load_textdomain( $domain, $path . '/' . $locale . '.mo' );
     
    11911224 * @access private
    11921225 *
    1193  * @see get_translations_for_domain()
    1194  * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
     1226 * @global MO[]                   $l10n_unloaded          An array of all text domains that have been unloaded again.
     1227 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
    11951228 *
    11961229 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
     
    11981231 */
    11991232function _load_textdomain_just_in_time( $domain ) {
    1200     global $l10n_unloaded;
     1233    global $l10n_unloaded, $wp_textdomain_registry;
    12011234
    12021235    $l10n_unloaded = (array) $l10n_unloaded;
     
    12071240    }
    12081241
    1209     $translation_path = _get_path_to_translation( $domain );
    1210     if ( false === $translation_path ) {
     1242    /** @var WP_Textdomain_Registry $wp_textdomain_registry */
     1243    $path = $wp_textdomain_registry->get( $domain );
     1244    if ( ! $path ) {
    12111245        return false;
    12121246    }
    12131247
    1214     return load_textdomain( $domain, $translation_path );
    1215 }
    1216 
    1217 /**
    1218  * Gets the path to a translation file for loading a textdomain just in time.
    1219  *
    1220  * Caches the retrieved results internally.
    1221  *
    1222  * @since 4.7.0
    1223  * @access private
    1224  *
    1225  * @see _load_textdomain_just_in_time()
    1226  *
    1227  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
    1228  * @param bool   $reset  Whether to reset the internal cache. Used by the switch to locale functionality.
    1229  * @return string|false The path to the translation file or false if no translation file was found.
    1230  */
    1231 function _get_path_to_translation( $domain, $reset = false ) {
    1232     static $available_translations = array();
    1233 
    1234     if ( true === $reset ) {
    1235         $available_translations = array();
    1236     }
    1237 
    1238     if ( ! isset( $available_translations[ $domain ] ) ) {
    1239         $available_translations[ $domain ] = _get_path_to_translation_from_lang_dir( $domain );
    1240     }
    1241 
    1242     return $available_translations[ $domain ];
    1243 }
    1244 
    1245 /**
    1246  * Gets the path to a translation file in the languages directory for the current locale.
    1247  *
    1248  * Holds a cached list of available .mo files to improve performance.
    1249  *
    1250  * @since 4.7.0
    1251  * @access private
    1252  *
    1253  * @see _get_path_to_translation()
    1254  *
    1255  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
    1256  * @return string|false The path to the translation file or false if no translation file was found.
    1257  */
    1258 function _get_path_to_translation_from_lang_dir( $domain ) {
    1259     static $cached_mofiles = null;
    1260 
    1261     if ( null === $cached_mofiles ) {
    1262         $cached_mofiles = array();
    1263 
    1264         $locations = array(
    1265             WP_LANG_DIR . '/plugins',
    1266             WP_LANG_DIR . '/themes',
    1267         );
    1268 
    1269         foreach ( $locations as $location ) {
    1270             $mofiles = glob( $location . '/*.mo' );
    1271             if ( $mofiles ) {
    1272                 $cached_mofiles = array_merge( $cached_mofiles, $mofiles );
    1273             }
    1274         }
    1275     }
    1276 
    12771248    $locale = determine_locale();
    1278     $mofile = "{$domain}-{$locale}.mo";
    1279 
    1280     $path = WP_LANG_DIR . '/plugins/' . $mofile;
    1281     if ( in_array( $path, $cached_mofiles, true ) ) {
    1282         return $path;
    1283     }
    1284 
    1285     $path = WP_LANG_DIR . '/themes/' . $mofile;
    1286     if ( in_array( $path, $cached_mofiles, true ) ) {
    1287         return $path;
    1288     }
    1289 
    1290     return false;
     1249
     1250    // Themes with their language directory outside of WP_LANG_DIR have a different file name.
     1251    $template_directory   = trailingslashit( get_template_directory() );
     1252    $stylesheet_directory = trailingslashit( get_stylesheet_directory() );
     1253    if ( 0 === strpos( $path, $template_directory ) || 0 === strpos( $path, $stylesheet_directory ) ) {
     1254        $mofile = "{$path}{$locale}.mo";
     1255    } else {
     1256        $mofile = "{$path}{$domain}-{$locale}.mo";
     1257    }
     1258
     1259    return load_textdomain( $domain, $mofile );
    12911260}
    12921261
     
    12981267 * @since 2.8.0
    12991268 *
    1300  * @global MO[] $l10n
     1269 * @global MO[] $l10n An array of all currently loaded text domains.
    13011270 *
    13021271 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
     
    13221291 * @since 3.0.0
    13231292 *
    1324  * @global MO[] $l10n
     1293 * @global MO[] $l10n An array of all currently loaded text domains.
    13251294 *
    13261295 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
Note: See TracChangeset for help on using the changeset viewer.