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