[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * I18N: WP_Translation_Controller class. 4 * 5 * @package WordPress 6 * @subpackage I18N 7 * @since 6.5.0 8 */ 9 10 /** 11 * Class WP_Translation_Controller. 12 * 13 * @since 6.5.0 14 */ 15 final class WP_Translation_Controller { 16 /** 17 * Current locale. 18 * 19 * @since 6.5.0 20 * @var string 21 */ 22 protected $current_locale = 'en_US'; 23 24 /** 25 * Map of loaded translations per locale and text domain. 26 * 27 * [ Locale => [ Textdomain => [ ..., ... ] ] ] 28 * 29 * @since 6.5.0 30 * @var array<string, array<string, WP_Translation_File[]>> 31 */ 32 protected $loaded_translations = array(); 33 34 /** 35 * List of loaded translation files. 36 * 37 * [ Filename => [ Locale => [ Textdomain => WP_Translation_File ] ] ] 38 * 39 * @since 6.5.0 40 * @var array<string, array<string, array<string, WP_Translation_File|false>>> 41 */ 42 protected $loaded_files = array(); 43 44 /** 45 * Container for the main instance of the class. 46 * 47 * @since 6.5.0 48 * @var WP_Translation_Controller|null 49 */ 50 private static $instance = null; 51 52 /** 53 * Utility method to retrieve the main instance of the class. 54 * 55 * The instance will be created if it does not exist yet. 56 * 57 * @since 6.5.0 58 * 59 * @return WP_Translation_Controller 60 */ 61 public static function get_instance(): WP_Translation_Controller { 62 if ( null === self::$instance ) { 63 self::$instance = new self(); 64 } 65 66 return self::$instance; 67 } 68 69 /** 70 * Returns the current locale. 71 * 72 * @since 6.5.0 73 * 74 * @return string Locale. 75 */ 76 public function get_locale(): string { 77 return $this->current_locale; 78 } 79 80 /** 81 * Sets the current locale. 82 * 83 * @since 6.5.0 84 * 85 * @param string $locale Locale. 86 */ 87 public function set_locale( string $locale ) { 88 $this->current_locale = $locale; 89 } 90 91 /** 92 * Loads a translation file for a given text domain. 93 * 94 * @since 6.5.0 95 * 96 * @param string $translation_file Translation file. 97 * @param string $textdomain Optional. Text domain. Default 'default'. 98 * @param string $locale Optional. Locale. Default current locale. 99 * @return bool True on success, false otherwise. 100 */ 101 public function load_file( string $translation_file, string $textdomain = 'default', ?string $locale = null ): bool { 102 if ( null === $locale ) { 103 $locale = $this->current_locale; 104 } 105 106 $translation_file = realpath( $translation_file ); 107 108 if ( false === $translation_file ) { 109 return false; 110 } 111 112 if ( 113 isset( $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] ) && 114 false !== $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] 115 ) { 116 return null === $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ]->error(); 117 } 118 119 if ( 120 isset( $this->loaded_files[ $translation_file ][ $locale ] ) && 121 array() !== $this->loaded_files[ $translation_file ][ $locale ] 122 ) { 123 $moe = reset( $this->loaded_files[ $translation_file ][ $locale ] ); 124 } else { 125 $moe = WP_Translation_File::create( $translation_file ); 126 if ( false === $moe || null !== $moe->error() ) { 127 $moe = false; 128 } 129 } 130 131 $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] = $moe; 132 133 if ( ! $moe instanceof WP_Translation_File ) { 134 return false; 135 } 136 137 if ( ! isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) { 138 $this->loaded_translations[ $locale ][ $textdomain ] = array(); 139 } 140 141 $this->loaded_translations[ $locale ][ $textdomain ][] = $moe; 142 143 return true; 144 } 145 146 /** 147 * Unloads a translation file for a given text domain. 148 * 149 * @since 6.5.0 150 * 151 * @param WP_Translation_File|string $file Translation file instance or file name. 152 * @param string $textdomain Optional. Text domain. Default 'default'. 153 * @param string $locale Optional. Locale. Defaults to all locales. 154 * @return bool True on success, false otherwise. 155 */ 156 public function unload_file( $file, string $textdomain = 'default', ?string $locale = null ): bool { 157 if ( is_string( $file ) ) { 158 $file = realpath( $file ); 159 } 160 161 if ( null !== $locale ) { 162 if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) { 163 foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $i => $moe ) { 164 if ( $file === $moe || $file === $moe->get_file() ) { 165 unset( $this->loaded_translations[ $locale ][ $textdomain ][ $i ] ); 166 unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] ); 167 return true; 168 } 169 } 170 } 171 172 return true; 173 } 174 175 foreach ( $this->loaded_translations as $l => $domains ) { 176 if ( ! isset( $domains[ $textdomain ] ) ) { 177 continue; 178 } 179 180 foreach ( $domains[ $textdomain ] as $i => $moe ) { 181 if ( $file === $moe || $file === $moe->get_file() ) { 182 unset( $this->loaded_translations[ $l ][ $textdomain ][ $i ] ); 183 unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] ); 184 return true; 185 } 186 } 187 } 188 189 return false; 190 } 191 192 /** 193 * Unloads all translation files for a given text domain. 194 * 195 * @since 6.5.0 196 * 197 * @param string $textdomain Optional. Text domain. Default 'default'. 198 * @param string $locale Optional. Locale. Defaults to all locales. 199 * @return bool True on success, false otherwise. 200 */ 201 public function unload_textdomain( string $textdomain = 'default', ?string $locale = null ): bool { 202 $unloaded = false; 203 204 if ( null !== $locale ) { 205 if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) { 206 $unloaded = true; 207 foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $moe ) { 208 unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] ); 209 } 210 } 211 212 unset( $this->loaded_translations[ $locale ][ $textdomain ] ); 213 214 return $unloaded; 215 } 216 217 foreach ( $this->loaded_translations as $l => $domains ) { 218 if ( ! isset( $domains[ $textdomain ] ) ) { 219 continue; 220 } 221 222 $unloaded = true; 223 224 foreach ( $domains[ $textdomain ] as $moe ) { 225 unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] ); 226 } 227 228 unset( $this->loaded_translations[ $l ][ $textdomain ] ); 229 } 230 231 return $unloaded; 232 } 233 234 /** 235 * Determines whether translations are loaded for a given text domain. 236 * 237 * @since 6.5.0 238 * 239 * @param string $textdomain Optional. Text domain. Default 'default'. 240 * @param string $locale Optional. Locale. Default current locale. 241 * @return bool True if there are any loaded translations, false otherwise. 242 */ 243 public function is_textdomain_loaded( string $textdomain = 'default', ?string $locale = null ): bool { 244 if ( null === $locale ) { 245 $locale = $this->current_locale; 246 } 247 248 return isset( $this->loaded_translations[ $locale ][ $textdomain ] ) && 249 array() !== $this->loaded_translations[ $locale ][ $textdomain ]; 250 } 251 252 /** 253 * Translates a singular string. 254 * 255 * @since 6.5.0 256 * 257 * @param string $text Text to translate. 258 * @param string $context Optional. Context for the string. Default empty string. 259 * @param string $textdomain Optional. Text domain. Default 'default'. 260 * @param string $locale Optional. Locale. Default current locale. 261 * @return string|false Translation on success, false otherwise. 262 */ 263 public function translate( string $text, string $context = '', string $textdomain = 'default', ?string $locale = null ) { 264 if ( '' !== $context ) { 265 $context .= "\4"; 266 } 267 268 $translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale ); 269 270 if ( false === $translation ) { 271 return false; 272 } 273 274 return $translation['entries'][0]; 275 } 276 277 /** 278 * Translates plurals. 279 * 280 * Checks both singular+plural combinations as well as just singulars, 281 * in case the translation file does not store the plural. 282 * 283 * @since 6.5.0 284 * 285 * @param array $plurals { 286 * Pair of singular and plural translations. 287 * 288 * @type string $0 Singular translation. 289 * @type string $1 Plural translation. 290 * } 291 * @param int $number Number of items. 292 * @param string $context Optional. Context for the string. Default empty string. 293 * @param string $textdomain Optional. Text domain. Default 'default'. 294 * @param string|null $locale Optional. Locale. Default current locale. 295 * @return string|false Translation on success, false otherwise. 296 */ 297 public function translate_plural( array $plurals, int $number, string $context = '', string $textdomain = 'default', ?string $locale = null ) { 298 if ( '' !== $context ) { 299 $context .= "\4"; 300 } 301 302 $text = implode( "\0", $plurals ); 303 $translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale ); 304 305 if ( false === $translation ) { 306 $text = $plurals[0]; 307 $translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale ); 308 309 if ( false === $translation ) { 310 return false; 311 } 312 } 313 314 /** @var WP_Translation_File $source */ 315 $source = $translation['source']; 316 $num = $source->get_plural_form( $number ); 317 318 // See \Translations::translate_plural(). 319 return $translation['entries'][ $num ] ?? $translation['entries'][0]; 320 } 321 322 /** 323 * Returns all existing headers for a given text domain. 324 * 325 * @since 6.5.0 326 * 327 * @param string $textdomain Optional. Text domain. Default 'default'. 328 * @return array<string, string> Headers. 329 */ 330 public function get_headers( string $textdomain = 'default' ): array { 331 if ( array() === $this->loaded_translations ) { 332 return array(); 333 } 334 335 $headers = array(); 336 337 foreach ( $this->get_files( $textdomain ) as $moe ) { 338 foreach ( $moe->headers() as $header => $value ) { 339 $headers[ $this->normalize_header( $header ) ] = $value; 340 } 341 } 342 343 return $headers; 344 } 345 346 /** 347 * Normalizes header names to be capitalized. 348 * 349 * @since 6.5.0 350 * 351 * @param string $header Header name. 352 * @return string Normalized header name. 353 */ 354 protected function normalize_header( string $header ): string { 355 $parts = explode( '-', $header ); 356 $parts = array_map( 'ucfirst', $parts ); 357 return implode( '-', $parts ); 358 } 359 360 /** 361 * Returns all entries for a given text domain. 362 * 363 * @since 6.5.0 364 * 365 * @param string $textdomain Optional. Text domain. Default 'default'. 366 * @return array<string, string> Entries. 367 */ 368 public function get_entries( string $textdomain = 'default' ): array { 369 if ( array() === $this->loaded_translations ) { 370 return array(); 371 } 372 373 $entries = array(); 374 375 foreach ( $this->get_files( $textdomain ) as $moe ) { 376 $entries = array_merge( $entries, $moe->entries() ); 377 } 378 379 return $entries; 380 } 381 382 /** 383 * Locates translation for a given string and text domain. 384 * 385 * @since 6.5.0 386 * 387 * @param string $singular Singular translation. 388 * @param string $textdomain Optional. Text domain. Default 'default'. 389 * @param string $locale Optional. Locale. Default current locale. 390 * @return array{source: WP_Translation_File, entries: string[]}|false { 391 * Translations on success, false otherwise. 392 * 393 * @type WP_Translation_File $source Translation file instance. 394 * @type string[] $entries Array of translation entries. 395 * } 396 */ 397 protected function locate_translation( string $singular, string $textdomain = 'default', ?string $locale = null ) { 398 if ( array() === $this->loaded_translations ) { 399 return false; 400 } 401 402 // Find the translation in all loaded files for this text domain. 403 foreach ( $this->get_files( $textdomain, $locale ) as $moe ) { 404 $translation = $moe->translate( $singular ); 405 if ( false !== $translation ) { 406 return array( 407 'entries' => explode( "\0", $translation ), 408 'source' => $moe, 409 ); 410 } 411 if ( null !== $moe->error() ) { 412 // Unload this file, something is wrong. 413 $this->unload_file( $moe, $textdomain, $locale ); 414 } 415 } 416 417 // Nothing could be found. 418 return false; 419 } 420 421 /** 422 * Returns all translation files for a given text domain. 423 * 424 * @since 6.5.0 425 * 426 * @param string $textdomain Optional. Text domain. Default 'default'. 427 * @param string $locale Optional. Locale. Default current locale. 428 * @return WP_Translation_File[] List of translation files. 429 */ 430 protected function get_files( string $textdomain = 'default', ?string $locale = null ): array { 431 if ( null === $locale ) { 432 $locale = $this->current_locale; 433 } 434 435 return $this->loaded_translations[ $locale ][ $textdomain ] ?? array(); 436 } 437 438 /** 439 * Returns a boolean to indicate whether a translation exists for a given string with optional text domain and locale. 440 * 441 * @since 6.7.0 442 * 443 * @param string $singular Singular translation to check. 444 * @param string $textdomain Optional. Text domain. Default 'default'. 445 * @param ?string $locale Optional. Locale. Default current locale. 446 * @return bool True if the translation exists, false otherwise. 447 */ 448 public function has_translation( string $singular, string $textdomain = 'default', ?string $locale = null ): bool { 449 if ( null === $locale ) { 450 $locale = $this->current_locale; 451 } 452 453 return false !== $this->locate_translation( $singular, $textdomain, $locale ); 454 } 455 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Tue Dec 24 08:20:01 2024 | Cross-referenced by PHPXref |