<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[38961] trunk: I18N: Introduce a locale-switching function.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/38961">38961</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/38961","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>ocean90</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2016-10-26 15:35:58 +0000 (Wed, 26 Oct 2016)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>I18N: Introduce a locale-switching function.

With the introduction of user-specific languages in <a href="https://core.trac.wordpress.org/changeset/38705">[38705]</a> it's necessary to be able to switch translations on the fly. For example emails should be sent in the language of the recipient and not the one of the current user.

This introduces a new `WP_Locale_Switcher` class which is used for switching locales and translations. It holds the stack of locales whenever `switch_to_locale( $locale )` is called. With `restore_previous_locale()` you can restore the previous locale. `restore_current_locale()` empties the stack and sets the locale back to the initial value.

`switch_to_locale()` is added to most of core's email functions, either with the value of `get_locale()` (site language) or `get_user_locale()` (user language with fallback to site language).

Props yoavf, tfrommen, swissspidy, pbearne, ocean90.
See <a href="https://core.trac.wordpress.org/ticket/29783">#29783</a>.
Fixes <a href="https://core.trac.wordpress.org/ticket/26511">#26511</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminincludesmsphp">trunk/src/wp-admin/includes/ms.php</a></li>
<li><a href="#trunksrcwpadminmsdeletesitephp">trunk/src/wp-admin/ms-delete-site.php</a></li>
<li><a href="#trunksrcwpadminusernewphp">trunk/src/wp-admin/user-new.php</a></li>
<li><a href="#trunksrcwpincludesdefaultfiltersphp">trunk/src/wp-includes/default-filters.php</a></li>
<li><a href="#trunksrcwpincludesl10nphp">trunk/src/wp-includes/l10n.php</a></li>
<li><a href="#trunksrcwpincludesloadphp">trunk/src/wp-includes/load.php</a></li>
<li><a href="#trunksrcwpincludesmsfunctionsphp">trunk/src/wp-includes/ms-functions.php</a></li>
<li><a href="#trunksrcwpincludespluggablephp">trunk/src/wp-includes/pluggable.php</a></li>
<li><a href="#trunksrcwpincludespomomophp">trunk/src/wp-includes/pomo/mo.php</a></li>
<li><a href="#trunksrcwpincludesuserphp">trunk/src/wp-includes/user.php</a></li>
<li><a href="#trunksrcwpsettingsphp">trunk/src/wp-settings.php</a></li>
<li><a href="#trunktestsphpunittestsl10nloadTextdomainJustInTimephp">trunk/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php</a></li>
<li><a href="#trunktestsphpunittestslocalephp">trunk/tests/phpunit/tests/locale.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunksrcwpincludesclasswplocaleswitcherphp">trunk/src/wp-includes/class-wp-locale-switcher.php</a></li>
<li><a href="#trunktestsphpunittestsl10nlocaleSwitcherphp">trunk/tests/phpunit/tests/l10n/localeSwitcher.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminincludesmsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/includes/ms.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/includes/ms.php        2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-admin/includes/ms.php  2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -272,6 +272,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        );
</span><span class="cx" style="display: block; padding: 0 10px">        update_option( 'adminhash', $new_admin_email );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $switched_locale = switch_to_locale( get_user_locale() );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
</span><span class="cx" style="display: block; padding: 0 10px">        $email_text = __( 'Howdy ###USERNAME###,
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -315,6 +317,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $content = str_replace( '###SITEURL###', network_home_url(), $content );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        wp_mail( $value, sprintf( __( '[%s] New Admin Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $switched_locale ) {
+               restore_previous_locale();
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -353,6 +359,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                );
</span><span class="cx" style="display: block; padding: 0 10px">                update_user_meta( $current_user->ID, '_new_email', $new_user_email );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $switched_locale = switch_to_locale( get_user_locale() );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 /* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
</span><span class="cx" style="display: block; padding: 0 10px">                $email_text = __( 'Howdy ###USERNAME###,
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -395,6 +403,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
</span><span class="cx" style="display: block; padding: 0 10px">                $_POST['email'] = $current_user->user_email;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               if ( $switched_locale ) {
+                       restore_previous_locale();
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpadminmsdeletesitephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/ms-delete-site.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/ms-delete-site.php     2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-admin/ms-delete-site.php       2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -42,6 +42,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $url_delete = esc_url( admin_url( 'ms-delete-site.php?h=' . $hash ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $switched_locale = switch_to_locale( get_locale() );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /* translators: Do not translate USERNAME, URL_DELETE, SITE_NAME: those are placeholders. */
</span><span class="cx" style="display: block; padding: 0 10px">        $content = __( "Howdy ###USERNAME###,
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -73,6 +75,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $content = str_replace( '###SITE_NAME###', get_network()->site_name, $content );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        wp_mail( get_option( 'admin_email' ), "[ " . wp_specialchars_decode( get_option( 'blogname' ) ) . " ] ".__( 'Delete My Site' ), $content );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $switched_locale ) {
+               restore_previous_locale();
+       }
</ins><span class="cx" style="display: block; padding: 0 10px">         ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        <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>
</span></span></pre></div>
<a id="trunksrcwpadminusernewphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/user-new.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/user-new.php   2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-admin/user-new.php     2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -87,6 +87,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                         */
</span><span class="cx" style="display: block; padding: 0 10px">                        do_action( 'invite_user', $user_id, $role, $newuser_key );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        $switched_locale = switch_to_locale( get_user_locale( $user_details ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         /* translators: 1: Site name, 2: site URL, 3: role, 4: activation URL */
</span><span class="cx" style="display: block; padding: 0 10px">                        $message = __( 'Hi,
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -96,6 +98,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> Please click the following link to confirm the invite:
</span><span class="cx" style="display: block; padding: 0 10px"> %4$s' );
</span><span class="cx" style="display: block; padding: 0 10px">                        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/" ) ) );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       if ( $switched_locale ) {
+                               restore_previous_locale();
+                       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         $redirect = add_query_arg( array('update' => 'add'), 'user-new.php' );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span></span></pre></div>
<a id="trunksrcwpincludesclasswplocaleswitcherphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/src/wp-includes/class-wp-locale-switcher.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/class-wp-locale-switcher.php                                (rev 0)
+++ trunk/src/wp-includes/class-wp-locale-switcher.php  2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,244 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * Locale API: WP_Locale_Switcher class
+ *
+ * @package WordPress
+ * @subpackage i18n
+ * @since 4.7.0
+ */
+
+/**
+ * Core class used for switching locales.
+ *
+ * @since 4.7.0
+ */
+class WP_Locale_Switcher {
+       /**
+        * Locale stack.
+        *
+        * @since 4.7.0
+        * @access private
+        * @var string[]
+        */
+       private $locales = array();
+
+       /**
+        * Original locale.
+        *
+        * @since 4.7.0
+        * @access private
+        * @var string
+        */
+       private $original_locale;
+
+       /**
+        * Holds all available languages.
+        *
+        * @since 4.7.0
+        * @access private
+        * @var array An array of language codes (file names without the .mo extension).
+        */
+       private $available_languages = array();
+
+       /**
+        * Constructor.
+        *
+        * Stores the original locale as well as a list of all available languages.
+        *
+        * @since 4.7.0
+        */
+       public function __construct() {
+               $this->original_locale     = is_admin() ? get_user_locale() : get_locale();
+               $this->available_languages = array_merge( array( 'en_US' ), get_available_languages() );
+       }
+
+       /**
+        * Initializes the locale switcher.
+        *
+        * Hooks into the {@see 'locale'} filter to change the locale on the fly.
+        */
+       public function init() {
+               add_filter( 'locale', array( $this, 'filter_locale' ) );
+       }
+
+       /**
+        * Switches the translations according to the given locale.
+        *
+        * @since 4.7.0
+        *
+        * @param string $locale The locale to switch to.
+        * @return bool True on success, false on failure.
+        */
+       public function switch_to_locale( $locale ) {
+               $current_locale = is_admin() ? get_user_locale() : get_locale();
+               if ( $current_locale === $locale ) {
+                       return false;
+               }
+
+               if ( ! in_array( $locale, $this->available_languages, true ) ) {
+                       return false;
+               }
+
+               $this->locales[] = $locale;
+
+               $this->change_locale( $locale );
+
+               /**
+                * Fires when the locale is switched.
+                *
+                * @since 4.7.0
+                *
+                * @param string $locale The new locale.
+                */
+               do_action( 'switch_locale', $locale );
+
+               return true;
+       }
+
+       /**
+        * Restores the translations according to the previous locale.
+        *
+        * @since 4.7.0
+        *
+        * @return string|false Locale on success, false on failure.
+        */
+       public function restore_previous_locale() {
+               $previous_locale = array_pop( $this->locales );
+
+               if ( null === $previous_locale ) {
+                       // The stack is empty, bail.
+                       return false;
+               }
+
+               $locale = end( $this->locales );
+
+               if ( ! $locale ) {
+                       // There's nothing left in the stack: go back to the original locale.
+                       $locale = $this->original_locale;
+               }
+
+               $this->change_locale( $locale );
+
+               /**
+                * Fires when the locale is restored to the previous one.
+                *
+                * @since 4.7.0
+                *
+                * @param string $locale          The new locale.
+                * @param string $previous_locale The previous locale.
+                */
+               do_action( 'restore_previous_locale', $locale, $previous_locale );
+
+               return $locale;
+       }
+
+       /**
+        * Restores the translations according to the original locale.
+        *
+        * @since 4.7.0
+        *
+        * @return string|false Locale on success, false on failure.
+        */
+       public function restore_current_locale() {
+               if ( empty( $this->locales ) ) {
+                       return false;
+               }
+
+               $this->locales = array( $this->original_locale );
+
+               return $this->restore_previous_locale();
+       }
+
+       /**
+        * Whether switch_to_locale() is in effect.
+        *
+        * @since 4.7.0
+        *
+        * @return bool True if the locale has been switched, false otherwise.
+        */
+       public function is_switched() {
+               return ! empty( $this->locales );
+       }
+
+       /**
+        * Filters the WordPress install's locale.
+        *
+        * @since 4.7.0
+        *
+        * @param string $locale The WordPress install's locale.
+        * @return string The locale currently being switched to.
+        */
+       public function filter_locale( $locale ) {
+               $switched_locale = end( $this->locales );
+
+               if ( $switched_locale ) {
+                       return $switched_locale;
+               }
+
+               return $locale;
+       }
+
+       /**
+        * Load translations for a given locale.
+        *
+        * When switching to a locale, translations for this locale must be loaded from scratch.
+        *
+        * @since 4.7.0
+        * @access private
+        *
+        * @global Mo[] $l10n An array of all currently loaded text domains.
+        *
+        * @param string $locale The locale to load translations for.
+        */
+       private function load_translations( $locale ) {
+               global $l10n;
+
+               $domains = $l10n ? array_keys( $l10n ) : array();
+
+               load_default_textdomain( $locale );
+
+               foreach ( $domains as $domain ) {
+                       if ( 'default' === $domain ) {
+                               continue;
+                       }
+
+                       $mofile = $l10n[ $domain ]->get_filename();
+
+                       unload_textdomain( $domain );
+
+                       if ( $mofile ) {
+                               load_textdomain( $domain, $mofile );
+                       }
+
+                       get_translations_for_domain( $domain );
+               }
+       }
+
+       /**
+        * Changes the site's locale to the given one.
+        *
+        * Loads the translations, changes the global `$wp_locale` object and updates
+        * all post type labels.
+        *
+        * @since 4.7.0
+        * @access private
+        *
+        * @global WP_Locale $wp_locale The WordPress date and time locale object.
+        *
+        * @param string $locale The locale to change to.
+        */
+       private function change_locale( $locale ) {
+               $this->load_translations( $locale );
+
+               $GLOBALS['wp_locale'] = new WP_Locale();
+
+               /**
+                * Fires when the locale is switched to or restored.
+                *
+                * @since 4.7.0
+                *
+                * @param string $locale The new locale.
+                */
+               do_action( 'change_locale', $locale );
+       }
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesdefaultfiltersphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/default-filters.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/default-filters.php 2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-includes/default-filters.php   2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -406,6 +406,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> add_action( 'admin_menu', '_add_post_type_submenus' );
</span><span class="cx" style="display: block; padding: 0 10px"> add_action( 'before_delete_post', '_reset_front_page_settings_for_post' );
</span><span class="cx" style="display: block; padding: 0 10px"> add_action( 'wp_trash_post',      '_reset_front_page_settings_for_post' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+add_action( 'change_locale', 'create_initial_post_types' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Post Formats
</span><span class="cx" style="display: block; padding: 0 10px"> add_filter( 'request', '_post_format_request' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -431,6 +432,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Taxonomy
</span><span class="cx" style="display: block; padding: 0 10px"> add_action( 'init', 'create_initial_taxonomies', 0 ); // highest priority
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+add_action( 'change_locale', 'create_initial_taxonomies' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Canonical
</span><span class="cx" style="display: block; padding: 0 10px"> add_action( 'template_redirect', 'redirect_canonical' );
</span></span></pre></div>
<a id="trunksrcwpincludesl10nphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/l10n.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/l10n.php    2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-includes/l10n.php      2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1178,3 +1178,68 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px">        return $wp_locale->is_rtl();
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+/**
+ * Switches the translations according to the given locale.
+ *
+ * @since 4.7.0
+ *
+ * @global WP_Locale_Switcher $wp_locale_switcher
+ *
+ * @param string $locale The locale.
+ * @return bool True on success, false on failure.
+ */
+function switch_to_locale( $locale ) {
+       /* @var WP_Locale_Switcher $wp_locale_switcher */
+       global $wp_locale_switcher;
+
+       return $wp_locale_switcher->switch_to_locale( $locale );
+}
+
+/**
+ * Restores the translations according to the previous locale.
+ *
+ * @since 4.7.0
+ *
+ * @global WP_Locale_Switcher $wp_locale_switcher
+ *
+ * @return string|false Locale on success, false on error.
+ */
+function restore_previous_locale() {
+       /* @var WP_Locale_Switcher $wp_locale_switcher */
+       global $wp_locale_switcher;
+
+       return $wp_locale_switcher->restore_previous_locale();
+}
+
+/**
+ * Restores the translations according to the original locale.
+ *
+ * @since 4.7.0
+ *
+ * @global WP_Locale_Switcher $wp_locale_switcher
+ *
+ * @return string|false Locale on success, false on error.
+ */
+function restore_current_locale() {
+       /* @var WP_Locale_Switcher $wp_locale_switcher */
+       global $wp_locale_switcher;
+
+       return $wp_locale_switcher->restore_current_locale();
+}
+
+/**
+ * Whether switch_to_locale() is in effect.
+ *
+ * @since 4.7.0
+ *
+ * @global WP_Locale_Switcher $wp_locale_switcher
+ *
+ * @return bool True if the locale has been switched, false otherwise.
+ */
+function is_locale_switched() {
+       /* @var WP_Locale_Switcher $wp_locale_switcher */
+       global $wp_locale_switcher;
+
+       return $wp_locale_switcher->is_switched();
+}
</ins></span></pre></div>
<a id="trunksrcwpincludesloadphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/load.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/load.php    2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-includes/load.php      2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -841,13 +841,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @since 3.4.0
</span><span class="cx" style="display: block; padding: 0 10px">  * @access private
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @global string    $text_direction
- * @global WP_Locale $wp_locale      The WordPress date and time locale object.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @global string             $text_direction
+ * @global WP_Locale          $wp_locale      The WordPress date and time locale object.
+ * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @staticvar bool $loaded
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function wp_load_translations_early() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        global $text_direction, $wp_locale;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ global $text_direction, $wp_locale, $wp_locale_switcher;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        static $loaded = false;
</span><span class="cx" style="display: block; padding: 0 10px">        if ( $loaded )
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -864,6 +865,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        require_once ABSPATH . WPINC . '/pomo/mo.php';
</span><span class="cx" style="display: block; padding: 0 10px">        require_once ABSPATH . WPINC . '/l10n.php';
</span><span class="cx" style="display: block; padding: 0 10px">        require_once ABSPATH . WPINC . '/class-wp-locale.php';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        // General libraries
</span><span class="cx" style="display: block; padding: 0 10px">        require_once ABSPATH . WPINC . '/plugin.php';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -915,6 +917,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $wp_locale = new WP_Locale();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $wp_locale_switcher = new WP_Locale_Switcher();
+       $wp_locale_switcher->init();
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span></span></pre></div>
<a id="trunksrcwpincludesmsfunctionsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/ms-functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/ms-functions.php    2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-includes/ms-functions.php      2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -800,6 +800,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
</span><span class="cx" style="display: block; padding: 0 10px">        $from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
</span><span class="cx" style="display: block; padding: 0 10px">        $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       $user = get_user_by( 'login', $user );
+       $switched_locale = switch_to_locale( get_user_locale( $user ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $message = sprintf(
</span><span class="cx" style="display: block; padding: 0 10px">                /**
</span><span class="cx" style="display: block; padding: 0 10px">                 * Filters the message content of the new blog notification email.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -849,6 +853,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                esc_url( 'http://' . $domain . $path )
</span><span class="cx" style="display: block; padding: 0 10px">        );
</span><span class="cx" style="display: block; padding: 0 10px">        wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $switched_locale ) {
+               restore_previous_locale();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         return true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -887,6 +896,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! apply_filters( 'wpmu_signup_user_notification', $user, $user_email, $key, $meta ) )
</span><span class="cx" style="display: block; padding: 0 10px">                return false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $user = get_user_by( 'login', $user );
+       $switched_locale = switch_to_locale( get_user_locale( $user ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         // Send email with activation link.
</span><span class="cx" style="display: block; padding: 0 10px">        $admin_email = get_site_option( 'admin_email' );
</span><span class="cx" style="display: block; padding: 0 10px">        if ( $admin_email == '' )
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -934,6 +946,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $user
</span><span class="cx" style="display: block; padding: 0 10px">        );
</span><span class="cx" style="display: block; padding: 0 10px">        wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $switched_locale ) {
+               restore_previous_locale();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         return true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1448,6 +1465,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! apply_filters( 'wpmu_welcome_notification', $blog_id, $user_id, $password, $title, $meta ) )
</span><span class="cx" style="display: block; padding: 0 10px">                return false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $user = get_userdata( $user_id );
+
+       $switched_locale = switch_to_locale( get_user_locale( $user ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $welcome_email = get_site_option( 'welcome_email' );
</span><span class="cx" style="display: block; padding: 0 10px">        if ( $welcome_email == false ) {
</span><span class="cx" style="display: block; padding: 0 10px">                /* translators: Do not translate USERNAME, SITE_NAME, BLOG_URL, PASSWORD: those are placeholders. */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1468,7 +1489,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $url = get_blogaddress_by_id($blog_id);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $user = get_userdata( $user_id );
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email );
</span><span class="cx" style="display: block; padding: 0 10px">        $welcome_email = str_replace( 'BLOG_TITLE', $title, $welcome_email );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1512,6 +1532,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        $subject = apply_filters( 'update_welcome_subject', sprintf( __( 'New %1$s Site: %2$s' ), $current_network->site_name, wp_unslash( $title ) ) );
</span><span class="cx" style="display: block; padding: 0 10px">        wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $switched_locale ) {
+               restore_previous_locale();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         return true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1551,6 +1576,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $user = get_userdata( $user_id );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $switched_locale = switch_to_locale( get_user_locale( $user ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         /**
</span><span class="cx" style="display: block; padding: 0 10px">         * Filters the content of the welcome email after user activation.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1590,6 +1617,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        $subject = apply_filters( 'update_welcome_user_subject', sprintf( __( 'New %1$s User: %2$s' ), $current_network->site_name, $user->user_login) );
</span><span class="cx" style="display: block; padding: 0 10px">        wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $switched_locale ) {
+               restore_previous_locale();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         return true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludespluggablephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/pluggable.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/pluggable.php       2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-includes/pluggable.php 2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -211,7 +211,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        // (Re)create it, if it's gone missing
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! ( $phpmailer instanceof PHPMailer ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                require_once ABSPATH . WPINC . '/class-phpmailer.php';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                require_once ABSPATH . WPINC . '/class-smtp.php'; 
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         require_once ABSPATH . WPINC . '/class-smtp.php';
</ins><span class="cx" style="display: block; padding: 0 10px">                 $phpmailer = new PHPMailer( true );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1418,6 +1418,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $emails = array_flip( $emails );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $switched_locale = switch_to_locale( get_locale() );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        // The blogname option is escaped with esc_html on the way into the database in sanitize_option
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1522,6 +1524,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if ( $switched_locale ) {
+               restore_previous_locale();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         return true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1569,6 +1575,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $emails[] = $user->user_email;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $switched_locale = switch_to_locale( get_locale() );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
</span><span class="cx" style="display: block; padding: 0 10px">        $comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1664,6 +1672,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                @wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if ( $switched_locale ) {
+               restore_previous_locale();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         return true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1723,11 +1735,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( 'user' !== $notify ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $switched_locale = switch_to_locale( get_locale() );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $message  = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
</span><span class="cx" style="display: block; padding: 0 10px">                $message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
</span><span class="cx" style="display: block; padding: 0 10px">                $message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                @wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] New User Registration' ), $blogname ), $message );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               if ( $switched_locale ) {
+                       restore_previous_locale();
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        // `$deprecated was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notifcation.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1748,6 +1765,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
</span><span class="cx" style="display: block; padding: 0 10px">        $wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        $switched_locale = switch_to_locale( get_user_locale( $user ) );
+
</ins><span class="cx" style="display: block; padding: 0 10px">         $message = sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n";
</span><span class="cx" style="display: block; padding: 0 10px">        $message .= __('To set your password, visit the following address:') . "\r\n\r\n";
</span><span class="cx" style="display: block; padding: 0 10px">        $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user->user_login), 'login') . ">\r\n\r\n";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1755,6 +1774,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $message .= wp_login_url() . "\r\n";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        wp_mail($user->user_email, sprintf(__('[%s] Your username and password info'), $blogname), $message);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       if ( $switched_locale ) {
+               restore_previous_locale();
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="trunksrcwpincludespomomophp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/pomo/mo.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/pomo/mo.php 2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-includes/pomo/mo.php   2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -16,15 +16,36 @@
</span><span class="cx" style="display: block; padding: 0 10px">        var $_nplurals = 2;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * Loaded MO file.
+        *
+        * @var string
+        */
+       private $filename = '';
+
+       /**
+        * Returns the loaded MO file.
+        *
+        * @return string The loaded MO file.
+        */
+       public function get_filename() {
+               return $this->filename;
+       }
+
+       /**
</ins><span class="cx" style="display: block; padding: 0 10px">          * Fills up with the entries from MO file $filename
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param string $filename MO file to load
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        function import_from_file($filename) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $reader = new POMO_FileReader($filename);
-               if (!$reader->is_resource())
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $reader = new POMO_FileReader( $filename );
+
+               if ( ! $reader->is_resource() ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         return false;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return $this->import_from_reader($reader);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         }
+
+               $this->filename = (string) $filename;
+
+               return $this->import_from_reader( $reader );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -299,4 +320,4 @@
</span><span class="cx" style="display: block; padding: 0 10px">                return $this->_nplurals;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-endif;
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of file
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+endif;
</ins></span></pre></div>
<a id="trunksrcwpincludesuserphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/user.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/user.php    2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-includes/user.php      2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1801,8 +1801,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $switched_locale = false;
+               if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) {
+                       $switched_locale = switch_to_locale( get_user_locale( $user_id ) );
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( ! empty( $send_password_change_email ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                         /* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
</span><span class="cx" style="display: block; padding: 0 10px">                        $pass_change_text = __( 'Hi ###USERNAME###,
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1910,6 +1914,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               if ( $switched_locale ) {
+                       restore_previous_locale();
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        // Update the cookies if the password changed.
</span></span></pre></div>
<a id="trunksrcwpsettingsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-settings.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-settings.php 2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/src/wp-settings.php   2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -130,6 +130,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> // Load the L10n library.
</span><span class="cx" style="display: block; padding: 0 10px"> require_once( ABSPATH . WPINC . '/l10n.php' );
</span><span class="cx" style="display: block; padding: 0 10px"> require_once( ABSPATH . WPINC . '/class-wp-locale.php' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require_once( ABSPATH . WPINC . '/class-wp-locale-switcher.php' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // Run the installer if WordPress is not installed.
</span><span class="cx" style="display: block; padding: 0 10px"> wp_not_installed();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -400,6 +401,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> $GLOBALS['wp_locale'] = new WP_Locale();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ *  WordPress Locale Switcher object for switching locales.
+ *
+ * @since 4.7.0
+ *
+ * @global WP_Locale_Switcher $wp_locale_switcher WordPress locale switcher object.
+ */
+$GLOBALS['wp_locale_switcher'] = new WP_Locale_Switcher();
+$GLOBALS['wp_locale_switcher']->init();
+
</ins><span class="cx" style="display: block; padding: 0 10px"> // Load the functions for the active theme, for both parent and child theme if applicable.
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! wp_installing() || 'wp-activate.php' === $pagenow ) {
</span><span class="cx" style="display: block; padding: 0 10px">        if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) )
</span></span></pre></div>
<a id="trunktestsphpunittestsl10nloadTextdomainJustInTimephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php       2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php 2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -9,7 +9,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        private $orig_theme_dir;
</span><span class="cx" style="display: block; padding: 0 10px">        private $theme_root;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function setUp() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function setUp() {
</ins><span class="cx" style="display: block; padding: 0 10px">                 parent::setUp();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->theme_root = DIR_TESTDATA . '/themedir1';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22,17 +22,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">                add_filter( 'template_root', array( $this, 'filter_theme_root' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                wp_clean_themes_cache();
</span><span class="cx" style="display: block; padding: 0 10px">                unset( $GLOBALS['wp_themes'] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         unset( $GLOBALS['l10n'] );
</ins><span class="cx" style="display: block; padding: 0 10px">                 unset( $GLOBALS['l10n_unloaded'] );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function tearDown() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function tearDown() {
</ins><span class="cx" style="display: block; padding: 0 10px">                 $GLOBALS['wp_theme_directories'] = $this->orig_theme_dir;
</span><span class="cx" style="display: block; padding: 0 10px">                remove_filter( 'theme_root', array( $this, 'filter_theme_root' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                remove_filter( 'stylesheet_root', array( $this, 'filter_theme_root' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                remove_filter( 'template_root', array( $this, 'filter_theme_root' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                wp_clean_themes_cache();
</span><span class="cx" style="display: block; padding: 0 10px">                unset( $GLOBALS['wp_themes'] );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                unset( $GLOBALS['l10n'] );
+               unset( $GLOBALS['l10n_unloaded'] );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                parent::tearDown();
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -60,7 +62,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $expected_output             = i18n_plugin_test();
</span><span class="cx" style="display: block; padding: 0 10px">                $is_textdomain_loaded_after  = is_textdomain_loaded( 'internationalized-plugin' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                unload_textdomain( 'internationalized-plugin' );
</del><span class="cx" style="display: block; padding: 0 10px">                 remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $is_textdomain_loaded_before );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -82,7 +83,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $expected_output             = i18n_theme_test();
</span><span class="cx" style="display: block; padding: 0 10px">                $is_textdomain_loaded_after  = is_textdomain_loaded( 'internationalized-theme' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                unload_textdomain( 'internationalized-theme' );
</del><span class="cx" style="display: block; padding: 0 10px">                 remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertFalse( $is_textdomain_loaded_before );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -141,4 +141,34 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( 'Das ist ein Dummy Plugin', $expected_output_final );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertTrue( $is_textdomain_loaded_final );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * @ticket 26511
+        */
+       public function test_plugin_translation_after_switching_locale() {
+               require_once DIR_TESTDATA . '/plugins/internationalized-plugin.php';
+
+               switch_to_locale( 'de_DE' );
+               $expected = i18n_plugin_test();
+               restore_previous_locale();
+
+               $this->assertSame( 'Das ist ein Dummy Plugin', $expected );
+       }
+
+       /**
+        * @ticket 26511
+        */
+       public function test_theme_translation_after_switching_locale() {
+               switch_theme( 'internationalized-theme' );
+
+               require_once get_stylesheet_directory() . '/functions.php';
+
+               switch_to_locale( 'de_DE' );
+               $expected = i18n_theme_test();
+               restore_previous_locale();
+
+               switch_theme( WP_DEFAULT_THEME );
+
+               $this->assertSame( 'Das ist ein Dummy Theme', $expected );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunktestsphpunittestsl10nlocaleSwitcherphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/tests/l10n/localeSwitcher.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/l10n/localeSwitcher.php                         (rev 0)
+++ trunk/tests/phpunit/tests/l10n/localeSwitcher.php   2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,386 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * @group l10n
+ * @group i18n
+ * @group 26511
+ */
+class Tests_Locale_Switcher extends WP_UnitTestCase {
+       /**
+        * @var string
+        */
+       protected $locale = '';
+
+       /**
+        * @var string
+        */
+       protected $previous_locale = '';
+
+       public function setUp() {
+               parent::setUp();
+
+               $this->locale = '';
+               $this->previous_locale = '';
+
+               unset( $GLOBALS['l10n'] );
+               unset( $GLOBALS['l10n_unloaded'] );
+       }
+
+       public function tearDown() {
+               unset( $GLOBALS['l10n'] );
+               unset( $GLOBALS['l10n_unloaded'] );
+
+               parent::tearDown();
+       }
+
+       public function test_switch_to_non_existent_locale_returns_false() {
+               $this->assertFalse( switch_to_locale( 'foo_BAR' ) );
+       }
+
+       public function test_switch_to_non_existent_locale_does_not_change_locale() {
+               switch_to_locale( 'foo_BAR' );
+
+               $this->assertSame( 'en_US', get_locale() );
+       }
+
+       public function test_switch_to_locale_returns_true() {
+               $expected = switch_to_locale( 'en_GB' );
+
+               // Cleanup.
+               restore_previous_locale();
+
+               $this->assertTrue( $expected );
+       }
+
+       public function test_switch_to_locale_changes_the_locale() {
+               switch_to_locale( 'en_GB' );
+
+               $locale = get_locale();
+
+               // Cleanup.
+               restore_previous_locale();
+
+               $this->assertSame( 'en_GB', $locale );
+       }
+
+       public function test_switch_to_locale_loads_translation() {
+               switch_to_locale( 'es_ES' );
+
+               $actual = __( 'Invalid parameter.' );
+
+               // Cleanup.
+               restore_previous_locale();
+
+               $this->assertSame( 'Parámetro no válido. ', $actual );
+       }
+
+       public function test_switch_to_locale_changes_wp_locale_global() {
+               global $wp_locale;
+
+               $expected = array(
+                       'thousands_sep' => '.',
+                       'decimal_point' => ',',
+               );
+
+               switch_to_locale( 'de_DE' );
+
+               $wp_locale_de_DE = clone $wp_locale;
+
+               // Cleanup.
+               restore_previous_locale();
+
+               $this->assertEqualSetsWithIndex( $expected, $wp_locale_de_DE->number_format );
+       }
+
+       public function test_switch_to_locale_en_US() {
+               switch_to_locale( 'en_GB' );
+               $locale_en_GB = get_locale();
+               switch_to_locale( 'en_US' );
+               $locale_en_US = get_locale();
+
+               // Cleanup.
+               restore_current_locale();
+
+               $this->assertSame( 'en_GB', $locale_en_GB );
+               $this->assertSame( 'en_US', $locale_en_US );
+       }
+
+       public function test_switch_to_locale_multiple_times() {
+               switch_to_locale( 'en_GB' );
+               switch_to_locale( 'es_ES' );
+               $locale = get_locale();
+
+               // Cleanup.
+               restore_previous_locale();
+               restore_previous_locale();
+
+               $this->assertSame( 'es_ES', $locale );
+       }
+
+       public function test_switch_to_locale_multiple_times_loads_translation() {
+               switch_to_locale( 'en_GB' );
+               switch_to_locale( 'de_DE' );
+               switch_to_locale( 'es_ES' );
+
+               $actual = __( 'Invalid parameter.' );
+
+               // Cleanup.
+               restore_previous_locale();
+               restore_previous_locale();
+               restore_previous_locale();
+
+               $this->assertSame( 'Parámetro no válido. ', $actual );
+       }
+
+       public function test_restore_previous_locale_without_switching() {
+               $this->assertFalse( restore_previous_locale() );
+       }
+
+       public function test_restore_previous_locale_changes_the_locale_back() {
+               switch_to_locale( 'en_GB' );
+
+               // Cleanup.
+               restore_previous_locale();
+
+               $this->assertSame( 'en_US', get_locale() );
+       }
+
+       public function test_restore_previous_locale_after_switching_multiple_times() {
+               switch_to_locale( 'en_GB' );
+               switch_to_locale( 'es_ES' );
+               restore_previous_locale();
+
+               $locale = get_locale();
+
+               // Cleanup.
+               restore_previous_locale();
+
+               $this->assertSame( 'en_GB', $locale );
+       }
+
+       public function test_restore_previous_locale_restores_translation() {
+               switch_to_locale( 'es_ES' );
+               restore_previous_locale();
+
+               $actual = __( 'Invalid parameter.' );
+
+               $this->assertSame( 'Invalid parameter.', $actual );
+       }
+
+       public function test_restore_previous_locale_action_passes_previous_locale() {
+               switch_to_locale( 'en_GB' );
+               switch_to_locale( 'es_ES' );
+
+               add_action( 'restore_previous_locale', array( $this, 'store_locale' ), 10, 2 );
+
+               restore_previous_locale();
+
+               $previous_locale = $this->previous_locale;
+
+               // Cleanup.
+               restore_previous_locale();
+
+               $this->assertSame( 'es_ES', $previous_locale );
+       }
+
+       public function test_restore_previous_locale_restores_wp_locale_global() {
+               global $wp_locale;
+
+               $expected = array(
+                       'thousands_sep' => ',',
+                       'decimal_point' => '.',
+               );
+
+               switch_to_locale( 'de_DE' );
+               restore_previous_locale();
+
+               $this->assertEqualSetsWithIndex( $expected, $wp_locale->number_format );
+       }
+
+       public function test_restore_current_locale_without_switching() {
+               $this->assertFalse( restore_current_locale() );
+       }
+
+       public function test_restore_current_locale_after_switching_multiple_times() {
+               switch_to_locale( 'en_GB' );
+               switch_to_locale( 'nl_NL' );
+               switch_to_locale( 'es_ES' );
+
+               restore_current_locale();
+
+               $this->assertSame( 'en_US', get_locale() );
+       }
+
+       public function store_locale( $locale, $previous_locale ) {
+               $this->locale = $locale;
+               $this->previous_locale = $previous_locale;
+       }
+
+       public function test_is_locale_switched_if_not_switched() {
+               $this->assertFalse( is_locale_switched() );
+       }
+
+       public function test_is_locale_switched_original_locale() {
+               $original_locale = get_locale();
+
+               switch_to_locale( 'en_GB' );
+               switch_to_locale( $original_locale );
+
+               $is_locale_switched = is_locale_switched();
+
+               restore_current_locale();
+
+               $this->assertTrue( $is_locale_switched );
+       }
+
+       public function test_is_locale_switched() {
+               switch_to_locale( 'en_GB' );
+               switch_to_locale( 'nl_NL' );
+
+               $is_locale_switched = is_locale_switched();
+
+               restore_current_locale();
+
+               $this->assertTrue( $is_locale_switched );
+       }
+
+       public function test_switch_to_site_locale_if_user_locale_is_set() {
+               global $l10n, $wp_locale_switcher;
+
+               $site_locale = get_locale();
+
+               $user_id = $this->factory()->user->create( array(
+                       'role'   => 'administrator',
+                       'locale' => 'de_DE',
+               ) );
+
+               wp_set_current_user( $user_id );
+               set_current_screen( 'dashboard' );
+
+               $locale_switcher = clone $wp_locale_switcher;
+
+               $wp_locale_switcher = new WP_Locale_Switcher();
+               $wp_locale_switcher->init();
+
+               $user_locale = get_user_locale();
+
+               $this->assertSame( 'de_DE', $user_locale );
+
+               load_default_textdomain( $user_locale );
+               $language_header_before_switch = $l10n['default']->headers['Language']; // de_DE
+
+               $locale_switched_user_locale = switch_to_locale( $user_locale ); // False.
+               $locale_switched_site_locale = switch_to_locale( $site_locale ); // True.
+               $site_locale_after_switch = get_locale();
+               $language_header_after_switch = isset( $l10n['default'] ); // en_US
+
+               restore_current_locale();
+
+               $language_header_after_restore = $l10n['default']->headers['Language']; // de_DE
+
+               $wp_locale_switcher = $locale_switcher;
+
+               set_current_screen( 'front' );
+
+               $this->assertFalse( $locale_switched_user_locale );
+               $this->assertTrue( $locale_switched_site_locale );
+               $this->assertSame( $site_locale, $site_locale_after_switch );
+               $this->assertSame( 'de_DE', $language_header_before_switch );
+               $this->assertFalse( $language_header_after_switch );
+               $this->assertSame( 'de_DE', $language_header_after_restore );
+       }
+
+       public function test_switch_to_different_site_locale_if_user_locale_is_set() {
+               global $l10n, $wp_locale_switcher;
+
+               // Change site locale to es_ES.
+               add_filter( 'locale', array( $this, 'filter_locale' ) );
+
+               $site_locale = get_locale();
+
+               $user_id = $this->factory()->user->create( array(
+                       'role'   => 'administrator',
+                       'locale' => 'de_DE',
+               ) );
+
+               wp_set_current_user( $user_id );
+               set_current_screen( 'dashboard' );
+
+               $locale_switcher = clone $wp_locale_switcher;
+
+               $wp_locale_switcher = new WP_Locale_Switcher();
+               $wp_locale_switcher->init();
+
+               $user_locale = get_user_locale();
+
+               $this->assertSame( 'de_DE', $user_locale );
+
+               load_default_textdomain( $user_locale );
+               $language_header_before_switch = $l10n['default']->headers['Language']; // de_DE
+
+               $locale_switched_user_locale = switch_to_locale( $user_locale ); // False.
+               $locale_switched_site_locale = switch_to_locale( $site_locale ); // True.
+               $site_locale_after_switch = get_locale();
+               $language_header_after_switch = $l10n['default']->headers['Language']; // es_ES
+
+               restore_current_locale();
+
+               $language_header_after_restore = $l10n['default']->headers['Language']; // de_DE
+
+               $wp_locale_switcher = $locale_switcher;
+
+               set_current_screen( 'front' );
+
+               remove_filter( 'locale', array( $this, 'filter_locale' ) );
+
+               $this->assertFalse( $locale_switched_user_locale );
+               $this->assertTrue( $locale_switched_site_locale );
+               $this->assertSame( $site_locale, $site_locale_after_switch );
+               $this->assertSame( 'de_DE', $language_header_before_switch );
+               $this->assertSame( 'es_ES', $language_header_after_switch );
+               $this->assertSame( 'de_DE', $language_header_after_restore );
+       }
+
+       public function test_multiple_switches_to_site_locale_and_user_locale() {
+               global $wp_locale_switcher;
+
+               $site_locale = get_locale();
+
+               $user_id = $this->factory()->user->create( array(
+                       'role'   => 'administrator',
+                       'locale' => 'en_GB',
+               ) );
+
+               wp_set_current_user( $user_id );
+               set_current_screen( 'dashboard' );
+
+               $locale_switcher = clone $wp_locale_switcher;
+
+               $wp_locale_switcher = new WP_Locale_Switcher();
+               $wp_locale_switcher->init();
+
+               $user_locale = get_user_locale();
+
+               load_default_textdomain( $user_locale );
+
+               require_once DIR_TESTDATA . '/plugins/internationalized-plugin.php';
+
+               switch_to_locale( 'de_DE' );
+               switch_to_locale( $site_locale );
+
+               $expected = i18n_plugin_test();
+
+               restore_current_locale();
+
+               $wp_locale_switcher = $locale_switcher;
+
+               set_current_screen( 'front' );
+
+               $this->assertSame( 'en_US', get_locale() );
+               $this->assertSame( 'This is a dummy plugin', $expected );
+       }
+
+       public function filter_locale() {
+               return 'es_ES';
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunittestslocalephp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/locale.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/locale.php      2016-10-26 14:51:54 UTC (rev 38960)
+++ trunk/tests/phpunit/tests/locale.php        2016-10-26 15:35:58 UTC (rev 38961)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,7 +1,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @group locale
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @group l10n
</ins><span class="cx" style="display: block; padding: 0 10px">  * @group i18n
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> class Tests_Locale extends WP_UnitTestCase {
</span></span></pre>
</div>
</div>

</body>
</html>