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


Generated : Thu Sep 3 08:20:25 2026 Cross-referenced by PHPXref