: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Filters a plugin's locale.
* @param string $locale The plugin's current locale.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
$mofile = $domain . '-' . $locale . '.mo';
// Try to load from the languages directory first.
if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) {
if ( false !== $plugin_rel_path ) {
$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
} elseif ( false !== $deprecated ) {
_deprecated_argument( __FUNCTION__, '2.7.0' );
$path = ABSPATH . trim( $deprecated, '/' );
$wp_textdomain_registry->set_custom_path( $domain, $path );
return load_textdomain( $domain, $path . '/' . $mofile, $locale );
* Loads the translated strings for a plugin residing in the mu-plugins directory.
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @param string $mu_plugin_rel_path Optional. Relative to `WPMU_PLUGIN_DIR` directory in which the .mo
* file resides. Default empty string.
* @return bool True when textdomain is successfully loaded, false otherwise.
function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
global $wp_textdomain_registry;
if ( ! is_string( $domain ) ) {
/** This filter is documented in wp-includes/l10n.php */
$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
$mofile = $domain . '-' . $locale . '.mo';
// Try to load from the languages directory first.
if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) {
$path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' );
$wp_textdomain_registry->set_custom_path( $domain, $path );
return load_textdomain( $domain, $path . '/' . $mofile, $locale );
* Loads the theme's translated strings.
* If the current locale exists as a .mo file in the theme's root directory, it
* will be included in the translated strings by the $domain.
* The .mo files must be named based on the locale exactly.
* @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @param string|false $path Optional. Path to the directory containing the .mo file.
* @return bool True when textdomain is successfully loaded, false otherwise.
function load_theme_textdomain( $domain, $path = false ) {
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
global $wp_textdomain_registry;
if ( ! is_string( $domain ) ) {
* Filters a theme's locale.
* @param string $locale The theme's current locale.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
$locale = apply_filters( 'theme_locale', determine_locale(), $domain );
$mofile = $domain . '-' . $locale . '.mo';
// Try to load from the languages directory first.
if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile, $locale ) ) {
$path = get_template_directory();
$wp_textdomain_registry->set_custom_path( $domain, $path );
return load_textdomain( $domain, $path . '/' . $locale . '.mo', $locale );
* Loads the child theme's translated strings.
* If the current locale exists as a .mo file in the child theme's
* root directory, it will be included in the translated strings by the $domain.
* The .mo files must be named based on the locale exactly.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @param string|false $path Optional. Path to the directory containing the .mo file.
* @return bool True when the theme textdomain is successfully loaded, false otherwise.
function load_child_theme_textdomain( $domain, $path = false ) {
$path = get_stylesheet_directory();
return load_theme_textdomain( $domain, $path );
* Loads the script translated strings.
* @since 5.0.2 Uses load_script_translations() to load translation data.
* @since 5.1.0 The `$domain` parameter was made optional.
* @see WP_Scripts::set_translations()
* @param string $handle Name of the script to register a translation domain to.
* @param string $domain Optional. Text domain. Default 'default'.
* @param string $path Optional. The full file path to the directory containing translation files.
* @return string|false The translated strings in JSON encoding on success,
* false if the script textdomain could not be loaded.
function load_script_textdomain( $handle, $domain = 'default', $path = '' ) {
$wp_scripts = wp_scripts();
if ( ! isset( $wp_scripts->registered[ $handle ] ) ) {
$path = untrailingslashit( $path );
$locale = determine_locale();
// If a path was given and the handle file exists simply return it.
$file_base = 'default' === $domain ? $locale : $domain . '-' . $locale;
$handle_filename = $file_base . '-' . $handle . '.json';
$translations = load_script_translations( $path . '/' . $handle_filename, $handle, $domain );
$src = $wp_scripts->registered[ $handle ]->src;
if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $wp_scripts->content_url && str_starts_with( $src, $wp_scripts->content_url ) ) ) {
$src = $wp_scripts->base_url . $src;
$languages_path = WP_LANG_DIR;
$src_url = wp_parse_url( $src );
$content_url = wp_parse_url( content_url() );
$plugins_url = wp_parse_url( plugins_url() );
$site_url = wp_parse_url( site_url() );
// If the host is the same or it's a relative URL.
( ! isset( $content_url['path'] ) || str_starts_with( $src_url['path'], $content_url['path'] ) ) &&
( ! isset( $src_url['host'] ) || ! isset( $content_url['host'] ) || $src_url['host'] === $content_url['host'] )
// Make the src relative the specific plugin or theme.
if ( isset( $content_url['path'] ) ) {
$relative = substr( $src_url['path'], strlen( $content_url['path'] ) );
$relative = $src_url['path'];
$relative = trim( $relative, '/' );
$relative = explode( '/', $relative );
$languages_path = WP_LANG_DIR . '/plugins';
$relative = array_slice( $relative, 2 ); // Remove plugins/<plugin name> or themes/<theme name>.
$relative = implode( '/', $relative );
( ! isset( $plugins_url['path'] ) || str_starts_with( $src_url['path'], $plugins_url['path'] ) ) &&
( ! isset( $src_url['host'] ) || ! isset( $plugins_url['host'] ) || $src_url['host'] === $plugins_url['host'] )
// Make the src relative the specific plugin.
if ( isset( $plugins_url['path'] ) ) {
$relative = substr( $src_url['path'], strlen( $plugins_url['path'] ) );
$relative = $src_url['path'];
$relative = trim( $relative, '/' );
$relative = explode( '/', $relative );
$languages_path = WP_LANG_DIR . '/plugins';
$relative = array_slice( $relative, 1 ); // Remove <plugin name>.
$relative = implode( '/', $relative );
} elseif ( ! isset( $src_url['host'] ) || ! isset( $site_url['host'] ) || $src_url['host'] === $site_url['host'] ) {
if ( ! isset( $site_url['path'] ) ) {
$relative = trim( $src_url['path'], '/' );
} elseif ( str_starts_with( $src_url['path'], trailingslashit( $site_url['path'] ) ) ) {
// Make the src relative to the WP root.
$relative = substr( $src_url['path'], strlen( $site_url['path'] ) );
$relative = trim( $relative, '/' );
* Filters the relative path of scripts used for finding translation files.
* @param string|false $relative The relative path of the script. False if it could not be determined.
* @param string $src The full source URL of the script.
$relative = apply_filters( 'load_script_textdomain_relative_path', $relative, $src );
// If the source is not from WP.
if ( false === $relative ) {
return load_script_translations( false, $handle, $domain );
// Translations are always based on the unminified filename.
if ( str_ends_with( $relative, '.min.js' ) ) {
$relative = substr( $relative, 0, -7 ) . '.js';
$md5_filename = $file_base . '-' . md5( $relative ) . '.json';
$translations = load_script_translations( $path . '/' . $md5_filename, $handle, $domain );
$translations = load_script_translations( $languages_path . '/' . $md5_filename, $handle, $domain );
return load_script_translations( false, $handle, $domain );
* Loads the translation data for the given script handle and text domain.
* @param string|false $file Path to the translation file to load. False if there isn't one.
* @param string $handle Name of the script to register a translation domain to.
* @param string $domain The text domain.
* @return string|false The JSON-encoded translated strings for the given script handle and text domain.
* False if there are none.
function load_script_translations( $file, $handle, $domain ) {
* Pre-filters script translations for the given file, script handle and text domain.
* Returning a non-null value allows to override the default logic, effectively short-circuiting the function.
* @param string|false|null $translations JSON-encoded translation data. Default null.
* @param string|false $file Path to the translation file to load. False if there isn't one.
* @param string $handle Name of the script to register a translation domain to.
* @param string $domain The text domain.
$translations = apply_filters( 'pre_load_script_translations', null, $file, $handle, $domain );
if ( null !== $translations ) {
* Filters the file path for loading script translations for the given script handle and text domain.
* @param string|false $file Path to the translation file to load. False if there isn't one.
* @param string $handle Name of the script to register a translation domain to.
* @param string $domain The text domain.
$file = apply_filters( 'load_script_translation_file', $file, $handle, $domain );
if ( ! $file || ! is_readable( $file ) ) {
$translations = file_get_contents( $file );
* Filters script translations for the given file, script handle and text domain.
* @param string $translations JSON-encoded translation data.
* @param string $file Path to the translation file that was loaded.
* @param string $handle Name of the script to register a translation domain to.
* @param string $domain The text domain.
return apply_filters( 'load_script_translations', $translations, $file, $handle, $domain );
* Loads plugin and theme text domains just-in-time.
* When a textdomain is encountered for the first time, we try to load
* the translation file from `wp-content/languages`, removing the need
* to call load_plugin_textdomain() or load_theme_textdomain().
* @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @return bool True when the textdomain is successfully loaded, false otherwise.
function _load_textdomain_just_in_time( $domain ) {
/** @var WP_Textdomain_Registry $wp_textdomain_registry */
global $l10n_unloaded, $wp_textdomain_registry;
$l10n_unloaded = (array) $l10n_unloaded;
// Short-circuit if domain is 'default' which is reserved for core.
if ( 'default' === $domain || isset( $l10n_unloaded[ $domain ] ) ) {
if ( ! $wp_textdomain_registry->has( $domain ) ) {
$locale = determine_locale();
$path = $wp_textdomain_registry->get( $domain, $locale );
// Themes with their language directory outside of WP_LANG_DIR have a different file name.
$template_directory = trailingslashit( get_template_directory() );
$stylesheet_directory = trailingslashit( get_stylesheet_directory() );
if ( str_starts_with( $path, $template_directory ) || str_starts_with( $path, $stylesheet_directory ) ) {
$mofile = "{$path}{$locale}.mo";
$mofile = "{$path}{$domain}-{$locale}.mo";
return load_textdomain( $domain, $mofile, $locale );
* Returns the Translations instance for a text domain.
* If there isn't one, returns empty Translations instance.
* @global MO[] $l10n An array of all currently loaded text domains.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @return Translations|NOOP_Translations A Translations instance.
function get_translations_for_domain( $domain ) {
if ( isset( $l10n[ $domain ] ) || ( _load_textdomain_just_in_time( $domain ) && isset( $l10n[ $domain ] ) ) ) {
static $noop_translations = null;
if ( null === $noop_translations ) {
$noop_translations = new NOOP_Translations();
$l10n[ $domain ] = &$noop_translations;
return $noop_translations;
* Determines whether there are translations for the text domain.
* @global MO[] $l10n An array of all currently loaded text domains.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
* @return bool Whether there are translations.
function is_textdomain_loaded( $domain ) {
return isset( $l10n[ $domain ] ) && ! $l10n[ $domain ] instanceof NOOP_Translations;
* Since the role names are in the database and not in the source there
* are dummy gettext calls to get them into the POT file and this function
* properly translates them back.
* The before_last_bar() call is needed, because older installations keep the roles
* using the old context format: 'Role name|User role' and just skipping the
* content after the last bar is easier than fixing them in the DB. New installations
* won't suffer from that problem.
* @since 5.2.0 Added the `$domain` parameter.
* @param string $name The role name.
* @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
* @return string Translated role name on success, original name on failure.
function translate_user_role( $name, $domain = 'default' ) {
return translate_with_gettext_context( before_last_bar( $name ), 'User role', $domain );
* Gets all available languages based on the presence of *.mo and *.l10n.php files in a given directory.
* The default directory is WP_LANG_DIR.
* @since 4.7.0 The results are now filterable with the {@see 'get_available_languages'} filter.
* @since 6.5.0 The initial file list is now cached and also takes into account *.l10n.php files.
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
* @param string $dir A directory to search for language files.
* @return string[] An array of language codes or an empty array if no languages are present.
* Language codes are formed by stripping the file extension from the language file names.
function get_available_languages( $dir = null ) {
global $wp_textdomain_registry;
$path = is_null( $dir ) ? WP_LANG_DIR : $dir;
$lang_files = $wp_textdomain_registry->get_language_files_from_path( $path );
foreach ( $lang_files as $lang_file ) {
$lang_file = basename( $lang_file, '.mo' );
$lang_file = basename( $lang_file, '.l10n.php' );
if ( ! str_starts_with( $lang_file, 'continents-cities' ) && ! str_starts_with( $lang_file, 'ms-' ) &&
! str_starts_with( $lang_file, 'admin-' ) ) {
$languages[] = $lang_file;
* Filters the list of available language codes.
* @param string[] $languages An array of available language codes.
* @param string $dir The directory where the language files were found.
return apply_filters( 'get_available_languages', array_unique( $languages ), $dir );