[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Core Translation API 4 * 5 * @package WordPress 6 * @subpackage i18n 7 * @since 1.2.0 8 */ 9 10 /** 11 * Retrieves the current locale. 12 * 13 * If the locale is set, then it will filter the locale in the {@see 'locale'} 14 * filter hook and return the value. 15 * 16 * If the locale is not set already, then the WPLANG constant is used if it is 17 * defined. Then it is filtered through the {@see 'locale'} filter hook and 18 * the value for the locale global set and the locale is returned. 19 * 20 * The process to get the locale should only be done once, but the locale will 21 * always be filtered using the {@see 'locale'} hook. 22 * 23 * @since 1.5.0 24 * 25 * @global string $locale The current locale. 26 * @global string $wp_local_package Locale code of the package. 27 * 28 * @return string The locale of the blog or from the {@see 'locale'} hook. 29 */ 30 function get_locale() { 31 global $locale, $wp_local_package; 32 33 if ( isset( $locale ) ) { 34 /** This filter is documented in wp-includes/l10n.php */ 35 return apply_filters( 'locale', $locale ); 36 } 37 38 if ( isset( $wp_local_package ) ) { 39 $locale = $wp_local_package; 40 } 41 42 // WPLANG was defined in wp-config. 43 if ( defined( 'WPLANG' ) ) { 44 $locale = WPLANG; 45 } 46 47 // If multisite, check options. 48 if ( is_multisite() ) { 49 // Don't check blog option when installing. 50 if ( wp_installing() ) { 51 $ms_locale = get_site_option( 'WPLANG' ); 52 } else { 53 $ms_locale = get_option( 'WPLANG' ); 54 if ( false === $ms_locale ) { 55 $ms_locale = get_site_option( 'WPLANG' ); 56 } 57 } 58 59 if ( false !== $ms_locale ) { 60 $locale = $ms_locale; 61 } 62 } else { 63 $db_locale = get_option( 'WPLANG' ); 64 if ( false !== $db_locale ) { 65 $locale = $db_locale; 66 } 67 } 68 69 if ( empty( $locale ) ) { 70 $locale = 'en_US'; 71 } 72 73 /** 74 * Filters the locale ID of the WordPress installation. 75 * 76 * @since 1.5.0 77 * 78 * @param string $locale The locale ID. 79 */ 80 return apply_filters( 'locale', $locale ); 81 } 82 83 /** 84 * Retrieves the locale of a user. 85 * 86 * If the user has a locale set to a non-empty string then it will be 87 * returned. Otherwise it returns the locale of get_locale(). 88 * 89 * @since 4.7.0 90 * 91 * @param int|WP_User $user User's ID or a WP_User object. Defaults to current user. 92 * @return string The locale of the user. 93 */ 94 function get_user_locale( $user = 0 ) { 95 $user_object = false; 96 97 if ( 0 === $user && function_exists( 'wp_get_current_user' ) ) { 98 $user_object = wp_get_current_user(); 99 } elseif ( $user instanceof WP_User ) { 100 $user_object = $user; 101 } elseif ( $user && is_numeric( $user ) ) { 102 $user_object = get_user_by( 'id', $user ); 103 } 104 105 if ( ! $user_object ) { 106 return get_locale(); 107 } 108 109 $locale = $user_object->locale; 110 111 return $locale ? $locale : get_locale(); 112 } 113 114 /** 115 * Determines the current locale desired for the request. 116 * 117 * @since 5.0.0 118 * 119 * @global string $pagenow The filename of the current screen. 120 * 121 * @return string The determined locale. 122 */ 123 function determine_locale() { 124 /** 125 * Filters the locale for the current request prior to the default determination process. 126 * 127 * Using this filter allows to override the default logic, effectively short-circuiting the function. 128 * 129 * @since 5.0.0 130 * 131 * @param string|null $locale The locale to return and short-circuit. Default null. 132 */ 133 $determined_locale = apply_filters( 'pre_determine_locale', null ); 134 135 if ( $determined_locale && is_string( $determined_locale ) ) { 136 return $determined_locale; 137 } 138 139 if ( 140 isset( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] && 141 ( ! empty( $_GET['wp_lang'] ) || ! empty( $_COOKIE['wp_lang'] ) ) 142 ) { 143 if ( ! empty( $_GET['wp_lang'] ) ) { 144 $determined_locale = sanitize_locale_name( $_GET['wp_lang'] ); 145 } else { 146 $determined_locale = sanitize_locale_name( $_COOKIE['wp_lang'] ); 147 } 148 } else if ( 149 ( isset( $_GET['_locale'] ) && 'user' === $_GET['_locale'] && wp_is_json_request() ) || 150 is_admin() 151 ) { 152 $determined_locale = get_user_locale(); 153 } else { 154 $determined_locale = get_locale(); 155 } 156 157 /** 158 * Filters the locale for the current request. 159 * 160 * @since 5.0.0 161 * 162 * @param string $locale The locale. 163 */ 164 return apply_filters( 'determine_locale', $determined_locale ); 165 } 166 167 /** 168 * Retrieves the translation of $text. 169 * 170 * If there is no translation, or the text domain isn't loaded, the original text is returned. 171 * 172 * *Note:* Don't use translate() directly, use __() or related functions. 173 * 174 * @since 2.2.0 175 * @since 5.5.0 Introduced `gettext-{$domain}` filter. 176 * 177 * @param string $text Text to translate. 178 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 179 * Default 'default'. 180 * @return string Translated text. 181 */ 182 function translate( $text, $domain = 'default' ) { 183 $translations = get_translations_for_domain( $domain ); 184 $translation = $translations->translate( $text ); 185 186 /** 187 * Filters text with its translation. 188 * 189 * @since 2.0.11 190 * 191 * @param string $translation Translated text. 192 * @param string $text Text to translate. 193 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 194 */ 195 $translation = apply_filters( 'gettext', $translation, $text, $domain ); 196 197 /** 198 * Filters text with its translation for a domain. 199 * 200 * The dynamic portion of the hook name, `$domain`, refers to the text domain. 201 * 202 * @since 5.5.0 203 * 204 * @param string $translation Translated text. 205 * @param string $text Text to translate. 206 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 207 */ 208 $translation = apply_filters( "gettext_{$domain}", $translation, $text, $domain ); 209 210 return $translation; 211 } 212 213 /** 214 * Removes last item on a pipe-delimited string. 215 * 216 * Meant for removing the last item in a string, such as 'Role name|User role'. The original 217 * string will be returned if no pipe '|' characters are found in the string. 218 * 219 * @since 2.8.0 220 * 221 * @param string $text A pipe-delimited string. 222 * @return string Either $text or everything before the last pipe. 223 */ 224 function before_last_bar( $text ) { 225 $last_bar = strrpos( $text, '|' ); 226 if ( false === $last_bar ) { 227 return $text; 228 } else { 229 return substr( $text, 0, $last_bar ); 230 } 231 } 232 233 /** 234 * Retrieves the translation of $text in the context defined in $context. 235 * 236 * If there is no translation, or the text domain isn't loaded, the original text is returned. 237 * 238 * *Note:* Don't use translate_with_gettext_context() directly, use _x() or related functions. 239 * 240 * @since 2.8.0 241 * @since 5.5.0 Introduced `gettext_with_context-{$domain}` filter. 242 * 243 * @param string $text Text to translate. 244 * @param string $context Context information for the translators. 245 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 246 * Default 'default'. 247 * @return string Translated text on success, original text on failure. 248 */ 249 function translate_with_gettext_context( $text, $context, $domain = 'default' ) { 250 $translations = get_translations_for_domain( $domain ); 251 $translation = $translations->translate( $text, $context ); 252 253 /** 254 * Filters text with its translation based on context information. 255 * 256 * @since 2.8.0 257 * 258 * @param string $translation Translated text. 259 * @param string $text Text to translate. 260 * @param string $context Context information for the translators. 261 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 262 */ 263 $translation = apply_filters( 'gettext_with_context', $translation, $text, $context, $domain ); 264 265 /** 266 * Filters text with its translation based on context information for a domain. 267 * 268 * The dynamic portion of the hook name, `$domain`, refers to the text domain. 269 * 270 * @since 5.5.0 271 * 272 * @param string $translation Translated text. 273 * @param string $text Text to translate. 274 * @param string $context Context information for the translators. 275 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 276 */ 277 $translation = apply_filters( "gettext_with_context_{$domain}", $translation, $text, $context, $domain ); 278 279 return $translation; 280 } 281 282 /** 283 * Retrieves the translation of $text. 284 * 285 * If there is no translation, or the text domain isn't loaded, the original text is returned. 286 * 287 * @since 2.1.0 288 * 289 * @param string $text Text to translate. 290 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 291 * Default 'default'. 292 * @return string Translated text. 293 */ 294 function __( $text, $domain = 'default' ) { 295 return translate( $text, $domain ); 296 } 297 298 /** 299 * Retrieves the translation of $text and escapes it for safe use in an attribute. 300 * 301 * If there is no translation, or the text domain isn't loaded, the original text is returned. 302 * 303 * @since 2.8.0 304 * 305 * @param string $text Text to translate. 306 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 307 * Default 'default'. 308 * @return string Translated text on success, original text on failure. 309 */ 310 function esc_attr__( $text, $domain = 'default' ) { 311 return esc_attr( translate( $text, $domain ) ); 312 } 313 314 /** 315 * Retrieves the translation of $text and escapes it for safe use in HTML output. 316 * 317 * If there is no translation, or the text domain isn't loaded, the original text 318 * is escaped and returned. 319 * 320 * @since 2.8.0 321 * 322 * @param string $text Text to translate. 323 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 324 * Default 'default'. 325 * @return string Translated text. 326 */ 327 function esc_html__( $text, $domain = 'default' ) { 328 return esc_html( translate( $text, $domain ) ); 329 } 330 331 /** 332 * Displays translated text. 333 * 334 * @since 1.2.0 335 * 336 * @param string $text Text to translate. 337 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 338 * Default 'default'. 339 */ 340 function _e( $text, $domain = 'default' ) { 341 echo translate( $text, $domain ); 342 } 343 344 /** 345 * Displays translated text that has been escaped for safe use in an attribute. 346 * 347 * Encodes `< > & " '` (less than, greater than, ampersand, double quote, single quote). 348 * Will never double encode entities. 349 * 350 * If you need the value for use in PHP, use esc_attr__(). 351 * 352 * @since 2.8.0 353 * 354 * @param string $text Text to translate. 355 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 356 * Default 'default'. 357 */ 358 function esc_attr_e( $text, $domain = 'default' ) { 359 echo esc_attr( translate( $text, $domain ) ); 360 } 361 362 /** 363 * Displays translated text that has been escaped for safe use in HTML output. 364 * 365 * If there is no translation, or the text domain isn't loaded, the original text 366 * is escaped and displayed. 367 * 368 * If you need the value for use in PHP, use esc_html__(). 369 * 370 * @since 2.8.0 371 * 372 * @param string $text Text to translate. 373 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 374 * Default 'default'. 375 */ 376 function esc_html_e( $text, $domain = 'default' ) { 377 echo esc_html( translate( $text, $domain ) ); 378 } 379 380 /** 381 * Retrieves translated string with gettext context. 382 * 383 * Quite a few times, there will be collisions with similar translatable text 384 * found in more than two places, but with different translated context. 385 * 386 * By including the context in the pot file, translators can translate the two 387 * strings differently. 388 * 389 * @since 2.8.0 390 * 391 * @param string $text Text to translate. 392 * @param string $context Context information for the translators. 393 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 394 * Default 'default'. 395 * @return string Translated context string without pipe. 396 */ 397 function _x( $text, $context, $domain = 'default' ) { 398 return translate_with_gettext_context( $text, $context, $domain ); 399 } 400 401 /** 402 * Displays translated string with gettext context. 403 * 404 * @since 3.0.0 405 * 406 * @param string $text Text to translate. 407 * @param string $context Context information for the translators. 408 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 409 * Default 'default'. 410 */ 411 function _ex( $text, $context, $domain = 'default' ) { 412 echo _x( $text, $context, $domain ); 413 } 414 415 /** 416 * Translates string with gettext context, and escapes it for safe use in an attribute. 417 * 418 * If there is no translation, or the text domain isn't loaded, the original text 419 * is escaped and returned. 420 * 421 * @since 2.8.0 422 * 423 * @param string $text Text to translate. 424 * @param string $context Context information for the translators. 425 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 426 * Default 'default'. 427 * @return string Translated text. 428 */ 429 function esc_attr_x( $text, $context, $domain = 'default' ) { 430 return esc_attr( translate_with_gettext_context( $text, $context, $domain ) ); 431 } 432 433 /** 434 * Translates string with gettext context, and escapes it for safe use in HTML output. 435 * 436 * If there is no translation, or the text domain isn't loaded, the original text 437 * is escaped and returned. 438 * 439 * @since 2.9.0 440 * 441 * @param string $text Text to translate. 442 * @param string $context Context information for the translators. 443 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 444 * Default 'default'. 445 * @return string Translated text. 446 */ 447 function esc_html_x( $text, $context, $domain = 'default' ) { 448 return esc_html( translate_with_gettext_context( $text, $context, $domain ) ); 449 } 450 451 /** 452 * Translates and retrieves the singular or plural form based on the supplied number. 453 * 454 * Used when you want to use the appropriate form of a string based on whether a 455 * number is singular or plural. 456 * 457 * Example: 458 * 459 * printf( _n( '%s person', '%s people', $count, 'text-domain' ), number_format_i18n( $count ) ); 460 * 461 * @since 2.8.0 462 * @since 5.5.0 Introduced `ngettext-{$domain}` filter. 463 * 464 * @param string $single The text to be used if the number is singular. 465 * @param string $plural The text to be used if the number is plural. 466 * @param int $number The number to compare against to use either the singular or plural form. 467 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 468 * Default 'default'. 469 * @return string The translated singular or plural form. 470 */ 471 function _n( $single, $plural, $number, $domain = 'default' ) { 472 $translations = get_translations_for_domain( $domain ); 473 $translation = $translations->translate_plural( $single, $plural, $number ); 474 475 /** 476 * Filters the singular or plural form of a string. 477 * 478 * @since 2.2.0 479 * 480 * @param string $translation Translated text. 481 * @param string $single The text to be used if the number is singular. 482 * @param string $plural The text to be used if the number is plural. 483 * @param int $number The number to compare against to use either the singular or plural form. 484 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 485 */ 486 $translation = apply_filters( 'ngettext', $translation, $single, $plural, $number, $domain ); 487 488 /** 489 * Filters the singular or plural form of a string for a domain. 490 * 491 * The dynamic portion of the hook name, `$domain`, refers to the text domain. 492 * 493 * @since 5.5.0 494 * 495 * @param string $translation Translated text. 496 * @param string $single The text to be used if the number is singular. 497 * @param string $plural The text to be used if the number is plural. 498 * @param int $number The number to compare against to use either the singular or plural form. 499 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 500 */ 501 $translation = apply_filters( "ngettext_{$domain}", $translation, $single, $plural, $number, $domain ); 502 503 return $translation; 504 } 505 506 /** 507 * Translates and retrieves the singular or plural form based on the supplied number, with gettext context. 508 * 509 * This is a hybrid of _n() and _x(). It supports context and plurals. 510 * 511 * Used when you want to use the appropriate form of a string with context based on whether a 512 * number is singular or plural. 513 * 514 * Example of a generic phrase which is disambiguated via the context parameter: 515 * 516 * printf( _nx( '%s group', '%s groups', $people, 'group of people', 'text-domain' ), number_format_i18n( $people ) ); 517 * printf( _nx( '%s group', '%s groups', $animals, 'group of animals', 'text-domain' ), number_format_i18n( $animals ) ); 518 * 519 * @since 2.8.0 520 * @since 5.5.0 Introduced `ngettext_with_context-{$domain}` filter. 521 * 522 * @param string $single The text to be used if the number is singular. 523 * @param string $plural The text to be used if the number is plural. 524 * @param int $number The number to compare against to use either the singular or plural form. 525 * @param string $context Context information for the translators. 526 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 527 * Default 'default'. 528 * @return string The translated singular or plural form. 529 */ 530 function _nx( $single, $plural, $number, $context, $domain = 'default' ) { 531 $translations = get_translations_for_domain( $domain ); 532 $translation = $translations->translate_plural( $single, $plural, $number, $context ); 533 534 /** 535 * Filters the singular or plural form of a string with gettext context. 536 * 537 * @since 2.8.0 538 * 539 * @param string $translation Translated text. 540 * @param string $single The text to be used if the number is singular. 541 * @param string $plural The text to be used if the number is plural. 542 * @param int $number The number to compare against to use either the singular or plural form. 543 * @param string $context Context information for the translators. 544 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 545 */ 546 $translation = apply_filters( 'ngettext_with_context', $translation, $single, $plural, $number, $context, $domain ); 547 548 /** 549 * Filters the singular or plural form of a string with gettext context for a domain. 550 * 551 * The dynamic portion of the hook name, `$domain`, refers to the text domain. 552 * 553 * @since 5.5.0 554 * 555 * @param string $translation Translated text. 556 * @param string $single The text to be used if the number is singular. 557 * @param string $plural The text to be used if the number is plural. 558 * @param int $number The number to compare against to use either the singular or plural form. 559 * @param string $context Context information for the translators. 560 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 561 */ 562 $translation = apply_filters( "ngettext_with_context_{$domain}", $translation, $single, $plural, $number, $context, $domain ); 563 564 return $translation; 565 } 566 567 /** 568 * Registers plural strings in POT file, but does not translate them. 569 * 570 * Used when you want to keep structures with translatable plural 571 * strings and use them later when the number is known. 572 * 573 * Example: 574 * 575 * $message = _n_noop( '%s post', '%s posts', 'text-domain' ); 576 * ... 577 * printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) ); 578 * 579 * @since 2.5.0 580 * 581 * @param string $singular Singular form to be localized. 582 * @param string $plural Plural form to be localized. 583 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 584 * Default null. 585 * @return array { 586 * Array of translation information for the strings. 587 * 588 * @type string $0 Singular form to be localized. No longer used. 589 * @type string $1 Plural form to be localized. No longer used. 590 * @type string $singular Singular form to be localized. 591 * @type string $plural Plural form to be localized. 592 * @type null $context Context information for the translators. 593 * @type string|null $domain Text domain. 594 * } 595 */ 596 function _n_noop( $singular, $plural, $domain = null ) { 597 return array( 598 0 => $singular, 599 1 => $plural, 600 'singular' => $singular, 601 'plural' => $plural, 602 'context' => null, 603 'domain' => $domain, 604 ); 605 } 606 607 /** 608 * Registers plural strings with gettext context in POT file, but does not translate them. 609 * 610 * Used when you want to keep structures with translatable plural 611 * strings and use them later when the number is known. 612 * 613 * Example of a generic phrase which is disambiguated via the context parameter: 614 * 615 * $messages = array( 616 * 'people' => _nx_noop( '%s group', '%s groups', 'people', 'text-domain' ), 617 * 'animals' => _nx_noop( '%s group', '%s groups', 'animals', 'text-domain' ), 618 * ); 619 * ... 620 * $message = $messages[ $type ]; 621 * printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) ); 622 * 623 * @since 2.8.0 624 * 625 * @param string $singular Singular form to be localized. 626 * @param string $plural Plural form to be localized. 627 * @param string $context Context information for the translators. 628 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 629 * Default null. 630 * @return array { 631 * Array of translation information for the strings. 632 * 633 * @type string $0 Singular form to be localized. No longer used. 634 * @type string $1 Plural form to be localized. No longer used. 635 * @type string $2 Context information for the translators. No longer used. 636 * @type string $singular Singular form to be localized. 637 * @type string $plural Plural form to be localized. 638 * @type string $context Context information for the translators. 639 * @type string|null $domain Text domain. 640 * } 641 */ 642 function _nx_noop( $singular, $plural, $context, $domain = null ) { 643 return array( 644 0 => $singular, 645 1 => $plural, 646 2 => $context, 647 'singular' => $singular, 648 'plural' => $plural, 649 'context' => $context, 650 'domain' => $domain, 651 ); 652 } 653 654 /** 655 * Translates and returns the singular or plural form of a string that's been registered 656 * with _n_noop() or _nx_noop(). 657 * 658 * Used when you want to use a translatable plural string once the number is known. 659 * 660 * Example: 661 * 662 * $message = _n_noop( '%s post', '%s posts', 'text-domain' ); 663 * ... 664 * printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) ); 665 * 666 * @since 3.1.0 667 * 668 * @param array $nooped_plural { 669 * Array that is usually a return value from _n_noop() or _nx_noop(). 670 * 671 * @type string $singular Singular form to be localized. 672 * @type string $plural Plural form to be localized. 673 * @type string|null $context Context information for the translators. 674 * @type string|null $domain Text domain. 675 * } 676 * @param int $count Number of objects. 677 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. If $nooped_plural contains 678 * a text domain passed to _n_noop() or _nx_noop(), it will override this value. Default 'default'. 679 * @return string Either $singular or $plural translated text. 680 */ 681 function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) { 682 if ( $nooped_plural['domain'] ) { 683 $domain = $nooped_plural['domain']; 684 } 685 686 if ( $nooped_plural['context'] ) { 687 return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain ); 688 } else { 689 return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain ); 690 } 691 } 692 693 /** 694 * Loads a .mo file into the text domain $domain. 695 * 696 * If the text domain already exists, the translations will be merged. If both 697 * sets have the same string, the translation from the original value will be taken. 698 * 699 * On success, the .mo file will be placed in the $l10n global by $domain 700 * and will be a MO object. 701 * 702 * @since 1.5.0 703 * @since 6.1.0 Added the `$locale` parameter. 704 * 705 * @global MO[] $l10n An array of all currently loaded text domains. 706 * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again. 707 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry. 708 * 709 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 710 * @param string $mofile Path to the .mo file. 711 * @param string $locale Optional. Locale. Default is the current locale. 712 * @return bool True on success, false on failure. 713 */ 714 function load_textdomain( $domain, $mofile, $locale = null ) { 715 /** @var WP_Textdomain_Registry $wp_textdomain_registry */ 716 global $l10n, $l10n_unloaded, $wp_textdomain_registry; 717 718 $l10n_unloaded = (array) $l10n_unloaded; 719 720 /** 721 * Filters whether to override the .mo file loading. 722 * 723 * @since 2.9.0 724 * @since 6.2.0 Added the `$locale` parameter. 725 * 726 * @param bool $override Whether to override the .mo file loading. Default false. 727 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 728 * @param string $mofile Path to the MO file. 729 * @param string|null $locale Locale. 730 */ 731 $plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile, $locale ); 732 733 if ( true === (bool) $plugin_override ) { 734 unset( $l10n_unloaded[ $domain ] ); 735 736 return true; 737 } 738 739 /** 740 * Fires before the MO translation file is loaded. 741 * 742 * @since 2.9.0 743 * 744 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 745 * @param string $mofile Path to the .mo file. 746 */ 747 do_action( 'load_textdomain', $domain, $mofile ); 748 749 /** 750 * Filters MO file path for loading translations for a specific text domain. 751 * 752 * @since 2.9.0 753 * 754 * @param string $mofile Path to the MO file. 755 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 756 */ 757 $mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain ); 758 759 if ( ! is_readable( $mofile ) ) { 760 return false; 761 } 762 763 if ( ! $locale ) { 764 $locale = determine_locale(); 765 } 766 767 $mo = new MO(); 768 if ( ! $mo->import_from_file( $mofile ) ) { 769 $wp_textdomain_registry->set( $domain, $locale, false ); 770 771 return false; 772 } 773 774 if ( isset( $l10n[ $domain ] ) ) { 775 $mo->merge_with( $l10n[ $domain ] ); 776 } 777 778 unset( $l10n_unloaded[ $domain ] ); 779 780 $l10n[ $domain ] = &$mo; 781 782 $wp_textdomain_registry->set( $domain, $locale, dirname( $mofile ) ); 783 784 return true; 785 } 786 787 /** 788 * Unloads translations for a text domain. 789 * 790 * @since 3.0.0 791 * @since 6.1.0 Added the `$reloadable` parameter. 792 * 793 * @global MO[] $l10n An array of all currently loaded text domains. 794 * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again. 795 * 796 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 797 * @param bool $reloadable Whether the text domain can be loaded just-in-time again. 798 * @return bool Whether textdomain was unloaded. 799 */ 800 function unload_textdomain( $domain, $reloadable = false ) { 801 global $l10n, $l10n_unloaded; 802 803 $l10n_unloaded = (array) $l10n_unloaded; 804 805 /** 806 * Filters whether to override the text domain unloading. 807 * 808 * @since 3.0.0 809 * @since 6.1.0 Added the `$reloadable` parameter. 810 * 811 * @param bool $override Whether to override the text domain unloading. Default false. 812 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 813 * @param bool $reloadable Whether the text domain can be loaded just-in-time again. 814 */ 815 $plugin_override = apply_filters( 'override_unload_textdomain', false, $domain, $reloadable ); 816 817 if ( $plugin_override ) { 818 if ( ! $reloadable ) { 819 $l10n_unloaded[ $domain ] = true; 820 } 821 822 return true; 823 } 824 825 /** 826 * Fires before the text domain is unloaded. 827 * 828 * @since 3.0.0 829 * @since 6.1.0 Added the `$reloadable` parameter. 830 * 831 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 832 * @param bool $reloadable Whether the text domain can be loaded just-in-time again. 833 */ 834 do_action( 'unload_textdomain', $domain, $reloadable ); 835 836 if ( isset( $l10n[ $domain ] ) ) { 837 if ( $l10n[ $domain ] instanceof NOOP_Translations ) { 838 unset( $l10n[ $domain ] ); 839 840 return false; 841 } 842 843 unset( $l10n[ $domain ] ); 844 845 if ( ! $reloadable ) { 846 $l10n_unloaded[ $domain ] = true; 847 } 848 849 return true; 850 } 851 852 return false; 853 } 854 855 /** 856 * Loads default translated strings based on locale. 857 * 858 * Loads the .mo file in WP_LANG_DIR constant path from WordPress root. 859 * The translated (.mo) file is named based on the locale. 860 * 861 * @see load_textdomain() 862 * 863 * @since 1.5.0 864 * 865 * @param string $locale Optional. Locale to load. Default is the value of get_locale(). 866 * @return bool Whether the textdomain was loaded. 867 */ 868 function load_default_textdomain( $locale = null ) { 869 if ( null === $locale ) { 870 $locale = determine_locale(); 871 } 872 873 // Unload previously loaded strings so we can switch translations. 874 unload_textdomain( 'default' ); 875 876 $return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo", $locale ); 877 878 if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) { 879 load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo", $locale ); 880 return $return; 881 } 882 883 if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) { 884 load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo", $locale ); 885 } 886 887 if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) { 888 load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo", $locale ); 889 } 890 891 return $return; 892 } 893 894 /** 895 * Loads a plugin's translated strings. 896 * 897 * If the path is not given then it will be the root of the plugin directory. 898 * 899 * The .mo file should be named based on the text domain with a dash, and then the locale exactly. 900 * 901 * @since 1.5.0 902 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first. 903 * 904 * @param string $domain Unique identifier for retrieving translated strings 905 * @param string|false $deprecated Optional. Deprecated. Use the $plugin_rel_path parameter instead. 906 * Default false. 907 * @param string|false $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides. 908 * Default false. 909 * @return bool True when textdomain is successfully loaded, false otherwise. 910 */ 911 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) { 912 /** @var WP_Textdomain_Registry $wp_textdomain_registry */ 913 global $wp_textdomain_registry; 914 915 /** 916 * Filters a plugin's locale. 917 * 918 * @since 3.0.0 919 * 920 * @param string $locale The plugin's current locale. 921 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 922 */ 923 $locale = apply_filters( 'plugin_locale', determine_locale(), $domain ); 924 925 $mofile = $domain . '-' . $locale . '.mo'; 926 927 // Try to load from the languages directory first. 928 if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) { 929 return true; 930 } 931 932 if ( false !== $plugin_rel_path ) { 933 $path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' ); 934 } elseif ( false !== $deprecated ) { 935 _deprecated_argument( __FUNCTION__, '2.7.0' ); 936 $path = ABSPATH . trim( $deprecated, '/' ); 937 } else { 938 $path = WP_PLUGIN_DIR; 939 } 940 941 $wp_textdomain_registry->set_custom_path( $domain, $path ); 942 943 return load_textdomain( $domain, $path . '/' . $mofile, $locale ); 944 } 945 946 /** 947 * Loads the translated strings for a plugin residing in the mu-plugins directory. 948 * 949 * @since 3.0.0 950 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first. 951 * 952 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry. 953 * 954 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 955 * @param string $mu_plugin_rel_path Optional. Relative to `WPMU_PLUGIN_DIR` directory in which the .mo 956 * file resides. Default empty string. 957 * @return bool True when textdomain is successfully loaded, false otherwise. 958 */ 959 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) { 960 /** @var WP_Textdomain_Registry $wp_textdomain_registry */ 961 global $wp_textdomain_registry; 962 963 /** This filter is documented in wp-includes/l10n.php */ 964 $locale = apply_filters( 'plugin_locale', determine_locale(), $domain ); 965 966 $mofile = $domain . '-' . $locale . '.mo'; 967 968 // Try to load from the languages directory first. 969 if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) { 970 return true; 971 } 972 973 $path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' ); 974 975 $wp_textdomain_registry->set_custom_path( $domain, $path ); 976 977 return load_textdomain( $domain, $path . '/' . $mofile, $locale ); 978 } 979 980 /** 981 * Loads the theme's translated strings. 982 * 983 * If the current locale exists as a .mo file in the theme's root directory, it 984 * will be included in the translated strings by the $domain. 985 * 986 * The .mo files must be named based on the locale exactly. 987 * 988 * @since 1.5.0 989 * @since 4.6.0 The function now tries to load the .mo file from the languages directory first. 990 * 991 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry. 992 * 993 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 994 * @param string|false $path Optional. Path to the directory containing the .mo file. 995 * Default false. 996 * @return bool True when textdomain is successfully loaded, false otherwise. 997 */ 998 function load_theme_textdomain( $domain, $path = false ) { 999 /** @var WP_Textdomain_Registry $wp_textdomain_registry */ 1000 global $wp_textdomain_registry; 1001 1002 /** 1003 * Filters a theme's locale. 1004 * 1005 * @since 3.0.0 1006 * 1007 * @param string $locale The theme's current locale. 1008 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 1009 */ 1010 $locale = apply_filters( 'theme_locale', determine_locale(), $domain ); 1011 1012 $mofile = $domain . '-' . $locale . '.mo'; 1013 1014 // Try to load from the languages directory first. 1015 if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile, $locale ) ) { 1016 return true; 1017 } 1018 1019 if ( ! $path ) { 1020 $path = get_template_directory(); 1021 } 1022 1023 $wp_textdomain_registry->set_custom_path( $domain, $path ); 1024 1025 return load_textdomain( $domain, $path . '/' . $locale . '.mo', $locale ); 1026 } 1027 1028 /** 1029 * Loads the child theme's translated strings. 1030 * 1031 * If the current locale exists as a .mo file in the child theme's 1032 * root directory, it will be included in the translated strings by the $domain. 1033 * 1034 * The .mo files must be named based on the locale exactly. 1035 * 1036 * @since 2.9.0 1037 * 1038 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 1039 * @param string|false $path Optional. Path to the directory containing the .mo file. 1040 * Default false. 1041 * @return bool True when the theme textdomain is successfully loaded, false otherwise. 1042 */ 1043 function load_child_theme_textdomain( $domain, $path = false ) { 1044 if ( ! $path ) { 1045 $path = get_stylesheet_directory(); 1046 } 1047 return load_theme_textdomain( $domain, $path ); 1048 } 1049 1050 /** 1051 * Loads the script translated strings. 1052 * 1053 * @since 5.0.0 1054 * @since 5.0.2 Uses load_script_translations() to load translation data. 1055 * @since 5.1.0 The `$domain` parameter was made optional. 1056 * 1057 * @see WP_Scripts::set_translations() 1058 * 1059 * @param string $handle Name of the script to register a translation domain to. 1060 * @param string $domain Optional. Text domain. Default 'default'. 1061 * @param string $path Optional. The full file path to the directory containing translation files. 1062 * @return string|false The translated strings in JSON encoding on success, 1063 * false if the script textdomain could not be loaded. 1064 */ 1065 function load_script_textdomain( $handle, $domain = 'default', $path = '' ) { 1066 $wp_scripts = wp_scripts(); 1067 1068 if ( ! isset( $wp_scripts->registered[ $handle ] ) ) { 1069 return false; 1070 } 1071 1072 $path = untrailingslashit( $path ); 1073 $locale = determine_locale(); 1074 1075 // If a path was given and the handle file exists simply return it. 1076 $file_base = 'default' === $domain ? $locale : $domain . '-' . $locale; 1077 $handle_filename = $file_base . '-' . $handle . '.json'; 1078 1079 if ( $path ) { 1080 $translations = load_script_translations( $path . '/' . $handle_filename, $handle, $domain ); 1081 1082 if ( $translations ) { 1083 return $translations; 1084 } 1085 } 1086 1087 $src = $wp_scripts->registered[ $handle ]->src; 1088 1089 if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $wp_scripts->content_url && str_starts_with( $src, $wp_scripts->content_url ) ) ) { 1090 $src = $wp_scripts->base_url . $src; 1091 } 1092 1093 $relative = false; 1094 $languages_path = WP_LANG_DIR; 1095 1096 $src_url = wp_parse_url( $src ); 1097 $content_url = wp_parse_url( content_url() ); 1098 $plugins_url = wp_parse_url( plugins_url() ); 1099 $site_url = wp_parse_url( site_url() ); 1100 1101 // If the host is the same or it's a relative URL. 1102 if ( 1103 ( ! isset( $content_url['path'] ) || str_starts_with( $src_url['path'], $content_url['path'] ) ) && 1104 ( ! isset( $src_url['host'] ) || ! isset( $content_url['host'] ) || $src_url['host'] === $content_url['host'] ) 1105 ) { 1106 // Make the src relative the specific plugin or theme. 1107 if ( isset( $content_url['path'] ) ) { 1108 $relative = substr( $src_url['path'], strlen( $content_url['path'] ) ); 1109 } else { 1110 $relative = $src_url['path']; 1111 } 1112 $relative = trim( $relative, '/' ); 1113 $relative = explode( '/', $relative ); 1114 1115 $languages_path = WP_LANG_DIR . '/' . $relative[0]; 1116 1117 $relative = array_slice( $relative, 2 ); // Remove plugins/<plugin name> or themes/<theme name>. 1118 $relative = implode( '/', $relative ); 1119 } elseif ( 1120 ( ! isset( $plugins_url['path'] ) || str_starts_with( $src_url['path'], $plugins_url['path'] ) ) && 1121 ( ! isset( $src_url['host'] ) || ! isset( $plugins_url['host'] ) || $src_url['host'] === $plugins_url['host'] ) 1122 ) { 1123 // Make the src relative the specific plugin. 1124 if ( isset( $plugins_url['path'] ) ) { 1125 $relative = substr( $src_url['path'], strlen( $plugins_url['path'] ) ); 1126 } else { 1127 $relative = $src_url['path']; 1128 } 1129 $relative = trim( $relative, '/' ); 1130 $relative = explode( '/', $relative ); 1131 1132 $languages_path = WP_LANG_DIR . '/plugins'; 1133 1134 $relative = array_slice( $relative, 1 ); // Remove <plugin name>. 1135 $relative = implode( '/', $relative ); 1136 } elseif ( ! isset( $src_url['host'] ) || ! isset( $site_url['host'] ) || $src_url['host'] === $site_url['host'] ) { 1137 if ( ! isset( $site_url['path'] ) ) { 1138 $relative = trim( $src_url['path'], '/' ); 1139 } elseif ( str_starts_with( $src_url['path'], trailingslashit( $site_url['path'] ) ) ) { 1140 // Make the src relative to the WP root. 1141 $relative = substr( $src_url['path'], strlen( $site_url['path'] ) ); 1142 $relative = trim( $relative, '/' ); 1143 } 1144 } 1145 1146 /** 1147 * Filters the relative path of scripts used for finding translation files. 1148 * 1149 * @since 5.0.2 1150 * 1151 * @param string|false $relative The relative path of the script. False if it could not be determined. 1152 * @param string $src The full source URL of the script. 1153 */ 1154 $relative = apply_filters( 'load_script_textdomain_relative_path', $relative, $src ); 1155 1156 // If the source is not from WP. 1157 if ( false === $relative ) { 1158 return load_script_translations( false, $handle, $domain ); 1159 } 1160 1161 // Translations are always based on the unminified filename. 1162 if ( substr( $relative, -7 ) === '.min.js' ) { 1163 $relative = substr( $relative, 0, -7 ) . '.js'; 1164 } 1165 1166 $md5_filename = $file_base . '-' . md5( $relative ) . '.json'; 1167 1168 if ( $path ) { 1169 $translations = load_script_translations( $path . '/' . $md5_filename, $handle, $domain ); 1170 1171 if ( $translations ) { 1172 return $translations; 1173 } 1174 } 1175 1176 $translations = load_script_translations( $languages_path . '/' . $md5_filename, $handle, $domain ); 1177 1178 if ( $translations ) { 1179 return $translations; 1180 } 1181 1182 return load_script_translations( false, $handle, $domain ); 1183 } 1184 1185 /** 1186 * Loads the translation data for the given script handle and text domain. 1187 * 1188 * @since 5.0.2 1189 * 1190 * @param string|false $file Path to the translation file to load. False if there isn't one. 1191 * @param string $handle Name of the script to register a translation domain to. 1192 * @param string $domain The text domain. 1193 * @return string|false The JSON-encoded translated strings for the given script handle and text domain. 1194 * False if there are none. 1195 */ 1196 function load_script_translations( $file, $handle, $domain ) { 1197 /** 1198 * Pre-filters script translations for the given file, script handle and text domain. 1199 * 1200 * Returning a non-null value allows to override the default logic, effectively short-circuiting the function. 1201 * 1202 * @since 5.0.2 1203 * 1204 * @param string|false|null $translations JSON-encoded translation data. Default null. 1205 * @param string|false $file Path to the translation file to load. False if there isn't one. 1206 * @param string $handle Name of the script to register a translation domain to. 1207 * @param string $domain The text domain. 1208 */ 1209 $translations = apply_filters( 'pre_load_script_translations', null, $file, $handle, $domain ); 1210 1211 if ( null !== $translations ) { 1212 return $translations; 1213 } 1214 1215 /** 1216 * Filters the file path for loading script translations for the given script handle and text domain. 1217 * 1218 * @since 5.0.2 1219 * 1220 * @param string|false $file Path to the translation file to load. False if there isn't one. 1221 * @param string $handle Name of the script to register a translation domain to. 1222 * @param string $domain The text domain. 1223 */ 1224 $file = apply_filters( 'load_script_translation_file', $file, $handle, $domain ); 1225 1226 if ( ! $file || ! is_readable( $file ) ) { 1227 return false; 1228 } 1229 1230 $translations = file_get_contents( $file ); 1231 1232 /** 1233 * Filters script translations for the given file, script handle and text domain. 1234 * 1235 * @since 5.0.2 1236 * 1237 * @param string $translations JSON-encoded translation data. 1238 * @param string $file Path to the translation file that was loaded. 1239 * @param string $handle Name of the script to register a translation domain to. 1240 * @param string $domain The text domain. 1241 */ 1242 return apply_filters( 'load_script_translations', $translations, $file, $handle, $domain ); 1243 } 1244 1245 /** 1246 * Loads plugin and theme text domains just-in-time. 1247 * 1248 * When a textdomain is encountered for the first time, we try to load 1249 * the translation file from `wp-content/languages`, removing the need 1250 * to call load_plugin_textdomain() or load_theme_textdomain(). 1251 * 1252 * @since 4.6.0 1253 * @access private 1254 * 1255 * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again. 1256 * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry. 1257 * 1258 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 1259 * @return bool True when the textdomain is successfully loaded, false otherwise. 1260 */ 1261 function _load_textdomain_just_in_time( $domain ) { 1262 /** @var WP_Textdomain_Registry $wp_textdomain_registry */ 1263 global $l10n_unloaded, $wp_textdomain_registry; 1264 1265 $l10n_unloaded = (array) $l10n_unloaded; 1266 1267 // Short-circuit if domain is 'default' which is reserved for core. 1268 if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) { 1269 return false; 1270 } 1271 1272 if ( ! $wp_textdomain_registry->has( $domain ) ) { 1273 return false; 1274 } 1275 1276 $locale = determine_locale(); 1277 $path = $wp_textdomain_registry->get( $domain, $locale ); 1278 if ( ! $path ) { 1279 return false; 1280 } 1281 // Themes with their language directory outside of WP_LANG_DIR have a different file name. 1282 $template_directory = trailingslashit( get_template_directory() ); 1283 $stylesheet_directory = trailingslashit( get_stylesheet_directory() ); 1284 if ( str_starts_with( $path, $template_directory ) || str_starts_with( $path, $stylesheet_directory ) ) { 1285 $mofile = "{$path}{$locale}.mo"; 1286 } else { 1287 $mofile = "{$path}{$domain}-{$locale}.mo"; 1288 } 1289 1290 return load_textdomain( $domain, $mofile, $locale ); 1291 } 1292 1293 /** 1294 * Returns the Translations instance for a text domain. 1295 * 1296 * If there isn't one, returns empty Translations instance. 1297 * 1298 * @since 2.8.0 1299 * 1300 * @global MO[] $l10n An array of all currently loaded text domains. 1301 * 1302 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 1303 * @return Translations|NOOP_Translations A Translations instance. 1304 */ 1305 function get_translations_for_domain( $domain ) { 1306 global $l10n; 1307 if ( isset( $l10n[ $domain ] ) || ( _load_textdomain_just_in_time( $domain ) && isset( $l10n[ $domain ] ) ) ) { 1308 return $l10n[ $domain ]; 1309 } 1310 1311 static $noop_translations = null; 1312 if ( null === $noop_translations ) { 1313 $noop_translations = new NOOP_Translations(); 1314 } 1315 1316 $l10n[ $domain ] = &$noop_translations; 1317 1318 return $noop_translations; 1319 } 1320 1321 /** 1322 * Determines whether there are translations for the text domain. 1323 * 1324 * @since 3.0.0 1325 * 1326 * @global MO[] $l10n An array of all currently loaded text domains. 1327 * 1328 * @param string $domain Text domain. Unique identifier for retrieving translated strings. 1329 * @return bool Whether there are translations. 1330 */ 1331 function is_textdomain_loaded( $domain ) { 1332 global $l10n; 1333 return isset( $l10n[ $domain ] ) && ! $l10n[ $domain ] instanceof NOOP_Translations; 1334 } 1335 1336 /** 1337 * Translates role name. 1338 * 1339 * Since the role names are in the database and not in the source there 1340 * are dummy gettext calls to get them into the POT file and this function 1341 * properly translates them back. 1342 * 1343 * The before_last_bar() call is needed, because older installations keep the roles 1344 * using the old context format: 'Role name|User role' and just skipping the 1345 * content after the last bar is easier than fixing them in the DB. New installations 1346 * won't suffer from that problem. 1347 * 1348 * @since 2.8.0 1349 * @since 5.2.0 Added the `$domain` parameter. 1350 * 1351 * @param string $name The role name. 1352 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 1353 * Default 'default'. 1354 * @return string Translated role name on success, original name on failure. 1355 */ 1356 function translate_user_role( $name, $domain = 'default' ) { 1357 return translate_with_gettext_context( before_last_bar( $name ), 'User role', $domain ); 1358 } 1359 1360 /** 1361 * Gets all available languages based on the presence of *.mo files in a given directory. 1362 * 1363 * The default directory is WP_LANG_DIR. 1364 * 1365 * @since 3.0.0 1366 * @since 4.7.0 The results are now filterable with the {@see 'get_available_languages'} filter. 1367 * 1368 * @param string $dir A directory to search for language files. 1369 * Default WP_LANG_DIR. 1370 * @return string[] An array of language codes or an empty array if no languages are present. 1371 * Language codes are formed by stripping the .mo extension from the language file names. 1372 */ 1373 function get_available_languages( $dir = null ) { 1374 $languages = array(); 1375 1376 $lang_files = glob( ( is_null( $dir ) ? WP_LANG_DIR : $dir ) . '/*.mo' ); 1377 if ( $lang_files ) { 1378 foreach ( $lang_files as $lang_file ) { 1379 $lang_file = basename( $lang_file, '.mo' ); 1380 if ( ! str_starts_with( $lang_file, 'continents-cities' ) && ! str_starts_with( $lang_file, 'ms-' ) && 1381 ! str_starts_with( $lang_file, 'admin-' ) ) { 1382 $languages[] = $lang_file; 1383 } 1384 } 1385 } 1386 1387 /** 1388 * Filters the list of available language codes. 1389 * 1390 * @since 4.7.0 1391 * 1392 * @param string[] $languages An array of available language codes. 1393 * @param string $dir The directory where the language files were found. 1394 */ 1395 return apply_filters( 'get_available_languages', $languages, $dir ); 1396 } 1397 1398 /** 1399 * Gets installed translations. 1400 * 1401 * Looks in the wp-content/languages directory for translations of 1402 * plugins or themes. 1403 * 1404 * @since 3.7.0 1405 * 1406 * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'. 1407 * @return array Array of language data. 1408 */ 1409 function wp_get_installed_translations( $type ) { 1410 if ( 'themes' !== $type && 'plugins' !== $type && 'core' !== $type ) { 1411 return array(); 1412 } 1413 1414 $dir = 'core' === $type ? '' : "/$type"; 1415 1416 if ( ! is_dir( WP_LANG_DIR ) ) { 1417 return array(); 1418 } 1419 1420 if ( $dir && ! is_dir( WP_LANG_DIR . $dir ) ) { 1421 return array(); 1422 } 1423 1424 $files = scandir( WP_LANG_DIR . $dir ); 1425 if ( ! $files ) { 1426 return array(); 1427 } 1428 1429 $language_data = array(); 1430 1431 foreach ( $files as $file ) { 1432 if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "$dir/$file" ) ) { 1433 continue; 1434 } 1435 if ( substr( $file, -3 ) !== '.po' ) { 1436 continue; 1437 } 1438 if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) { 1439 continue; 1440 } 1441 if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files, true ) ) { 1442 continue; 1443 } 1444 1445 list( , $textdomain, $language ) = $match; 1446 if ( '' === $textdomain ) { 1447 $textdomain = 'default'; 1448 } 1449 $language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "$dir/$file" ); 1450 } 1451 return $language_data; 1452 } 1453 1454 /** 1455 * Extracts headers from a PO file. 1456 * 1457 * @since 3.7.0 1458 * 1459 * @param string $po_file Path to PO file. 1460 * @return string[] Array of PO file header values keyed by header name. 1461 */ 1462 function wp_get_pomo_file_data( $po_file ) { 1463 $headers = get_file_data( 1464 $po_file, 1465 array( 1466 'POT-Creation-Date' => '"POT-Creation-Date', 1467 'PO-Revision-Date' => '"PO-Revision-Date', 1468 'Project-Id-Version' => '"Project-Id-Version', 1469 'X-Generator' => '"X-Generator', 1470 ) 1471 ); 1472 foreach ( $headers as $header => $value ) { 1473 // Remove possible contextual '\n' and closing double quote. 1474 $headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value ); 1475 } 1476 return $headers; 1477 } 1478 1479 /** 1480 * Displays or returns a Language selector. 1481 * 1482 * @since 4.0.0 1483 * @since 4.3.0 Introduced the `echo` argument. 1484 * @since 4.7.0 Introduced the `show_option_site_default` argument. 1485 * @since 5.1.0 Introduced the `show_option_en_us` argument. 1486 * @since 5.9.0 Introduced the `explicit_option_en_us` argument. 1487 * 1488 * @see get_available_languages() 1489 * @see wp_get_available_translations() 1490 * 1491 * @param string|array $args { 1492 * Optional. Array or string of arguments for outputting the language selector. 1493 * 1494 * @type string $id ID attribute of the select element. Default 'locale'. 1495 * @type string $name Name attribute of the select element. Default 'locale'. 1496 * @type array $languages List of installed languages, contain only the locales. 1497 * Default empty array. 1498 * @type array $translations List of available translations. Default result of 1499 * wp_get_available_translations(). 1500 * @type string $selected Language which should be selected. Default empty. 1501 * @type bool|int $echo Whether to echo the generated markup. Accepts 0, 1, or their 1502 * boolean equivalents. Default 1. 1503 * @type bool $show_available_translations Whether to show available translations. Default true. 1504 * @type bool $show_option_site_default Whether to show an option to fall back to the site's locale. Default false. 1505 * @type bool $show_option_en_us Whether to show an option for English (United States). Default true. 1506 * @type bool $explicit_option_en_us Whether the English (United States) option uses an explicit value of en_US 1507 * instead of an empty value. Default false. 1508 * } 1509 * @return string HTML dropdown list of languages. 1510 */ 1511 function wp_dropdown_languages( $args = array() ) { 1512 1513 $parsed_args = wp_parse_args( 1514 $args, 1515 array( 1516 'id' => 'locale', 1517 'name' => 'locale', 1518 'languages' => array(), 1519 'translations' => array(), 1520 'selected' => '', 1521 'echo' => 1, 1522 'show_available_translations' => true, 1523 'show_option_site_default' => false, 1524 'show_option_en_us' => true, 1525 'explicit_option_en_us' => false, 1526 ) 1527 ); 1528 1529 // Bail if no ID or no name. 1530 if ( ! $parsed_args['id'] || ! $parsed_args['name'] ) { 1531 return; 1532 } 1533 1534 // English (United States) uses an empty string for the value attribute. 1535 if ( 'en_US' === $parsed_args['selected'] && ! $parsed_args['explicit_option_en_us'] ) { 1536 $parsed_args['selected'] = ''; 1537 } 1538 1539 $translations = $parsed_args['translations']; 1540 if ( empty( $translations ) ) { 1541 require_once ABSPATH . 'wp-admin/includes/translation-install.php'; 1542 $translations = wp_get_available_translations(); 1543 } 1544 1545 /* 1546 * $parsed_args['languages'] should only contain the locales. Find the locale in 1547 * $translations to get the native name. Fall back to locale. 1548 */ 1549 $languages = array(); 1550 foreach ( $parsed_args['languages'] as $locale ) { 1551 if ( isset( $translations[ $locale ] ) ) { 1552 $translation = $translations[ $locale ]; 1553 $languages[] = array( 1554 'language' => $translation['language'], 1555 'native_name' => $translation['native_name'], 1556 'lang' => current( $translation['iso'] ), 1557 ); 1558 1559 // Remove installed language from available translations. 1560 unset( $translations[ $locale ] ); 1561 } else { 1562 $languages[] = array( 1563 'language' => $locale, 1564 'native_name' => $locale, 1565 'lang' => '', 1566 ); 1567 } 1568 } 1569 1570 $translations_available = ( ! empty( $translations ) && $parsed_args['show_available_translations'] ); 1571 1572 // Holds the HTML markup. 1573 $structure = array(); 1574 1575 // List installed languages. 1576 if ( $translations_available ) { 1577 $structure[] = '<optgroup label="' . esc_attr_x( 'Installed', 'translations' ) . '">'; 1578 } 1579 1580 // Site default. 1581 if ( $parsed_args['show_option_site_default'] ) { 1582 $structure[] = sprintf( 1583 '<option value="site-default" data-installed="1"%s>%s</option>', 1584 selected( 'site-default', $parsed_args['selected'], false ), 1585 _x( 'Site Default', 'default site language' ) 1586 ); 1587 } 1588 1589 if ( $parsed_args['show_option_en_us'] ) { 1590 $value = ( $parsed_args['explicit_option_en_us'] ) ? 'en_US' : ''; 1591 $structure[] = sprintf( 1592 '<option value="%s" lang="en" data-installed="1"%s>English (United States)</option>', 1593 esc_attr( $value ), 1594 selected( '', $parsed_args['selected'], false ) 1595 ); 1596 } 1597 1598 // List installed languages. 1599 foreach ( $languages as $language ) { 1600 $structure[] = sprintf( 1601 '<option value="%s" lang="%s"%s data-installed="1">%s</option>', 1602 esc_attr( $language['language'] ), 1603 esc_attr( $language['lang'] ), 1604 selected( $language['language'], $parsed_args['selected'], false ), 1605 esc_html( $language['native_name'] ) 1606 ); 1607 } 1608 if ( $translations_available ) { 1609 $structure[] = '</optgroup>'; 1610 } 1611 1612 // List available translations. 1613 if ( $translations_available ) { 1614 $structure[] = '<optgroup label="' . esc_attr_x( 'Available', 'translations' ) . '">'; 1615 foreach ( $translations as $translation ) { 1616 $structure[] = sprintf( 1617 '<option value="%s" lang="%s"%s>%s</option>', 1618 esc_attr( $translation['language'] ), 1619 esc_attr( current( $translation['iso'] ) ), 1620 selected( $translation['language'], $parsed_args['selected'], false ), 1621 esc_html( $translation['native_name'] ) 1622 ); 1623 } 1624 $structure[] = '</optgroup>'; 1625 } 1626 1627 // Combine the output string. 1628 $output = sprintf( '<select name="%s" id="%s">', esc_attr( $parsed_args['name'] ), esc_attr( $parsed_args['id'] ) ); 1629 $output .= implode( "\n", $structure ); 1630 $output .= '</select>'; 1631 1632 if ( $parsed_args['echo'] ) { 1633 echo $output; 1634 } 1635 1636 return $output; 1637 } 1638 1639 /** 1640 * Determines whether the current locale is right-to-left (RTL). 1641 * 1642 * For more information on this and similar theme functions, check out 1643 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ 1644 * Conditional Tags} article in the Theme Developer Handbook. 1645 * 1646 * @since 3.0.0 1647 * 1648 * @global WP_Locale $wp_locale WordPress date and time locale object. 1649 * 1650 * @return bool Whether locale is RTL. 1651 */ 1652 function is_rtl() { 1653 global $wp_locale; 1654 if ( ! ( $wp_locale instanceof WP_Locale ) ) { 1655 return false; 1656 } 1657 return $wp_locale->is_rtl(); 1658 } 1659 1660 /** 1661 * Switches the translations according to the given locale. 1662 * 1663 * @since 4.7.0 1664 * 1665 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object. 1666 * 1667 * @param string $locale The locale. 1668 * @return bool True on success, false on failure. 1669 */ 1670 function switch_to_locale( $locale ) { 1671 /* @var WP_Locale_Switcher $wp_locale_switcher */ 1672 global $wp_locale_switcher; 1673 1674 if ( ! $wp_locale_switcher ) { 1675 return false; 1676 } 1677 1678 return $wp_locale_switcher->switch_to_locale( $locale ); 1679 } 1680 1681 /** 1682 * Switches the translations according to the given user's locale. 1683 * 1684 * @since 6.2.0 1685 * 1686 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object. 1687 * 1688 * @param int $user_id User ID. 1689 * @return bool True on success, false on failure. 1690 */ 1691 function switch_to_user_locale( $user_id ) { 1692 /* @var WP_Locale_Switcher $wp_locale_switcher */ 1693 global $wp_locale_switcher; 1694 1695 if ( ! $wp_locale_switcher ) { 1696 return false; 1697 } 1698 1699 return $wp_locale_switcher->switch_to_user_locale( $user_id ); 1700 } 1701 1702 /** 1703 * Restores the translations according to the previous locale. 1704 * 1705 * @since 4.7.0 1706 * 1707 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object. 1708 * 1709 * @return string|false Locale on success, false on error. 1710 */ 1711 function restore_previous_locale() { 1712 /* @var WP_Locale_Switcher $wp_locale_switcher */ 1713 global $wp_locale_switcher; 1714 1715 if ( ! $wp_locale_switcher ) { 1716 return false; 1717 } 1718 1719 return $wp_locale_switcher->restore_previous_locale(); 1720 } 1721 1722 /** 1723 * Restores the translations according to the original locale. 1724 * 1725 * @since 4.7.0 1726 * 1727 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object. 1728 * 1729 * @return string|false Locale on success, false on error. 1730 */ 1731 function restore_current_locale() { 1732 /* @var WP_Locale_Switcher $wp_locale_switcher */ 1733 global $wp_locale_switcher; 1734 1735 if ( ! $wp_locale_switcher ) { 1736 return false; 1737 } 1738 1739 return $wp_locale_switcher->restore_current_locale(); 1740 } 1741 1742 /** 1743 * Determines whether switch_to_locale() is in effect. 1744 * 1745 * @since 4.7.0 1746 * 1747 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object. 1748 * 1749 * @return bool True if the locale has been switched, false otherwise. 1750 */ 1751 function is_locale_switched() { 1752 /* @var WP_Locale_Switcher $wp_locale_switcher */ 1753 global $wp_locale_switcher; 1754 1755 return $wp_locale_switcher->is_switched(); 1756 } 1757 1758 /** 1759 * Translates the provided settings value using its i18n schema. 1760 * 1761 * @since 5.9.0 1762 * @access private 1763 * 1764 * @param string|string[]|array[]|object $i18n_schema I18n schema for the setting. 1765 * @param string|string[]|array[] $settings Value for the settings. 1766 * @param string $textdomain Textdomain to use with translations. 1767 * 1768 * @return string|string[]|array[] Translated settings. 1769 */ 1770 function translate_settings_using_i18n_schema( $i18n_schema, $settings, $textdomain ) { 1771 if ( empty( $i18n_schema ) || empty( $settings ) || empty( $textdomain ) ) { 1772 return $settings; 1773 } 1774 1775 if ( is_string( $i18n_schema ) && is_string( $settings ) ) { 1776 return translate_with_gettext_context( $settings, $i18n_schema, $textdomain ); 1777 } 1778 if ( is_array( $i18n_schema ) && is_array( $settings ) ) { 1779 $translated_settings = array(); 1780 foreach ( $settings as $value ) { 1781 $translated_settings[] = translate_settings_using_i18n_schema( $i18n_schema[0], $value, $textdomain ); 1782 } 1783 return $translated_settings; 1784 } 1785 if ( is_object( $i18n_schema ) && is_array( $settings ) ) { 1786 $group_key = '*'; 1787 $translated_settings = array(); 1788 foreach ( $settings as $key => $value ) { 1789 if ( isset( $i18n_schema->$key ) ) { 1790 $translated_settings[ $key ] = translate_settings_using_i18n_schema( $i18n_schema->$key, $value, $textdomain ); 1791 } elseif ( isset( $i18n_schema->$group_key ) ) { 1792 $translated_settings[ $key ] = translate_settings_using_i18n_schema( $i18n_schema->$group_key, $value, $textdomain ); 1793 } else { 1794 $translated_settings[ $key ] = $value; 1795 } 1796 } 1797 return $translated_settings; 1798 } 1799 return $settings; 1800 } 1801 1802 /** 1803 * Retrieves the list item separator based on the locale. 1804 * 1805 * @since 6.0.0 1806 * 1807 * @global WP_Locale $wp_locale WordPress date and time locale object. 1808 * 1809 * @return string Locale-specific list item separator. 1810 */ 1811 function wp_get_list_item_separator() { 1812 global $wp_locale; 1813 1814 if ( ! ( $wp_locale instanceof WP_Locale ) ) { 1815 // Default value of WP_Locale::get_list_item_separator(). 1816 /* translators: Used between list items, there is a space after the comma. */ 1817 return __( ', ' ); 1818 } 1819 1820 return $wp_locale->get_list_item_separator(); 1821 } 1822 1823 /** 1824 * Retrieves the word count type based on the locale. 1825 * 1826 * @since 6.2.0 1827 * 1828 * @global WP_Locale $wp_locale WordPress date and time locale object. 1829 * 1830 * @return string Locale-specific word count type. Possible values are `characters_excluding_spaces`, 1831 * `characters_including_spaces`, or `words`. Defaults to `words`. 1832 */ 1833 function wp_get_word_count_type() { 1834 global $wp_locale; 1835 1836 if ( ! ( $wp_locale instanceof WP_Locale ) ) { 1837 // Default value of WP_Locale::get_word_count_type(). 1838 return 'words'; 1839 } 1840 1841 return $wp_locale->get_word_count_type(); 1842 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Tue May 30 08:20:02 2023 | Cross-referenced by PHPXref |