Index: src/wp-includes/class-wp-locale-switcher.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/wp-includes/class-wp-locale-switcher.php	(revision )
+++ src/wp-includes/class-wp-locale-switcher.php	(revision )
@@ -0,0 +1,212 @@
+<?php
+/**
+ * Locale switcher object.
+ *
+ * @package WordPress
+ * @subpackage i18n
+ * @since 4.7.0
+ */
+
+/**
+ * Class for switching locales.
+ *
+ * @since 4.7.0
+ */
+class WP_Locale_Switcher {
+
+	/**
+	 * Filter callbacks.
+	 *
+	 * @since 4.7.0
+	 * @var callable[]
+	 */
+	private $filters = array();
+
+	/**
+	 * Locale stack.
+	 *
+	 * @since 4.7.0
+	 * @var string[]
+	 */
+	private $locales = array();
+
+	/**
+	 * Original locale.
+	 *
+	 * @since 4.7.0
+	 * @var string
+	 */
+	private $original_locale;
+
+	/**
+	 * Translation objects.
+	 *
+	 * @since 4.7.0
+	 * @var NOOP_Translations[][]
+	 */
+	private $translations = array();
+
+	/**
+	 * Constructor. Stores the original locale.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param string $original_locale Optional. The original locale. Defaults to result of get_locale().
+	 */
+	public function __construct( $original_locale = '' ) {
+
+		$this->original_locale = $original_locale ? (string) $original_locale : get_locale();
+	}
+
+	/**
+	 * Switches the translations according to the given locale.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param string $locale The locale.
+	 */
+	public function switch_to_locale( $locale ) {
+
+		$this->locales[] = $locale;
+
+		$current_locale = get_locale();
+		if ( $current_locale === $locale ) {
+			return;
+		}
+
+		/**
+		 * @global MO[] $l10n
+		 */
+		global $l10n;
+
+		$textdomains = array_keys( $l10n );
+
+		if ( ! $this->has_translations_for_locale( $current_locale ) ) {
+			foreach ( $textdomains as $textdomain ) {
+				$this->translations[ $current_locale ][ $textdomain ] = get_translations_for_domain( $textdomain );
+			}
+		}
+
+		$this->remove_filters();
+
+		$this->add_filter_for_locale( $locale );
+
+		if ( $this->has_translations_for_locale( $locale ) ) {
+			foreach ( $textdomains as $textdomain ) {
+				if ( isset( $this->translations[ $locale ][ $textdomain ] ) ) {
+					$l10n[ $textdomain ] = $this->translations[ $locale ][ $textdomain ];
+				}
+			}
+		} else {
+			foreach ( $l10n as $textdomain => $mo ) {
+				if ( 'default' === $textdomain ) {
+					load_default_textdomain();
+
+					continue;
+				}
+
+				unload_textdomain( $textdomain );
+
+				if ( $mofile = $mo->get_filename() ) {
+					load_textdomain( $textdomain, $mofile );
+				}
+
+				$this->translations[ $locale ][ $textdomain ] = get_translations_for_domain( $textdomain );
+			}
+		}
+
+		/**
+		 * @global WP_Locale $wp_locale
+		 */
+		$GLOBALS['wp_locale'] = new WP_Locale();
+	}
+
+	/**
+	 * Restores the translations according to the previous locale.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @return string|false Locale on success, false on error.
+	 */
+	public function restore_locale() {
+
+		if ( ! array_pop( $this->locales ) ) {
+			// The stack is empty, bail.
+			return false;
+		}
+
+		$this->remove_filters();
+
+		if ( $locale = end( $this->locales ) ) {
+			if ( isset( $filters[ $locale ] ) ) {
+				add_filter( 'locale', $filters[ $locale ] );
+			}
+		} else {
+			// There's nothing left in the stack: go back to the original locale.
+			$locale = $this->original_locale;
+		}
+
+		/**
+		 * @global MO[] $l10n
+		 */
+		global $l10n;
+
+		foreach ( array_keys( $l10n ) as $textdomain ) {
+			if ( isset( $this->translations[ $locale ][ $textdomain ] ) ) {
+				$l10n[ $textdomain ] = $this->translations[ $locale ][ $textdomain ];
+			}
+		}
+
+		/**
+		 * @global WP_Locale $wp_locale
+		 */
+		$GLOBALS['wp_locale'] = new WP_Locale();
+
+		return $locale;
+	}
+
+	/**
+	 * Checks if there are cached translations for the given locale.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param string $locale The locale.
+	 *
+	 * @return bool True if there are cached translations for the given locale, false otherwise.
+	 */
+	private function has_translations_for_locale( $locale ) {
+
+		return ! empty( $this->translations[ $locale ] );
+	}
+
+	/**
+	 * Removes all filter callbacks added before.
+	 *
+	 * @since 4.7.0
+	 */
+	private function remove_filters() {
+
+		foreach ( $this->filters as $filter ) {
+			remove_filter( 'locale', $filter );
+		}
+	}
+
+	/**
+	 * Adds a filter callback returning the given locale.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param string $locale The locale.
+	 */
+	private function add_filter_for_locale( $locale ) {
+
+		if ( ! isset( $this->filters[ $locale ] ) ) {
+			require_once ABSPATH . WPINC . '/class-wp-locale-storage.php';
+
+			// This SHOULD be a closure.
+			$this->filters[ $locale ] = array( new WP_Locale_Storage( $locale ), 'get_locale' );
+		}
+
+		add_filter( 'locale', $this->filters[ $locale ] );
+	}
+}
Index: src/wp-includes/locale.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/wp-includes/locale.php	(date 1471458587000)
+++ src/wp-includes/locale.php	(revision )
@@ -10,6 +10,9 @@
 /** WP_Locale class */
 require_once ABSPATH . WPINC . '/class-wp-locale.php';
 
