wp/wp-includes/l10n.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
   103 	$locale = $user->locale;
   103 	$locale = $user->locale;
   104 	return $locale ? $locale : get_locale();
   104 	return $locale ? $locale : get_locale();
   105 }
   105 }
   106 
   106 
   107 /**
   107 /**
       
   108  * Determine the current locale desired for the request.
       
   109  *
       
   110  * @since 5.0.0
       
   111  *
       
   112  * @global string $pagenow
       
   113  *
       
   114  * @return string The determined locale.
       
   115  */
       
   116 function determine_locale() {
       
   117 	/**
       
   118 	 * Filters the locale for the current request prior to the default determination process.
       
   119 	 *
       
   120 	 * Using this filter allows to override the default logic, effectively short-circuiting the function.
       
   121 	 *
       
   122 	 * @since 5.0.0
       
   123 	 *
       
   124 	 * @param string|null The locale to return and short-circuit, or null as default.
       
   125 	 */
       
   126 	$determined_locale = apply_filters( 'pre_determine_locale', null );
       
   127 	if ( ! empty( $determined_locale ) && is_string( $determined_locale ) ) {
       
   128 		return $determined_locale;
       
   129 	}
       
   130 
       
   131 	$determined_locale = get_locale();
       
   132 
       
   133 	if ( is_admin() ) {
       
   134 		$determined_locale = get_user_locale();
       
   135 	}
       
   136 
       
   137 	if ( isset( $_GET['_locale'] ) && 'user' === $_GET['_locale'] && wp_is_json_request() ) {
       
   138 		$determined_locale = get_user_locale();
       
   139 	}
       
   140 
       
   141 	if ( ! empty( $_GET['wp_lang'] ) && ! empty( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) {
       
   142 		$determined_locale = sanitize_text_field( $_GET['wp_lang'] );
       
   143 	}
       
   144 
       
   145 	/**
       
   146 	 * Filters the locale for the current request.
       
   147 	 *
       
   148 	 * @since 5.0.0
       
   149 	 *
       
   150 	 * @param string $locale The locale.
       
   151 	 */
       
   152 	return apply_filters( 'determine_locale', $determined_locale );
       
   153 }
       
   154 
       
   155 /**
   108  * Retrieve the translation of $text.
   156  * Retrieve the translation of $text.
   109  *
   157  *
   110  * If there is no translation, or the text domain isn't loaded, the original text is returned.
   158  * If there is no translation, or the text domain isn't loaded, the original text is returned.
   111  *
   159  *
   112  * *Note:* Don't use translate() directly, use __() or related functions.
   160  * *Note:* Don't use translate() directly, use __() or related functions.
   220 
   268 
   221 /**
   269 /**
   222  * Retrieve the translation of $text and escapes it for safe use in HTML output.
   270  * Retrieve the translation of $text and escapes it for safe use in HTML output.
   223  *
   271  *
   224  * If there is no translation, or the text domain isn't loaded, the original text
   272  * If there is no translation, or the text domain isn't loaded, the original text
   225  * is escaped and returned..
   273  * is escaped and returned.
   226  *
   274  *
   227  * @since 2.8.0
   275  * @since 2.8.0
   228  *
   276  *
   229  * @param string $text   Text to translate.
   277  * @param string $text   Text to translate.
   230  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
   278  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
   398  * @param string $context Context information for the translators.
   446  * @param string $context Context information for the translators.
   399  * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
   447  * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
   400  *                        Default 'default'.
   448  *                        Default 'default'.
   401  * @return string The translated singular or plural form.
   449  * @return string The translated singular or plural form.
   402  */
   450  */
   403 function _nx($single, $plural, $number, $context, $domain = 'default') {
   451 function _nx( $single, $plural, $number, $context, $domain = 'default' ) {
   404 	$translations = get_translations_for_domain( $domain );
   452 	$translations = get_translations_for_domain( $domain );
   405 	$translation  = $translations->translate_plural( $single, $plural, $number, $context );
   453 	$translation  = $translations->translate_plural( $single, $plural, $number, $context );
   406 
   454 
   407 	/**
   455 	/**
   408 	 * Filters the singular or plural form of a string with gettext context.
   456 	 * Filters the singular or plural form of a string with gettext context.
   447  *     @type null   $context  Context information for the translators.
   495  *     @type null   $context  Context information for the translators.
   448  *     @type string $domain   Text domain.
   496  *     @type string $domain   Text domain.
   449  * }
   497  * }
   450  */
   498  */
   451 function _n_noop( $singular, $plural, $domain = null ) {
   499 function _n_noop( $singular, $plural, $domain = null ) {
   452 	return array( 0 => $singular, 1 => $plural, 'singular' => $singular, 'plural' => $plural, 'context' => null, 'domain' => $domain );
   500 	return array(
       
   501 		0          => $singular,
       
   502 		1          => $plural,
       
   503 		'singular' => $singular,
       
   504 		'plural'   => $plural,
       
   505 		'context'  => null,
       
   506 		'domain'   => $domain,
       
   507 	);
   453 }
   508 }
   454 
   509 
   455 /**
   510 /**
   456  * Registers plural strings with gettext context in POT file, but does not translate them.
   511  * Registers plural strings with gettext context in POT file, but does not translate them.
   457  *
   512  *
   459  * strings and use them later when the number is known.
   514  * strings and use them later when the number is known.
   460  *
   515  *
   461  * Example of a generic phrase which is disambiguated via the context parameter:
   516  * Example of a generic phrase which is disambiguated via the context parameter:
   462  *
   517  *
   463  *     $messages = array(
   518  *     $messages = array(
   464  *      	'people'  => _nx_noop( '%s group', '%s groups', 'people', 'text-domain' ),
   519  *          'people'  => _nx_noop( '%s group', '%s groups', 'people', 'text-domain' ),
   465  *      	'animals' => _nx_noop( '%s group', '%s groups', 'animals', 'text-domain' ),
   520  *          'animals' => _nx_noop( '%s group', '%s groups', 'animals', 'text-domain' ),
   466  *     );
   521  *     );
   467  *     ...
   522  *     ...
   468  *     $message = $messages[ $type ];
   523  *     $message = $messages[ $type ];
   469  *     printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
   524  *     printf( translate_nooped_plural( $message, $count, 'text-domain' ), number_format_i18n( $count ) );
   470  *
   525  *
   486  *     @type string $context  Context information for the translators.
   541  *     @type string $context  Context information for the translators.
   487  *     @type string $domain   Text domain.
   542  *     @type string $domain   Text domain.
   488  * }
   543  * }
   489  */
   544  */
   490 function _nx_noop( $singular, $plural, $context, $domain = null ) {
   545 function _nx_noop( $singular, $plural, $context, $domain = null ) {
   491 	return array( 0 => $singular, 1 => $plural, 2 => $context, 'singular' => $singular, 'plural' => $plural, 'context' => $context, 'domain' => $domain );
   546 	return array(
       
   547 		0          => $singular,
       
   548 		1          => $plural,
       
   549 		2          => $context,
       
   550 		'singular' => $singular,
       
   551 		'plural'   => $plural,
       
   552 		'context'  => $context,
       
   553 		'domain'   => $domain,
       
   554 	);
   492 }
   555 }
   493 
   556 
   494 /**
   557 /**
   495  * Translates and retrieves the singular or plural form of a string that's been registered
   558  * Translates and retrieves the singular or plural form of a string that's been registered
   496  * with _n_noop() or _nx_noop().
   559  * with _n_noop() or _nx_noop().
   510  * @param string $domain        Optional. Text domain. Unique identifier for retrieving translated strings. If $nooped_plural contains
   573  * @param string $domain        Optional. Text domain. Unique identifier for retrieving translated strings. If $nooped_plural contains
   511  *                              a text domain passed to _n_noop() or _nx_noop(), it will override this value. Default 'default'.
   574  *                              a text domain passed to _n_noop() or _nx_noop(), it will override this value. Default 'default'.
   512  * @return string Either $single or $plural translated text.
   575  * @return string Either $single or $plural translated text.
   513  */
   576  */
   514 function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {
   577 function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {
   515 	if ( $nooped_plural['domain'] )
   578 	if ( $nooped_plural['domain'] ) {
   516 		$domain = $nooped_plural['domain'];
   579 		$domain = $nooped_plural['domain'];
   517 
   580 	}
   518 	if ( $nooped_plural['context'] )
   581 
       
   582 	if ( $nooped_plural['context'] ) {
   519 		return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );
   583 		return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );
   520 	else
   584 	} else {
   521 		return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );
   585 		return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );
       
   586 	}
   522 }
   587 }
   523 
   588 
   524 /**
   589 /**
   525  * Load a .mo file into the text domain $domain.
   590  * Load a .mo file into the text domain $domain.
   526  *
   591  *
   530  * On success, the .mo file will be placed in the $l10n global by $domain
   595  * On success, the .mo file will be placed in the $l10n global by $domain
   531  * and will be a MO object.
   596  * and will be a MO object.
   532  *
   597  *
   533  * @since 1.5.0
   598  * @since 1.5.0
   534  *
   599  *
   535  * @global array $l10n          An array of all currently loaded text domains.
   600  * @global MO[] $l10n          An array of all currently loaded text domains.
   536  * @global array $l10n_unloaded An array of all text domains that have been unloaded again.
   601  * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
   537  *
   602  *
   538  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   603  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   539  * @param string $mofile Path to the .mo file.
   604  * @param string $mofile Path to the .mo file.
   540  * @return bool True on success, false on failure.
   605  * @return bool True on success, false on failure.
   541  */
   606  */
   579 	 * @param string $mofile Path to the MO file.
   644 	 * @param string $mofile Path to the MO file.
   580 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   645 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   581 	 */
   646 	 */
   582 	$mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
   647 	$mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
   583 
   648 
   584 	if ( !is_readable( $mofile ) ) return false;
   649 	if ( ! is_readable( $mofile ) ) {
       
   650 		return false;
       
   651 	}
   585 
   652 
   586 	$mo = new MO();
   653 	$mo = new MO();
   587 	if ( !$mo->import_from_file( $mofile ) ) return false;
   654 	if ( ! $mo->import_from_file( $mofile ) ) {
   588 
   655 		return false;
   589 	if ( isset( $l10n[$domain] ) )
   656 	}
   590 		$mo->merge_with( $l10n[$domain] );
   657 
       
   658 	if ( isset( $l10n[ $domain ] ) ) {
       
   659 		$mo->merge_with( $l10n[ $domain ] );
       
   660 	}
   591 
   661 
   592 	unset( $l10n_unloaded[ $domain ] );
   662 	unset( $l10n_unloaded[ $domain ] );
   593 
   663 
   594 	$l10n[$domain] = &$mo;
   664 	$l10n[ $domain ] = &$mo;
   595 
   665 
   596 	return true;
   666 	return true;
   597 }
   667 }
   598 
   668 
   599 /**
   669 /**
   600  * Unload translations for a text domain.
   670  * Unload translations for a text domain.
   601  *
   671  *
   602  * @since 3.0.0
   672  * @since 3.0.0
   603  *
   673  *
   604  * @global array $l10n          An array of all currently loaded text domains.
   674  * @global MO[] $l10n          An array of all currently loaded text domains.
   605  * @global array $l10n_unloaded An array of all text domains that have been unloaded again.
   675  * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
   606  *
   676  *
   607  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   677  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   608  * @return bool Whether textdomain was unloaded.
   678  * @return bool Whether textdomain was unloaded.
   609  */
   679  */
   610 function unload_textdomain( $domain ) {
   680 function unload_textdomain( $domain ) {
   635 	 *
   705 	 *
   636 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   706 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   637 	 */
   707 	 */
   638 	do_action( 'unload_textdomain', $domain );
   708 	do_action( 'unload_textdomain', $domain );
   639 
   709 
   640 	if ( isset( $l10n[$domain] ) ) {
   710 	if ( isset( $l10n[ $domain ] ) ) {
   641 		unset( $l10n[$domain] );
   711 		unset( $l10n[ $domain ] );
   642 
   712 
   643 		$l10n_unloaded[ $domain ] = true;
   713 		$l10n_unloaded[ $domain ] = true;
   644 
   714 
   645 		return true;
   715 		return true;
   646 	}
   716 	}
   661  * @param string $locale Optional. Locale to load. Default is the value of get_locale().
   731  * @param string $locale Optional. Locale to load. Default is the value of get_locale().
   662  * @return bool Whether the textdomain was loaded.
   732  * @return bool Whether the textdomain was loaded.
   663  */
   733  */
   664 function load_default_textdomain( $locale = null ) {
   734 function load_default_textdomain( $locale = null ) {
   665 	if ( null === $locale ) {
   735 	if ( null === $locale ) {
   666 		$locale = is_admin() ? get_user_locale() : get_locale();
   736 		$locale = determine_locale();
   667 	}
   737 	}
   668 
   738 
   669 	// Unload previously loaded strings so we can switch translations.
   739 	// Unload previously loaded strings so we can switch translations.
   670 	unload_textdomain( 'default' );
   740 	unload_textdomain( 'default' );
   671 
   741 
   672 	$return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" );
   742 	$return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" );
   673 
   743 
   674 	if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists(  WP_LANG_DIR . "/admin-$locale.mo" ) ) {
   744 	if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) {
   675 		load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" );
   745 		load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" );
   676 		return $return;
   746 		return $return;
   677 	}
   747 	}
   678 
   748 
   679 	if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) {
   749 	if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) {
   680 		load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
   750 		load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
   681 	}
   751 	}
   682 
   752 
   683 	if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) )
   753 	if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) {
   684 		load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" );
   754 		load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" );
       
   755 	}
   685 
   756 
   686 	return $return;
   757 	return $return;
   687 }
   758 }
   688 
   759 
   689 /**
   760 /**
   694  * The .mo file should be named based on the text domain with a dash, and then the locale exactly.
   765  * The .mo file should be named based on the text domain with a dash, and then the locale exactly.
   695  *
   766  *
   696  * @since 1.5.0
   767  * @since 1.5.0
   697  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
   768  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
   698  *
   769  *
   699  * @param string $domain          Unique identifier for retrieving translated strings
   770  * @param string       $domain          Unique identifier for retrieving translated strings
   700  * @param string $deprecated      Optional. Use the $plugin_rel_path parameter instead. Default false.
   771  * @param string|false $deprecated      Optional. Deprecated. Use the $plugin_rel_path parameter instead.
   701  * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
   772  *                                      Default false.
   702  *                                Default false.
   773  * @param string|false $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
       
   774  *                                      Default false.
   703  * @return bool True when textdomain is successfully loaded, false otherwise.
   775  * @return bool True when textdomain is successfully loaded, false otherwise.
   704  */
   776  */
   705 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
   777 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
   706 	/**
   778 	/**
   707 	 * Filters a plugin's locale.
   779 	 * Filters a plugin's locale.
   709 	 * @since 3.0.0
   781 	 * @since 3.0.0
   710 	 *
   782 	 *
   711 	 * @param string $locale The plugin's current locale.
   783 	 * @param string $locale The plugin's current locale.
   712 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   784 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   713 	 */
   785 	 */
   714 	$locale = apply_filters( 'plugin_locale', is_admin() ? get_user_locale() : get_locale(), $domain );
   786 	$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
   715 
   787 
   716 	$mofile = $domain . '-' . $locale . '.mo';
   788 	$mofile = $domain . '-' . $locale . '.mo';
   717 
   789 
   718 	// Try to load from the languages directory first.
   790 	// Try to load from the languages directory first.
   719 	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) {
   791 	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) {
   743  *                                   file resides. Default empty string.
   815  *                                   file resides. Default empty string.
   744  * @return bool True when textdomain is successfully loaded, false otherwise.
   816  * @return bool True when textdomain is successfully loaded, false otherwise.
   745  */
   817  */
   746 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
   818 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
   747 	/** This filter is documented in wp-includes/l10n.php */
   819 	/** This filter is documented in wp-includes/l10n.php */
   748 	$locale = apply_filters( 'plugin_locale', is_admin() ? get_user_locale() : get_locale(), $domain );
   820 	$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
   749 
   821 
   750 	$mofile = $domain . '-' . $locale . '.mo';
   822 	$mofile = $domain . '-' . $locale . '.mo';
   751 
   823 
   752 	// Try to load from the languages directory first.
   824 	// Try to load from the languages directory first.
   753 	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) {
   825 	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) {
   782 	 * @since 3.0.0
   854 	 * @since 3.0.0
   783 	 *
   855 	 *
   784 	 * @param string $locale The theme's current locale.
   856 	 * @param string $locale The theme's current locale.
   785 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   857 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   786 	 */
   858 	 */
   787 	$locale = apply_filters( 'theme_locale', is_admin() ? get_user_locale() : get_locale(), $domain );
   859 	$locale = apply_filters( 'theme_locale', determine_locale(), $domain );
   788 
   860 
   789 	$mofile = $domain . '-' . $locale . '.mo';
   861 	$mofile = $domain . '-' . $locale . '.mo';
   790 
   862 
   791 	// Try to load from the languages directory first.
   863 	// Try to load from the languages directory first.
   792 	if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile ) ) {
   864 	if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile ) ) {
   814  * @param string $path   Optional. Path to the directory containing the .mo file.
   886  * @param string $path   Optional. Path to the directory containing the .mo file.
   815  *                       Default false.
   887  *                       Default false.
   816  * @return bool True when the theme textdomain is successfully loaded, false otherwise.
   888  * @return bool True when the theme textdomain is successfully loaded, false otherwise.
   817  */
   889  */
   818 function load_child_theme_textdomain( $domain, $path = false ) {
   890 function load_child_theme_textdomain( $domain, $path = false ) {
   819 	if ( ! $path )
   891 	if ( ! $path ) {
   820 		$path = get_stylesheet_directory();
   892 		$path = get_stylesheet_directory();
       
   893 	}
   821 	return load_theme_textdomain( $domain, $path );
   894 	return load_theme_textdomain( $domain, $path );
       
   895 }
       
   896 
       
   897 /**
       
   898  * Loads the script translated strings.
       
   899  *
       
   900  * @since 5.0.0
       
   901  * @since 5.0.2 Uses load_script_translations() to load translation data.
       
   902  * @since 5.1.0 The `$domain` parameter was made optional.
       
   903  *
       
   904  * @see WP_Scripts::set_translations()
       
   905  *
       
   906  * @param string $handle Name of the script to register a translation domain to.
       
   907  * @param string $domain Optional. Text domain. Default 'default'.
       
   908  * @param string $path   Optional. The full file path to the directory containing translation files.
       
   909  *
       
   910  * @return false|string False if the script textdomain could not be loaded, the translated strings
       
   911  *                      in JSON encoding otherwise.
       
   912  */
       
   913 function load_script_textdomain( $handle, $domain = 'default', $path = null ) {
       
   914 	$wp_scripts = wp_scripts();
       
   915 
       
   916 	if ( ! isset( $wp_scripts->registered[ $handle ] ) ) {
       
   917 		return false;
       
   918 	}
       
   919 
       
   920 	$path   = untrailingslashit( $path );
       
   921 	$locale = determine_locale();
       
   922 
       
   923 	// If a path was given and the handle file exists simply return it.
       
   924 	$file_base       = $domain === 'default' ? $locale : $domain . '-' . $locale;
       
   925 	$handle_filename = $file_base . '-' . $handle . '.json';
       
   926 
       
   927 	if ( $path ) {
       
   928 		$translations = load_script_translations( $path . '/' . $handle_filename, $handle, $domain );
       
   929 
       
   930 		if ( $translations ) {
       
   931 			return $translations;
       
   932 		}
       
   933 	}
       
   934 
       
   935 	$src = $wp_scripts->registered[ $handle ]->src;
       
   936 
       
   937 	if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $wp_scripts->content_url && 0 === strpos( $src, $wp_scripts->content_url ) ) ) {
       
   938 		$src = $wp_scripts->base_url . $src;
       
   939 	}
       
   940 
       
   941 	$relative       = false;
       
   942 	$languages_path = WP_LANG_DIR;
       
   943 
       
   944 	$src_url     = wp_parse_url( $src );
       
   945 	$content_url = wp_parse_url( content_url() );
       
   946 	$site_url    = wp_parse_url( site_url() );
       
   947 
       
   948 	// If the host is the same or it's a relative URL.
       
   949 	if (
       
   950 		strpos( $src_url['path'], $content_url['path'] ) === 0 &&
       
   951 		( ! isset( $src_url['host'] ) || $src_url['host'] === $content_url['host'] )
       
   952 	) {
       
   953 		// Make the src relative the specific plugin or theme.
       
   954 		$relative = trim( substr( $src_url['path'], strlen( $content_url['path'] ) ), '/' );
       
   955 		$relative = explode( '/', $relative );
       
   956 
       
   957 		$languages_path = WP_LANG_DIR . '/' . $relative[0];
       
   958 
       
   959 		$relative = array_slice( $relative, 2 );
       
   960 		$relative = implode( '/', $relative );
       
   961 	} elseif ( ! isset( $src_url['host'] ) || $src_url['host'] === $site_url['host'] ) {
       
   962 		if ( ! isset( $site_url['path'] ) ) {
       
   963 			$relative = trim( $src_url['path'], '/' );
       
   964 		} elseif ( ( strpos( $src_url['path'], trailingslashit( $site_url['path'] ) ) === 0 ) ) {
       
   965 			// Make the src relative to the WP root.
       
   966 			$relative = substr( $src_url['path'], strlen( $site_url['path'] ) );
       
   967 			$relative = trim( $relative, '/' );
       
   968 		}
       
   969 	}
       
   970 
       
   971 	/**
       
   972 	 * Filters the relative path of scripts used for finding translation files.
       
   973 	 *
       
   974 	 * @since 5.0.2
       
   975 	 *
       
   976 	 * @param string $relative The relative path of the script. False if it could not be determined.
       
   977 	 * @param string $src      The full source url of the script.
       
   978 	 */
       
   979 	$relative = apply_filters( 'load_script_textdomain_relative_path', $relative, $src );
       
   980 
       
   981 	// If the source is not from WP.
       
   982 	if ( false === $relative ) {
       
   983 		return load_script_translations( false, $handle, $domain );
       
   984 	}
       
   985 
       
   986 	// Translations are always based on the unminified filename.
       
   987 	if ( substr( $relative, -7 ) === '.min.js' ) {
       
   988 		$relative = substr( $relative, 0, -7 ) . '.js';
       
   989 	}
       
   990 
       
   991 	$md5_filename = $file_base . '-' . md5( $relative ) . '.json';
       
   992 
       
   993 	if ( $path ) {
       
   994 		$translations = load_script_translations( $path . '/' . $md5_filename, $handle, $domain );
       
   995 
       
   996 		if ( $translations ) {
       
   997 			return $translations;
       
   998 		}
       
   999 	}
       
  1000 
       
  1001 	$translations = load_script_translations( $languages_path . '/' . $md5_filename, $handle, $domain );
       
  1002 
       
  1003 	if ( $translations ) {
       
  1004 		return $translations;
       
  1005 	}
       
  1006 
       
  1007 	return load_script_translations( false, $handle, $domain );
       
  1008 }
       
  1009 
       
  1010 /**
       
  1011  * Loads the translation data for the given script handle and text domain.
       
  1012  *
       
  1013  * @since 5.0.2
       
  1014  *
       
  1015  * @param string|false $file   Path to the translation file to load. False if there isn't one.
       
  1016  * @param string       $handle Name of the script to register a translation domain to.
       
  1017  * @param string       $domain The text domain.
       
  1018  * @return string|false The JSON-encoded translated strings for the given script handle and text domain. False if there are none.
       
  1019  */
       
  1020 function load_script_translations( $file, $handle, $domain ) {
       
  1021 	/**
       
  1022 	 * Pre-filters script translations for the given file, script handle and text domain.
       
  1023 	 *
       
  1024 	 * Returning a non-null value allows to override the default logic, effectively short-circuiting the function.
       
  1025 	 *
       
  1026 	 * @since 5.0.2
       
  1027 	 *
       
  1028 	 * @param string|false $translations JSON-encoded translation data. Default null.
       
  1029 	 * @param string|false $file         Path to the translation file to load. False if there isn't one.
       
  1030 	 * @param string       $handle       Name of the script to register a translation domain to.
       
  1031 	 * @param string       $domain       The text domain.
       
  1032 	 */
       
  1033 	$translations = apply_filters( 'pre_load_script_translations', null, $file, $handle, $domain );
       
  1034 
       
  1035 	if ( null !== $translations ) {
       
  1036 		return $translations;
       
  1037 	}
       
  1038 
       
  1039 	/**
       
  1040 	 * Filters the file path for loading script translations for the given script handle and text domain.
       
  1041 	 *
       
  1042 	 * @since 5.0.2
       
  1043 	 *
       
  1044 	 * @param string|false $file   Path to the translation file to load. False if there isn't one.
       
  1045 	 * @param string       $handle Name of the script to register a translation domain to.
       
  1046 	 * @param string       $domain The text domain.
       
  1047 	 */
       
  1048 	$file = apply_filters( 'load_script_translation_file', $file, $handle, $domain );
       
  1049 
       
  1050 	if ( ! $file || ! is_readable( $file ) ) {
       
  1051 		return false;
       
  1052 	}
       
  1053 
       
  1054 	$translations = file_get_contents( $file );
       
  1055 
       
  1056 	/**
       
  1057 	 * Filters script translations for the given file, script handle and text domain.
       
  1058 	 *
       
  1059 	 * @since 5.0.2
       
  1060 	 *
       
  1061 	 * @param string $translations JSON-encoded translation data.
       
  1062 	 * @param string $file         Path to the translation file that was loaded.
       
  1063 	 * @param string $handle       Name of the script to register a translation domain to.
       
  1064 	 * @param string $domain       The text domain.
       
  1065 	 */
       
  1066 	return apply_filters( 'load_script_translations', $translations, $file, $handle, $domain );
   822 }
  1067 }
   823 
  1068 
   824 /**
  1069 /**
   825  * Loads plugin and theme textdomains just-in-time.
  1070  * Loads plugin and theme textdomains just-in-time.
   826  *
  1071  *
   830  *
  1075  *
   831  * @since 4.6.0
  1076  * @since 4.6.0
   832  * @access private
  1077  * @access private
   833  *
  1078  *
   834  * @see get_translations_for_domain()
  1079  * @see get_translations_for_domain()
   835  * @global array $l10n_unloaded An array of all text domains that have been unloaded again.
  1080  * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
   836  *
  1081  *
   837  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
  1082  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   838  * @return bool True when the textdomain is successfully loaded, false otherwise.
  1083  * @return bool True when the textdomain is successfully loaded, false otherwise.
   839  */
  1084  */
   840 function _load_textdomain_just_in_time( $domain ) {
  1085 function _load_textdomain_just_in_time( $domain ) {
   862  *
  1107  *
   863  * @since 4.7.0
  1108  * @since 4.7.0
   864  * @access private
  1109  * @access private
   865  *
  1110  *
   866  * @see _load_textdomain_just_in_time()
  1111  * @see _load_textdomain_just_in_time()
       
  1112  * @staticvar array $available_translations
   867  *
  1113  *
   868  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
  1114  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   869  * @param bool   $reset  Whether to reset the internal cache. Used by the switch to locale functionality.
  1115  * @param bool   $reset  Whether to reset the internal cache. Used by the switch to locale functionality.
   870  * @return string|false The path to the translation file or false if no translation file was found.
  1116  * @return string|false The path to the translation file or false if no translation file was found.
   871  */
  1117  */
   890  *
  1136  *
   891  * @since 4.7.0
  1137  * @since 4.7.0
   892  * @access private
  1138  * @access private
   893  *
  1139  *
   894  * @see _get_path_to_translation()
  1140  * @see _get_path_to_translation()
       
  1141  * @staticvar array $cached_mofiles
   895  *
  1142  *
   896  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
  1143  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   897  * @return string|false The path to the translation file or false if no translation file was found.
  1144  * @return string|false The path to the translation file or false if no translation file was found.
   898  */
  1145  */
   899 function _get_path_to_translation_from_lang_dir( $domain ) {
  1146 function _get_path_to_translation_from_lang_dir( $domain ) {
   913 				$cached_mofiles = array_merge( $cached_mofiles, $mofiles );
  1160 				$cached_mofiles = array_merge( $cached_mofiles, $mofiles );
   914 			}
  1161 			}
   915 		}
  1162 		}
   916 	}
  1163 	}
   917 
  1164 
   918 	$locale = is_admin() ? get_user_locale() : get_locale();
  1165 	$locale = determine_locale();
   919 	$mofile = "{$domain}-{$locale}.mo";
  1166 	$mofile = "{$domain}-{$locale}.mo";
   920 
  1167 
   921 	$path = WP_LANG_DIR . '/plugins/' . $mofile;
  1168 	$path = WP_LANG_DIR . '/plugins/' . $mofile;
   922 	if ( in_array( $path, $cached_mofiles ) ) {
  1169 	if ( in_array( $path, $cached_mofiles ) ) {
   923 		return $path;
  1170 		return $path;
   936  *
  1183  *
   937  * If there isn't one, returns empty Translations instance.
  1184  * If there isn't one, returns empty Translations instance.
   938  *
  1185  *
   939  * @since 2.8.0
  1186  * @since 2.8.0
   940  *
  1187  *
   941  * @global array $l10n
  1188  * @global MO[] $l10n
       
  1189  * @staticvar NOOP_Translations $noop_translations
   942  *
  1190  *
   943  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
  1191  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   944  * @return Translations|NOOP_Translations A Translations instance.
  1192  * @return Translations|NOOP_Translations A Translations instance.
   945  */
  1193  */
   946 function get_translations_for_domain( $domain ) {
  1194 function get_translations_for_domain( $domain ) {
   960 /**
  1208 /**
   961  * Whether there are translations for the text domain.
  1209  * Whether there are translations for the text domain.
   962  *
  1210  *
   963  * @since 3.0.0
  1211  * @since 3.0.0
   964  *
  1212  *
   965  * @global array $l10n
  1213  * @global MO[] $l10n
   966  *
  1214  *
   967  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
  1215  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   968  * @return bool Whether there are translations.
  1216  * @return bool Whether there are translations.
   969  */
  1217  */
   970 function is_textdomain_loaded( $domain ) {
  1218 function is_textdomain_loaded( $domain ) {
   983  * using the old context format: 'Role name|User role' and just skipping the
  1231  * using the old context format: 'Role name|User role' and just skipping the
   984  * content after the last bar is easier than fixing them in the DB. New installations
  1232  * content after the last bar is easier than fixing them in the DB. New installations
   985  * won't suffer from that problem.
  1233  * won't suffer from that problem.
   986  *
  1234  *
   987  * @since 2.8.0
  1235  * @since 2.8.0
   988  *
  1236  * @since 5.2.0 Added the `$domain` parameter.
   989  * @param string $name The role name.
  1237  *
       
  1238  * @param string $name   The role name.
       
  1239  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
       
  1240  *                       Default 'default'.
   990  * @return string Translated role name on success, original name on failure.
  1241  * @return string Translated role name on success, original name on failure.
   991  */
  1242  */
   992 function translate_user_role( $name ) {
  1243 function translate_user_role( $name, $domain = 'default' ) {
   993 	return translate_with_gettext_context( before_last_bar($name), 'User role' );
  1244 	return translate_with_gettext_context( before_last_bar( $name ), 'User role', $domain );
   994 }
  1245 }
   995 
  1246 
   996 /**
  1247 /**
   997  * Get all available languages based on the presence of *.mo files in a given directory.
  1248  * Get all available languages based on the presence of *.mo files in a given directory.
   998  *
  1249  *
  1040  *
  1291  *
  1041  * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
  1292  * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
  1042  * @return array Array of language data.
  1293  * @return array Array of language data.
  1043  */
  1294  */
  1044 function wp_get_installed_translations( $type ) {
  1295 function wp_get_installed_translations( $type ) {
  1045 	if ( $type !== 'themes' && $type !== 'plugins' && $type !== 'core' )
  1296 	if ( $type !== 'themes' && $type !== 'plugins' && $type !== 'core' ) {
  1046 		return array();
  1297 		return array();
       
  1298 	}
  1047 
  1299 
  1048 	$dir = 'core' === $type ? '' : "/$type";
  1300 	$dir = 'core' === $type ? '' : "/$type";
  1049 
  1301 
  1050 	if ( ! is_dir( WP_LANG_DIR ) )
  1302 	if ( ! is_dir( WP_LANG_DIR ) ) {
  1051 		return array();
  1303 		return array();
  1052 
  1304 	}
  1053 	if ( $dir && ! is_dir( WP_LANG_DIR . $dir ) )
  1305 
       
  1306 	if ( $dir && ! is_dir( WP_LANG_DIR . $dir ) ) {
  1054 		return array();
  1307 		return array();
       
  1308 	}
  1055 
  1309 
  1056 	$files = scandir( WP_LANG_DIR . $dir );
  1310 	$files = scandir( WP_LANG_DIR . $dir );
  1057 	if ( ! $files )
  1311 	if ( ! $files ) {
  1058 		return array();
  1312 		return array();
       
  1313 	}
  1059 
  1314 
  1060 	$language_data = array();
  1315 	$language_data = array();
  1061 
  1316 
  1062 	foreach ( $files as $file ) {
  1317 	foreach ( $files as $file ) {
  1063 		if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "$dir/$file" ) ) {
  1318 		if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "$dir/$file" ) ) {
  1067 			continue;
  1322 			continue;
  1068 		}
  1323 		}
  1069 		if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
  1324 		if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
  1070 			continue;
  1325 			continue;
  1071 		}
  1326 		}
  1072 		if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) )  {
  1327 		if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) {
  1073 			continue;
  1328 			continue;
  1074 		}
  1329 		}
  1075 
  1330 
  1076 		list( , $textdomain, $language ) = $match;
  1331 		list( , $textdomain, $language ) = $match;
  1077 		if ( '' === $textdomain ) {
  1332 		if ( '' === $textdomain ) {
  1089  *
  1344  *
  1090  * @param string $po_file Path to PO file.
  1345  * @param string $po_file Path to PO file.
  1091  * @return array PO file headers.
  1346  * @return array PO file headers.
  1092  */
  1347  */
  1093 function wp_get_pomo_file_data( $po_file ) {
  1348 function wp_get_pomo_file_data( $po_file ) {
  1094 	$headers = get_file_data( $po_file, array(
  1349 	$headers = get_file_data(
  1095 		'POT-Creation-Date'  => '"POT-Creation-Date',
  1350 		$po_file,
  1096 		'PO-Revision-Date'   => '"PO-Revision-Date',
  1351 		array(
  1097 		'Project-Id-Version' => '"Project-Id-Version',
  1352 			'POT-Creation-Date'  => '"POT-Creation-Date',
  1098 		'X-Generator'        => '"X-Generator',
  1353 			'PO-Revision-Date'   => '"PO-Revision-Date',
  1099 	) );
  1354 			'Project-Id-Version' => '"Project-Id-Version',
       
  1355 			'X-Generator'        => '"X-Generator',
       
  1356 		)
       
  1357 	);
  1100 	foreach ( $headers as $header => $value ) {
  1358 	foreach ( $headers as $header => $value ) {
  1101 		// Remove possible contextual '\n' and closing double quote.
  1359 		// Remove possible contextual '\n' and closing double quote.
  1102 		$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
  1360 		$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
  1103 	}
  1361 	}
  1104 	return $headers;
  1362 	return $headers;
  1108  * Language selector.
  1366  * Language selector.
  1109  *
  1367  *
  1110  * @since 4.0.0
  1368  * @since 4.0.0
  1111  * @since 4.3.0 Introduced the `echo` argument.
  1369  * @since 4.3.0 Introduced the `echo` argument.
  1112  * @since 4.7.0 Introduced the `show_option_site_default` argument.
  1370  * @since 4.7.0 Introduced the `show_option_site_default` argument.
       
  1371  * @since 5.1.0 Introduced the `show_option_en_us` argument.
  1113  *
  1372  *
  1114  * @see get_available_languages()
  1373  * @see get_available_languages()
  1115  * @see wp_get_available_translations()
  1374  * @see wp_get_available_translations()
  1116  *
  1375  *
  1117  * @param string|array $args {
  1376  * @param string|array $args {
  1126  *     @type string   $selected                     Language which should be selected. Default empty.
  1385  *     @type string   $selected                     Language which should be selected. Default empty.
  1127  *     @type bool|int $echo                         Whether to echo the generated markup. Accepts 0, 1, or their
  1386  *     @type bool|int $echo                         Whether to echo the generated markup. Accepts 0, 1, or their
  1128  *                                                  boolean equivalents. Default 1.
  1387  *                                                  boolean equivalents. Default 1.
  1129  *     @type bool     $show_available_translations  Whether to show available translations. Default true.
  1388  *     @type bool     $show_available_translations  Whether to show available translations. Default true.
  1130  *     @type bool     $show_option_site_default     Whether to show an option to fall back to the site's locale. Default false.
  1389  *     @type bool     $show_option_site_default     Whether to show an option to fall back to the site's locale. Default false.
       
  1390  *     @type bool     $show_option_en_us            Whether to show an option for English (United States). Default true.
  1131  * }
  1391  * }
  1132  * @return string HTML content
  1392  * @return string HTML content
  1133  */
  1393  */
  1134 function wp_dropdown_languages( $args = array() ) {
  1394 function wp_dropdown_languages( $args = array() ) {
  1135 
  1395 
  1136 	$parsed_args = wp_parse_args( $args, array(
  1396 	$parsed_args = wp_parse_args(
  1137 		'id'           => 'locale',
  1397 		$args,
  1138 		'name'         => 'locale',
  1398 		array(
  1139 		'languages'    => array(),
  1399 			'id'                          => 'locale',
  1140 		'translations' => array(),
  1400 			'name'                        => 'locale',
  1141 		'selected'     => '',
  1401 			'languages'                   => array(),
  1142 		'echo'         => 1,
  1402 			'translations'                => array(),
  1143 		'show_available_translations' => true,
  1403 			'selected'                    => '',
  1144 		'show_option_site_default'    => false,
  1404 			'echo'                        => 1,
  1145 	) );
  1405 			'show_available_translations' => true,
       
  1406 			'show_option_site_default'    => false,
       
  1407 			'show_option_en_us'           => true,
       
  1408 		)
       
  1409 	);
  1146 
  1410 
  1147 	// Bail if no ID or no name.
  1411 	// Bail if no ID or no name.
  1148 	if ( ! $parsed_args['id'] || ! $parsed_args['name'] ) {
  1412 	if ( ! $parsed_args['id'] || ! $parsed_args['name'] ) {
  1149 		return;
  1413 		return;
  1150 	}
  1414 	}
  1202 			selected( 'site-default', $parsed_args['selected'], false ),
  1466 			selected( 'site-default', $parsed_args['selected'], false ),
  1203 			_x( 'Site Default', 'default site language' )
  1467 			_x( 'Site Default', 'default site language' )
  1204 		);
  1468 		);
  1205 	}
  1469 	}
  1206 
  1470 
  1207 	// Always show English.
  1471 	if ( $parsed_args['show_option_en_us'] ) {
  1208 	$structure[] = sprintf(
  1472 		$structure[] = sprintf(
  1209 		'<option value="" lang="en" data-installed="1"%s>English (United States)</option>',
  1473 			'<option value="" lang="en" data-installed="1"%s>English (United States)</option>',
  1210 		selected( '', $parsed_args['selected'], false )
  1474 			selected( '', $parsed_args['selected'], false )
  1211 	);
  1475 		);
  1212 
  1476 	}
  1213 	// List installed languages. 
  1477 
       
  1478 	// List installed languages.
  1214 	foreach ( $languages as $language ) {
  1479 	foreach ( $languages as $language ) {
  1215 		$structure[] = sprintf(
  1480 		$structure[] = sprintf(
  1216 			'<option value="%s" lang="%s"%s data-installed="1">%s</option>',
  1481 			'<option value="%s" lang="%s"%s data-installed="1">%s</option>',
  1217 			esc_attr( $language['language'] ),
  1482 			esc_attr( $language['language'] ),
  1218 			esc_attr( $language['lang'] ),
  1483 			esc_attr( $language['lang'] ),
  1250 
  1515 
  1251 	return $output;
  1516 	return $output;
  1252 }
  1517 }
  1253 
  1518 
  1254 /**
  1519 /**
  1255  * Checks if current locale is RTL.
  1520  * Determines whether the current locale is right-to-left (RTL).
       
  1521  *
       
  1522  * For more information on this and similar theme functions, check out
       
  1523  * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
       
  1524  * Conditional Tags} article in the Theme Developer Handbook.
  1256  *
  1525  *
  1257  * @since 3.0.0
  1526  * @since 3.0.0
  1258  *
  1527  *
  1259  * @global WP_Locale $wp_locale
  1528  * @global WP_Locale $wp_locale
  1260  *
  1529  *