: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Gets installed translations.
* Looks in the wp-content/languages directory for translations of
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
* @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
* @return array Array of language data.
function wp_get_installed_translations( $type ) {
global $wp_textdomain_registry;
if ( 'themes' !== $type && 'plugins' !== $type && 'core' !== $type ) {
$dir = 'core' === $type ? WP_LANG_DIR : WP_LANG_DIR . "/$type";
if ( ! is_dir( $dir ) ) {
$files = $wp_textdomain_registry->get_language_files_from_path( $dir );
$language_data = array();
foreach ( $files as $file ) {
if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?)\.(?:mo|l10n\.php)/', basename( $file ), $match ) ) {
list( , $textdomain, $language ) = $match;
if ( '' === $textdomain ) {
if ( str_ends_with( $file, '.mo' ) ) {
$pofile = substr_replace( $file, '.po', - strlen( '.mo' ) );
if ( ! file_exists( $pofile ) ) {
$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( $pofile );
$pofile = substr_replace( $file, '.po', - strlen( '.l10n.php' ) );
// If both a PO and a PHP file exist, prefer the PO file.
if ( file_exists( $pofile ) ) {
$language_data[ $textdomain ][ $language ] = wp_get_l10n_php_file_data( $file );
* Extracts headers from a PO file.
* @param string $po_file Path to PO file.
* @return string[] Array of PO file header values keyed by header name.
function wp_get_pomo_file_data( $po_file ) {
$headers = get_file_data(
'POT-Creation-Date' => '"POT-Creation-Date',
'PO-Revision-Date' => '"PO-Revision-Date',
'Project-Id-Version' => '"Project-Id-Version',
'X-Generator' => '"X-Generator',
foreach ( $headers as $header => $value ) {
// Remove possible contextual '\n' and closing double quote.
$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
* Extracts headers from a PHP translation file.
* @param string $php_file Path to a `.l10n.php` file.
* @return string[] Array of file header values keyed by header name.
function wp_get_l10n_php_file_data( $php_file ) {
$data = (array) include $php_file;
unset( $data['messages'] );
'POT-Creation-Date' => 'pot-creation-date',
'PO-Revision-Date' => 'po-revision-date',
'Project-Id-Version' => 'project-id-version',
'X-Generator' => 'x-generator',
'POT-Creation-Date' => '',
'PO-Revision-Date' => '',
'Project-Id-Version' => '',
foreach ( $headers as $po_header => $php_header ) {
if ( isset( $data[ $php_header ] ) ) {
$result[ $po_header ] = $data[ $php_header ];
* Displays or returns a Language selector.
* @since 4.3.0 Introduced the `echo` argument.
* @since 4.7.0 Introduced the `show_option_site_default` argument.
* @since 5.1.0 Introduced the `show_option_en_us` argument.
* @since 5.9.0 Introduced the `explicit_option_en_us` argument.
* @see get_available_languages()
* @see wp_get_available_translations()
* @param string|array $args {
* Optional. Array or string of arguments for outputting the language selector.
* @type string $id ID attribute of the select element. Default 'locale'.
* @type string $name Name attribute of the select element. Default 'locale'.
* @type string[] $languages List of installed languages, contain only the locales.
* @type array $translations List of available translations. Default result of
* wp_get_available_translations().
* @type string $selected Language which should be selected. Default empty.
* @type bool|int $echo Whether to echo the generated markup. Accepts 0, 1, or their
* boolean equivalents. Default 1.
* @type bool $show_available_translations Whether to show available translations. Default true.
* @type bool $show_option_site_default Whether to show an option to fall back to the site's locale. Default false.
* @type bool $show_option_en_us Whether to show an option for English (United States). Default true.
* @type bool $explicit_option_en_us Whether the English (United States) option uses an explicit value of en_US
* instead of an empty value. Default false.
* @return string HTML dropdown list of languages.
function wp_dropdown_languages( $args = array() ) {
$parsed_args = wp_parse_args(
'translations' => array(),
'show_available_translations' => true,
'show_option_site_default' => false,
'show_option_en_us' => true,
'explicit_option_en_us' => false,
// Bail if no ID or no name.
if ( ! $parsed_args['id'] || ! $parsed_args['name'] ) {
// English (United States) uses an empty string for the value attribute.
if ( 'en_US' === $parsed_args['selected'] && ! $parsed_args['explicit_option_en_us'] ) {
$parsed_args['selected'] = '';
$translations = $parsed_args['translations'];
if ( empty( $translations ) ) {
require_once ABSPATH . 'wp-admin/includes/translation-install.php';
$translations = wp_get_available_translations();
* $parsed_args['languages'] should only contain the locales. Find the locale in
* $translations to get the native name. Fall back to locale.
foreach ( $parsed_args['languages'] as $locale ) {
if ( isset( $translations[ $locale ] ) ) {
$translation = $translations[ $locale ];
'language' => $translation['language'],
'native_name' => $translation['native_name'],
'lang' => current( $translation['iso'] ),
// Remove installed language from available translations.
unset( $translations[ $locale ] );
'native_name' => $locale,
$translations_available = ( ! empty( $translations ) && $parsed_args['show_available_translations'] );
// Holds the HTML markup.
// List installed languages.
if ( $translations_available ) {
$structure[] = '<optgroup label="' . esc_attr_x( 'Installed', 'translations' ) . '">';
if ( $parsed_args['show_option_site_default'] ) {
'<option value="site-default" data-installed="1"%s>%s</option>',
selected( 'site-default', $parsed_args['selected'], false ),
_x( 'Site Default', 'default site language' )
if ( $parsed_args['show_option_en_us'] ) {
$value = ( $parsed_args['explicit_option_en_us'] ) ? 'en_US' : '';
'<option value="%s" lang="en" data-installed="1"%s>English (United States)</option>',
selected( '', $parsed_args['selected'], false )
// List installed languages.
foreach ( $languages as $language ) {
'<option value="%s" lang="%s"%s data-installed="1">%s</option>',
esc_attr( $language['language'] ),
esc_attr( $language['lang'] ),
selected( $language['language'], $parsed_args['selected'], false ),
esc_html( $language['native_name'] )
if ( $translations_available ) {
$structure[] = '</optgroup>';
// List available translations.
if ( $translations_available ) {
$structure[] = '<optgroup label="' . esc_attr_x( 'Available', 'translations' ) . '">';
foreach ( $translations as $translation ) {
'<option value="%s" lang="%s"%s>%s</option>',
esc_attr( $translation['language'] ),
esc_attr( current( $translation['iso'] ) ),
selected( $translation['language'], $parsed_args['selected'], false ),
esc_html( $translation['native_name'] )
$structure[] = '</optgroup>';
// Combine the output string.
$output = sprintf( '<select name="%s" id="%s">', esc_attr( $parsed_args['name'] ), esc_attr( $parsed_args['id'] ) );
$output .= implode( "\n", $structure );
if ( $parsed_args['echo'] ) {
* Determines whether the current locale is right-to-left (RTL).
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @return bool Whether locale is RTL.
if ( ! ( $wp_locale instanceof WP_Locale ) ) {
return $wp_locale->is_rtl();
* Switches the translations according to the given locale.
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
* @param string $locale The locale.
* @return bool True on success, false on failure.
function switch_to_locale( $locale ) {
/* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher;
if ( ! $wp_locale_switcher ) {
return $wp_locale_switcher->switch_to_locale( $locale );
* Switches the translations according to the given user's locale.
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
* @param int $user_id User ID.
* @return bool True on success, false on failure.
function switch_to_user_locale( $user_id ) {
/* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher;
if ( ! $wp_locale_switcher ) {
return $wp_locale_switcher->switch_to_user_locale( $user_id );
* Restores the translations according to the previous locale.
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
* @return string|false Locale on success, false on error.
function restore_previous_locale() {
/* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher;
if ( ! $wp_locale_switcher ) {
return $wp_locale_switcher->restore_previous_locale();
* Restores the translations according to the original locale.
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
* @return string|false Locale on success, false on error.
function restore_current_locale() {
/* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher;
if ( ! $wp_locale_switcher ) {
return $wp_locale_switcher->restore_current_locale();
* Determines whether switch_to_locale() is in effect.
* @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
* @return bool True if the locale has been switched, false otherwise.
function is_locale_switched() {
/* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher;
return $wp_locale_switcher->is_switched();
* Translates the provided settings value using its i18n schema.
* @param string|string[]|array[]|object $i18n_schema I18n schema for the setting.
* @param string|string[]|array[] $settings Value for the settings.
* @param string $textdomain Textdomain to use with translations.
* @return string|string[]|array[] Translated settings.
function translate_settings_using_i18n_schema( $i18n_schema, $settings, $textdomain ) {
if ( empty( $i18n_schema ) || empty( $settings ) || empty( $textdomain ) ) {
if ( is_string( $i18n_schema ) && is_string( $settings ) ) {
return translate_with_gettext_context( $settings, $i18n_schema, $textdomain );
if ( is_array( $i18n_schema ) && is_array( $settings ) ) {
$translated_settings = array();
foreach ( $settings as $value ) {
$translated_settings[] = translate_settings_using_i18n_schema( $i18n_schema[0], $value, $textdomain );
return $translated_settings;
if ( is_object( $i18n_schema ) && is_array( $settings ) ) {
$translated_settings = array();
foreach ( $settings as $key => $value ) {
if ( isset( $i18n_schema->$key ) ) {
$translated_settings[ $key ] = translate_settings_using_i18n_schema( $i18n_schema->$key, $value, $textdomain );
} elseif ( isset( $i18n_schema->$group_key ) ) {
$translated_settings[ $key ] = translate_settings_using_i18n_schema( $i18n_schema->$group_key, $value, $textdomain );
$translated_settings[ $key ] = $value;
return $translated_settings;
* Retrieves the list item separator based on the locale.
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @return string Locale-specific list item separator.
function wp_get_list_item_separator() {
if ( ! ( $wp_locale instanceof WP_Locale ) ) {
// Default value of WP_Locale::get_list_item_separator().
/* translators: Used between list items, there is a space after the comma. */
return $wp_locale->get_list_item_separator();
* Retrieves the word count type based on the locale.
* @global WP_Locale $wp_locale WordPress date and time locale object.
* @return string Locale-specific word count type. Possible values are `characters_excluding_spaces`,
* `characters_including_spaces`, or `words`. Defaults to `words`.
function wp_get_word_count_type() {
if ( ! ( $wp_locale instanceof WP_Locale ) ) {
// Default value of WP_Locale::get_word_count_type().
return $wp_locale->get_word_count_type();