From 5edb22187d2ddfdc3c18b0a687a4c6c4b83f2d05 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Mon, 30 Jan 2023 10:27:16 +0000 Subject: [PATCH] I18N: Introduce `switch_to_user_locale()`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- wp-admin/includes/misc.php | 2 +- wp-admin/includes/privacy-tools.php | 6 +- wp-admin/user-new.php | 2 +- wp-includes/class-wp-customize-manager.php | 2 +- wp-includes/class-wp-customize-widgets.php | 2 +- wp-includes/class-wp-locale-switcher.php | 85 +++++++++++++++---- .../class-wp-recovery-mode-email-service.php | 7 +- .../class-wp-customize-selective-refresh.php | 2 +- wp-includes/l10n.php | 33 +++++++ wp-includes/ms-functions.php | 12 +-- wp-includes/pluggable.php | 2 +- wp-includes/user.php | 16 ++-- wp-includes/version.php | 2 +- 13 files changed, 124 insertions(+), 49 deletions(-) diff --git a/wp-admin/includes/misc.php b/wp-admin/includes/misc.php index 78c1aab1c8..e13ce39f7e 100644 --- a/wp-admin/includes/misc.php +++ b/wp-admin/includes/misc.php @@ -1457,7 +1457,7 @@ function update_option_new_admin_email( $old_value, $value ) { ); 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. */ $email_text = __( diff --git a/wp-admin/includes/privacy-tools.php b/wp-admin/includes/privacy-tools.php index 9682e94fcf..ba0f27534c 100644 --- a/wp-admin/includes/privacy-tools.php +++ b/wp-admin/includes/privacy-tools.php @@ -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. if ( ! empty( $request->user_id ) ) { - $locale = get_user_locale( $request->user_id ); + $switched_locale = switch_to_user_locale( $request->user_id ); } 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 */ $expiration = apply_filters( 'wp_privacy_export_expiration', 3 * DAY_IN_SECONDS ); $expiration_date = date_i18n( get_option( 'date_format' ), time() + $expiration ); diff --git a/wp-admin/user-new.php b/wp-admin/user-new.php index b3b675948f..0d779e21c1 100644 --- a/wp-admin/user-new.php +++ b/wp-admin/user-new.php @@ -110,7 +110,7 @@ if ( isset( $_REQUEST['action'] ) && 'adduser' === $_REQUEST['action'] ) { */ 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' ) ) { $site_title = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ); diff --git a/wp-includes/class-wp-customize-manager.php b/wp-includes/class-wp-customize-manager.php index 093243ef15..0ef684b40f 100644 --- a/wp-includes/class-wp-customize-manager.php +++ b/wp-includes/class-wp-customize-manager.php @@ -2134,7 +2134,7 @@ final class WP_Customize_Manager { $allowed_hosts[] = $host; } - $switched_locale = switch_to_locale( get_user_locale() ); + $switched_locale = switch_to_user_locale( get_current_user_id() ); $l10n = array( 'shiftClickToEdit' => __( 'Shift-click to edit this element.' ), 'linkUnpreviewable' => __( 'This link is not live-previewable.' ), diff --git a/wp-includes/class-wp-customize-widgets.php b/wp-includes/class-wp-customize-widgets.php index 2bf8a39a25..4363338bee 100644 --- a/wp-includes/class-wp-customize-widgets.php +++ b/wp-includes/class-wp-customize-widgets.php @@ -1264,7 +1264,7 @@ final class WP_Customize_Widgets { public function export_preview_data() { 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( 'widgetTooltip' => __( 'Shift-click to edit this widget.' ), diff --git a/wp-includes/class-wp-locale-switcher.php b/wp-includes/class-wp-locale-switcher.php index c95c8ada03..424561a21a 100644 --- a/wp-includes/class-wp-locale-switcher.php +++ b/wp-includes/class-wp-locale-switcher.php @@ -15,12 +15,12 @@ #[AllowDynamicProperties] class WP_Locale_Switcher { /** - * Locale stack. + * Locale switching stack. * * @since 4.7.0 - * @var string[] + * @var array */ - private $locales = array(); + private $stack = array(); /** * Original locale. @@ -53,12 +53,14 @@ class WP_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 */ public function init() { 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 * - * @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. */ - public function switch_to_locale( $locale ) { + public function switch_to_locale( $locale, $user_id = false ) { $current_locale = determine_locale(); if ( $current_locale === $locale ) { return false; @@ -79,7 +82,7 @@ class WP_Locale_Switcher { return false; } - $this->locales[] = $locale; + $this->stack[] = array( $locale, $user_id ); $this->change_locale( $locale ); @@ -87,14 +90,29 @@ class WP_Locale_Switcher { * Fires when the locale is switched. * * @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; } + /** + * 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. * @@ -103,14 +121,15 @@ class WP_Locale_Switcher { * @return string|false Locale on success, false on failure. */ public function restore_previous_locale() { - $previous_locale = array_pop( $this->locales ); + $previous_locale = array_pop( $this->stack ); if ( null === $previous_locale ) { // The stack is empty, bail. return false; } - $locale = end( $this->locales ); + $entry = end( $this->stack ); + $locale = is_array( $entry ) ? $entry[0] : false; if ( ! $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 $previous_locale The previous locale. */ - do_action( 'restore_previous_locale', $locale, $previous_locale ); + do_action( 'restore_previous_locale', $locale, $previous_locale[0] ); return $locale; } @@ -140,11 +159,11 @@ class WP_Locale_Switcher { * @return string|false Locale on success, false on failure. */ public function restore_current_locale() { - if ( empty( $this->locales ) ) { + if ( empty( $this->stack ) ) { return false; } - $this->locales = array( $this->original_locale ); + $this->stack = array( array( $this->original_locale, false ) ); return $this->restore_previous_locale(); } @@ -157,7 +176,41 @@ class WP_Locale_Switcher { * @return bool True if the locale has been switched, false otherwise. */ 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. */ public function filter_locale( $locale ) { - $switched_locale = end( $this->locales ); + $switched_locale = $this->get_current_locale(); if ( $switched_locale ) { return $switched_locale; diff --git a/wp-includes/class-wp-recovery-mode-email-service.php b/wp-includes/class-wp-recovery-mode-email-service.php index 14dbbf9c4c..75f271c010 100644 --- a/wp-includes/class-wp-recovery-mode-email-service.php +++ b/wp-includes/class-wp-recovery-mode-email-service.php @@ -116,12 +116,7 @@ final class WP_Recovery_Mode_Email_Service { $url = $this->link_service->generate_url(); $blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ); - $switched_locale = false; - - // 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() ); - } + $switched_locale = switch_to_locale( get_locale() ); if ( $extension ) { $cause = $this->get_cause( $extension ); diff --git a/wp-includes/customize/class-wp-customize-selective-refresh.php b/wp-includes/customize/class-wp-customize-selective-refresh.php index 6119e68944..f75baff3e4 100644 --- a/wp-includes/customize/class-wp-customize-selective-refresh.php +++ b/wp-includes/customize/class-wp-customize-selective-refresh.php @@ -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( 'shiftClickToEdit' => __( 'Shift-click to edit this element.' ), 'clickEditMenu' => __( 'Click to edit this menu.' ), diff --git a/wp-includes/l10n.php b/wp-includes/l10n.php index 651c78e791..e83706df66 100644 --- a/wp-includes/l10n.php +++ b/wp-includes/l10n.php @@ -1665,9 +1665,34 @@ function switch_to_locale( $locale ) { /* @var WP_Locale_Switcher $wp_locale_switcher */ global $wp_locale_switcher; + if ( ! $wp_locale_switcher ) { + return false; + } + 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. * @@ -1681,6 +1706,10 @@ function restore_previous_locale() { /* @var WP_Locale_Switcher $wp_locale_switcher */ global $wp_locale_switcher; + if ( ! $wp_locale_switcher ) { + return false; + } + return $wp_locale_switcher->restore_previous_locale(); } @@ -1697,6 +1726,10 @@ function restore_current_locale() { /* @var WP_Locale_Switcher $wp_locale_switcher */ global $wp_locale_switcher; + if ( ! $wp_locale_switcher ) { + return false; + } + return $wp_locale_switcher->restore_current_locale(); } diff --git a/wp-includes/ms-functions.php b/wp-includes/ms-functions.php index 6c1b9eb815..edc482d466 100644 --- a/wp-includes/ms-functions.php +++ b/wp-includes/ms-functions.php @@ -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"; $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( /** @@ -1068,7 +1068,7 @@ function wpmu_signup_user_notification( $user_login, $user_email, $key, $meta = } $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. $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 ); - $switched_locale = switch_to_locale( get_user_locale( $user ) ); + $switched_locale = switch_to_user_locale( $user_id ); $welcome_email = get_site_option( 'welcome_email' ); if ( false == $welcome_email ) { @@ -1734,7 +1734,7 @@ function wpmu_new_site_admin_notification( $site_id, $user_id ) { if ( $network_admin ) { // 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 { // Otherwise switch to the locale of the current site. $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 ); - $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. @@ -2726,7 +2726,7 @@ function update_network_option_new_admin_email( $old_value, $value ) { ); 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. */ $email_text = __( diff --git a/wp-includes/pluggable.php b/wp-includes/pluggable.php index c7decd1e8e..c4b5bf4a75 100644 --- a/wp-includes/pluggable.php +++ b/wp-includes/pluggable.php @@ -2188,7 +2188,7 @@ if ( ! function_exists( 'wp_new_user_notification' ) ) : return; } - $switched_locale = switch_to_locale( get_user_locale( $user ) ); + $switched_locale = switch_to_user_locale( $user_id ); /* translators: %s: User login. */ $message = sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n"; diff --git a/wp-includes/user.php b/wp-includes/user.php index ca4b3d03fd..7fc0dfb584 100644 --- a/wp-includes/user.php +++ b/wp-includes/user.php @@ -2578,7 +2578,7 @@ function wp_update_user( $userdata ) { $switched_locale = false; 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 ) ) { @@ -3139,7 +3139,7 @@ function retrieve_password( $user_login = null ) { // Localize password reset message content for user. $locale = get_user_locale( $user_data ); - $switched_locale = switch_to_locale( $locale ); + $switched_locale = switch_to_user_locale( $user_data->ID ); if ( is_multisite() ) { $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. if ( ! empty( $request->user_id ) ) { - $locale = get_user_locale( $request->user_id ); + $switched_locale = switch_to_user_locale( $request->user_id ); } 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. * @@ -4655,13 +4653,11 @@ function wp_send_user_request( $request_id ) { // Localize message content for user; fallback to site default for visitors. if ( ! empty( $request->user_id ) ) { - $locale = get_user_locale( $request->user_id ); + $switched_locale = switch_to_user_locale( $request->user_id ); } else { - $locale = get_locale(); + $switched_locale = switch_to_locale( get_locale() ); } - $switched_locale = switch_to_locale( $locale ); - $email_data = array( 'request' => $request, 'email' => $request->email, diff --git a/wp-includes/version.php b/wp-includes/version.php index 942fe68492..a60e8c6130 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @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.