Make WordPress Core


Ignore:
Timestamp:
12/20/2022 03:10:35 PM (22 months ago)
Author:
swissspidy
Message:

I18N: Change how WP_Textdomain_Registry caches translation information.

WP_Textdomain_Registry was introduced in [53874] and later adjusted in [54682] to store text domains and their language directory paths, addressing issues with just-in-time loading of textdomains when using locale switching and load_*_textdomain() functions.

This change improves how the class stores information about all existing MO files on the site, addressing an issue where translations are not loaded after calling switch_to_locale().

Props johnbillion, ocean90, SergeyBiryukov.
Fixes #57116.

File:
1 edited

Legend:

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

    r54669 r55010  
    5252     * @var array
    5353     */
    54     protected $cached_mo_files;
     54    protected $cached_mo_files = array();
     55
     56    /**
     57     * Holds a cached list of domains with translations to improve performance.
     58     *
     59     * @since 6.1.2
     60     *
     61     * @var string[]
     62     */
     63    protected $domains_with_translations = array();
    5564
    5665    /**
     
    8594     */
    8695    public function has( $domain ) {
    87         return ! empty( $this->current[ $domain ] ) || empty( $this->all[ $domain ] );
     96        return (
     97            ! empty( $this->current[ $domain ] ) ||
     98            empty( $this->all[ $domain ] ) ||
     99            in_array( $domain, $this->domains_with_translations, true )
     100        );
    88101    }
    89102
     
    110123     * Used by {@see load_plugin_textdomain()} and {@see load_theme_textdomain()}.
    111124     *
     125     * @since 6.1.0
     126     *
    112127     * @param string $domain Text domain.
    113128     * @param string $path   Language directory path.
     
    118133
    119134    /**
    120      * Gets the path to the language directory for the current locale.
    121      *
    122      * Checks the plugins and themes language directories as well as any
    123      * custom directory set via {@see load_plugin_textdomain()} or {@see load_theme_textdomain()}.
    124      *
    125      * @since 6.1.0
    126      *
    127      * @see _get_path_to_translation_from_lang_dir()
    128      *
    129      * @param string $domain Text domain.
    130      * @param string $locale Locale.
    131      * @return string|false Language directory path or false if there is none available.
    132      */
    133     private function get_path_from_lang_dir( $domain, $locale ) {
     135     * Returns possible language directory paths for a given text domain.
     136     *
     137     * @since 6.1.2
     138     *
     139     * @param string $domain Text domain.
     140     * @return string[] Array of language directory paths.
     141     */
     142    private function get_paths_for_domain( $domain ) {
    134143        $locations = array(
    135144            WP_LANG_DIR . '/plugins',
     
    141150        }
    142151
    143         $mofile = "$domain-$locale.mo";
     152        return $locations;
     153    }
     154
     155    /**
     156     * Gets the path to the language directory for the current locale.
     157     *
     158     * Checks the plugins and themes language directories as well as any
     159     * custom directory set via {@see load_plugin_textdomain()} or {@see load_theme_textdomain()}.
     160     *
     161     * @since 6.1.0
     162     *
     163     * @see _get_path_to_translation_from_lang_dir()
     164     *
     165     * @param string $domain Text domain.
     166     * @param string $locale Locale.
     167     * @return string|false Language directory path or false if there is none available.
     168     */
     169    private function get_path_from_lang_dir( $domain, $locale ) {
     170        $locations = $this->get_paths_for_domain( $domain );
     171
     172        $found_location = false;
    144173
    145174        foreach ( $locations as $location ) {
     
    148177            }
    149178
    150             $path = $location . '/' . $mofile;
    151 
    152             if ( in_array( $path, $this->cached_mo_files[ $location ], true ) ) {
    153                 $this->set( $domain, $locale, $location );
    154 
    155                 return trailingslashit( $location );
     179            $path = "$location/$domain-$locale.mo";
     180
     181            foreach ( $this->cached_mo_files[ $location ] as $mo_path ) {
     182                if (
     183                    ! in_array( $domain, $this->domains_with_translations, true ) &&
     184                    str_starts_with( str_replace( "$location/", '', $mo_path ), "$domain-" )
     185                ) {
     186                    $this->domains_with_translations[] = $domain;
     187                }
     188
     189                if ( $mo_path === $path ) {
     190                    $found_location = trailingslashit( $location );
     191                }
    156192            }
     193        }
     194
     195        if ( $found_location ) {
     196            $this->set( $domain, $locale, $found_location );
     197
     198            return $found_location;
    157199        }
    158200
     
    160202        // using load_plugin_textdomain/load_theme_textdomain, use that one.
    161203        if ( 'en_US' !== $locale && isset( $this->custom_paths[ $domain ] ) ) {
    162             $path = trailingslashit( $this->custom_paths[ $domain ] );
    163             $this->set( $domain, $locale, $path );
    164             return $path;
     204            $fallback_location = trailingslashit( $this->custom_paths[ $domain ] );
     205            $this->set( $domain, $locale, $fallback_location );
     206            return $fallback_location;
    165207        }
    166208
Note: See TracChangeset for help on using the changeset viewer.