wp/wp-includes/l10n.php
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
4:346c88efed21 5:5e2f62d02dcd
    22  * @since 1.5.0
    22  * @since 1.5.0
    23  *
    23  *
    24  * @return string The locale of the blog or from the 'locale' hook.
    24  * @return string The locale of the blog or from the 'locale' hook.
    25  */
    25  */
    26 function get_locale() {
    26 function get_locale() {
    27 	global $locale;
    27 	global $locale, $wp_local_package;
    28 
    28 
    29 	if ( isset( $locale ) )
    29 	if ( isset( $locale ) ) {
    30 		/**
    30 		/**
    31 		 * Filter WordPress install's locale ID.
    31 		 * Filter WordPress install's locale ID.
    32 		 *
    32 		 *
    33 		 * @since 1.5.2
    33 		 * @since 1.5.0
    34 		 *
    34 		 *
    35 		 * @param string $locale The locale ID.
    35 		 * @param string $locale The locale ID.
    36 		 */
    36 		 */
    37 		return apply_filters( 'locale', $locale );
    37 		return apply_filters( 'locale', $locale );
    38 
    38 	}
    39 	// WPLANG is defined in wp-config.
    39 
    40 	if ( defined( 'WPLANG' ) )
    40 	if ( isset( $wp_local_package ) ) {
       
    41 		$locale = $wp_local_package;
       
    42 	}
       
    43 
       
    44 	// WPLANG was defined in wp-config.
       
    45 	if ( defined( 'WPLANG' ) ) {
    41 		$locale = WPLANG;
    46 		$locale = WPLANG;
       
    47 	}
    42 
    48 
    43 	// If multisite, check options.
    49 	// If multisite, check options.
    44 	if ( is_multisite() ) {
    50 	if ( is_multisite() ) {
    45 		// Don't check blog option when installing.
    51 		// Don't check blog option when installing.
    46 		if ( defined( 'WP_INSTALLING' ) || ( false === $ms_locale = get_option( 'WPLANG' ) ) )
    52 		if ( defined( 'WP_INSTALLING' ) || ( false === $ms_locale = get_option( 'WPLANG' ) ) ) {
    47 			$ms_locale = get_site_option('WPLANG');
    53 			$ms_locale = get_site_option( 'WPLANG' );
    48 
    54 		}
    49 		if ( $ms_locale !== false )
    55 
       
    56 		if ( $ms_locale !== false ) {
    50 			$locale = $ms_locale;
    57 			$locale = $ms_locale;
    51 	}
    58 		}
    52 
    59 	} else {
    53 	if ( empty( $locale ) )
    60 		$db_locale = get_option( 'WPLANG' );
       
    61 		if ( $db_locale !== false ) {
       
    62 			$locale = $db_locale;
       
    63 		}
       
    64 	}
       
    65 
       
    66 	if ( empty( $locale ) ) {
    54 		$locale = 'en_US';
    67 		$locale = 'en_US';
    55 
    68 	}
    56 	// duplicate_hook
    69 
       
    70 	/** This filter is documented in wp-includes/l10n.php */
    57 	return apply_filters( 'locale', $locale );
    71 	return apply_filters( 'locale', $locale );
    58 }
    72 }
    59 
    73 
    60 /**
    74 /**
    61  * Retrieve the translation of $text.
    75  * Retrieve the translation of $text.
    62  *
    76  *
    63  * If there is no translation, or the text domain isn't loaded, the original text is returned.
    77  * If there is no translation, or the text domain isn't loaded, the original text is returned.
    64  *
    78  *
    65  * <strong>Note:</strong> Don't use translate() directly, use __() or related functions.
    79  * *Note:* Don't use {@see translate()} directly, use `{@see __()} or related functions.
    66  *
    80  *
    67  * @since 2.2.0
    81  * @since 2.2.0
    68  *
    82  *
    69  * @param string $text   Text to translate.
    83  * @param string $text   Text to translate.
    70  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    84  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    71  * @return string Translated text
    85  * @return string Translated text
    72  */
    86  */
    73 function translate( $text, $domain = 'default' ) {
    87 function translate( $text, $domain = 'default' ) {
    74 	$translations = get_translations_for_domain( $domain );
    88 	$translations = get_translations_for_domain( $domain );
    75 	$translations = $translations->translate( $text );
    89 	$translations = $translations->translate( $text );
       
    90 
    76 	/**
    91 	/**
    77 	 * Filter text with its translation.
    92 	 * Filter text with its translation.
    78 	 *
    93 	 *
    79 	 * @since 2.0.11
    94 	 * @since 2.0.11
    80 	 *
    95 	 *
   348  *
   363  *
   349  * Used when you want to keep structures with translatable plural
   364  * Used when you want to keep structures with translatable plural
   350  * strings and use them later.
   365  * strings and use them later.
   351  *
   366  *
   352  * Example:
   367  * Example:
   353  * <code>
   368  *
   354  * $messages = array(
   369  *     $messages = array(
   355  *  	'post' => _n_noop('%s post', '%s posts'),
   370  *      	'post' => _n_noop( '%s post', '%s posts' ),
   356  *  	'page' => _n_noop('%s pages', '%s pages')
   371  *      	'page' => _n_noop( '%s pages', '%s pages' ),
   357  * );
   372  *     );
   358  * ...
   373  *     ...
   359  * $message = $messages[$type];
   374  *     $message = $messages[ $type ];
   360  * $usable_text = sprintf( translate_nooped_plural( $message, $count ), $count );
   375  *     $usable_text = sprintf( translate_nooped_plural( $message, $count ), $count );
   361  * </code>
       
   362  *
   376  *
   363  * @since 2.5.0
   377  * @since 2.5.0
   364  *
   378  *
   365  * @param string $singular Single form to be i18ned.
   379  * @param string $singular Single form to be i18ned.
   366  * @param string $plural   Plural form to be i18ned.
   380  * @param string $plural   Plural form to be i18ned.
   373 
   387 
   374 /**
   388 /**
   375  * Register plural strings with context in POT file, but don't translate them.
   389  * Register plural strings with context in POT file, but don't translate them.
   376  *
   390  *
   377  * @since 2.8.0
   391  * @since 2.8.0
       
   392  * @param string $singular
       
   393  * @param string $plural
       
   394  * @param string $context
       
   395  * @param string|null $domain
       
   396  * @return array
   378  */
   397  */
   379 function _nx_noop( $singular, $plural, $context, $domain = null ) {
   398 function _nx_noop( $singular, $plural, $context, $domain = null ) {
   380 	return array( 0 => $singular, 1 => $plural, 2 => $context, 'singular' => $singular, 'plural' => $plural, 'context' => $context, 'domain' => $domain );
   399 	return array( 0 => $singular, 1 => $plural, 2 => $context, 'singular' => $singular, 'plural' => $plural, 'context' => $context, 'domain' => $domain );
   381 }
   400 }
   382 
   401 
   422 	/**
   441 	/**
   423 	 * Filter text domain and/or MO file path for loading translations.
   442 	 * Filter text domain and/or MO file path for loading translations.
   424 	 *
   443 	 *
   425 	 * @since 2.9.0
   444 	 * @since 2.9.0
   426 	 *
   445 	 *
   427 	 * @param boolean        Whether to override the text domain. Default false.
   446 	 * @param bool   $override Whether to override the text domain. Default false.
   428 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   447 	 * @param string $domain   Text domain. Unique identifier for retrieving translated strings.
   429 	 * @param string $mofile Path to the MO file.
   448 	 * @param string $mofile   Path to the MO file.
   430 	 */
   449 	 */
   431 	$plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile );
   450 	$plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile );
   432 
   451 
   433 	if ( true == $plugin_override ) {
   452 	if ( true == $plugin_override ) {
   434 		return true;
   453 		return true;
   477  */
   496  */
   478 function unload_textdomain( $domain ) {
   497 function unload_textdomain( $domain ) {
   479 	global $l10n;
   498 	global $l10n;
   480 
   499 
   481 	/**
   500 	/**
   482 	 * Filter text text domain for loading translation.
   501 	 * Filter the text domain for loading translation.
   483 	 *
   502 	 *
   484 	 * @since 3.0.0
   503 	 * @since 3.0.0
   485 	 *
   504 	 *
   486 	 * @param boolean        Whether to override unloading the text domain. Default false.
   505 	 * @param bool   $override Whether to override unloading the text domain. Default false.
   487 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   506 	 * @param string $domain   Text domain. Unique identifier for retrieving translated strings.
   488 	 */
   507 	 */
   489 	$plugin_override = apply_filters( 'override_unload_textdomain', false, $domain );
   508 	$plugin_override = apply_filters( 'override_unload_textdomain', false, $domain );
   490 
   509 
   491 	if ( $plugin_override )
   510 	if ( $plugin_override )
   492 		return true;
   511 		return true;
   515  * The translated (.mo) file is named based on the locale.
   534  * The translated (.mo) file is named based on the locale.
   516  *
   535  *
   517  * @see load_textdomain()
   536  * @see load_textdomain()
   518  *
   537  *
   519  * @since 1.5.0
   538  * @since 1.5.0
   520  */
   539  *
   521 function load_default_textdomain() {
   540  * @param string $locale Optional. Locale to load. Default is the value of {@see get_locale()}.
   522 	$locale = get_locale();
   541  * @return bool Whether the textdomain was loaded.
   523 
   542  */
   524 	load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" );
   543 function load_default_textdomain( $locale = null ) {
       
   544 	if ( null === $locale ) {
       
   545 		$locale = get_locale();
       
   546 	}
       
   547 
       
   548 	// Unload previously loaded strings so we can switch translations.
       
   549 	unload_textdomain( 'default' );
       
   550 
       
   551 	$return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" );
   525 
   552 
   526 	if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists(  WP_LANG_DIR . "/admin-$locale.mo" ) ) {
   553 	if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists(  WP_LANG_DIR . "/admin-$locale.mo" ) ) {
   527 		load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" );
   554 		load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" );
   528 		return;
   555 		return $return;
   529 	}
   556 	}
   530 
   557 
   531 	if ( is_admin() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) )
   558 	if ( is_admin() || defined( 'WP_INSTALLING' ) || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) {
   532 		load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
   559 		load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
       
   560 	}
   533 
   561 
   534 	if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) )
   562 	if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) )
   535 		load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" );
   563 		load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" );
   536 
   564 
       
   565 	return $return;
   537 }
   566 }
   538 
   567 
   539 /**
   568 /**
   540  * Load a plugin's translated strings.
   569  * Load a plugin's translated strings.
   541  *
   570  *
   546  * @since 1.5.0
   575  * @since 1.5.0
   547  *
   576  *
   548  * @param string $domain          Unique identifier for retrieving translated strings
   577  * @param string $domain          Unique identifier for retrieving translated strings
   549  * @param string $deprecated      Use the $plugin_rel_path parameter instead.
   578  * @param string $deprecated      Use the $plugin_rel_path parameter instead.
   550  * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
   579  * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
       
   580  *                                Default false.
       
   581  * @return bool True when textdomain is successfully loaded, false otherwise.
   551  */
   582  */
   552 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
   583 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
   553 	$locale = get_locale();
   584 	$locale = get_locale();
   554 	/**
   585 	/**
   555 	 * Filter a plugin's locale.
   586 	 * Filter a plugin's locale.
   561 	 */
   592 	 */
   562 	$locale = apply_filters( 'plugin_locale', $locale, $domain );
   593 	$locale = apply_filters( 'plugin_locale', $locale, $domain );
   563 
   594 
   564 	if ( false !== $plugin_rel_path	) {
   595 	if ( false !== $plugin_rel_path	) {
   565 		$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
   596 		$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
   566 	} else if ( false !== $deprecated ) {
   597 	} elseif ( false !== $deprecated ) {
   567 		_deprecated_argument( __FUNCTION__, '2.7' );
   598 		_deprecated_argument( __FUNCTION__, '2.7' );
   568 		$path = ABSPATH . trim( $deprecated, '/' );
   599 		$path = ABSPATH . trim( $deprecated, '/' );
   569 	} else {
   600 	} else {
   570 		$path = WP_PLUGIN_DIR;
   601 		$path = WP_PLUGIN_DIR;
   571 	}
   602 	}
   589  * @param string $mu_plugin_rel_path Relative to WPMU_PLUGIN_DIR directory in which the .mo file resides.
   620  * @param string $mu_plugin_rel_path Relative to WPMU_PLUGIN_DIR directory in which the .mo file resides.
   590  *                                   Default empty string.
   621  *                                   Default empty string.
   591  * @return bool True when textdomain is successfully loaded, false otherwise.
   622  * @return bool True when textdomain is successfully loaded, false otherwise.
   592  */
   623  */
   593 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
   624 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
   594 	// duplicate_hook
   625 	/** This filter is documented in wp-includes/l10n.php */
   595 	$locale = apply_filters( 'plugin_locale', get_locale(), $domain );
   626 	$locale = apply_filters( 'plugin_locale', get_locale(), $domain );
   596 	$path = trailingslashit( WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' ) );
   627 	$path = trailingslashit( WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' ) );
   597 
   628 
   598 	// Load the textdomain according to the plugin first
   629 	// Load the textdomain according to the plugin first
   599 	$mofile = $domain . '-' . $locale . '.mo';
   630 	$mofile = $domain . '-' . $locale . '.mo';
   634 
   665 
   635 	if ( ! $path )
   666 	if ( ! $path )
   636 		$path = get_template_directory();
   667 		$path = get_template_directory();
   637 
   668 
   638 	// Load the textdomain according to the theme
   669 	// Load the textdomain according to the theme
   639 	$mofile = "{$path}/{$locale}.mo";
   670 	$mofile = untrailingslashit( $path ) . "/{$locale}.mo";
   640 	if ( $loaded = load_textdomain( $domain, $mofile ) )
   671 	if ( $loaded = load_textdomain( $domain, $mofile ) )
   641 		return $loaded;
   672 		return $loaded;
   642 
   673 
   643 	// Otherwise, load from the languages directory
   674 	// Otherwise, load from the languages directory
   644 	$mofile = WP_LANG_DIR . "/themes/{$domain}-{$locale}.mo";
   675 	$mofile = WP_LANG_DIR . "/themes/{$domain}-{$locale}.mo";
   654  * The .mo files must be named based on the locale exactly.
   685  * The .mo files must be named based on the locale exactly.
   655  *
   686  *
   656  * @since 2.9.0
   687  * @since 2.9.0
   657  *
   688  *
   658  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   689  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
       
   690  * @param string $path   Optional. Path to the directory containing the .mo file.
       
   691  *                       Default false.
   659  * @return bool True when the theme textdomain is successfully loaded, false otherwise.
   692  * @return bool True when the theme textdomain is successfully loaded, false otherwise.
   660  */
   693  */
   661 function load_child_theme_textdomain( $domain, $path = false ) {
   694 function load_child_theme_textdomain( $domain, $path = false ) {
   662 	if ( ! $path )
   695 	if ( ! $path )
   663 		$path = get_stylesheet_directory();
   696 		$path = get_stylesheet_directory();
   667 /**
   700 /**
   668  * Return the Translations instance for a text domain.
   701  * Return the Translations instance for a text domain.
   669  *
   702  *
   670  * If there isn't one, returns empty Translations instance.
   703  * If there isn't one, returns empty Translations instance.
   671  *
   704  *
       
   705  * @since 2.8.0
       
   706  *
   672  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   707  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   673  * @return Translations A Translations instance.
   708  * @return NOOP_Translations A Translations instance.
   674  */
   709  */
   675 function get_translations_for_domain( $domain ) {
   710 function get_translations_for_domain( $domain ) {
   676 	global $l10n;
   711 	global $l10n;
   677 	if ( !isset( $l10n[$domain] ) ) {
   712 	if ( !isset( $l10n[$domain] ) ) {
   678 		$l10n[$domain] = new NOOP_Translations;
   713 		$l10n[$domain] = new NOOP_Translations;
   682 
   717 
   683 /**
   718 /**
   684  * Whether there are translations for the text domain.
   719  * Whether there are translations for the text domain.
   685  *
   720  *
   686  * @since 3.0.0
   721  * @since 3.0.0
       
   722  *
   687  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   723  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
   688  * @return bool Whether there are translations.
   724  * @return bool Whether there are translations.
   689  */
   725  */
   690 function is_textdomain_loaded( $domain ) {
   726 function is_textdomain_loaded( $domain ) {
   691 	global $l10n;
   727 	global $l10n;
   765 		return array();
   801 		return array();
   766 
   802 
   767 	$language_data = array();
   803 	$language_data = array();
   768 
   804 
   769 	foreach ( $files as $file ) {
   805 	foreach ( $files as $file ) {
   770 		if ( '.' === $file[0] || is_dir( $file ) )
   806 		if ( '.' === $file[0] || is_dir( $file ) ) {
   771 			continue;
   807 			continue;
   772 		if ( substr( $file, -3 ) !== '.po' )
   808 		}
       
   809 		if ( substr( $file, -3 ) !== '.po' ) {
   773 			continue;
   810 			continue;
   774 		if ( ! preg_match( '/(?:(.+)-)?([A-Za-z_]{2,6}).po/', $file, $match ) )
   811 		}
       
   812 		if ( ! preg_match( '/(?:(.+)-)?([A-Za-z_]{2,6}).po/', $file, $match ) ) {
   775 			continue;
   813 			continue;
       
   814 		}
       
   815 		if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) )  {
       
   816 			continue;
       
   817 		}
   776 
   818 
   777 		list( , $textdomain, $language ) = $match;
   819 		list( , $textdomain, $language ) = $match;
   778 		if ( '' === $textdomain )
   820 		if ( '' === $textdomain ) {
   779 			$textdomain = 'default';
   821 			$textdomain = 'default';
       
   822 		}
   780 		$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "$dir/$file" );
   823 		$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "$dir/$file" );
   781 	}
   824 	}
   782 	return $language_data;
   825 	return $language_data;
   783 }
   826 }
   784 
   827 
   801 		// Remove possible contextual '\n' and closing double quote.
   844 		// Remove possible contextual '\n' and closing double quote.
   802 		$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
   845 		$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
   803 	}
   846 	}
   804 	return $headers;
   847 	return $headers;
   805 }
   848 }
       
   849 
       
   850 /**
       
   851  * Language selector.
       
   852  *
       
   853  * @since 4.0.0
       
   854  *
       
   855  * @see get_available_languages()
       
   856  * @see wp_get_available_translations()
       
   857  *
       
   858  * @param string|array $args {
       
   859  *     Optional. Array or string of arguments for outputting the language selector.
       
   860  *
       
   861  *     @type string  $id                           ID attribute of the select element. Default empty.
       
   862  *     @type string  $name                         Name attribute of the select element. Default empty.
       
   863  *     @type array   $languages                    List of installed languages, contain only the locales.
       
   864  *                                                 Default empty array.
       
   865  *     @type array   $translations                 List of available translations. Default result of
       
   866  *                                                 {@see wp_get_available_translations()}.
       
   867  *     @type string  $selected                     Language which should be selected. Default empty.
       
   868  *     @type bool    $show_available_translations  Whether to show available translations. Default true.
       
   869  * }
       
   870  */
       
   871 function wp_dropdown_languages( $args = array() ) {
       
   872 
       
   873 	$args = wp_parse_args( $args, array(
       
   874 		'id'           => '',
       
   875 		'name'         => '',
       
   876 		'languages'    => array(),
       
   877 		'translations' => array(),
       
   878 		'selected'     => '',
       
   879 		'show_available_translations' => true,
       
   880 	) );
       
   881 
       
   882 	$translations = $args['translations'];
       
   883 	if ( empty( $translations ) ) {
       
   884 		require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
       
   885 		$translations = wp_get_available_translations();
       
   886 	}
       
   887 
       
   888 	/*
       
   889 	 * $args['languages'] should only contain the locales. Find the locale in
       
   890 	 * $translations to get the native name. Fall back to locale.
       
   891 	 */
       
   892 	$languages = array();
       
   893 	foreach ( $args['languages'] as $locale ) {
       
   894 		if ( isset( $translations[ $locale ] ) ) {
       
   895 			$translation = $translations[ $locale ];
       
   896 			$languages[] = array(
       
   897 				'language'    => $translation['language'],
       
   898 				'native_name' => $translation['native_name'],
       
   899 				'lang'        => current( $translation['iso'] ),
       
   900 			);
       
   901 
       
   902 			// Remove installed language from available translations.
       
   903 			unset( $translations[ $locale ] );
       
   904 		} else {
       
   905 			$languages[] = array(
       
   906 				'language'    => $locale,
       
   907 				'native_name' => $locale,
       
   908 				'lang'        => '',
       
   909 			);
       
   910 		}
       
   911 	}
       
   912 
       
   913 	$translations_available = ( ! empty( $translations ) && $args['show_available_translations'] );
       
   914 
       
   915 	printf( '<select name="%s" id="%s">', esc_attr( $args['name'] ), esc_attr( $args['id'] ) );
       
   916 
       
   917 	// Holds the HTML markup.
       
   918 	$structure = array();
       
   919 
       
   920 	// List installed languages.
       
   921 	if ( $translations_available ) {
       
   922 		$structure[] = '<optgroup label="' . esc_attr_x( 'Installed', 'translations' ) . '">';
       
   923 	}
       
   924 	$structure[] = '<option value="" lang="en" data-installed="1">English (United States)</option>';
       
   925 	foreach ( $languages as $language ) {
       
   926 		$structure[] = sprintf(
       
   927 			'<option value="%s" lang="%s"%s data-installed="1">%s</option>',
       
   928 			esc_attr( $language['language'] ),
       
   929 			esc_attr( $language['lang'] ),
       
   930 			selected( $language['language'], $args['selected'], false ),
       
   931 			esc_html( $language['native_name'] )
       
   932 		);
       
   933 	}
       
   934 	if ( $translations_available ) {
       
   935 		$structure[] = '</optgroup>';
       
   936 	}
       
   937 
       
   938 	// List available translations.
       
   939 	if ( $translations_available ) {
       
   940 		$structure[] = '<optgroup label="' . esc_attr_x( 'Available', 'translations' ) . '">';
       
   941 		foreach ( $translations as $translation ) {
       
   942 			$structure[] = sprintf(
       
   943 				'<option value="%s" lang="%s"%s>%s</option>',
       
   944 				esc_attr( $translation['language'] ),
       
   945 				esc_attr( current( $translation['iso'] ) ),
       
   946 				selected( $translation['language'], $args['selected'], false ),
       
   947 				esc_html( $translation['native_name'] )
       
   948 			);
       
   949 		}
       
   950 		$structure[] = '</optgroup>';
       
   951 	}
       
   952 
       
   953 	echo join( "\n", $structure );
       
   954 
       
   955 	echo '</select>';
       
   956 }