I18N: Introduce `switch_to_user_locale()`.

This new function makes it easier to switch to a specific user’s locale by reducing duplicate code and storing the user’s ID as additional context for plugins to consume. Existing usage of `switch_to_locale()` in core has been replaced with `switch_to_user_locale()` where appropriate.

Also, this change ensures `WP_Locale_Switcher` properly filters `determine_locale` so that anyyone using the `determine_locale()` function will get the correct locale information when switching is in effect.

Props costdev.
Fixes #57123.
See #26511.
Built from https://develop.svn.wordpress.org/trunk@55161


git-svn-id: http://core.svn.wordpress.org/trunk@54694 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Pascal Birchler 2023-01-30 10:27:16 +00:00
parent 319fadaa9c
commit 5edb22187d
13 changed files with 124 additions and 49 deletions

View File

@ -1457,7 +1457,7 @@ function update_option_new_admin_email( $old_value, $value ) {
); );
update_option( 'adminhash', $new_admin_email ); update_option( 'adminhash', $new_admin_email );
$switched_locale = switch_to_locale( get_user_locale() ); $switched_locale = switch_to_user_locale( get_current_user_id() );
/* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */ /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
$email_text = __( $email_text = __(

View File

@ -595,13 +595,11 @@ function wp_privacy_send_personal_data_export_email( $request_id ) {
// Localize message content for user; fallback to site default for visitors. // Localize message content for user; fallback to site default for visitors.
if ( ! empty( $request->user_id ) ) { if ( ! empty( $request->user_id ) ) {
$locale = get_user_locale( $request->user_id ); $switched_locale = switch_to_user_locale( $request->user_id );
} else { } else {
$locale = get_locale(); $switched_locale = switch_to_locale( get_locale() );
} }
$switched_locale = switch_to_locale( $locale );
/** This filter is documented in wp-includes/functions.php */ /** This filter is documented in wp-includes/functions.php */
$expiration = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS ); $expiration = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS );
$expiration_date = date_i18n( get_option( 'date_format' ), time() + $expiration ); $expiration_date = date_i18n( get_option( 'date_format' ), time() + $expiration );

View File

@ -110,7 +110,7 @@ if ( isset( $_REQUEST['action'] ) && 'adduser' === $_REQUEST['action'] ) {
*/ */
do_action( 'invite_user', $user_id, $role, $newuser_key ); do_action( 'invite_user', $user_id, $role, $newuser_key );
$switched_locale = switch_to_locale( get_user_locale( $user_details ) ); $switched_locale = switch_to_user_locale( $user_id );
if ( '' !== get_option( 'blogname' ) ) { if ( '' !== get_option( 'blogname' ) ) {
$site_title = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ); $site_title = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );

View File

@ -2134,7 +2134,7 @@ final class WP_Customize_Manager {
$allowed_hosts[] = $host; $allowed_hosts[] = $host;
} }
$switched_locale = switch_to_locale( get_user_locale() ); $switched_locale = switch_to_user_locale( get_current_user_id() );
$l10n = array( $l10n = array(
'shiftClickToEdit' => __( 'Shift-click to edit this element.' ), 'shiftClickToEdit' => __( 'Shift-click to edit this element.' ),
'linkUnpreviewable' => __( 'This link is not live-previewable.' ), 'linkUnpreviewable' => __( 'This link is not live-previewable.' ),

View File

@ -1264,7 +1264,7 @@ final class WP_Customize_Widgets {
public function export_preview_data() { public function export_preview_data() {
global $wp_registered_sidebars, $wp_registered_widgets; global $wp_registered_sidebars, $wp_registered_widgets;
$switched_locale = switch_to_locale( get_user_locale() ); $switched_locale = switch_to_user_locale( get_current_user_id() );
$l10n = array( $l10n = array(
'widgetTooltip' => __( 'Shift-click to edit this widget.' ), 'widgetTooltip' => __( 'Shift-click to edit this widget.' ),

View File

@ -15,12 +15,12 @@
#[AllowDynamicProperties] #[AllowDynamicProperties]
class WP_Locale_Switcher { class WP_Locale_Switcher {
/** /**
* Locale stack. * Locale switching stack.
* *
* @since 4.7.0 * @since 4.7.0
* @var string[] * @var array
*/ */
private $locales = array(); private $stack = array();
/** /**
* Original locale. * Original locale.
@ -53,12 +53,14 @@ class WP_Locale_Switcher {
/** /**
* Initializes the locale switcher. * Initializes the locale switcher.
* *
* Hooks into the {@see 'locale'} filter to change the locale on the fly. * Hooks into the {@see 'locale'} and {@see 'determine_locale'} filters
* to change the locale on the fly.
* *
* @since 4.7.0 * @since 4.7.0
*/ */
public function init() { public function init() {
add_filter( 'locale', array( $this, 'filter_locale' ) ); add_filter( 'locale', array( $this, 'filter_locale' ) );
add_filter( 'determine_locale', array( $this, 'filter_locale' ) );
} }
/** /**
@ -66,10 +68,11 @@ class WP_Locale_Switcher {
* *
* @since 4.7.0 * @since 4.7.0
* *
* @param string $locale The locale to switch to. * @param string $locale The locale to switch to.
* @param int|false $user_id Optional. User ID as context. Default false.
* @return bool True on success, false on failure. * @return bool True on success, false on failure.
*/ */
public function switch_to_locale( $locale ) { public function switch_to_locale( $locale, $user_id = false ) {
$current_locale = determine_locale(); $current_locale = determine_locale();
if ( $current_locale === $locale ) { if ( $current_locale === $locale ) {
return false; return false;
@ -79,7 +82,7 @@ class WP_Locale_Switcher {
return false; return false;
} }
$this->locales[] = $locale; $this->stack[] = array( $locale, $user_id );
$this->change_locale( $locale ); $this->change_locale( $locale );
@ -87,14 +90,29 @@ class WP_Locale_Switcher {
* Fires when the locale is switched. * Fires when the locale is switched.
* *
* @since 4.7.0 * @since 4.7.0
* @since 6.2.0 The `$user_id` parameter was added.
* *
* @param string $locale The new locale. * @param string $locale The new locale.
* @param null|int $user_id User ID for context if available.
*/ */
do_action( 'switch_locale', $locale ); do_action( 'switch_locale', $locale, $user_id );
return true; return true;
} }
/**
* Switches the translations according to the given user's locale.
*
* @since 6.2.0
*
* @param int $user_id User ID.
* @return bool True on success, false on failure.
*/
public function switch_to_user_locale( $user_id ) {
$locale = get_user_locale( $user_id );
return $this->switch_to_locale( $locale, $user_id );
}
/** /**
* Restores the translations according to the previous locale. * Restores the translations according to the previous locale.
* *
@ -103,14 +121,15 @@ class WP_Locale_Switcher {
* @return string|false Locale on success, false on failure. * @return string|false Locale on success, false on failure.
*/ */
public function restore_previous_locale() { public function restore_previous_locale() {
$previous_locale = array_pop( $this->locales ); $previous_locale = array_pop( $this->stack );
if ( null === $previous_locale ) { if ( null === $previous_locale ) {
// The stack is empty, bail. // The stack is empty, bail.
return false; return false;
} }
$locale = end( $this->locales ); $entry = end( $this->stack );
$locale = is_array( $entry ) ? $entry[0] : false;
if ( ! $locale ) { if ( ! $locale ) {
// There's nothing left in the stack: go back to the original locale. // There's nothing left in the stack: go back to the original locale.
@ -127,7 +146,7 @@ class WP_Locale_Switcher {
* @param string $locale The new locale. * @param string $locale The new locale.
* @param string $previous_locale The previous locale. * @param string $previous_locale The previous locale.
*/ */
do_action( 'restore_previous_locale', $locale, $previous_locale ); do_action( 'restore_previous_locale', $locale, $previous_locale[0] );
return $locale; return $locale;
} }
@ -140,11 +159,11 @@ class WP_Locale_Switcher {
* @return string|false Locale on success, false on failure. * @return string|false Locale on success, false on failure.
*/ */
public function restore_current_locale() { public function restore_current_locale() {
if ( empty( $this->locales ) ) { if ( empty( $this->stack ) ) {
return false; return false;
} }
$this->locales = array( $this->original_locale ); $this->stack = array( array( $this->original_locale, false ) );
return $this->restore_previous_locale(); return $this->restore_previous_locale();
} }
@ -157,7 +176,41 @@ class WP_Locale_Switcher {
* @return bool True if the locale has been switched, false otherwise. * @return bool True if the locale has been switched, false otherwise.
*/ */
public function is_switched() { public function is_switched() {
return ! empty( $this->locales ); return ! empty( $this->stack );
}
/**
* Returns the locale currently switched to.
*
* @since 6.2.0
*
* @return string|false Locale if the locale has been switched, false otherwise.
*/
public function get_current_locale() {
$entry = end( $this->stack );
if ( $entry ) {
return $entry[0];
}
return false;
}
/**
* Returns the user ID related to the currently switched locale.
*
* @since 6.2.0
*
* @return int|false User ID if set and if the locale has been switched, false otherwise.
*/
public function get_current_user_id() {
$entry = end( $this->stack );
if ( $entry ) {
return $entry[1];
}
return false;
} }
/** /**
@ -169,7 +222,7 @@ class WP_Locale_Switcher {
* @return string The locale currently being switched to. * @return string The locale currently being switched to.
*/ */
public function filter_locale( $locale ) { public function filter_locale( $locale ) {
$switched_locale = end( $this->locales ); $switched_locale = $this->get_current_locale();
if ( $switched_locale ) { if ( $switched_locale ) {
return $switched_locale; return $switched_locale;

View File

@ -116,12 +116,7 @@ final class WP_Recovery_Mode_Email_Service {
$url = $this->link_service->generate_url(); $url = $this->link_service->generate_url();
$blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ); $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
$switched_locale = false; $switched_locale = switch_to_locale( get_locale() );
// The switch_to_locale() function is loaded before it can actually be used.
if ( function_exists( 'switch_to_locale' ) && isset( $GLOBALS['wp_locale_switcher'] ) ) {
$switched_locale = switch_to_locale( get_locale() );
}
if ( $extension ) { if ( $extension ) {
$cause = $this->get_cause( $extension ); $cause = $this->get_cause( $extension );

View File

@ -172,7 +172,7 @@ final class WP_Customize_Selective_Refresh {
} }
} }
$switched_locale = switch_to_locale( get_user_locale() ); $switched_locale = switch_to_user_locale( get_current_user_id() );
$l10n = array( $l10n = array(
'shiftClickToEdit' => __( 'Shift-click to edit this element.' ), 'shiftClickToEdit' => __( 'Shift-click to edit this element.' ),
'clickEditMenu' => __( 'Click to edit this menu.' ), 'clickEditMenu' => __( 'Click to edit this menu.' ),

View File

@ -1665,9 +1665,34 @@ function switch_to_locale( $locale ) {
/* @var WP_Locale_Switcher $wp_locale_switcher */ /* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher; global $wp_locale_switcher;
if ( ! $wp_locale_switcher ) {
return false;
}
return $wp_locale_switcher->switch_to_locale( $locale ); return $wp_locale_switcher->switch_to_locale( $locale );
} }
/**
* Switches the translations according to the given user's locale.
*
* @since 6.2.0
*
* @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 false;
}
return $wp_locale_switcher->switch_to_user_locale( $user_id );
}
/** /**
* Restores the translations according to the previous locale. * Restores the translations according to the previous locale.
* *
@ -1681,6 +1706,10 @@ function restore_previous_locale() {
/* @var WP_Locale_Switcher $wp_locale_switcher */ /* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher; global $wp_locale_switcher;
if ( ! $wp_locale_switcher ) {
return false;
}
return $wp_locale_switcher->restore_previous_locale(); return $wp_locale_switcher->restore_previous_locale();
} }
@ -1697,6 +1726,10 @@ function restore_current_locale() {
/* @var WP_Locale_Switcher $wp_locale_switcher */ /* @var WP_Locale_Switcher $wp_locale_switcher */
global $wp_locale_switcher; global $wp_locale_switcher;
if ( ! $wp_locale_switcher ) {
return false;
}
return $wp_locale_switcher->restore_current_locale(); return $wp_locale_switcher->restore_current_locale();
} }

View File

@ -954,7 +954,7 @@ function wpmu_signup_blog_notification( $domain, $path, $title, $user_login, $us
$message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n"; $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . "\"\n";
$user = get_user_by( 'login', $user_login ); $user = get_user_by( 'login', $user_login );
$switched_locale = switch_to_locale( get_user_locale( $user ) ); $switched_locale = $user && switch_to_user_locale( $user->ID );
$message = sprintf( $message = sprintf(
/** /**
@ -1068,7 +1068,7 @@ function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta =
} }
$user = get_user_by( 'login', $user_login ); $user = get_user_by( 'login', $user_login );
$switched_locale = switch_to_locale( get_user_locale( $user ) ); $switched_locale = $user && switch_to_user_locale( $user->ID );
// Send email with activation link. // Send email with activation link.
$admin_email = get_site_option( 'admin_email' ); $admin_email = get_site_option( 'admin_email' );
@ -1610,7 +1610,7 @@ function wpmu_welcome_notification( $blog_id, $user_id, $password, $title, $meta
$user = get_userdata( $user_id ); $user = get_userdata( $user_id );
$switched_locale = switch_to_locale( get_user_locale( $user ) ); $switched_locale = switch_to_user_locale( $user_id );
$welcome_email = get_site_option( 'welcome_email' ); $welcome_email = get_site_option( 'welcome_email' );
if ( false == $welcome_email ) { if ( false == $welcome_email ) {
@ -1734,7 +1734,7 @@ function wpmu_new_site_admin_notification( $site_id, $user_id ) {
if ( $network_admin ) { if ( $network_admin ) {
// If the network admin email address corresponds to a user, switch to their locale. // If the network admin email address corresponds to a user, switch to their locale.
$switched_locale = switch_to_locale( get_user_locale( $network_admin ) ); $switched_locale = switch_to_user_locale( $network_admin->ID );
} else { } else {
// Otherwise switch to the locale of the current site. // Otherwise switch to the locale of the current site.
$switched_locale = switch_to_locale( get_locale() ); $switched_locale = switch_to_locale( get_locale() );
@ -1843,7 +1843,7 @@ function wpmu_welcome_user_notification( $user_id, $password, $meta = array() )
$user = get_userdata( $user_id ); $user = get_userdata( $user_id );
$switched_locale = switch_to_locale( get_user_locale( $user ) ); $switched_locale = switch_to_user_locale( $user_id );
/** /**
* Filters the content of the welcome email after user activation. * Filters the content of the welcome email after user activation.
@ -2726,7 +2726,7 @@ function update_network_option_new_admin_email( $old_value, $value ) {
); );
update_site_option( 'network_admin_hash', $new_admin_email ); update_site_option( 'network_admin_hash', $new_admin_email );
$switched_locale = switch_to_locale( get_user_locale() ); $switched_locale = switch_to_user_locale( get_current_user_id() );
/* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */ /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
$email_text = __( $email_text = __(

View File

@ -2188,7 +2188,7 @@ if ( ! function_exists( 'wp_new_user_notification' ) ) :
return; return;
} }
$switched_locale = switch_to_locale( get_user_locale( $user ) ); $switched_locale = switch_to_user_locale( $user_id );
/* translators: %s: User login. */ /* translators: %s: User login. */
$message = sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n"; $message = sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";

View File

@ -2578,7 +2578,7 @@ function wp_update_user( $userdata ) {
$switched_locale = false; $switched_locale = false;
if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) { if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) {
$switched_locale = switch_to_locale( get_user_locale( $user_id ) ); $switched_locale = switch_to_user_locale( $user_id );
} }
if ( ! empty( $send_password_change_email ) ) { if ( ! empty( $send_password_change_email ) ) {
@ -3139,7 +3139,7 @@ function retrieve_password( $user_login = null ) {
// Localize password reset message content for user. // Localize password reset message content for user.
$locale = get_user_locale( $user_data ); $locale = get_user_locale( $user_data );
$switched_locale = switch_to_locale( $locale ); $switched_locale = switch_to_user_locale( $user_data->ID );
if ( is_multisite() ) { if ( is_multisite() ) {
$site_name = get_network()->site_name; $site_name = get_network()->site_name;
@ -4244,13 +4244,11 @@ function _wp_privacy_send_erasure_fulfillment_notification( $request_id ) {
// Localize message content for user; fallback to site default for visitors. // Localize message content for user; fallback to site default for visitors.
if ( ! empty( $request->user_id ) ) { if ( ! empty( $request->user_id ) ) {
$locale = get_user_locale( $request->user_id ); $switched_locale = switch_to_user_locale( $request->user_id );
} else { } else {
$locale = get_locale(); $switched_locale = switch_to_locale( get_locale() );
} }
$switched_locale = switch_to_locale( $locale );
/** /**
* Filters the recipient of the data erasure fulfillment notification. * Filters the recipient of the data erasure fulfillment notification.
* *
@ -4655,13 +4653,11 @@ function wp_send_user_request( $request_id ) {
// Localize message content for user; fallback to site default for visitors. // Localize message content for user; fallback to site default for visitors.
if ( ! empty( $request->user_id ) ) { if ( ! empty( $request->user_id ) ) {
$locale = get_user_locale( $request->user_id ); $switched_locale = switch_to_user_locale( $request->user_id );
} else { } else {
$locale = get_locale(); $switched_locale = switch_to_locale( get_locale() );
} }
$switched_locale = switch_to_locale( $locale );
$email_data = array( $email_data = array(
'request' => $request, 'request' => $request,
'email' => $request->email, 'email' => $request->email,

View File

@ -16,7 +16,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '6.2-alpha-55160'; $wp_version = '6.2-alpha-55161';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.