[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/ -> l10n.php (source)

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


Generated: Tue Jul 16 08:20:01 2019 Cross-referenced by PHPXref 0.7