[ 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      $plugins_url = wp_parse_url( plugins_url() );
 952      $site_url    = wp_parse_url( site_url() );
 953  
 954      // If the host is the same or it's a relative URL.
 955      if (
 956          ( ! isset( $content_url['path'] ) || strpos( $src_url['path'], $content_url['path'] ) === 0 ) &&
 957          ( ! isset( $src_url['host'] ) || $src_url['host'] === $content_url['host'] )
 958      ) {
 959          // Make the src relative the specific plugin or theme.
 960          if ( isset( $content_url['path'] ) ) {
 961              $relative = substr( $src_url['path'], strlen( $content_url['path'] ) );
 962          } else {
 963              $relative = $src_url['path'];
 964          }
 965          $relative = trim( $relative, '/' );
 966          $relative = explode( '/', $relative );
 967  
 968          $languages_path = WP_LANG_DIR . '/' . $relative[0];
 969  
 970          $relative = array_slice( $relative, 2 ); // Remove plugins/<plugin name> or themes/<theme name>.
 971          $relative = implode( '/', $relative );
 972      } elseif (
 973          ( ! isset( $plugins_url['path'] ) || strpos( $src_url['path'], $plugins_url['path'] ) === 0 ) &&
 974          ( ! isset( $src_url['host'] ) || $src_url['host'] === $plugins_url['host'] )
 975      ) {
 976          // Make the src relative the specific plugin.
 977          if ( isset( $plugins_url['path'] ) ) {
 978              $relative = substr( $src_url['path'], strlen( $plugins_url['path'] ) );
 979          } else {
 980              $relative = $src_url['path'];
 981          }
 982          $relative = trim( $relative, '/' );
 983          $relative = explode( '/', $relative );
 984  
 985          $languages_path = WP_LANG_DIR . '/plugins';
 986  
 987          $relative = array_slice( $relative, 1 ); // Remove <plugin name>.
 988          $relative = implode( '/', $relative );
 989      } elseif ( ! isset( $src_url['host'] ) || $src_url['host'] === $site_url['host'] ) {
 990          if ( ! isset( $site_url['path'] ) ) {
 991              $relative = trim( $src_url['path'], '/' );
 992          } elseif ( ( strpos( $src_url['path'], trailingslashit( $site_url['path'] ) ) === 0 ) ) {
 993              // Make the src relative to the WP root.
 994              $relative = substr( $src_url['path'], strlen( $site_url['path'] ) );
 995              $relative = trim( $relative, '/' );
 996          }
 997      }
 998  
 999      /**
1000       * Filters the relative path of scripts used for finding translation files.
1001       *
1002       * @since 5.0.2
1003       *
1004       * @param string $relative The relative path of the script. False if it could not be determined.
1005       * @param string $src      The full source url of the script.
1006       */
1007      $relative = apply_filters( 'load_script_textdomain_relative_path', $relative, $src );
1008  
1009      // If the source is not from WP.
1010      if ( false === $relative ) {
1011          return load_script_translations( false, $handle, $domain );
1012      }
1013  
1014      // Translations are always based on the unminified filename.
1015      if ( substr( $relative, -7 ) === '.min.js' ) {
1016          $relative = substr( $relative, 0, -7 ) . '.js';
1017      }
1018  
1019      $md5_filename = $file_base . '-' . md5( $relative ) . '.json';
1020  
1021      if ( $path ) {
1022          $translations = load_script_translations( $path . '/' . $md5_filename, $handle, $domain );
1023  
1024          if ( $translations ) {
1025              return $translations;
1026          }
1027      }
1028  
1029      $translations = load_script_translations( $languages_path . '/' . $md5_filename, $handle, $domain );
1030  
1031      if ( $translations ) {
1032          return $translations;
1033      }
1034  
1035      return load_script_translations( false, $handle, $domain );
1036  }
1037  
1038  /**
1039   * Loads the translation data for the given script handle and text domain.
1040   *
1041   * @since 5.0.2
1042   *
1043   * @param string|false $file   Path to the translation file to load. False if there isn't one.
1044   * @param string       $handle Name of the script to register a translation domain to.
1045   * @param string       $domain The text domain.
1046   * @return string|false The JSON-encoded translated strings for the given script handle and text domain. False if there are none.
1047   */
1048  function load_script_translations( $file, $handle, $domain ) {
1049      /**
1050       * Pre-filters script translations for the given file, script handle and text domain.
1051       *
1052       * Returning a non-null value allows to override the default logic, effectively short-circuiting the function.
1053       *
1054       * @since 5.0.2
1055       *
1056       * @param string|false|null $translations JSON-encoded translation data. Default null.
1057       * @param string|false      $file         Path to the translation file to load. False if there isn't one.
1058       * @param string            $handle       Name of the script to register a translation domain to.
1059       * @param string            $domain       The text domain.
1060       */
1061      $translations = apply_filters( 'pre_load_script_translations', null, $file, $handle, $domain );
1062  
1063      if ( null !== $translations ) {
1064          return $translations;
1065      }
1066  
1067      /**
1068       * Filters the file path for loading script translations for the given script handle and text domain.
1069       *
1070       * @since 5.0.2
1071       *
1072       * @param string|false $file   Path to the translation file to load. False if there isn't one.
1073       * @param string       $handle Name of the script to register a translation domain to.
1074       * @param string       $domain The text domain.
1075       */
1076      $file = apply_filters( 'load_script_translation_file', $file, $handle, $domain );
1077  
1078      if ( ! $file || ! is_readable( $file ) ) {
1079          return false;
1080      }
1081  
1082      $translations = file_get_contents( $file );
1083  
1084      /**
1085       * Filters script translations for the given file, script handle and text domain.
1086       *
1087       * @since 5.0.2
1088       *
1089       * @param string $translations JSON-encoded translation data.
1090       * @param string $file         Path to the translation file that was loaded.
1091       * @param string $handle       Name of the script to register a translation domain to.
1092       * @param string $domain       The text domain.
1093       */
1094      return apply_filters( 'load_script_translations', $translations, $file, $handle, $domain );
1095  }
1096  
1097  /**
1098   * Loads plugin and theme textdomains just-in-time.
1099   *
1100   * When a textdomain is encountered for the first time, we try to load
1101   * the translation file from `wp-content/languages`, removing the need
1102   * to call load_plugin_texdomain() or load_theme_texdomain().
1103   *
1104   * @since 4.6.0
1105   * @access private
1106   *
1107   * @see get_translations_for_domain()
1108   * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
1109   *
1110   * @param string $domain Text domain. Unique identifier for retrieving translated strings.
1111   * @return bool True when the textdomain is successfully loaded, false otherwise.
1112   */
1113  function _load_textdomain_just_in_time( $domain ) {
1114      global $l10n_unloaded;
1115  
1116      $l10n_unloaded = (array) $l10n_unloaded;
1117  
1118      // Short-circuit if domain is 'default' which is reserved for core.
1119      if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) {
1120          return false;
1121      }
1122  
1123      $translation_path = _get_path_to_translation( $domain );
1124      if ( false === $translation_path ) {
1125          return false;
1126      }
1127  
1128      return load_textdomain( $domain, $translation_path );
1129  }
1130  
1131  /**
1132   * Gets the path to a translation file for loading a textdomain just in time.
1133   *
1134   * Caches the retrieved results internally.
1135   *
1136   * @since 4.7.0
1137   * @access private
1138   *
1139   * @see _load_textdomain_just_in_time()
1140   * @staticvar array $available_translations
1141   *
1142   * @param string $domain Text domain. Unique identifier for retrieving translated strings.
1143   * @param bool   $reset  Whether to reset the internal cache. Used by the switch to locale functionality.
1144   * @return string|false The path to the translation file or false if no translation file was found.
1145   */
1146  function _get_path_to_translation( $domain, $reset = false ) {
1147      static $available_translations = array();
1148  
1149      if ( true === $reset ) {
1150          $available_translations = array();
1151      }
1152  
1153      if ( ! isset( $available_translations[ $domain ] ) ) {
1154          $available_translations[ $domain ] = _get_path_to_translation_from_lang_dir( $domain );
1155      }
1156  
1157      return $available_translations[ $domain ];
1158  }
1159  
1160  /**
1161   * Gets the path to a translation file in the languages directory for the current locale.
1162   *
1163   * Holds a cached list of available .mo files to improve performance.
1164   *
1165   * @since 4.7.0
1166   * @access private
1167   *
1168   * @see _get_path_to_translation()
1169   * @staticvar array $cached_mofiles
1170   *
1171   * @param string $domain Text domain. Unique identifier for retrieving translated strings.
1172   * @return string|false The path to the translation file or false if no translation file was found.
1173   */
1174  function _get_path_to_translation_from_lang_dir( $domain ) {
1175      static $cached_mofiles = null;
1176  
1177      if ( null === $cached_mofiles ) {
1178          $cached_mofiles = array();
1179  
1180          $locations = array(
1181              WP_LANG_DIR . '/plugins',
1182              WP_LANG_DIR . '/themes',
1183          );
1184  
1185          foreach ( $locations as $location ) {
1186              $mofiles = glob( $location . '/*.mo' );
1187              if ( $mofiles ) {
1188                  $cached_mofiles = array_merge( $cached_mofiles, $mofiles );
1189              }
1190          }
1191      }
1192  
1193      $locale = determine_locale();
1194      $mofile = "{$domain}-{$locale}.mo";
1195  
1196      $path = WP_LANG_DIR . '/plugins/' . $mofile;
1197      if ( in_array( $path, $cached_mofiles ) ) {
1198          return $path;
1199      }
1200  
1201      $path = WP_LANG_DIR . '/themes/' . $mofile;
1202      if ( in_array( $path, $cached_mofiles ) ) {
1203          return $path;
1204      }
1205  
1206      return false;
1207  }
1208  
1209  /**
1210   * Return the Translations instance for a text domain.
1211   *
1212   * If there isn't one, returns empty Translations instance.
1213   *
1214   * @since 2.8.0
1215   *
1216   * @global MO[] $l10n
1217   * @staticvar NOOP_Translations $noop_translations
1218   *
1219   * @param string $domain Text domain. Unique identifier for retrieving translated strings.
1220   * @return Translations|NOOP_Translations A Translations instance.
1221   */
1222  function get_translations_for_domain( $domain ) {
1223      global $l10n;
1224      if ( isset( $l10n[ $domain ] ) || ( _load_textdomain_just_in_time( $domain ) && isset( $l10n[ $domain ] ) ) ) {
1225          return $l10n[ $domain ];
1226      }
1227  
1228      static $noop_translations = null;
1229      if ( null === $noop_translations ) {
1230          $noop_translations = new NOOP_Translations;
1231      }
1232  
1233      return $noop_translations;
1234  }
1235  
1236  /**
1237   * Whether there are translations for the text domain.
1238   *
1239   * @since 3.0.0
1240   *
1241   * @global MO[] $l10n
1242   *
1243   * @param string $domain Text domain. Unique identifier for retrieving translated strings.
1244   * @return bool Whether there are translations.
1245   */
1246  function is_textdomain_loaded( $domain ) {
1247      global $l10n;
1248      return isset( $l10n[ $domain ] );
1249  }
1250  
1251  /**
1252   * Translates role name.
1253   *
1254   * Since the role names are in the database and not in the source there
1255   * are dummy gettext calls to get them into the POT file and this function
1256   * properly translates them back.
1257   *
1258   * The before_last_bar() call is needed, because older installations keep the roles
1259   * using the old context format: 'Role name|User role' and just skipping the
1260   * content after the last bar is easier than fixing them in the DB. New installations
1261   * won't suffer from that problem.
1262   *
1263   * @since 2.8.0
1264   * @since 5.2.0 Added the `$domain` parameter.
1265   *
1266   * @param string $name   The role name.
1267   * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
1268   *                       Default 'default'.
1269   * @return string Translated role name on success, original name on failure.
1270   */
1271  function translate_user_role( $name, $domain = 'default' ) {
1272      return translate_with_gettext_context( before_last_bar( $name ), 'User role', $domain );
1273  }
1274  
1275  /**
1276   * Get all available languages based on the presence of *.mo files in a given directory.
1277   *
1278   * The default directory is WP_LANG_DIR.
1279   *
1280   * @since 3.0.0
1281   * @since 4.7.0 The results are now filterable with the {@see 'get_available_languages'} filter.
1282   *
1283   * @param string $dir A directory to search for language files.
1284   *                    Default WP_LANG_DIR.
1285   * @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.
1286   */
1287  function get_available_languages( $dir = null ) {
1288      $languages = array();
1289  
1290      $lang_files = glob( ( is_null( $dir ) ? WP_LANG_DIR : $dir ) . '/*.mo' );
1291      if ( $lang_files ) {
1292          foreach ( $lang_files as $lang_file ) {
1293              $lang_file = basename( $lang_file, '.mo' );
1294              if ( 0 !== strpos( $lang_file, 'continents-cities' ) && 0 !== strpos( $lang_file, 'ms-' ) &&
1295                  0 !== strpos( $lang_file, 'admin-' ) ) {
1296                  $languages[] = $lang_file;
1297              }
1298          }
1299      }
1300  
1301      /**
1302       * Filters the list of available language codes.
1303       *
1304       * @since 4.7.0
1305       *
1306       * @param array  $languages An array of available language codes.
1307       * @param string $dir       The directory where the language files were found.
1308       */
1309      return apply_filters( 'get_available_languages', $languages, $dir );
1310  }
1311  
1312  /**
1313   * Get installed translations.
1314   *
1315   * Looks in the wp-content/languages directory for translations of
1316   * plugins or themes.
1317   *
1318   * @since 3.7.0
1319   *
1320   * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
1321   * @return array Array of language data.
1322   */
1323  function wp_get_installed_translations( $type ) {
1324      if ( $type !== 'themes' && $type !== 'plugins' && $type !== 'core' ) {
1325          return array();
1326      }
1327  
1328      $dir = 'core' === $type ? '' : "/$type";
1329  
1330      if ( ! is_dir( WP_LANG_DIR ) ) {
1331          return array();
1332      }
1333  
1334      if ( $dir && ! is_dir( WP_LANG_DIR . $dir ) ) {
1335          return array();
1336      }
1337  
1338      $files = scandir( WP_LANG_DIR . $dir );
1339      if ( ! $files ) {
1340          return array();
1341      }
1342  
1343      $language_data = array();
1344  
1345      foreach ( $files as $file ) {
1346          if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "$dir/$file" ) ) {
1347              continue;
1348          }
1349          if ( substr( $file, -3 ) !== '.po' ) {
1350              continue;
1351          }
1352          if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
1353              continue;
1354          }
1355          if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) {
1356              continue;
1357          }
1358  
1359          list( , $textdomain, $language ) = $match;
1360          if ( '' === $textdomain ) {
1361              $textdomain = 'default';
1362          }
1363          $language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "$dir/$file" );
1364      }
1365      return $language_data;
1366  }
1367  
1368  /**
1369   * Extract headers from a PO file.
1370   *
1371   * @since 3.7.0
1372   *
1373   * @param string $po_file Path to PO file.
1374   * @return array PO file headers.
1375   */
1376  function wp_get_pomo_file_data( $po_file ) {
1377      $headers = get_file_data(
1378          $po_file,
1379          array(
1380              'POT-Creation-Date'  => '"POT-Creation-Date',
1381              'PO-Revision-Date'   => '"PO-Revision-Date',
1382              'Project-Id-Version' => '"Project-Id-Version',
1383              'X-Generator'        => '"X-Generator',
1384          )
1385      );
1386      foreach ( $headers as $header => $value ) {
1387          // Remove possible contextual '\n' and closing double quote.
1388          $headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
1389      }
1390      return $headers;
1391  }
1392  
1393  /**
1394   * Language selector.
1395   *
1396   * @since 4.0.0
1397   * @since 4.3.0 Introduced the `echo` argument.
1398   * @since 4.7.0 Introduced the `show_option_site_default` argument.
1399   * @since 5.1.0 Introduced the `show_option_en_us` argument.
1400   *
1401   * @see get_available_languages()
1402   * @see wp_get_available_translations()
1403   *
1404   * @param string|array $args {
1405   *     Optional. Array or string of arguments for outputting the language selector.
1406   *
1407   *     @type string   $id                           ID attribute of the select element. Default 'locale'.
1408   *     @type string   $name                         Name attribute of the select element. Default 'locale'.
1409   *     @type array    $languages                    List of installed languages, contain only the locales.
1410   *                                                  Default empty array.
1411   *     @type array    $translations                 List of available translations. Default result of
1412   *                                                  wp_get_available_translations().
1413   *     @type string   $selected                     Language which should be selected. Default empty.
1414   *     @type bool|int $echo                         Whether to echo the generated markup. Accepts 0, 1, or their
1415   *                                                  boolean equivalents. Default 1.
1416   *     @type bool     $show_available_translations  Whether to show available translations. Default true.
1417   *     @type bool     $show_option_site_default     Whether to show an option to fall back to the site's locale. Default false.
1418   *     @type bool     $show_option_en_us            Whether to show an option for English (United States). Default true.
1419   * }
1420   * @return string HTML content
1421   */
1422  function wp_dropdown_languages( $args = array() ) {
1423  
1424      $parsed_args = wp_parse_args(
1425          $args,
1426          array(
1427              'id'                          => 'locale',
1428              'name'                        => 'locale',
1429              'languages'                   => array(),
1430              'translations'                => array(),
1431              'selected'                    => '',
1432              'echo'                        => 1,
1433              'show_available_translations' => true,
1434              'show_option_site_default'    => false,
1435              'show_option_en_us'           => true,
1436          )
1437      );
1438  
1439      // Bail if no ID or no name.
1440      if ( ! $parsed_args['id'] || ! $parsed_args['name'] ) {
1441          return;
1442      }
1443  
1444      // English (United States) uses an empty string for the value attribute.
1445      if ( 'en_US' === $parsed_args['selected'] ) {
1446          $parsed_args['selected'] = '';
1447      }
1448  
1449      $translations = $parsed_args['translations'];
1450      if ( empty( $translations ) ) {
1451          require_once ( ABSPATH . 'wp-admin/includes/translation-install.php' );
1452          $translations = wp_get_available_translations();
1453      }
1454  
1455      /*
1456       * $parsed_args['languages'] should only contain the locales. Find the locale in
1457       * $translations to get the native name. Fall back to locale.
1458       */
1459      $languages = array();
1460      foreach ( $parsed_args['languages'] as $locale ) {
1461          if ( isset( $translations[ $locale ] ) ) {
1462              $translation = $translations[ $locale ];
1463              $languages[] = array(
1464                  'language'    => $translation['language'],
1465                  'native_name' => $translation['native_name'],
1466                  'lang'        => current( $translation['iso'] ),
1467              );
1468  
1469              // Remove installed language from available translations.
1470              unset( $translations[ $locale ] );
1471          } else {
1472              $languages[] = array(
1473                  'language'    => $locale,
1474                  'native_name' => $locale,
1475                  'lang'        => '',
1476              );
1477          }
1478      }
1479  
1480      $translations_available = ( ! empty( $translations ) && $parsed_args['show_available_translations'] );
1481  
1482      // Holds the HTML markup.
1483      $structure = array();
1484  
1485      // List installed languages.
1486      if ( $translations_available ) {
1487          $structure[] = '<optgroup label="' . esc_attr_x( 'Installed', 'translations' ) . '">';
1488      }
1489  
1490      // Site default.
1491      if ( $parsed_args['show_option_site_default'] ) {
1492          $structure[] = sprintf(
1493              '<option value="site-default" data-installed="1"%s>%s</option>',
1494              selected( 'site-default', $parsed_args['selected'], false ),
1495              _x( 'Site Default', 'default site language' )
1496          );
1497      }
1498  
1499      if ( $parsed_args['show_option_en_us'] ) {
1500          $structure[] = sprintf(
1501              '<option value="" lang="en" data-installed="1"%s>English (United States)</option>',
1502              selected( '', $parsed_args['selected'], false )
1503          );
1504      }
1505  
1506      // List installed languages.
1507      foreach ( $languages as $language ) {
1508          $structure[] = sprintf(
1509              '<option value="%s" lang="%s"%s data-installed="1">%s</option>',
1510              esc_attr( $language['language'] ),
1511              esc_attr( $language['lang'] ),
1512              selected( $language['language'], $parsed_args['selected'], false ),
1513              esc_html( $language['native_name'] )
1514          );
1515      }
1516      if ( $translations_available ) {
1517          $structure[] = '</optgroup>';
1518      }
1519  
1520      // List available translations.
1521      if ( $translations_available ) {
1522          $structure[] = '<optgroup label="' . esc_attr_x( 'Available', 'translations' ) . '">';
1523          foreach ( $translations as $translation ) {
1524              $structure[] = sprintf(
1525                  '<option value="%s" lang="%s"%s>%s</option>',
1526                  esc_attr( $translation['language'] ),
1527                  esc_attr( current( $translation['iso'] ) ),
1528                  selected( $translation['language'], $parsed_args['selected'], false ),
1529                  esc_html( $translation['native_name'] )
1530              );
1531          }
1532          $structure[] = '</optgroup>';
1533      }
1534  
1535      // Combine the output string.
1536      $output  = sprintf( '<select name="%s" id="%s">', esc_attr( $parsed_args['name'] ), esc_attr( $parsed_args['id'] ) );
1537      $output .= join( "\n", $structure );
1538      $output .= '</select>';
1539  
1540      if ( $parsed_args['echo'] ) {
1541          echo $output;
1542      }
1543  
1544      return $output;
1545  }
1546  
1547  /**
1548   * Determines whether the current locale is right-to-left (RTL).
1549   *
1550   * For more information on this and similar theme functions, check out
1551   * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
1552   * Conditional Tags} article in the Theme Developer Handbook.
1553   *
1554   * @since 3.0.0
1555   *
1556   * @global WP_Locale $wp_locale WordPress date and time locale object.
1557   *
1558   * @return bool Whether locale is RTL.
1559   */
1560  function is_rtl() {
1561      global $wp_locale;
1562      if ( ! ( $wp_locale instanceof WP_Locale ) ) {
1563          return false;
1564      }
1565      return $wp_locale->is_rtl();
1566  }
1567  
1568  /**
1569   * Switches the translations according to the given locale.
1570   *
1571   * @since 4.7.0
1572   *
1573   * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1574   *
1575   * @param string $locale The locale.
1576   * @return bool True on success, false on failure.
1577   */
1578  function switch_to_locale( $locale ) {
1579      /* @var WP_Locale_Switcher $wp_locale_switcher */
1580      global $wp_locale_switcher;
1581  
1582      return $wp_locale_switcher->switch_to_locale( $locale );
1583  }
1584  
1585  /**
1586   * Restores the translations according to the previous locale.
1587   *
1588   * @since 4.7.0
1589   *
1590   * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1591   *
1592   * @return string|false Locale on success, false on error.
1593   */
1594  function restore_previous_locale() {
1595      /* @var WP_Locale_Switcher $wp_locale_switcher */
1596      global $wp_locale_switcher;
1597  
1598      return $wp_locale_switcher->restore_previous_locale();
1599  }
1600  
1601  /**
1602   * Restores the translations according to the original locale.
1603   *
1604   * @since 4.7.0
1605   *
1606   * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1607   *
1608   * @return string|false Locale on success, false on error.
1609   */
1610  function restore_current_locale() {
1611      /* @var WP_Locale_Switcher $wp_locale_switcher */
1612      global $wp_locale_switcher;
1613  
1614      return $wp_locale_switcher->restore_current_locale();
1615  }
1616  
1617  /**
1618   * Whether switch_to_locale() is in effect.
1619   *
1620   * @since 4.7.0
1621   *
1622   * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
1623   *
1624   * @return bool True if the locale has been switched, false otherwise.
1625   */
1626  function is_locale_switched() {
1627      /* @var WP_Locale_Switcher $wp_locale_switcher */
1628      global $wp_locale_switcher;
1629  
1630      return $wp_locale_switcher->is_switched();
1631  }


Generated: Fri Oct 18 08:20:01 2019 Cross-referenced by PHPXref 0.7