Make WordPress Core


Ignore:
Timestamp:
10/20/2020 04:03:58 PM (6 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.