3 * WordPress Translation API
10 * Get the current locale.
12 * If the locale is set, then it will filter the locale in the 'locale' filter
13 * hook and return the value.
15 * If the locale is not set already, then the WPLANG constant is used if it is
16 * defined. Then it is filtered through the 'locale' filter hook and the value
17 * for the locale global set and the locale is returned.
19 * The process to get the locale should only be done once, but the locale will
20 * always be filtered using the 'locale' hook.
24 * @return string The locale of the blog or from the 'locale' hook.
26 function get_locale() {
27 global $locale, $wp_local_package;
29 if ( isset( $locale ) ) {
31 * Filter WordPress install's locale ID.
35 * @param string $locale The locale ID.
37 return apply_filters( 'locale', $locale );
40 if ( isset( $wp_local_package ) ) {
41 $locale = $wp_local_package;
44 // WPLANG was defined in wp-config.
45 if ( defined( 'WPLANG' ) ) {
49 // If multisite, check options.
50 if ( is_multisite() ) {
51 // Don't check blog option when installing.
52 if ( defined( 'WP_INSTALLING' ) || ( false === $ms_locale = get_option( 'WPLANG' ) ) ) {
53 $ms_locale = get_site_option( 'WPLANG' );
56 if ( $ms_locale !== false ) {
60 $db_locale = get_option( 'WPLANG' );
61 if ( $db_locale !== false ) {
66 if ( empty( $locale ) ) {
70 /** This filter is documented in wp-includes/l10n.php */
71 return apply_filters( 'locale', $locale );
75 * Retrieve the translation of $text.
77 * If there is no translation, or the text domain isn't loaded, the original text is returned.
79 * <strong>Note:</strong> Don't use translate() directly, use __() or related functions.
83 * @param string $text Text to translate.
84 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
85 * @return string Translated text
87 function translate( $text, $domain = 'default' ) {
88 $translations = get_translations_for_domain( $domain );
89 $translations = $translations->translate( $text );
91 * Filter text with its translation.
95 * @param string $translations Translated text.
96 * @param string $text Text to translate.
97 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
99 return apply_filters( 'gettext', $translations, $text, $domain );
103 * Remove last item on a pipe-delimited string.
105 * Meant for removing the last item in a string, such as 'Role name|User role'. The original
106 * string will be returned if no pipe '|' characters are found in the string.
110 * @param string $string A pipe-delimited string.
111 * @return string Either $string or everything before the last pipe.
113 function before_last_bar( $string ) {
114 $last_bar = strrpos( $string, '|' );
115 if ( false == $last_bar )
118 return substr( $string, 0, $last_bar );
122 * Retrieve the translation of $text in the context defined in $context.
124 * If there is no translation, or the text domain isn't loaded the original
129 * @param string $text Text to translate.
130 * @param string $context Context information for the translators.
131 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
132 * @return string Translated text on success, original text on failure.
134 function translate_with_gettext_context( $text, $context, $domain = 'default' ) {
135 $translations = get_translations_for_domain( $domain );
136 $translations = $translations->translate( $text, $context );
138 * Filter text with its translation based on context information.
142 * @param string $translations Translated text.
143 * @param string $text Text to translate.
144 * @param string $context Context information for the translators.
145 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
147 return apply_filters( 'gettext_with_context', $translations, $text, $context, $domain );
151 * Retrieve the translation of $text. If there is no translation,
152 * or the text domain isn't loaded, the original text is returned.
156 * @param string $text Text to translate.
157 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
158 * @return string Translated text.
160 function __( $text, $domain = 'default' ) {
161 return translate( $text, $domain );
165 * Retrieve the translation of $text and escapes it for safe use in an attribute.
167 * If there is no translation, or the text domain isn't loaded, the original text is returned.
171 * @param string $text Text to translate.
172 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
173 * @return string Translated text on success, original text on failure.
175 function esc_attr__( $text, $domain = 'default' ) {
176 return esc_attr( translate( $text, $domain ) );
180 * Retrieve the translation of $text and escapes it for safe use in HTML output.
182 * If there is no translation, or the text domain isn't loaded, the original text is returned.
186 * @param string $text Text to translate.
187 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
188 * @return string Translated text
190 function esc_html__( $text, $domain = 'default' ) {
191 return esc_html( translate( $text, $domain ) );
195 * Display translated text.
199 * @param string $text Text to translate.
200 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
202 function _e( $text, $domain = 'default' ) {
203 echo translate( $text, $domain );
207 * Display translated text that has been escaped for safe use in an attribute.
211 * @param string $text Text to translate.
212 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
214 function esc_attr_e( $text, $domain = 'default' ) {
215 echo esc_attr( translate( $text, $domain ) );
219 * Display translated text that has been escaped for safe use in HTML output.
223 * @param string $text Text to translate.
224 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
226 function esc_html_e( $text, $domain = 'default' ) {
227 echo esc_html( translate( $text, $domain ) );
231 * Retrieve translated string with gettext context.
233 * Quite a few times, there will be collisions with similar translatable text
234 * found in more than two places, but with different translated context.
236 * By including the context in the pot file, translators can translate the two
237 * strings differently.
241 * @param string $text Text to translate.
242 * @param string $context Context information for the translators.
243 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
244 * @return string Translated context string without pipe.
246 function _x( $text, $context, $domain = 'default' ) {
247 return translate_with_gettext_context( $text, $context, $domain );
251 * Display translated string with gettext context.
255 * @param string $text Text to translate.
256 * @param string $context Context information for the translators.
257 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
258 * @return string Translated context string without pipe.
260 function _ex( $text, $context, $domain = 'default' ) {
261 echo _x( $text, $context, $domain );
265 * Translate string with gettext context, and escapes it for safe use in an attribute.
269 * @param string $text Text to translate.
270 * @param string $context Context information for the translators.
271 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
272 * @return string Translated text
274 function esc_attr_x( $text, $context, $domain = 'default' ) {
275 return esc_attr( translate_with_gettext_context( $text, $context, $domain ) );
279 * Translate string with gettext context, and escapes it for safe use in HTML output.
283 * @param string $text Text to translate.
284 * @param string $context Context information for the translators.
285 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
286 * @return string Translated text.
288 function esc_html_x( $text, $context, $domain = 'default' ) {
289 return esc_html( translate_with_gettext_context( $text, $context, $domain ) );
293 * Retrieve the plural or single form based on the supplied amount.
295 * If the text domain is not set in the $l10n list, then a comparison will be made
296 * and either $plural or $single parameters returned.
298 * If the text domain does exist, then the parameters $single, $plural, and $number
299 * will first be passed to the text domain's ngettext method. Then it will be passed
300 * to the 'ngettext' filter hook along with the same parameters. The expected
301 * type will be a string.
305 * @param string $single The text that will be used if $number is 1.
306 * @param string $plural The text that will be used if $number is not 1.
307 * @param int $number The number to compare against to use either $single or $plural.
308 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
309 * @return string Either $single or $plural translated text.
311 function _n( $single, $plural, $number, $domain = 'default' ) {
312 $translations = get_translations_for_domain( $domain );
313 $translation = $translations->translate_plural( $single, $plural, $number );
315 * Filter text with its translation when plural option is available.
319 * @param string $translation Translated text.
320 * @param string $single The text that will be used if $number is 1.
321 * @param string $plural The text that will be used if $number is not 1.
322 * @param string $number The number to compare against to use either $single or $plural.
323 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
325 return apply_filters( 'ngettext', $translation, $single, $plural, $number, $domain );
329 * Retrieve the plural or single form based on the supplied amount with gettext context.
331 * This is a hybrid of _n() and _x(). It supports contexts and plurals.
335 * @param string $single The text that will be used if $number is 1.
336 * @param string $plural The text that will be used if $number is not 1.
337 * @param int $number The number to compare against to use either $single or $plural.
338 * @param string $context Context information for the translators.
339 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
340 * @return string Either $single or $plural translated text with context.
342 function _nx($single, $plural, $number, $context, $domain = 'default') {
343 $translations = get_translations_for_domain( $domain );
344 $translation = $translations->translate_plural( $single, $plural, $number, $context );
346 * Filter text with its translation while plural option and context are available.
350 * @param string $translation Translated text.
351 * @param string $single The text that will be used if $number is 1.
352 * @param string $plural The text that will be used if $number is not 1.
353 * @param string $number The number to compare against to use either $single or $plural.
354 * @param string $context Context information for the translators.
355 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
357 return apply_filters( 'ngettext_with_context', $translation, $single, $plural, $number, $context, $domain );
361 * Register plural strings in POT file, but don't translate them.
363 * Used when you want to keep structures with translatable plural
364 * strings and use them later.
369 * 'post' => _n_noop('%s post', '%s posts'),
370 * 'page' => _n_noop('%s pages', '%s pages')
373 * $message = $messages[$type];
374 * $usable_text = sprintf( translate_nooped_plural( $message, $count ), $count );
379 * @param string $singular Single form to be i18ned.
380 * @param string $plural Plural form to be i18ned.
381 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
382 * @return array array($singular, $plural)
384 function _n_noop( $singular, $plural, $domain = null ) {
385 return array( 0 => $singular, 1 => $plural, 'singular' => $singular, 'plural' => $plural, 'context' => null, 'domain' => $domain );
389 * Register plural strings with context in POT file, but don't translate them.
393 function _nx_noop( $singular, $plural, $context, $domain = null ) {
394 return array( 0 => $singular, 1 => $plural, 2 => $context, 'singular' => $singular, 'plural' => $plural, 'context' => $context, 'domain' => $domain );
398 * Translate the result of _n_noop() or _nx_noop().
402 * @param array $nooped_plural Array with singular, plural and context keys, usually the result of _n_noop() or _nx_noop()
403 * @param int $count Number of objects
404 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. If $nooped_plural contains
405 * a text domain passed to _n_noop() or _nx_noop(), it will override this value.
406 * @return string Either $single or $plural translated text.
408 function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {
409 if ( $nooped_plural['domain'] )
410 $domain = $nooped_plural['domain'];
412 if ( $nooped_plural['context'] )
413 return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );
415 return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );
419 * Load a .mo file into the text domain $domain.
421 * If the text domain already exists, the translations will be merged. If both
422 * sets have the same string, the translation from the original value will be taken.
424 * On success, the .mo file will be placed in the $l10n global by $domain
425 * and will be a MO object.
429 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
430 * @param string $mofile Path to the .mo file.
431 * @return bool True on success, false on failure.
433 function load_textdomain( $domain, $mofile ) {
437 * Filter text domain and/or MO file path for loading translations.
441 * @param bool $override Whether to override the text domain. Default false.
442 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
443 * @param string $mofile Path to the MO file.
445 $plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile );
447 if ( true == $plugin_override ) {
452 * Fires before the MO translation file is loaded.
456 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
457 * @param string $mofile Path to the .mo file.
459 do_action( 'load_textdomain', $domain, $mofile );
462 * Filter MO file path for loading translations for a specific text domain.
466 * @param string $mofile Path to the MO file.
467 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
469 $mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
471 if ( !is_readable( $mofile ) ) return false;
474 if ( !$mo->import_from_file( $mofile ) ) return false;
476 if ( isset( $l10n[$domain] ) )
477 $mo->merge_with( $l10n[$domain] );
479 $l10n[$domain] = &$mo;
485 * Unload translations for a text domain.
489 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
490 * @return bool Whether textdomain was unloaded.
492 function unload_textdomain( $domain ) {
496 * Filter the text domain for loading translation.
500 * @param bool $override Whether to override unloading the text domain. Default false.
501 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
503 $plugin_override = apply_filters( 'override_unload_textdomain', false, $domain );
505 if ( $plugin_override )
509 * Fires before the text domain is unloaded.
513 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
515 do_action( 'unload_textdomain', $domain );
517 if ( isset( $l10n[$domain] ) ) {
518 unset( $l10n[$domain] );
526 * Load default translated strings based on locale.
528 * Loads the .mo file in WP_LANG_DIR constant path from WordPress root.
529 * The translated (.mo) file is named based on the locale.
531 * @see load_textdomain()
535 * @param string $locale Optional. Locale to load. Defaults to get_locale().
537 function load_default_textdomain( $locale = null ) {
538 if ( null === $locale ) {
539 $locale = get_locale();
542 // Unload previously loaded strings so we can switch translations.
543 unload_textdomain( 'default' );
545 $return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" );
547 if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) {
548 load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" );
552 if ( is_admin() || defined( 'WP_INSTALLING' ) || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) {
553 load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
556 if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) )
557 load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" );
563 * Load a plugin's translated strings.
565 * If the path is not given then it will be the root of the plugin directory.
567 * The .mo file should be named based on the text domain with a dash, and then the locale exactly.
571 * @param string $domain Unique identifier for retrieving translated strings
572 * @param string $deprecated Use the $plugin_rel_path parameter instead.
573 * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
575 * @return bool True when textdomain is successfully loaded, false otherwise.
577 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
578 $locale = get_locale();
580 * Filter a plugin's locale.
584 * @param string $locale The plugin's current locale.
585 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
587 $locale = apply_filters( 'plugin_locale', $locale, $domain );
589 if ( false !== $plugin_rel_path ) {
590 $path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
591 } else if ( false !== $deprecated ) {
592 _deprecated_argument( __FUNCTION__, '2.7' );
593 $path = ABSPATH . trim( $deprecated, '/' );
595 $path = WP_PLUGIN_DIR;
598 // Load the textdomain according to the plugin first
599 $mofile = $domain . '-' . $locale . '.mo';
600 if ( $loaded = load_textdomain( $domain, $path . '/'. $mofile ) )
603 // Otherwise, load from the languages directory
604 $mofile = WP_LANG_DIR . '/plugins/' . $mofile;
605 return load_textdomain( $domain, $mofile );
609 * Load the translated strings for a plugin residing in the mu-plugins directory.
613 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
614 * @param string $mu_plugin_rel_path Relative to WPMU_PLUGIN_DIR directory in which the .mo file resides.
615 * Default empty string.
616 * @return bool True when textdomain is successfully loaded, false otherwise.
618 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
619 /** This filter is documented in wp-includes/l10n.php */
620 $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
621 $path = trailingslashit( WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' ) );
623 // Load the textdomain according to the plugin first
624 $mofile = $domain . '-' . $locale . '.mo';
625 if ( $loaded = load_textdomain( $domain, $path . $mofile ) )
628 // Otherwise, load from the languages directory
629 $mofile = WP_LANG_DIR . '/plugins/' . $mofile;
630 return load_textdomain( $domain, $mofile );
634 * Load the theme's translated strings.
636 * If the current locale exists as a .mo file in the theme's root directory, it
637 * will be included in the translated strings by the $domain.
639 * The .mo files must be named based on the locale exactly.
643 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
644 * @param string $path Optional. Path to the directory containing the .mo file.
646 * @return bool True when textdomain is successfully loaded, false otherwise.
648 function load_theme_textdomain( $domain, $path = false ) {
649 $locale = get_locale();
651 * Filter a theme's locale.
655 * @param string $locale The theme's current locale.
656 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
658 $locale = apply_filters( 'theme_locale', $locale, $domain );
661 $path = get_template_directory();
663 // Load the textdomain according to the theme
664 $mofile = "{$path}/{$locale}.mo";
665 if ( $loaded = load_textdomain( $domain, $mofile ) )
668 // Otherwise, load from the languages directory
669 $mofile = WP_LANG_DIR . "/themes/{$domain}-{$locale}.mo";
670 return load_textdomain( $domain, $mofile );
674 * Load the child themes translated strings.
676 * If the current locale exists as a .mo file in the child themes
677 * root directory, it will be included in the translated strings by the $domain.
679 * The .mo files must be named based on the locale exactly.
683 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
684 * @param string $path Optional. Path to the directory containing the .mo file.
686 * @return bool True when the theme textdomain is successfully loaded, false otherwise.
688 function load_child_theme_textdomain( $domain, $path = false ) {
690 $path = get_stylesheet_directory();
691 return load_theme_textdomain( $domain, $path );
695 * Return the Translations instance for a text domain.
697 * If there isn't one, returns empty Translations instance.
701 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
702 * @return Translations A Translations instance.
704 function get_translations_for_domain( $domain ) {
706 if ( !isset( $l10n[$domain] ) ) {
707 $l10n[$domain] = new NOOP_Translations;
709 return $l10n[$domain];
713 * Whether there are translations for the text domain.
717 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
718 * @return bool Whether there are translations.
720 function is_textdomain_loaded( $domain ) {
722 return isset( $l10n[$domain] );
726 * Translates role name.
728 * Since the role names are in the database and not in the source there
729 * are dummy gettext calls to get them into the POT file and this function
730 * properly translates them back.
732 * The before_last_bar() call is needed, because older installs keep the roles
733 * using the old context format: 'Role name|User role' and just skipping the
734 * content after the last bar is easier than fixing them in the DB. New installs
735 * won't suffer from that problem.
739 * @param string $name The role name.
740 * @return string Translated role name on success, original name on failure.
742 function translate_user_role( $name ) {
743 return translate_with_gettext_context( before_last_bar($name), 'User role' );
747 * Get all available languages based on the presence of *.mo files in a given directory.
749 * The default directory is WP_LANG_DIR.
753 * @param string $dir A directory to search for language files.
754 * Default WP_LANG_DIR.
755 * @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.
757 function get_available_languages( $dir = null ) {
758 $languages = array();
760 foreach( (array)glob( ( is_null( $dir) ? WP_LANG_DIR : $dir ) . '/*.mo' ) as $lang_file ) {
761 $lang_file = basename($lang_file, '.mo');
762 if ( 0 !== strpos( $lang_file, 'continents-cities' ) && 0 !== strpos( $lang_file, 'ms-' ) &&
763 0 !== strpos( $lang_file, 'admin-' ))
764 $languages[] = $lang_file;
771 * Get installed translations.
773 * Looks in the wp-content/languages directory for translations of
778 * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
779 * @return array Array of language data.
781 function wp_get_installed_translations( $type ) {
782 if ( $type !== 'themes' && $type !== 'plugins' && $type !== 'core' )
785 $dir = 'core' === $type ? '' : "/$type";
787 if ( ! is_dir( WP_LANG_DIR ) )
790 if ( $dir && ! is_dir( WP_LANG_DIR . $dir ) )
793 $files = scandir( WP_LANG_DIR . $dir );
797 $language_data = array();
799 foreach ( $files as $file ) {
800 if ( '.' === $file[0] || is_dir( $file ) )
802 if ( substr( $file, -3 ) !== '.po' )
804 if ( ! preg_match( '/(?:(.+)-)?([A-Za-z_]{2,6}).po/', $file, $match ) )
807 list( , $textdomain, $language ) = $match;
808 if ( '' === $textdomain )
809 $textdomain = 'default';
810 $language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "$dir/$file" );
812 return $language_data;
816 * Extract headers from a PO file.
820 * @param string $po_file Path to PO file.
821 * @return array PO file headers.
823 function wp_get_pomo_file_data( $po_file ) {
824 $headers = get_file_data( $po_file, array(
825 'POT-Creation-Date' => '"POT-Creation-Date',
826 'PO-Revision-Date' => '"PO-Revision-Date',
827 'Project-Id-Version' => '"Project-Id-Version',
828 'X-Generator' => '"X-Generator',
830 foreach ( $headers as $header => $value ) {
831 // Remove possible contextual '\n' and closing double quote.
832 $headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
842 * @see get_available_languages()
843 * @see wp_get_available_translations()
845 * @param array $args Optional arguments. Default empty array.
847 function wp_dropdown_languages( $args = array() ) {
848 require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
850 $args = wp_parse_args( $args, array(
853 'languages' => array(),
857 if ( empty( $args['languages'] ) ) {
861 $translations = wp_get_available_translations();
864 * $args['languages'] should only contain the locales. Find the locale in
865 * $translations to get the native name. Fall back to locale.
867 $languages = array();
868 foreach ( $args['languages'] as $locale ) {
869 if ( isset( $translations[ $locale ] ) ) {
870 $translation = $translations[ $locale ];
871 $languages[] = array(
872 'language' => $translation['language'],
873 'native_name' => $translation['native_name'],
874 'lang' => $translation['iso'][1],
877 $languages[] = array(
878 'language' => $locale,
879 'native_name' => $locale,
885 printf( '<select name="%s" id="%s">', esc_attr( $args['name'] ), esc_attr( $args['id'] ) );
887 // List installed languages.
888 echo '<option value="" lang="en">English (United States)</option>';
889 foreach ( $languages as $language ) {
890 $selected = selected( $language['language'], $args['selected'], false );
892 '<option value="%s" lang="%s"%s>%s</option>',
893 esc_attr( $language['language'] ),
894 esc_attr( $language['lang'] ),
896 esc_html( $language['native_name'] )