[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-textdomain-registry.php (source)

   1  <?php
   2  /**
   3   * Locale API: WP_Textdomain_Registry class.
   4   *
   5   * This file uses rtrim() instead of untrailingslashit() and trailingslashit()
   6   * to avoid formatting.php dependency.
   7   *
   8   * @package WordPress
   9   * @subpackage i18n
  10   * @since 6.1.0
  11   */
  12  
  13  /**
  14   * Core class used for registering text domains.
  15   *
  16   * @since 6.1.0
  17   */
  18  #[AllowDynamicProperties]
  19  class WP_Textdomain_Registry {
  20      /**
  21       * List of domains and all their language directory paths for each locale.
  22       *
  23       * @since 6.1.0
  24       *
  25       * @var array
  26       */
  27      protected $all = array();
  28  
  29      /**
  30       * List of domains and their language directory path for the current (most recent) locale.
  31       *
  32       * @since 6.1.0
  33       *
  34       * @var array
  35       */
  36      protected $current = array();
  37  
  38      /**
  39       * List of domains and their custom language directory paths.
  40       *
  41       * @see load_plugin_textdomain()
  42       * @see load_theme_textdomain()
  43       *
  44       * @since 6.1.0
  45       *
  46       * @var array
  47       */
  48      protected $custom_paths = array();
  49  
  50      /**
  51       * Holds a cached list of available .mo files to improve performance.
  52       *
  53       * @since 6.1.0
  54       * @since 6.5.0 This property is no longer used.
  55       *
  56       * @var array
  57       *
  58       * @deprecated
  59       */
  60      protected $cached_mo_files = array();
  61  
  62      /**
  63       * Holds a cached list of domains with translations to improve performance.
  64       *
  65       * @since 6.2.0
  66       *
  67       * @var string[]
  68       */
  69      protected $domains_with_translations = array();
  70  
  71      /**
  72       * Initializes the registry.
  73       *
  74       * Hooks into the {@see 'upgrader_process_complete'} filter
  75       * to invalidate MO files caches.
  76       *
  77       * @since 6.5.0
  78       */
  79  	public function init() {
  80          add_action( 'upgrader_process_complete', array( $this, 'invalidate_mo_files_cache' ), 10, 2 );
  81      }
  82  
  83      /**
  84       * Returns the languages directory path for a specific domain and locale.
  85       *
  86       * @since 6.1.0
  87       *
  88       * @param string $domain Text domain.
  89       * @param string $locale Locale.
  90       *
  91       * @return string|false Languages directory path or false if there is none available.
  92       */
  93  	public function get( $domain, $locale ) {
  94          $path = $this->all[ $domain ][ $locale ] ?? $this->get_path_from_lang_dir( $domain, $locale );
  95  
  96          /**
  97           * Filters the determined languages directory path for a specific domain and locale.
  98           *
  99           * @since 6.6.0
 100           *
 101           * @param string|false $path   Languages directory path for the given domain and locale.
 102           * @param string       $domain Text domain.
 103           * @param string       $locale Locale.
 104           */
 105          return apply_filters( 'lang_dir_for_domain', $path, $domain, $locale );
 106      }
 107  
 108      /**
 109       * Determines whether any MO file paths are available for the domain.
 110       *
 111       * This is the case if a path has been set for the current locale,
 112       * or if there is no information stored yet, in which case
 113       * {@see _load_textdomain_just_in_time()} will fetch the information first.
 114       *
 115       * @since 6.1.0
 116       *
 117       * @param string $domain Text domain.
 118       * @return bool Whether any MO file paths are available for the domain.
 119       */
 120  	public function has( $domain ) {
 121          return (
 122              isset( $this->current[ $domain ] ) ||
 123              empty( $this->all[ $domain ] ) ||
 124              in_array( $domain, $this->domains_with_translations, true )
 125          );
 126      }
 127  
 128      /**
 129       * Sets the language directory path for a specific domain and locale.
 130       *
 131       * Also sets the 'current' property for direct access
 132       * to the path for the current (most recent) locale.
 133       *
 134       * @since 6.1.0
 135       *
 136       * @param string       $domain Text domain.
 137       * @param string       $locale Locale.
 138       * @param string|false $path   Language directory path or false if there is none available.
 139       */
 140  	public function set( $domain, $locale, $path ) {
 141          $this->all[ $domain ][ $locale ] = $path ? rtrim( $path, '/' ) . '/' : false;
 142          $this->current[ $domain ]        = $this->all[ $domain ][ $locale ];
 143      }
 144  
 145      /**
 146       * Sets the custom path to the plugin's/theme's languages directory.
 147       *
 148       * Used by {@see load_plugin_textdomain()} and {@see load_theme_textdomain()}.
 149       *
 150       * @since 6.1.0
 151       *
 152       * @param string $domain Text domain.
 153       * @param string $path   Language directory path.
 154       */
 155  	public function set_custom_path( $domain, $path ) {
 156          // If just-in-time loading was triggered before, reset the entry so it can be tried again.
 157  
 158          if ( isset( $this->all[ $domain ] ) ) {
 159              $this->all[ $domain ] = array_filter( $this->all[ $domain ] );
 160          }
 161  
 162          if ( empty( $this->current[ $domain ] ) ) {
 163              unset( $this->current[ $domain ] );
 164          }
 165  
 166          $this->custom_paths[ $domain ] = rtrim( $path, '/' );
 167      }
 168  
 169      /**
 170       * Retrieves translation files from the specified path.
 171       *
 172       * Allows early retrieval through the {@see 'pre_get_mo_files_from_path'} filter to optimize
 173       * performance, especially in directories with many files.
 174       *
 175       * @since 6.5.0
 176       *
 177       * @param string $path The directory path to search for translation files.
 178       * @return array Array of translation file paths. Can contain .mo and .l10n.php files.
 179       */
 180  	public function get_language_files_from_path( $path ) {
 181          $path = rtrim( $path, '/' ) . '/';
 182  
 183          /**
 184           * Filters the translation files retrieved from a specified path before the actual lookup.
 185           *
 186           * Returning a non-null value from the filter will effectively short-circuit
 187           * the MO files lookup, returning that value instead.
 188           *
 189           * This can be useful in situations where the directory contains a large number of files
 190           * and the default glob() function becomes expensive in terms of performance.
 191           *
 192           * @since 6.5.0
 193           *
 194           * @param null|array $files List of translation files. Default null.
 195           * @param string     $path  The path from which translation files are being fetched.
 196           */
 197          $files = apply_filters( 'pre_get_language_files_from_path', null, $path );
 198  
 199          if ( null !== $files ) {
 200              return $files;
 201          }
 202  
 203          $cache_key = md5( $path );
 204          $files     = wp_cache_get( $cache_key, 'translation_files' );
 205  
 206          if ( false === $files ) {
 207              $files = glob( $path . '*.mo' );
 208              if ( false === $files ) {
 209                  $files = array();
 210              }
 211  
 212              $php_files = glob( $path . '*.l10n.php' );
 213              if ( is_array( $php_files ) ) {
 214                  $files = array_merge( $files, $php_files );
 215              }
 216  
 217              wp_cache_set( $cache_key, $files, 'translation_files', HOUR_IN_SECONDS );
 218          }
 219  
 220          return $files;
 221      }
 222  
 223      /**
 224       * Invalidate the cache for .mo files.
 225       *
 226       * This function deletes the cache entries related to .mo files when triggered
 227       * by specific actions, such as the completion of an upgrade process.
 228       *
 229       * @since 6.5.0
 230       *
 231       * @param WP_Upgrader $upgrader   Unused. WP_Upgrader instance. In other contexts this might be a
 232       *                                Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader instance.
 233       * @param array       $hook_extra {
 234       *     Array of bulk item update data.
 235       *
 236       *     @type string $action       Type of action. Default 'update'.
 237       *     @type string $type         Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'.
 238       *     @type bool   $bulk         Whether the update process is a bulk update. Default true.
 239       *     @type array  $plugins      Array of the basename paths of the plugins' main files.
 240       *     @type array  $themes       The theme slugs.
 241       *     @type array  $translations {
 242       *         Array of translations update data.
 243       *
 244       *         @type string $language The locale the translation is for.
 245       *         @type string $type     Type of translation. Accepts 'plugin', 'theme', or 'core'.
 246       *         @type string $slug     Text domain the translation is for. The slug of a theme/plugin or
 247       *                                'default' for core translations.
 248       *         @type string $version  The version of a theme, plugin, or core.
 249       *     }
 250       * }
 251       */
 252  	public function invalidate_mo_files_cache( $upgrader, $hook_extra ) {
 253          if (
 254              ! isset( $hook_extra['type'] ) ||
 255              'translation' !== $hook_extra['type'] ||
 256              array() === $hook_extra['translations']
 257          ) {
 258              return;
 259          }
 260  
 261          $translation_types = array_unique( wp_list_pluck( $hook_extra['translations'], 'type' ) );
 262  
 263          foreach ( $translation_types as $type ) {
 264              switch ( $type ) {
 265                  case 'plugin':
 266                      wp_cache_delete( md5( WP_LANG_DIR . '/plugins/' ), 'translation_files' );
 267                      break;
 268                  case 'theme':
 269                      wp_cache_delete( md5( WP_LANG_DIR . '/themes/' ), 'translation_files' );
 270                      break;
 271                  default:
 272                      wp_cache_delete( md5( WP_LANG_DIR . '/' ), 'translation_files' );
 273                      break;
 274              }
 275          }
 276      }
 277  
 278      /**
 279       * Returns possible language directory paths for a given text domain.
 280       *
 281       * @since 6.2.0
 282       *
 283       * @param string $domain Text domain.
 284       * @return string[] Array of language directory paths.
 285       */
 286  	private function get_paths_for_domain( $domain ) {
 287          $locations = array(
 288              WP_LANG_DIR . '/plugins',
 289              WP_LANG_DIR . '/themes',
 290          );
 291  
 292          if ( isset( $this->custom_paths[ $domain ] ) ) {
 293              $locations[] = $this->custom_paths[ $domain ];
 294          }
 295  
 296          return $locations;
 297      }
 298  
 299      /**
 300       * Gets the path to the language directory for the current domain and locale.
 301       *
 302       * Checks the plugins and themes language directories as well as any
 303       * custom directory set via {@see load_plugin_textdomain()} or {@see load_theme_textdomain()}.
 304       *
 305       * @since 6.1.0
 306       *
 307       * @see _get_path_to_translation_from_lang_dir()
 308       *
 309       * @param string $domain Text domain.
 310       * @param string $locale Locale.
 311       * @return string|false Language directory path or false if there is none available.
 312       */
 313  	private function get_path_from_lang_dir( $domain, $locale ) {
 314          $locations = $this->get_paths_for_domain( $domain );
 315  
 316          $found_location = false;
 317  
 318          foreach ( $locations as $location ) {
 319              $files = $this->get_language_files_from_path( $location );
 320  
 321              $mo_path  = "$location/$domain-$locale.mo";
 322              $php_path = "$location/$domain-$locale.l10n.php";
 323  
 324              foreach ( $files as $file_path ) {
 325                  if (
 326                      ! in_array( $domain, $this->domains_with_translations, true ) &&
 327                      str_starts_with( str_replace( "$location/", '', $file_path ), "$domain-" )
 328                  ) {
 329                      $this->domains_with_translations[] = $domain;
 330                  }
 331  
 332                  if ( $file_path === $mo_path || $file_path === $php_path ) {
 333                      $found_location = rtrim( $location, '/' ) . '/';
 334                      break 2;
 335                  }
 336              }
 337          }
 338  
 339          if ( $found_location ) {
 340              $this->set( $domain, $locale, $found_location );
 341  
 342              return $found_location;
 343          }
 344  
 345          /*
 346           * If no path is found for the given locale and a custom path has been set
 347           * using load_plugin_textdomain/load_theme_textdomain, use that one.
 348           */
 349          if ( isset( $this->custom_paths[ $domain ] ) ) {
 350              $fallback_location = rtrim( $this->custom_paths[ $domain ], '/' ) . '/';
 351              $this->set( $domain, $locale, $fallback_location );
 352              return $fallback_location;
 353          }
 354  
 355          $this->set( $domain, $locale, false );
 356  
 357          return false;
 358      }
 359  }


Generated : Thu Nov 21 08:20:01 2024 Cross-referenced by PHPXref