+/** WP_Locale_Switcher class */
+require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
+
 /**
  * Checks if current locale is RTL.
  *
@@ -22,4 +25,38 @@
 function is_rtl() {
 	global $wp_locale;
 	return $wp_locale->is_rtl();
+}
+
+/**
+ * Switches the translations according to the given locale.
+ *
+ * @since 4.7.0
+ *
+ * @param string $locale The locale.
+ */
+function switch_to_locale( $locale ) {
+
+	/**
+	 * @global WP_Locale_Switcher $wp_locale_switcher
+	 */
+	global $wp_locale_switcher;
+
+	$wp_locale_switcher->switch_to_locale( $locale );
+}
+
+/**
+ * Restores the translations according to the previous locale.
+ *
+ * @since 4.7.0
+ *
+ * @return string|false Locale on success, false on error.
+ */
+function restore_locale() {
+
+	/**
+	 * @global WP_Locale_Switcher $wp_locale_switcher
+	 */
+	global $wp_locale_switcher;
+
+	return $wp_locale_switcher->restore_locale();
 }
Index: src/wp-includes/pomo/mo.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/wp-includes/pomo/mo.php	(date 1471458587000)
+++ src/wp-includes/pomo/mo.php	(revision )
@@ -16,6 +16,26 @@
 	var $_nplurals = 2;
 
 	/**
+	 * Loaded MO file.
+	 *
+	 * @since 4.7.0
+	 * @var string
+	 */
+	private $filename = '';
+
+	/**
+	 * Returns the loaded MO file.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @return string The loaded MO file.
+	 */
+	public function get_filename() {
+
+		return $this->filename;
+	}
+
+	/**
 	 * Fills up with the entries from MO file $filename
 	 *
 	 * @param string $filename MO file to load
@@ -24,6 +44,9 @@
 		$reader = new POMO_FileReader($filename);
 		if (!$reader->is_resource())
 			return false;
+
+		$this->filename = (string) $filename;
+
 		return $this->import_from_reader($reader);
 	}
 
\ No newline at end of file
Index: src/wp-settings.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/wp-settings.php	(date 1471458587000)
+++ src/wp-settings.php	(revision )
@@ -379,6 +379,13 @@
  */
 $GLOBALS['wp_locale'] = new WP_Locale();
 
+/**
+ * WordPress Locale Switcher object for switching locales.
+ * @global WP_Locale_Switcher $wp_locale_switcher
+ * @since 4.7.0
+ */
+$GLOBALS['wp_locale_switcher'] = new WP_Locale_Switcher( $locale );
+
 // Load the functions for the active theme, for both parent and child theme if applicable.
 if ( ! wp_installing() || 'wp-activate.php' === $pagenow ) {
 	if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) )
Index: src/wp-includes/class-wp-locale-storage.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/wp-includes/class-wp-locale-storage.php	(revision )
+++ src/wp-includes/class-wp-locale-storage.php	(revision )
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Simple locale storage.
+ *
+ * @package WordPress
+ * @subpackage i18n
+ * @since 4.7.0
+ */
+
+/**
+ * Class for locale storage objects with a getter.
+ *
+ * @since 4.7.0
+ */
+class WP_Locale_Storage {
+
+	/**
+	 * The stored locale.
+	 *
+	 * @since 4.7.0
+	 * @var string
+	 */
+	private $locale;
+
+	/**
+	 * Constructor. Stores the given locale.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @param string $locale A locale.
+	 */
+	public function __construct( $locale ) {
+
+		$this->locale = (string) $locale;
+	}
+
+	/**
+	 * Returns the stored locale.
+	 *
+	 * @since 4.7.0
+	 *
+	 * @return string The stored locale.
+	 */
+	public function get_locale() {
+
+		return $this->locale;
+	}
+}
