WordPress.org

Make WordPress Core

Ticket #26511: 26511.17.diff

File 26511.17.diff, 35.6 KB (added by swissspidy, 15 months ago)
  • src/wp-admin/includes/ms.php

    diff --git src/wp-admin/includes/ms.php src/wp-admin/includes/ms.php
    index 7e08e6f..48dbf55 100644
    function update_option_new_admin_email( $old_value, $value ) { 
    272272        ); 
    273273        update_option( 'adminhash', $new_admin_email ); 
    274274 
     275        $switched_locale = switch_to_locale( get_user_locale() ); 
     276 
    275277        /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */ 
    276278        $email_text = __( 'Howdy ###USERNAME###, 
    277279 
    All at ###SITENAME### 
    315317        $content = str_replace( '###SITEURL###', network_home_url(), $content ); 
    316318 
    317319        wp_mail( $value, sprintf( __( '[%s] New Admin Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content ); 
     320 
     321        if ( $switched_locale ) { 
     322                restore_previous_locale(); 
     323        } 
    318324} 
    319325 
    320326/** 
    function send_confirmation_on_profile_email() { 
    353359                ); 
    354360                update_user_meta( $current_user->ID, '_new_email', $new_user_email ); 
    355361 
     362                $switched_locale = switch_to_locale( get_user_locale() ); 
     363 
    356364                /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */ 
    357365                $email_text = __( 'Howdy ###USERNAME###, 
    358366 
    All at ###SITENAME### 
    395403 
    396404                wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content ); 
    397405                $_POST['email'] = $current_user->user_email; 
     406 
     407                if ( $switched_locale ) { 
     408                        restore_previous_locale(); 
     409                } 
    398410        } 
    399411} 
    400412 
  • src/wp-admin/includes/upgrade.php

    diff --git src/wp-admin/includes/upgrade.php src/wp-admin/includes/upgrade.php
    index 848002e..8f56031 100644
    function wp_new_blog_notification($blog_title, $blog_url, $user_id, $password) { 
    372372        $email = $user->user_email; 
    373373        $name = $user->user_login; 
    374374        $login_url = wp_login_url(); 
     375 
     376        $switched_locale = switch_to_locale( $user->locale ); 
     377 
    375378        $message = sprintf( __( "Your new WordPress site has been successfully set up at: 
    376379 
    377380%1\$s 
    https://wordpress.org/ 
    389392"), $blog_url, $name, $password, $login_url ); 
    390393 
    391394        @wp_mail($email, __('New WordPress Site'), $message); 
     395 
     396        if ( $switched_locale ) { 
     397                restore_previous_locale(); 
     398        } 
    392399} 
    393400endif; 
    394401 
  • src/wp-admin/ms-delete-site.php

    diff --git src/wp-admin/ms-delete-site.php src/wp-admin/ms-delete-site.php
    index 9192509..6bc3cfc 100644
    if ( isset( $_POST['action'] ) && $_POST['action'] == 'deleteblog' && isset( $_P 
    4242 
    4343        $url_delete = esc_url( admin_url( 'ms-delete-site.php?h=' . $hash ) ); 
    4444 
     45        $switched_locale = switch_to_locale( get_locale() ); 
     46 
    4547        /* translators: Do not translate USERNAME, URL_DELETE, SITE_NAME: those are placeholders. */ 
    4648        $content = __( "Howdy ###USERNAME###, 
    4749 
    Webmaster 
    7375        $content = str_replace( '###SITE_NAME###', get_network()->site_name, $content ); 
    7476 
    7577        wp_mail( get_option( 'admin_email' ), "[ " . wp_specialchars_decode( get_option( 'blogname' ) ) . " ] ".__( 'Delete My Site' ), $content ); 
     78 
     79        if ( $switched_locale ) { 
     80                restore_previous_locale(); 
     81        } 
    7682        ?> 
    7783 
    7884        <p><?php _e( 'Thank you. Please check your email for a link to confirm your action. Your site will not be deleted until this link is clicked.' ) ?></p> 
  • src/wp-admin/user-new.php

    diff --git src/wp-admin/user-new.php src/wp-admin/user-new.php
    index 38b78dd..13d753d 100644
    if ( isset($_REQUEST['action']) && 'adduser' == $_REQUEST['action'] ) { 
    8787                         */ 
    8888                        do_action( 'invite_user', $user_id, $role, $newuser_key ); 
    8989 
     90                        $switched_locale = switch_to_locale( $user_details->locale ); 
     91 
    9092                        /* translators: 1: Site name, 2: site URL, 3: role, 4: activation URL */ 
    9193                        $message = __( 'Hi, 
    9294 
    You\'ve been invited to join \'%1$s\' at 
    9698Please click the following link to confirm the invite: 
    9799%4$s' ); 
    98100                        wp_mail( $new_user_email, sprintf( __( '[%s] Joining confirmation' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), sprintf( $message, get_option( 'blogname' ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ), home_url( "/newbloguser/$newuser_key/" ) ) ); 
     101 
     102                        if ( $switched_locale ) { 
     103                                restore_previous_locale(); 
     104                        } 
     105 
    99106                        $redirect = add_query_arg( array('update' => 'add'), 'user-new.php' ); 
    100107                } 
    101108        } 
  • new file src/wp-includes/class-wp-locale-switcher.php

    diff --git src/wp-includes/class-wp-locale-switcher.php src/wp-includes/class-wp-locale-switcher.php
    new file mode 100644
    index 0000000..3d288c8
    - +  
     1<?php 
     2/** 
     3 * Locale API: WP_Locale_Switcher class 
     4 * 
     5 * @package WordPress 
     6 * @subpackage i18n 
     7 * @since 4.7.0 
     8 */ 
     9 
     10/** 
     11 * Core class used for switching locales. 
     12 * 
     13 * @since 4.7.0 
     14 */ 
     15class WP_Locale_Switcher { 
     16        /** 
     17         * Locale stack. 
     18         * 
     19         * @since 4.7.0 
     20         * @access private 
     21         * @var string[] 
     22         */ 
     23        private $locales = array(); 
     24 
     25        /** 
     26         * Original locale. 
     27         * 
     28         * @since 4.7.0 
     29         * @access private 
     30         * @var string 
     31         */ 
     32        private $original_locale; 
     33 
     34        /** 
     35         * Holds all available languages. 
     36         * 
     37         * @since 4.7.0 
     38         * @access private 
     39         * @var array An array of language codes (file names without the .mo extension). 
     40         */ 
     41        private $available_languages = array(); 
     42 
     43        /** 
     44         * Constructor. 
     45         * 
     46         * Stores the original locale as well as a list of all available languages. 
     47         * 
     48         * @since 4.7.0 
     49         */ 
     50        public function __construct() { 
     51                $this->original_locale     = is_admin() ? get_user_locale() : get_locale(); 
     52                $this->available_languages = array_merge( array( 'en_US' ), get_available_languages() ); 
     53        } 
     54 
     55        /** 
     56         * Initializes the locale switcher. 
     57         * 
     58         * Hooks into the {@see 'locale'} filter to change the locale on the fly. 
     59         */ 
     60        public function init() { 
     61                add_filter( 'locale', array( $this, 'filter_locale' ) ); 
     62        } 
     63 
     64        /** 
     65         * Switches the translations according to the given locale. 
     66         * 
     67         * @since 4.7.0 
     68         * 
     69         * @param string $locale The locale to switch to. 
     70         * @return bool True on success, false on failure. 
     71         */ 
     72        public function switch_to_locale( $locale ) { 
     73                $current_locale = is_admin() ? get_user_locale() : get_locale(); 
     74                if ( $current_locale === $locale ) { 
     75                        return false; 
     76                } 
     77 
     78                if ( ! in_array( $locale, $this->available_languages, true ) ) { 
     79                        return false; 
     80                } 
     81 
     82                $this->locales[] = $locale; 
     83 
     84                $this->change_locale( $locale ); 
     85 
     86                /** 
     87                 * Fires when the locale is switched. 
     88                 * 
     89                 * @since 4.7.0 
     90                 * 
     91                 * @param string $locale The new locale. 
     92                 */ 
     93                do_action( 'switch_locale', $locale ); 
     94 
     95                return true; 
     96        } 
     97 
     98        /** 
     99         * Restores the translations according to the previous locale. 
     100         * 
     101         * @since 4.7.0 
     102         * 
     103         * @return string|false Locale on success, false on failure. 
     104         */ 
     105        public function restore_previous_locale() { 
     106                $previous_locale = array_pop( $this->locales ); 
     107 
     108                if ( null === $previous_locale ) { 
     109                        // The stack is empty, bail. 
     110                        return false; 
     111                } 
     112 
     113                $locale = end( $this->locales ); 
     114 
     115                if ( ! $locale ) { 
     116                        // There's nothing left in the stack: go back to the original locale. 
     117                        $locale = $this->original_locale; 
     118                } 
     119 
     120                $this->change_locale( $locale ); 
     121 
     122                /** 
     123                 * Fires when the locale is restored to the previous one. 
     124                 * 
     125                 * @since 4.7.0 
     126                 * 
     127                 * @param string $locale          The new locale. 
     128                 * @param string $previous_locale The previous locale. 
     129                 */ 
     130                do_action( 'restore_previous_locale', $locale, $previous_locale ); 
     131 
     132                return $locale; 
     133        } 
     134 
     135        /** 
     136         * Restores the translations according to the original locale. 
     137         * 
     138         * @since 4.7.0 
     139         * 
     140         * @return string|false Locale on success, false on failure. 
     141         */ 
     142        public function restore_current_locale() { 
     143                if ( empty( $this->locales ) ) { 
     144                        return false; 
     145                } 
     146 
     147                $this->locales = array( $this->original_locale ); 
     148 
     149                return $this->restore_previous_locale(); 
     150        } 
     151 
     152        /** 
     153         * Whether switch_to_locale() is in effect. 
     154         * 
     155         * @since 4.7.0 
     156         * 
     157         * @return bool True if the locale has been switched, false otherwise. 
     158         */ 
     159        public function is_switched() { 
     160                return ! empty( $this->locales ); 
     161        } 
     162 
     163        /** 
     164         * Filters the WordPress install's locale. 
     165         * 
     166         * @since 4.7.0 
     167         * 
     168         * @param string $locale The WordPress install's locale. 
     169         * @return string The locale currently being switched to. 
     170         */ 
     171        public function filter_locale( $locale ) { 
     172                $switched_locale = end( $this->locales ); 
     173 
     174                if ( $switched_locale ) { 
     175                        return $switched_locale; 
     176                } 
     177 
     178                return $locale; 
     179        } 
     180 
     181        /** 
     182         * Load translations for a given locale. 
     183         * 
     184         * When switching to a locale, translations for this locale must be loaded from scratch. 
     185         * 
     186         * @since 4.7.0 
     187         * @access private 
     188         * 
     189         * @global Mo[] $l10n An array of all currently loaded text domains. 
     190         * 
     191         * @param string $locale The locale to load translations for. 
     192         */ 
     193        private function load_translations( $locale ) { 
     194                global $l10n; 
     195 
     196                $domains = $l10n ? array_keys( $l10n ) : array(); 
     197 
     198                load_default_textdomain( $locale ); 
     199 
     200                foreach ( $domains as $domain ) { 
     201                        if ( 'default' === $domain ) { 
     202                                continue; 
     203                        } 
     204 
     205                        $mofile = $l10n[ $domain ]->get_filename(); 
     206 
     207                        unload_textdomain( $domain ); 
     208 
     209                        if ( $mofile ) { 
     210                                load_textdomain( $domain, $mofile ); 
     211                        } 
     212 
     213                        get_translations_for_domain( $domain ); 
     214                } 
     215        } 
     216 
     217        /** 
     218         * Changes the site's locale to the given one. 
     219         * 
     220         * Loads the translations, changes the global `$wp_locale` object and updates 
     221         * all post type labels. 
     222         * 
     223         * @since 4.7.0 
     224         * @access private 
     225         * 
     226         * @global WP_Locale $wp_locale The WordPress date and time locale object. 
     227         * 
     228         * @param string $locale The locale to change to. 
     229         */ 
     230        private function change_locale( $locale ) { 
     231                $this->load_translations( $locale ); 
     232 
     233                $GLOBALS['wp_locale'] = new WP_Locale(); 
     234 
     235                /** 
     236                 * Fires when the locale is switched to or restored. 
     237                 * 
     238                 * @since 4.7.0 
     239                 * 
     240                 * @param string $locale The new locale. 
     241                 */ 
     242                do_action( 'change_locale', $locale ); 
     243        } 
     244} 
  • src/wp-includes/default-filters.php

    diff --git src/wp-includes/default-filters.php src/wp-includes/default-filters.php
    index 71255c3..e38d3f5 100644
    add_action( 'init', 'create_initial_post_types', 0 ); // highest priority 
    404404add_action( 'admin_menu', '_add_post_type_submenus' ); 
    405405add_action( 'before_delete_post', '_reset_front_page_settings_for_post' ); 
    406406add_action( 'wp_trash_post',      '_reset_front_page_settings_for_post' ); 
     407add_action( 'change_locale', 'create_initial_post_types' ); 
    407408 
    408409// Post Formats 
    409410add_filter( 'request', '_post_format_request' ); 
    add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 ); 
    429430 
    430431// Taxonomy 
    431432add_action( 'init', 'create_initial_taxonomies', 0 ); // highest priority 
     433add_action( 'change_locale', 'create_initial_taxonomies' ); 
    432434 
    433435// Canonical 
    434436add_action( 'template_redirect', 'redirect_canonical' ); 
  • src/wp-includes/l10n.php

    diff --git src/wp-includes/l10n.php src/wp-includes/l10n.php
    index 03a7a11..902a978 100644
    function is_rtl() { 
    11661166        } 
    11671167        return $wp_locale->is_rtl(); 
    11681168} 
     1169 
     1170/** 
     1171 * Switches the translations according to the given locale. 
     1172 * 
     1173 * @since 4.7.0 
     1174 * 
     1175 * @global WP_Locale_Switcher $wp_locale_switcher 
     1176 * 
     1177 * @param string $locale The locale. 
     1178 * @return bool True on success, false on failure. 
     1179 */ 
     1180function switch_to_locale( $locale ) { 
     1181        /* @var WP_Locale_Switcher $wp_locale_switcher */ 
     1182        global $wp_locale_switcher; 
     1183 
     1184        return $wp_locale_switcher->switch_to_locale( $locale ); 
     1185} 
     1186 
     1187/** 
     1188 * Restores the translations according to the previous locale. 
     1189 * 
     1190 * @since 4.7.0 
     1191 * 
     1192 * @global WP_Locale_Switcher $wp_locale_switcher 
     1193 * 
     1194 * @return string|false Locale on success, false on error. 
     1195 */ 
     1196function restore_previous_locale() { 
     1197        /* @var WP_Locale_Switcher $wp_locale_switcher */ 
     1198        global $wp_locale_switcher; 
     1199 
     1200        return $wp_locale_switcher->restore_previous_locale(); 
     1201} 
     1202 
     1203/** 
     1204 * Restores the translations according to the original locale. 
     1205 * 
     1206 * @since 4.7.0 
     1207 * 
     1208 * @global WP_Locale_Switcher $wp_locale_switcher 
     1209 * 
     1210 * @return string|false Locale on success, false on error. 
     1211 */ 
     1212function restore_current_locale() { 
     1213        /* @var WP_Locale_Switcher $wp_locale_switcher */ 
     1214        global $wp_locale_switcher; 
     1215 
     1216        return $wp_locale_switcher->restore_current_locale(); 
     1217} 
     1218 
     1219/** 
     1220 * Whether switch_to_locale() is in effect. 
     1221 * 
     1222 * @since 4.7.0 
     1223 * 
     1224 * @global WP_Locale_Switcher $wp_locale_switcher 
     1225 * 
     1226 * @return bool True if the locale has been switched, false otherwise. 
     1227 */ 
     1228function is_locale_switched() { 
     1229        /* @var WP_Locale_Switcher $wp_locale_switcher */ 
     1230        global $wp_locale_switcher; 
     1231 
     1232        return $wp_locale_switcher->is_switched(); 
     1233} 
  • src/wp-includes/load.php

    diff --git src/wp-includes/load.php src/wp-includes/load.php
    index 4a3e1c3..523960f 100644
    function get_current_network_id() { 
    841841 * @since 3.4.0 
    842842 * @access private 
    843843 * 
    844  * @global string    $text_direction 
    845  * @global WP_Locale $wp_locale      The WordPress date and time locale object. 
     844 * @global string             $text_direction 
     845 * @global WP_Locale          $wp_locale      The WordPress date and time locale object. 
     846 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object. 
    846847 * 
    847848 * @staticvar bool $loaded 
    848849 */ 
    849850function wp_load_translations_early() { 
    850         global $text_direction, $wp_locale; 
     851        global $text_direction, $wp_locale, $wp_locale_switcher; 
    851852 
    852853        static $loaded = false; 
    853854        if ( $loaded ) 
    function wp_load_translations_early() { 
    864865        require_once ABSPATH . WPINC . '/pomo/mo.php'; 
    865866        require_once ABSPATH . WPINC . '/l10n.php'; 
    866867        require_once ABSPATH . WPINC . '/class-wp-locale.php'; 
     868        require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php'; 
    867869 
    868870        // General libraries 
    869871        require_once ABSPATH . WPINC . '/plugin.php'; 
    function wp_load_translations_early() { 
    915917        } 
    916918 
    917919        $wp_locale = new WP_Locale(); 
     920        $wp_locale_switcher = new WP_Locale_Switcher(); 
     921        $wp_locale_switcher->init(); 
    918922} 
    919923 
    920924/** 
  • src/wp-includes/ms-functions.php

    diff --git src/wp-includes/ms-functions.php src/wp-includes/ms-functions.php
    index 5e32a86..9ea2c86 100644
    function wpmu_signup_blog_notification( $domain, $path, $title, $user, $user_ema 
    800800                $admin_email = 'support@' . $_SERVER['SERVER_NAME']; 
    801801        $from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) ); 
    802802        $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n"; 
     803 
     804        $user = get_user_by( 'login', $user ); 
     805        $switched_locale = switch_to_locale( $user && $user->locale ? $user->locale : get_locale() ); 
     806 
    803807        $message = sprintf( 
    804808                /** 
    805809                 * Filters the message content of the new blog notification email. 
    function wpmu_signup_blog_notification( $domain, $path, $title, $user, $user_ema 
    849853                esc_url( 'http://' . $domain . $path ) 
    850854        ); 
    851855        wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers ); 
     856 
     857        if ( $switched_locale ) { 
     858                restore_previous_locale(); 
     859        } 
     860 
    852861        return true; 
    853862} 
    854863 
    function wpmu_signup_user_notification( $user, $user_email, $key, $meta = array( 
    887896        if ( ! apply_filters( 'wpmu_signup_user_notification', $user, $user_email, $key, $meta ) ) 
    888897                return false; 
    889898 
     899        $user = get_user_by( 'login', $user ); 
     900        $switched_locale = switch_to_locale( $user && $user->locale ? $user->locale : get_locale() ); 
     901 
    890902        // Send email with activation link. 
    891903        $admin_email = get_site_option( 'admin_email' ); 
    892904        if ( $admin_email == '' ) 
    function wpmu_signup_user_notification( $user, $user_email, $key, $meta = array( 
    934946                $user 
    935947        ); 
    936948        wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers ); 
     949 
     950        if ( $switched_locale ) { 
     951                restore_previous_locale(); 
     952        } 
     953 
    937954        return true; 
    938955} 
    939956 
    function wpmu_welcome_notification( $blog_id, $user_id, $password, $title, $meta 
    14481465        if ( ! apply_filters( 'wpmu_welcome_notification', $blog_id, $user_id, $password, $title, $meta ) ) 
    14491466                return false; 
    14501467 
     1468        $user = get_userdata( $user_id ); 
     1469 
     1470        $switched_locale = switch_to_locale( $user->locale ); 
     1471 
    14511472        $welcome_email = get_site_option( 'welcome_email' ); 
    14521473        if ( $welcome_email == false ) { 
    14531474                /* translators: Do not translate USERNAME, SITE_NAME, BLOG_URL, PASSWORD: those are placeholders. */ 
    We hope you enjoy your new site. Thanks! 
    14681489        } 
    14691490 
    14701491        $url = get_blogaddress_by_id($blog_id); 
    1471         $user = get_userdata( $user_id ); 
    14721492 
    14731493        $welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email ); 
    14741494        $welcome_email = str_replace( 'BLOG_TITLE', $title, $welcome_email ); 
    We hope you enjoy your new site. Thanks! 
    15121532         */ 
    15131533        $subject = apply_filters( 'update_welcome_subject', sprintf( __( 'New %1$s Site: %2$s' ), $current_network->site_name, wp_unslash( $title ) ) ); 
    15141534        wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers ); 
     1535 
     1536        if ( $switched_locale ) { 
     1537                restore_previous_locale(); 
     1538        } 
     1539 
    15151540        return true; 
    15161541} 
    15171542 
    function wpmu_welcome_user_notification( $user_id, $password, $meta = array() ) 
    15511576 
    15521577        $user = get_userdata( $user_id ); 
    15531578 
     1579        $switched_locale = switch_to_locale( $user->locale ); 
     1580 
    15541581        /** 
    15551582         * Filters the content of the welcome email after user activation. 
    15561583         * 
    function wpmu_welcome_user_notification( $user_id, $password, $meta = array() ) 
    15901617         */ 
    15911618        $subject = apply_filters( 'update_welcome_user_subject', sprintf( __( 'New %1$s User: %2$s' ), $current_network->site_name, $user->user_login) ); 
    15921619        wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers ); 
     1620 
     1621        if ( $switched_locale ) { 
     1622                restore_previous_locale(); 
     1623        } 
     1624 
    15931625        return true; 
    15941626} 
    15951627 
  • src/wp-includes/pluggable.php

    diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php
    index d7713b7..a7193cb 100644
    function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() 
    211211        // (Re)create it, if it's gone missing 
    212212        if ( ! ( $phpmailer instanceof PHPMailer ) ) { 
    213213                require_once ABSPATH . WPINC . '/class-phpmailer.php'; 
    214                 require_once ABSPATH . WPINC . '/class-smtp.php';  
     214                require_once ABSPATH . WPINC . '/class-smtp.php'; 
    215215                $phpmailer = new PHPMailer( true ); 
    216216        } 
    217217 
    function wp_notify_postauthor( $comment_id, $deprecated = null ) { 
    14181418                $emails = array_flip( $emails ); 
    14191419        } 
    14201420 
     1421        $switched_locale = switch_to_locale( get_locale() ); 
     1422 
    14211423        $comment_author_domain = @gethostbyaddr($comment->comment_author_IP); 
    14221424 
    14231425        // The blogname option is escaped with esc_html on the way into the database in sanitize_option 
    function wp_notify_postauthor( $comment_id, $deprecated = null ) { 
    15221524                @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers ); 
    15231525        } 
    15241526 
     1527        if ( $switched_locale ) { 
     1528                restore_previous_locale(); 
     1529        } 
     1530 
    15251531        return true; 
    15261532} 
    15271533endif; 
    function wp_notify_moderator($comment_id) { 
    15691575                        $emails[] = $user->user_email; 
    15701576        } 
    15711577 
     1578        $switched_locale = switch_to_locale( get_locale() ); 
     1579 
    15721580        $comment_author_domain = @gethostbyaddr($comment->comment_author_IP); 
    15731581        $comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'"); 
    15741582 
    function wp_notify_moderator($comment_id) { 
    16641672                @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers ); 
    16651673        } 
    16661674 
     1675        if ( $switched_locale ) { 
     1676                restore_previous_locale(); 
     1677        } 
     1678 
    16671679        return true; 
    16681680} 
    16691681endif; 
    function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) 
    17231735        $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES); 
    17241736 
    17251737        if ( 'user' !== $notify ) { 
     1738                $switched_locale = switch_to_locale( get_locale() ); 
    17261739                $message  = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n"; 
    17271740                $message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n"; 
    17281741                $message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n"; 
    17291742 
    17301743                @wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] New User Registration' ), $blogname ), $message ); 
     1744 
     1745                if ( $switched_locale ) { 
     1746                        restore_previous_locale(); 
     1747                } 
    17311748        } 
    17321749 
    17331750        // `$deprecated was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notifcation. 
    function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) 
    17481765        $hashed = time() . ':' . $wp_hasher->HashPassword( $key ); 
    17491766        $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) ); 
    17501767 
     1768        $switched_locale = switch_to_locale( $user->locale ); 
     1769 
    17511770        $message = sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n"; 
    17521771        $message .= __('To set your password, visit the following address:') . "\r\n\r\n"; 
    17531772        $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user->user_login), 'login') . ">\r\n\r\n"; 
    function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) 
    17551774        $message .= wp_login_url() . "\r\n"; 
    17561775 
    17571776        wp_mail($user->user_email, sprintf(__('[%s] Your username and password info'), $blogname), $message); 
     1777 
     1778        if ( $switched_locale ) { 
     1779                restore_previous_locale(); 
     1780        } 
    17581781} 
    17591782endif; 
    17601783 
  • src/wp-includes/pomo/mo.php

    diff --git src/wp-includes/pomo/mo.php src/wp-includes/pomo/mo.php
    index 6bc44d6..47e9b6a 100644
    class MO extends Gettext_Translations { 
    1616        var $_nplurals = 2; 
    1717 
    1818        /** 
     19         * Loaded MO file. 
     20         * 
     21         * @var string 
     22         */ 
     23        private $filename = ''; 
     24 
     25        /** 
     26         * Returns the loaded MO file. 
     27         * 
     28         * @return string The loaded MO file. 
     29         */ 
     30        public function get_filename() { 
     31                return $this->filename; 
     32        } 
     33 
     34        /** 
    1935         * Fills up with the entries from MO file $filename 
    2036         * 
    2137         * @param string $filename MO file to load 
    2238         */ 
    2339        function import_from_file($filename) { 
    24                 $reader = new POMO_FileReader($filename); 
    25                 if (!$reader->is_resource()) 
     40                $reader = new POMO_FileReader( $filename ); 
     41 
     42                if ( ! $reader->is_resource() ) { 
    2643                        return false; 
    27                 return $this->import_from_reader($reader); 
     44                } 
     45 
     46                $this->filename = (string) $filename; 
     47 
     48                return $this->import_from_reader( $reader ); 
    2849        } 
    2950 
    3051        /** 
    class MO extends Gettext_Translations { 
    299320                return $this->_nplurals; 
    300321        } 
    301322} 
    302 endif; 
    303  No newline at end of file 
     323endif; 
  • src/wp-includes/user.php

    diff --git src/wp-includes/user.php src/wp-includes/user.php
    index 734d26e..a673b92 100644
    function wp_update_user($userdata) { 
    18011801 
    18021802                $blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ); 
    18031803 
    1804                 if ( ! empty( $send_password_change_email ) ) { 
     1804                $switched_locale = false; 
     1805                if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) { 
     1806                        $switched_locale = switch_to_locale( isset( $user['locale'] ) ? $user['locale'] : get_locale() ); 
     1807                } 
    18051808 
     1809                if ( ! empty( $send_password_change_email ) ) { 
    18061810                        /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */ 
    18071811                        $pass_change_text = __( 'Hi ###USERNAME###, 
    18081812 
    All at ###SITENAME### 
    19101914 
    19111915                        wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] ); 
    19121916                } 
     1917 
     1918                if ( $switched_locale ) { 
     1919                        restore_previous_locale(); 
     1920                } 
    19131921        } 
    19141922 
    19151923        // Update the cookies if the password changed. 
  • src/wp-settings.php

    diff --git src/wp-settings.php src/wp-settings.php
    index 3347cc9..4aac905 100644
    if ( SHORTINIT ) 
    129129// Load the L10n library. 
    130130require_once( ABSPATH . WPINC . '/l10n.php' ); 
    131131require_once( ABSPATH . WPINC . '/class-wp-locale.php' ); 
     132require_once( ABSPATH . WPINC . '/class-wp-locale-switcher.php' ); 
    132133 
    133134// Run the installer if WordPress is not installed. 
    134135wp_not_installed(); 
    unset( $locale_file ); 
    399400 */ 
    400401$GLOBALS['wp_locale'] = new WP_Locale(); 
    401402 
     403/** 
     404 *  WordPress Locale Switcher object for switching locales. 
     405 * 
     406 * @since 4.7.0 
     407 * 
     408 * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object. 
     409 */ 
     410$GLOBALS['wp_locale_switcher'] = new WP_Locale_Switcher(); 
     411$GLOBALS['wp_locale_switcher']->init(); 
     412 
    402413// Load the functions for the active theme, for both parent and child theme if applicable. 
    403414if ( ! wp_installing() || 'wp-activate.php' === $pagenow ) { 
    404415        if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) ) 
  • tests/phpunit/tests/l10n.php

    diff --git tests/phpunit/tests/l10n.php tests/phpunit/tests/l10n.php
    index f1048aa..7b0091c 100644
    class Tests_L10n extends WP_UnitTestCase { 
    8585                $this->assertEmpty( $array ); 
    8686 
    8787                $array = get_available_languages( DIR_TESTDATA . '/languages/' ); 
    88                 $this->assertEquals( array( 'en_GB', 'es_ES' ), $array ); 
     88                $this->assertEquals( array( 'de_DE', 'en_GB', 'es_ES' ), $array ); 
    8989        } 
    9090 
    9191        /** 
    class Tests_L10n extends WP_UnitTestCase { 
    105105 
    106106                $this->assertNotEmpty( $installed_translations['admin']['es_ES'] ); 
    107107                $data_es_ES = $installed_translations['admin']['es_ES']; 
    108                 $this->assertEquals( '2015-12-22 20:26:46+0000', $data_es_ES['PO-Revision-Date'] ); 
     108                $this->assertEquals( '2016-10-25 18:29+0200', $data_es_ES['PO-Revision-Date'] ); 
    109109                $this->assertEquals( 'Administration', $data_es_ES['Project-Id-Version'] ); 
    110                 $this->assertEquals( 'GlotPress/1.0-alpha-1100', $data_es_ES['X-Generator'] ); 
     110                $this->assertEquals( 'Poedit 1.8.10', $data_es_ES['X-Generator'] ); 
    111111        } 
    112112 
    113113        /** 
  • tests/phpunit/tests/l10n/loadTextdomainJustInTime.php

    diff --git tests/phpunit/tests/l10n/loadTextdomainJustInTime.php tests/phpunit/tests/l10n/loadTextdomainJustInTime.php
    index f73cfd5..d183c96 100644
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    141141                $this->assertSame( 'Das ist ein Dummy Plugin', $expected_output_final ); 
    142142                $this->assertTrue( $is_textdomain_loaded_final ); 
    143143        } 
     144 
     145        /** 
     146         * @ticket 26511 
     147         */ 
     148        public function test_plugin_translation_after_switching_locale() { 
     149                require_once DIR_TESTDATA . '/plugins/internationalized-plugin.php'; 
     150 
     151                switch_to_locale( 'de_DE' ); 
     152                $expected = i18n_plugin_test(); 
     153                restore_previous_locale(); 
     154 
     155                $this->assertSame( 'Das ist ein Dummy Plugin', $expected ); 
     156        } 
     157 
     158        /** 
     159         * @ticket 26511 
     160         */ 
     161        public function test_theme_translation_after_switching_locale() { 
     162                switch_theme( 'internationalized-theme' ); 
     163 
     164                require_once get_stylesheet_directory() . '/functions.php'; 
     165 
     166                switch_to_locale( 'de_DE' ); 
     167                $expected = i18n_theme_test(); 
     168                restore_previous_locale(); 
     169 
     170                switch_theme( WP_DEFAULT_THEME ); 
     171 
     172                $this->assertSame( 'Das ist ein Dummy Theme', $expected ); 
     173        } 
    144174} 
  • new file tests/phpunit/tests/l10n/localeSwitcher.php

    diff --git tests/phpunit/tests/l10n/localeSwitcher.php tests/phpunit/tests/l10n/localeSwitcher.php
    new file mode 100644
    index 0000000..d18ee5f
    - +  
     1<?php 
     2 
     3/** 
     4 * @group l10n 
     5 * @group i18n 
     6 * @group 26511 
     7 */ 
     8class Tests_Locale_Switcher extends WP_UnitTestCase { 
     9        /** 
     10         * @var string 
     11         */ 
     12        protected $locale = ''; 
     13 
     14        /** 
     15         * @var string 
     16         */ 
     17        protected $previous_locale = ''; 
     18 
     19        public function setUp() { 
     20                $this->locale = ''; 
     21                $this->previous_locale = ''; 
     22        } 
     23 
     24        public function test_switch_to_non_existent_locale_returns_false() { 
     25                $this->assertFalse( switch_to_locale( 'foo_BAR' ) ); 
     26        } 
     27 
     28        public function test_switch_to_non_existent_locale_does_not_change_locale() { 
     29                switch_to_locale( 'foo_BAR' ); 
     30 
     31                $this->assertSame( 'en_US', get_locale() ); 
     32        } 
     33 
     34        public function test_switch_to_locale_returns_true() { 
     35                $expected = switch_to_locale( 'en_GB' ); 
     36 
     37                // Cleanup. 
     38                restore_previous_locale(); 
     39 
     40                $this->assertTrue( $expected ); 
     41        } 
     42 
     43        public function test_switch_to_locale_changes_the_locale() { 
     44                switch_to_locale( 'en_GB' ); 
     45 
     46                $locale = get_locale(); 
     47 
     48                // Cleanup. 
     49                restore_previous_locale(); 
     50 
     51                $this->assertSame( 'en_GB', $locale ); 
     52        } 
     53 
     54        public function test_switch_to_locale_loads_translation() { 
     55                switch_to_locale( 'es_ES' ); 
     56 
     57                $actual = __( 'Invalid parameter.' ); 
     58 
     59                // Cleanup. 
     60                restore_previous_locale(); 
     61 
     62                $this->assertSame( 'Parámetro no válido. ', $actual ); 
     63        } 
     64 
     65        public function test_switch_to_locale_changes_wp_locale_global() { 
     66                global $wp_locale; 
     67 
     68                $expected = array( 
     69                        'thousands_sep' => '.', 
     70                        'decimal_point' => ',', 
     71                ); 
     72 
     73                switch_to_locale( 'de_DE' ); 
     74 
     75                $wp_locale_de_DE = clone $wp_locale; 
     76 
     77                // Cleanup. 
     78                restore_previous_locale(); 
     79 
     80                $this->assertEqualSetsWithIndex( $expected, $wp_locale_de_DE->number_format ); 
     81        } 
     82 
     83        public function test_switch_to_locale_en_US() { 
     84                switch_to_locale( 'en_GB' ); 
     85                $locale_en_GB = get_locale(); 
     86                switch_to_locale( 'en_US' ); 
     87                $locale_en_US = get_locale(); 
     88 
     89                // Cleanup. 
     90                restore_current_locale(); 
     91 
     92                $this->assertSame( 'en_GB', $locale_en_GB ); 
     93                $this->assertSame( 'en_US', $locale_en_US ); 
     94        } 
     95 
     96        public function test_switch_to_locale_multiple_times() { 
     97                switch_to_locale( 'en_GB' ); 
     98                switch_to_locale( 'es_ES' ); 
     99                $locale = get_locale(); 
     100 
     101                // Cleanup. 
     102                restore_previous_locale(); 
     103                restore_previous_locale(); 
     104 
     105                $this->assertSame( 'es_ES', $locale ); 
     106        } 
     107 
     108        public function test_switch_to_locale_multiple_times_loads_translation() { 
     109                switch_to_locale( 'en_GB' ); 
     110                switch_to_locale( 'de_DE' ); 
     111                switch_to_locale( 'es_ES' ); 
     112 
     113                $actual = __( 'Invalid parameter.' ); 
     114 
     115                // Cleanup. 
     116                restore_previous_locale(); 
     117                restore_previous_locale(); 
     118                restore_previous_locale(); 
     119 
     120                $this->assertSame( 'Parámetro no válido. ', $actual ); 
     121        } 
     122 
     123        public function test_restore_previous_locale_without_switching() { 
     124                $this->assertFalse( restore_previous_locale() ); 
     125        } 
     126 
     127        public function test_restore_previous_locale_changes_the_locale_back() { 
     128                switch_to_locale( 'en_GB' ); 
     129 
     130                // Cleanup. 
     131                restore_previous_locale(); 
     132 
     133                $this->assertSame( 'en_US', get_locale() ); 
     134        } 
     135 
     136        public function test_restore_previous_locale_after_switching_multiple_times() { 
     137                switch_to_locale( 'en_GB' ); 
     138                switch_to_locale( 'es_ES' ); 
     139                restore_previous_locale(); 
     140 
     141                $locale = get_locale(); 
     142 
     143                // Cleanup. 
     144                restore_previous_locale(); 
     145 
     146                $this->assertSame( 'en_GB', $locale ); 
     147        } 
     148 
     149        public function test_restore_previous_locale_restores_translation() { 
     150                switch_to_locale( 'es_ES' ); 
     151                restore_previous_locale(); 
     152 
     153                $actual = __( 'Invalid parameter.' ); 
     154 
     155                $this->assertSame( 'Invalid parameter.', $actual ); 
     156        } 
     157 
     158        public function test_restore_previous_locale_action_passes_previous_locale() { 
     159                switch_to_locale( 'en_GB' ); 
     160                switch_to_locale( 'es_ES' ); 
     161 
     162                add_action( 'restore_previous_locale', array( $this, 'store_locale' ), 10, 2 ); 
     163 
     164                restore_previous_locale(); 
     165 
     166                $previous_locale = $this->previous_locale; 
     167 
     168                // Cleanup. 
     169                restore_previous_locale(); 
     170 
     171                $this->assertSame( 'es_ES', $previous_locale ); 
     172        } 
     173 
     174        public function test_restore_previous_locale_restores_wp_locale_global() { 
     175                global $wp_locale; 
     176 
     177                $expected = array( 
     178                        'thousands_sep' => ',', 
     179                        'decimal_point' => '.', 
     180                ); 
     181 
     182                switch_to_locale( 'de_DE' ); 
     183                restore_previous_locale(); 
     184 
     185                $this->assertEqualSetsWithIndex( $expected, $wp_locale->number_format ); 
     186        } 
     187 
     188        public function test_restore_current_locale_without_switching() { 
     189                $this->assertFalse( restore_current_locale() ); 
     190        } 
     191 
     192        public function test_restore_current_locale_after_switching_multiple_times() { 
     193                switch_to_locale( 'en_GB' ); 
     194                switch_to_locale( 'nl_NL' ); 
     195                switch_to_locale( 'es_ES' ); 
     196 
     197                restore_current_locale(); 
     198 
     199                $this->assertSame( 'en_US', get_locale() ); 
     200        } 
     201 
     202        public function store_locale( $locale, $previous_locale ) { 
     203                $this->locale = $locale; 
     204                $this->previous_locale = $previous_locale; 
     205        } 
     206 
     207        public function test_is_locale_switched_if_not_switched() { 
     208                $this->assertFalse( is_locale_switched() ); 
     209        } 
     210 
     211        public function test_is_locale_switched_original_locale() { 
     212                $original_locale = get_locale(); 
     213 
     214                switch_to_locale( 'en_GB' ); 
     215                switch_to_locale( $original_locale ); 
     216 
     217                $is_locale_switched = is_locale_switched(); 
     218 
     219                restore_current_locale(); 
     220 
     221                $this->assertTrue( $is_locale_switched ); 
     222        } 
     223 
     224        public function test_is_locale_switched() { 
     225                switch_to_locale( 'en_GB' ); 
     226                switch_to_locale( 'nl_NL' ); 
     227 
     228                $is_locale_switched = is_locale_switched(); 
     229 
     230                restore_current_locale(); 
     231 
     232                $this->assertTrue( $is_locale_switched ); 
     233        } 
     234 
     235        public function test_switch_to_site_locale_if_user_locale_is_set() { 
     236                global $l10n, $wp_locale_switcher; 
     237 
     238                $site_locale = get_locale(); 
     239 
     240                $user_id = $this->factory()->user->create( array( 
     241                        'role'   => 'administrator', 
     242                        'locale' => 'de_DE', 
     243                ) ); 
     244 
     245                wp_set_current_user( $user_id ); 
     246                set_current_screen( 'dashboard' ); 
     247 
     248                $locale_switcher = clone $wp_locale_switcher; 
     249 
     250                $wp_locale_switcher = new WP_Locale_Switcher(); 
     251                $wp_locale_switcher->init(); 
     252 
     253                $user_locale = get_user_locale(); 
     254 
     255                $this->assertSame( 'de_DE', $user_locale ); 
     256 
     257                load_default_textdomain( $user_locale ); 
     258                $language_header_before_switch = $l10n['default']->headers['Language']; // de_DE 
     259 
     260                $locale_switched_user_locale = switch_to_locale( $user_locale ); // False. 
     261                $locale_switched_site_locale = switch_to_locale( $site_locale ); // True. 
     262                $site_locale_after_switch = get_locale(); 
     263                $language_header_after_switch = isset( $l10n['default'] ); // en_US 
     264 
     265                restore_current_locale(); 
     266 
     267                $language_header_after_restore = $l10n['default']->headers['Language']; // de_DE 
     268 
     269                $wp_locale_switcher = $locale_switcher; 
     270 
     271                $this->assertFalse( $locale_switched_user_locale ); 
     272                $this->assertTrue( $locale_switched_site_locale ); 
     273                $this->assertSame( $site_locale, $site_locale_after_switch ); 
     274                $this->assertSame( 'de_DE', $language_header_before_switch ); 
     275                $this->assertFalse( $language_header_after_switch ); 
     276                $this->assertSame( 'de_DE', $language_header_after_restore ); 
     277        } 
     278 
     279        public function test_switch_to_different_site_locale_if_user_locale_is_set() { 
     280                global $l10n, $wp_locale_switcher; 
     281 
     282                // Change site locale to es_ES. 
     283                add_filter( 'locale', array( $this, 'filter_locale' ) ); 
     284 
     285                $site_locale = get_locale(); 
     286 
     287                $user_id = $this->factory()->user->create( array( 
     288                        'role'   => 'administrator', 
     289                        'locale' => 'de_DE', 
     290                ) ); 
     291 
     292                wp_set_current_user( $user_id ); 
     293                set_current_screen( 'dashboard' ); 
     294 
     295                $locale_switcher = clone $wp_locale_switcher; 
     296 
     297                $wp_locale_switcher = new WP_Locale_Switcher(); 
     298                $wp_locale_switcher->init(); 
     299 
     300                $user_locale = get_user_locale(); 
     301 
     302                $this->assertSame( 'de_DE', $user_locale ); 
     303 
     304                load_default_textdomain( $user_locale ); 
     305                $language_header_before_switch = $l10n['default']->headers['Language']; // de_DE 
     306 
     307                $locale_switched_user_locale = switch_to_locale( $user_locale ); // False. 
     308                $locale_switched_site_locale = switch_to_locale( $site_locale ); // True. 
     309                $site_locale_after_switch = get_locale(); 
     310                $language_header_after_switch = $l10n['default']->headers['Language']; // es_ES 
     311 
     312                restore_current_locale(); 
     313 
     314                $language_header_after_restore = $l10n['default']->headers['Language']; // de_DE 
     315 
     316                $wp_locale_switcher = $locale_switcher; 
     317 
     318                remove_filter( 'locale', array( $this, 'filter_locale' ) ); 
     319 
     320                $this->assertFalse( $locale_switched_user_locale ); 
     321                $this->assertTrue( $locale_switched_site_locale ); 
     322                $this->assertSame( $site_locale, $site_locale_after_switch ); 
     323                $this->assertSame( 'de_DE', $language_header_before_switch ); 
     324                $this->assertSame( 'es_ES', $language_header_after_switch ); 
     325                $this->assertSame( 'de_DE', $language_header_after_restore ); 
     326        } 
     327 
     328        public function filter_locale() { 
     329                return 'es_ES'; 
     330        } 
     331} 
  • tests/phpunit/tests/locale.php

    diff --git tests/phpunit/tests/locale.php tests/phpunit/tests/locale.php
    index 1c335f4..79372d6 100644
     
    11<?php 
    22 
    33/** 
    4  * @group locale 
     4 * @group l10n 
    55 * @group i18n 
    66 */ 
    77class Tests_Locale extends WP_UnitTestCase {