wp/wp-includes/l10n.php
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
   114 /**
   114 /**
   115  * Determines the current locale desired for the request.
   115  * Determines the current locale desired for the request.
   116  *
   116  *
   117  * @since 5.0.0
   117  * @since 5.0.0
   118  *
   118  *
   119  * @global string $pagenow The filename of the current screen.
   119  * @global string $pagenow          The filename of the current screen.
       
   120  * @global string $wp_local_package Locale code of the package.
   120  *
   121  *
   121  * @return string The determined locale.
   122  * @return string The determined locale.
   122  */
   123  */
   123 function determine_locale() {
   124 function determine_locale() {
   124 	/**
   125 	/**
   961 	if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) {
   962 	if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) {
   962 		load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo", $locale );
   963 		load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo", $locale );
   963 		return $return;
   964 		return $return;
   964 	}
   965 	}
   965 
   966 
   966 	if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) ) {
   967 	if ( is_admin() || wp_installing() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) || doing_action( 'wp_maybe_auto_update' ) ) {
   967 		load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo", $locale );
   968 		load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo", $locale );
   968 	}
   969 	}
   969 
   970 
   970 	if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) {
   971 	if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) {
   971 		load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo", $locale );
   972 		load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo", $locale );
   981  *
   982  *
   982  * The .mo file should be named based on the text domain with a dash, and then the locale exactly.
   983  * The .mo file should be named based on the text domain with a dash, and then the locale exactly.
   983  *
   984  *
   984  * @since 1.5.0
   985  * @since 1.5.0
   985  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
   986  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
       
   987  * @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
       
   988  *
       
   989  * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
       
   990  * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
   986  *
   991  *
   987  * @param string       $domain          Unique identifier for retrieving translated strings
   992  * @param string       $domain          Unique identifier for retrieving translated strings
   988  * @param string|false $deprecated      Optional. Deprecated. Use the $plugin_rel_path parameter instead.
   993  * @param string|false $deprecated      Optional. Deprecated. Use the $plugin_rel_path parameter instead.
   989  *                                      Default false.
   994  *                                      Default false.
   990  * @param string|false $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
   995  * @param string|false $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR where the .mo file resides.
   991  *                                      Default false.
   996  *                                      Default false.
   992  * @return bool True when textdomain is successfully loaded, false otherwise.
   997  * @return bool True when textdomain is successfully loaded, false otherwise.
   993  */
   998  */
   994 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
   999 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
   995 	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
  1000 	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
   996 	global $wp_textdomain_registry;
  1001 	/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
       
  1002 	global $wp_textdomain_registry, $l10n;
   997 
  1003 
   998 	if ( ! is_string( $domain ) ) {
  1004 	if ( ! is_string( $domain ) ) {
   999 		return false;
  1005 		return false;
  1000 	}
       
  1001 
       
  1002 	/**
       
  1003 	 * Filters a plugin's locale.
       
  1004 	 *
       
  1005 	 * @since 3.0.0
       
  1006 	 *
       
  1007 	 * @param string $locale The plugin's current locale.
       
  1008 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
       
  1009 	 */
       
  1010 	$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
       
  1011 
       
  1012 	$mofile = $domain . '-' . $locale . '.mo';
       
  1013 
       
  1014 	// Try to load from the languages directory first.
       
  1015 	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) {
       
  1016 		return true;
       
  1017 	}
  1006 	}
  1018 
  1007 
  1019 	if ( false !== $plugin_rel_path ) {
  1008 	if ( false !== $plugin_rel_path ) {
  1020 		$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
  1009 		$path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
  1021 	} elseif ( false !== $deprecated ) {
  1010 	} elseif ( false !== $deprecated ) {
  1025 		$path = WP_PLUGIN_DIR;
  1014 		$path = WP_PLUGIN_DIR;
  1026 	}
  1015 	}
  1027 
  1016 
  1028 	$wp_textdomain_registry->set_custom_path( $domain, $path );
  1017 	$wp_textdomain_registry->set_custom_path( $domain, $path );
  1029 
  1018 
  1030 	return load_textdomain( $domain, $path . '/' . $mofile, $locale );
  1019 	// If just-in-time loading was triggered before, reset the entry so it can be tried again.
       
  1020 	if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
       
  1021 		unset( $l10n[ $domain ] );
       
  1022 	}
       
  1023 
       
  1024 	return true;
  1031 }
  1025 }
  1032 
  1026 
  1033 /**
  1027 /**
  1034  * Loads the translated strings for a plugin residing in the mu-plugins directory.
  1028  * Loads the translated strings for a plugin residing in the mu-plugins directory.
  1035  *
  1029  *
  1036  * @since 3.0.0
  1030  * @since 3.0.0
  1037  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
  1031  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
       
  1032  * @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
  1038  *
  1033  *
  1039  * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
  1034  * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
       
  1035  * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
  1040  *
  1036  *
  1041  * @param string $domain             Text domain. Unique identifier for retrieving translated strings.
  1037  * @param string $domain             Text domain. Unique identifier for retrieving translated strings.
  1042  * @param string $mu_plugin_rel_path Optional. Relative to `WPMU_PLUGIN_DIR` directory in which the .mo
  1038  * @param string $mu_plugin_rel_path Optional. Relative to `WPMU_PLUGIN_DIR` directory in which the .mo
  1043  *                                   file resides. Default empty string.
  1039  *                                   file resides. Default empty string.
  1044  * @return bool True when textdomain is successfully loaded, false otherwise.
  1040  * @return bool True when textdomain is successfully loaded, false otherwise.
  1045  */
  1041  */
  1046 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
  1042 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
  1047 	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
  1043 	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
  1048 	global $wp_textdomain_registry;
  1044 	/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
       
  1045 	global $wp_textdomain_registry, $l10n;
  1049 
  1046 
  1050 	if ( ! is_string( $domain ) ) {
  1047 	if ( ! is_string( $domain ) ) {
  1051 		return false;
  1048 		return false;
  1052 	}
  1049 	}
  1053 
  1050 
  1054 	/** This filter is documented in wp-includes/l10n.php */
       
  1055 	$locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
       
  1056 
       
  1057 	$mofile = $domain . '-' . $locale . '.mo';
       
  1058 
       
  1059 	// Try to load from the languages directory first.
       
  1060 	if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile, $locale ) ) {
       
  1061 		return true;
       
  1062 	}
       
  1063 
       
  1064 	$path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' );
  1051 	$path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' );
  1065 
  1052 
  1066 	$wp_textdomain_registry->set_custom_path( $domain, $path );
  1053 	$wp_textdomain_registry->set_custom_path( $domain, $path );
  1067 
  1054 
  1068 	return load_textdomain( $domain, $path . '/' . $mofile, $locale );
  1055 	// If just-in-time loading was triggered before, reset the entry so it can be tried again.
       
  1056 	if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
       
  1057 		unset( $l10n[ $domain ] );
       
  1058 	}
       
  1059 
       
  1060 	return true;
  1069 }
  1061 }
  1070 
  1062 
  1071 /**
  1063 /**
  1072  * Loads the theme's translated strings.
  1064  * Loads the theme's translated strings.
  1073  *
  1065  *
  1076  *
  1068  *
  1077  * The .mo files must be named based on the locale exactly.
  1069  * The .mo files must be named based on the locale exactly.
  1078  *
  1070  *
  1079  * @since 1.5.0
  1071  * @since 1.5.0
  1080  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
  1072  * @since 4.6.0 The function now tries to load the .mo file from the languages directory first.
       
  1073  * @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
  1081  *
  1074  *
  1082  * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
  1075  * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
       
  1076  * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
  1083  *
  1077  *
  1084  * @param string       $domain Text domain. Unique identifier for retrieving translated strings.
  1078  * @param string       $domain Text domain. Unique identifier for retrieving translated strings.
  1085  * @param string|false $path   Optional. Path to the directory containing the .mo file.
  1079  * @param string|false $path   Optional. Path to the directory containing the .mo file.
  1086  *                             Default false.
  1080  *                             Default false.
  1087  * @return bool True when textdomain is successfully loaded, false otherwise.
  1081  * @return bool True when textdomain is successfully loaded, false otherwise.
  1088  */
  1082  */
  1089 function load_theme_textdomain( $domain, $path = false ) {
  1083 function load_theme_textdomain( $domain, $path = false ) {
  1090 	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
  1084 	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
  1091 	global $wp_textdomain_registry;
  1085 	/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
       
  1086 	global $wp_textdomain_registry, $l10n;
  1092 
  1087 
  1093 	if ( ! is_string( $domain ) ) {
  1088 	if ( ! is_string( $domain ) ) {
  1094 		return false;
  1089 		return false;
  1095 	}
  1090 	}
  1096 
  1091 
  1097 	/**
       
  1098 	 * Filters a theme's locale.
       
  1099 	 *
       
  1100 	 * @since 3.0.0
       
  1101 	 *
       
  1102 	 * @param string $locale The theme's current locale.
       
  1103 	 * @param string $domain Text domain. Unique identifier for retrieving translated strings.
       
  1104 	 */
       
  1105 	$locale = apply_filters( 'theme_locale', determine_locale(), $domain );
       
  1106 
       
  1107 	$mofile = $domain . '-' . $locale . '.mo';
       
  1108 
       
  1109 	// Try to load from the languages directory first.
       
  1110 	if ( load_textdomain( $domain, WP_LANG_DIR . '/themes/' . $mofile, $locale ) ) {
       
  1111 		return true;
       
  1112 	}
       
  1113 
       
  1114 	if ( ! $path ) {
  1092 	if ( ! $path ) {
  1115 		$path = get_template_directory();
  1093 		$path = get_template_directory();
  1116 	}
  1094 	}
  1117 
  1095 
  1118 	$wp_textdomain_registry->set_custom_path( $domain, $path );
  1096 	$wp_textdomain_registry->set_custom_path( $domain, $path );
  1119 
  1097 
  1120 	return load_textdomain( $domain, $path . '/' . $locale . '.mo', $locale );
  1098 	// If just-in-time loading was triggered before, reset the entry so it can be tried again.
       
  1099 	if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof NOOP_Translations ) {
       
  1100 		unset( $l10n[ $domain ] );
       
  1101 	}
       
  1102 
       
  1103 	return true;
  1121 }
  1104 }
  1122 
  1105 
  1123 /**
  1106 /**
  1124  * Loads the child theme's translated strings.
  1107  * Loads the child theme's translated strings.
  1125  *
  1108  *
  1190 
  1173 
  1191 	$src_url     = wp_parse_url( $src );
  1174 	$src_url     = wp_parse_url( $src );
  1192 	$content_url = wp_parse_url( content_url() );
  1175 	$content_url = wp_parse_url( content_url() );
  1193 	$plugins_url = wp_parse_url( plugins_url() );
  1176 	$plugins_url = wp_parse_url( plugins_url() );
  1194 	$site_url    = wp_parse_url( site_url() );
  1177 	$site_url    = wp_parse_url( site_url() );
       
  1178 	$theme_root  = get_theme_root();
  1195 
  1179 
  1196 	// If the host is the same or it's a relative URL.
  1180 	// If the host is the same or it's a relative URL.
  1197 	if (
  1181 	if (
  1198 		( ! isset( $content_url['path'] ) || str_starts_with( $src_url['path'], $content_url['path'] ) ) &&
  1182 		( ! isset( $content_url['path'] ) || str_starts_with( $src_url['path'], $content_url['path'] ) ) &&
  1199 		( ! isset( $src_url['host'] ) || ! isset( $content_url['host'] ) || $src_url['host'] === $content_url['host'] )
  1183 		( ! isset( $src_url['host'] ) || ! isset( $content_url['host'] ) || $src_url['host'] === $content_url['host'] )
  1205 			$relative = $src_url['path'];
  1189 			$relative = $src_url['path'];
  1206 		}
  1190 		}
  1207 		$relative = trim( $relative, '/' );
  1191 		$relative = trim( $relative, '/' );
  1208 		$relative = explode( '/', $relative );
  1192 		$relative = explode( '/', $relative );
  1209 
  1193 
  1210 		$languages_path = WP_LANG_DIR . '/plugins';
  1194 		/*
       
  1195 		 * Ensure correct languages path when using a custom `WP_PLUGIN_DIR` / `WP_PLUGIN_URL` configuration,
       
  1196 		 * a custom theme root, and/or using Multisite with subdirectories.
       
  1197 		 * See https://core.trac.wordpress.org/ticket/60891 and https://core.trac.wordpress.org/ticket/62016.
       
  1198 		 */
       
  1199 
       
  1200 		$theme_dir = array_slice( explode( '/', $theme_root ), -1 );
       
  1201 		$dirname   = $theme_dir[0] === $relative[0] ? 'themes' : 'plugins';
       
  1202 
       
  1203 		$languages_path = WP_LANG_DIR . '/' . $dirname;
  1211 
  1204 
  1212 		$relative = array_slice( $relative, 2 ); // Remove plugins/<plugin name> or themes/<theme name>.
  1205 		$relative = array_slice( $relative, 2 ); // Remove plugins/<plugin name> or themes/<theme name>.
  1213 		$relative = implode( '/', $relative );
  1206 		$relative = implode( '/', $relative );
  1214 	} elseif (
  1207 	} elseif (
  1215 		( ! isset( $plugins_url['path'] ) || str_starts_with( $src_url['path'], $plugins_url['path'] ) ) &&
  1208 		( ! isset( $plugins_url['path'] ) || str_starts_with( $src_url['path'], $plugins_url['path'] ) ) &&
  1371 	$locale = determine_locale();
  1364 	$locale = determine_locale();
  1372 	$path   = $wp_textdomain_registry->get( $domain, $locale );
  1365 	$path   = $wp_textdomain_registry->get( $domain, $locale );
  1373 	if ( ! $path ) {
  1366 	if ( ! $path ) {
  1374 		return false;
  1367 		return false;
  1375 	}
  1368 	}
       
  1369 
       
  1370 	if ( ! doing_action( 'after_setup_theme' ) && ! did_action( 'after_setup_theme' ) ) {
       
  1371 		_doing_it_wrong(
       
  1372 			__FUNCTION__,
       
  1373 			sprintf(
       
  1374 				/* translators: 1: The text domain. 2: 'init'. */
       
  1375 				__( 'Translation loading for the %1$s domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the %2$s action or later.' ),
       
  1376 				'<code>' . $domain . '</code>',
       
  1377 				'<code>init</code>'
       
  1378 			),
       
  1379 			'6.7.0'
       
  1380 		);
       
  1381 	}
       
  1382 
  1376 	// Themes with their language directory outside of WP_LANG_DIR have a different file name.
  1383 	// Themes with their language directory outside of WP_LANG_DIR have a different file name.
  1377 	$template_directory   = trailingslashit( get_template_directory() );
  1384 	$template_directory   = trailingslashit( get_template_directory() );
  1378 	$stylesheet_directory = trailingslashit( get_stylesheet_directory() );
  1385 	$stylesheet_directory = trailingslashit( get_stylesheet_directory() );
  1379 	if ( str_starts_with( $path, $template_directory ) || str_starts_with( $path, $stylesheet_directory ) ) {
  1386 	if ( str_starts_with( $path, $template_directory ) || str_starts_with( $path, $stylesheet_directory ) ) {
  1380 		$mofile = "{$path}{$locale}.mo";
  1387 		$mofile = "{$path}{$locale}.mo";
  1986 		return 'words';
  1993 		return 'words';
  1987 	}
  1994 	}
  1988 
  1995 
  1989 	return $wp_locale->get_word_count_type();
  1996 	return $wp_locale->get_word_count_type();
  1990 }
  1997 }
       
  1998 
       
  1999 /**
       
  2000  * Returns a boolean to indicate whether a translation exists for a given string with optional text domain and locale.
       
  2001  *
       
  2002  * @since 6.7.0
       
  2003  *
       
  2004  * @param string  $singular   Singular translation to check.
       
  2005  * @param string  $textdomain Optional. Text domain. Default 'default'.
       
  2006  * @param ?string $locale     Optional. Locale. Default current locale.
       
  2007  * @return bool  True if the translation exists, false otherwise.
       
  2008  */
       
  2009 function has_translation( string $singular, string $textdomain = 'default', ?string $locale = null ): bool {
       
  2010 	return WP_Translation_Controller::get_instance()->has_translation( $singular, $textdomain, $locale );
       
  2011 }