diff --git src/wp-admin/includes/ms.php src/wp-admin/includes/ms.php
index acdd09f..2b1cc16 100644
--- src/wp-admin/includes/ms.php
+++ src/wp-admin/includes/ms.php
@@ -272,6 +272,8 @@ function update_option_new_admin_email( $old_value, $value ) {
 	);
 	update_option( 'adminhash', $new_admin_email );
 
+	$switched_locale = switch_to_locale( get_user_locale() );
+
 	/* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
 	$email_text = __( 'Howdy ###USERNAME###,
 
@@ -315,6 +317,10 @@ All at ###SITENAME###
 	$content = str_replace( '###SITEURL###', network_home_url(), $content );
 
 	wp_mail( $value, sprintf( __( '[%s] New Admin Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
 }
 
 /**
@@ -353,6 +359,8 @@ function send_confirmation_on_profile_email() {
 		);
 		update_user_meta( $current_user->ID, '_new_email', $new_user_email );
 
+		$switched_locale = switch_to_locale( get_user_locale() );
+
 		/* translators: Do not translate USERNAME, ADMIN_URL, EMAIL, SITENAME, SITEURL: those are placeholders. */
 		$email_text = __( 'Howdy ###USERNAME###,
 
@@ -395,6 +403,10 @@ All at ###SITENAME###
 
 		wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), wp_specialchars_decode( get_option( 'blogname' ) ) ), $content );
 		$_POST['email'] = $current_user->user_email;
+
+		if ( $switched_locale ) {
+			restore_previous_locale();
+		}
 	}
 }
 
diff --git src/wp-admin/includes/upgrade.php src/wp-admin/includes/upgrade.php
index f37fccc..0ec2e32 100644
--- src/wp-admin/includes/upgrade.php
+++ src/wp-admin/includes/upgrade.php
@@ -373,6 +373,9 @@ function wp_new_blog_notification($blog_title, $blog_url, $user_id, $password) {
 	$email = $user->user_email;
 	$name = $user->user_login;
 	$login_url = wp_login_url();
+
+	$switched_locale = switch_to_locale( $user->locale );
+
 	$message = sprintf( __( "Your new WordPress site has been successfully set up at:
 
 %1\$s
@@ -390,6 +393,10 @@ https://wordpress.org/
 "), $blog_url, $name, $password, $login_url );
 
 	@wp_mail($email, __('New WordPress Site'), $message);
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
 }
 endif;
 
diff --git src/wp-admin/ms-delete-site.php src/wp-admin/ms-delete-site.php
index 9192509..6bc3cfc 100644
--- src/wp-admin/ms-delete-site.php
+++ src/wp-admin/ms-delete-site.php
@@ -42,6 +42,8 @@ if ( isset( $_POST['action'] ) && $_POST['action'] == 'deleteblog' && isset( $_P
 
 	$url_delete = esc_url( admin_url( 'ms-delete-site.php?h=' . $hash ) );
 
+	$switched_locale = switch_to_locale( get_locale() );
+
 	/* translators: Do not translate USERNAME, URL_DELETE, SITE_NAME: those are placeholders. */
 	$content = __( "Howdy ###USERNAME###,
 
@@ -73,6 +75,10 @@ Webmaster
 	$content = str_replace( '###SITE_NAME###', get_network()->site_name, $content );
 
 	wp_mail( get_option( 'admin_email' ), "[ " . wp_specialchars_decode( get_option( 'blogname' ) ) . " ] ".__( 'Delete My Site' ), $content );
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
 	?>
 
 	<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>
diff --git src/wp-admin/user-new.php src/wp-admin/user-new.php
index 38b78dd..13d753d 100644
--- src/wp-admin/user-new.php
+++ src/wp-admin/user-new.php
@@ -87,6 +87,8 @@ if ( isset($_REQUEST['action']) && 'adduser' == $_REQUEST['action'] ) {
 			 */
 			do_action( 'invite_user', $user_id, $role, $newuser_key );
 
+			$switched_locale = switch_to_locale( $user_details->locale );
+
 			/* translators: 1: Site name, 2: site URL, 3: role, 4: activation URL */
 			$message = __( 'Hi,
 
@@ -96,6 +98,11 @@ You\'ve been invited to join \'%1$s\' at
 Please click the following link to confirm the invite:
 %4$s' );
 			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/" ) ) );
+
+			if ( $switched_locale ) {
+				restore_previous_locale();
+			}
+
 			$redirect = add_query_arg( array('update' => 'add'), 'user-new.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..8fb4d79
--- /dev/null
+++ src/wp-includes/class-wp-locale-switcher.php
@@ -0,0 +1,244 @@
+<?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     = get_locale();
+		$this->available_languages = 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 ) {
+		if ( $locale === get_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;
+
+		if ( ! $l10n ) {
+			$l10n = array();
+		}
+
+		load_default_textdomain( $locale );
+
+		/* @var MO $mo */
+		foreach ( $l10n as $domain => $mo ) {
+			if ( 'default' === $domain ) {
+				continue;
+			}
+
+			unload_textdomain( $domain );
+
+			if ( $mo->get_filename() ) {
+				load_textdomain( $domain, $mo->get_filename() );
+			}
+
+			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 );
+	}
+}
diff --git src/wp-includes/default-filters.php src/wp-includes/default-filters.php
index 71255c3..e38d3f5 100644
--- src/wp-includes/default-filters.php
+++ src/wp-includes/default-filters.php
@@ -404,6 +404,7 @@ add_action( 'init', 'create_initial_post_types', 0 ); // highest priority
 add_action( 'admin_menu', '_add_post_type_submenus' );
 add_action( 'before_delete_post', '_reset_front_page_settings_for_post' );
 add_action( 'wp_trash_post',      '_reset_front_page_settings_for_post' );
+add_action( 'change_locale', 'create_initial_post_types' );
 
 // Post Formats
 add_filter( 'request', '_post_format_request' );
@@ -429,6 +430,7 @@ add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );
 
 // Taxonomy
 add_action( 'init', 'create_initial_taxonomies', 0 ); // highest priority
+add_action( 'change_locale', 'create_initial_taxonomies' );
 
 // Canonical
 add_action( 'template_redirect', 'redirect_canonical' );
diff --git src/wp-includes/l10n.php src/wp-includes/l10n.php
index 03a7a11..902a978 100644
--- src/wp-includes/l10n.php
+++ src/wp-includes/l10n.php
@@ -1166,3 +1166,68 @@ function is_rtl() {
 	}
 	return $wp_locale->is_rtl();
 }
+
+/**
+ * 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();
+}
diff --git src/wp-includes/load.php src/wp-includes/load.php
index 887a6b1..d6ce9f8 100644
--- src/wp-includes/load.php
+++ src/wp-includes/load.php
@@ -843,13 +843,14 @@ function get_current_network_id() {
  * @since 3.4.0
  * @access private
  *
- * @global string    $text_direction
- * @global WP_Locale $wp_locale      The WordPress date and time locale object.
+ * @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.
  *
  * @staticvar bool $loaded
  */
 function wp_load_translations_early() {
-	global $text_direction, $wp_locale;
+	global $text_direction, $wp_locale, $wp_locale_switcher;
 
 	static $loaded = false;
 	if ( $loaded )
@@ -866,6 +867,7 @@ function wp_load_translations_early() {
 	require_once ABSPATH . WPINC . '/pomo/mo.php';
 	require_once ABSPATH . WPINC . '/l10n.php';
 	require_once ABSPATH . WPINC . '/class-wp-locale.php';
+	require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
 
 	// General libraries
 	require_once ABSPATH . WPINC . '/plugin.php';
@@ -917,6 +919,8 @@ function wp_load_translations_early() {
 	}
 
 	$wp_locale = new WP_Locale();
+	$wp_locale_switcher = new WP_Locale_Switcher();
+	$wp_locale_switcher->init();
 }
 
 /**
diff --git src/wp-includes/ms-functions.php src/wp-includes/ms-functions.php
index 697da4b..66da381 100644
--- src/wp-includes/ms-functions.php
+++ src/wp-includes/ms-functions.php
@@ -800,6 +800,10 @@ function wpmu_signup_blog_notification( $domain, $path, $title, $user, $user_ema
 		$admin_email = 'support@' . $_SERVER['SERVER_NAME'];
 	$from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
 	$message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
+
+	$user = get_user_by( 'login', $user );
+	$switched_locale = switch_to_locale( $user && $user->locale ? $user->locale : get_locale() );
+
 	$message = sprintf(
 		/**
 		 * Filters the message content of the new blog notification email.
@@ -849,6 +853,11 @@ function wpmu_signup_blog_notification( $domain, $path, $title, $user, $user_ema
 		esc_url( 'http://' . $domain . $path )
 	);
 	wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
+
 	return true;
 }
 
@@ -887,6 +896,9 @@ function wpmu_signup_user_notification( $user, $user_email, $key, $meta = array(
 	if ( ! apply_filters( 'wpmu_signup_user_notification', $user, $user_email, $key, $meta ) )
 		return false;
 
+	$user = get_user_by( 'login', $user );
+	$switched_locale = switch_to_locale( $user && $user->locale ? $user->locale : get_locale() );
+
 	// Send email with activation link.
 	$admin_email = get_site_option( 'admin_email' );
 	if ( $admin_email == '' )
@@ -934,6 +946,11 @@ function wpmu_signup_user_notification( $user, $user_email, $key, $meta = array(
 		$user
 	);
 	wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
+
 	return true;
 }
 
@@ -1448,6 +1465,10 @@ function wpmu_welcome_notification( $blog_id, $user_id, $password, $title, $meta
 	if ( ! apply_filters( 'wpmu_welcome_notification', $blog_id, $user_id, $password, $title, $meta ) )
 		return false;
 
+	$user = get_userdata( $user_id );
+
+	$switched_locale = switch_to_locale( $user->locale );
+
 	$welcome_email = get_site_option( 'welcome_email' );
 	if ( $welcome_email == false ) {
 		/* translators: Do not translate USERNAME, SITE_NAME, BLOG_URL, PASSWORD: those are placeholders. */
@@ -1468,7 +1489,6 @@ We hope you enjoy your new site. Thanks!
 	}
 
 	$url = get_blogaddress_by_id($blog_id);
-	$user = get_userdata( $user_id );
 
 	$welcome_email = str_replace( 'SITE_NAME', $current_network->site_name, $welcome_email );
 	$welcome_email = str_replace( 'BLOG_TITLE', $title, $welcome_email );
@@ -1512,6 +1532,11 @@ We hope you enjoy your new site. Thanks!
 	 */
 	$subject = apply_filters( 'update_welcome_subject', sprintf( __( 'New %1$s Site: %2$s' ), $current_network->site_name, wp_unslash( $title ) ) );
 	wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
+
 	return true;
 }
 
@@ -1551,6 +1576,8 @@ function wpmu_welcome_user_notification( $user_id, $password, $meta = array() )
 
 	$user = get_userdata( $user_id );
 
+	$switched_locale = switch_to_locale( $user->locale );
+
 	/**
 	 * Filters the content of the welcome email after user activation.
 	 *
@@ -1590,6 +1617,11 @@ function wpmu_welcome_user_notification( $user_id, $password, $meta = array() )
 	 */
 	$subject = apply_filters( 'update_welcome_user_subject', sprintf( __( 'New %1$s User: %2$s' ), $current_network->site_name, $user->user_login) );
 	wp_mail( $user->user_email, wp_specialchars_decode( $subject ), $message, $message_headers );
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
+
 	return true;
 }
 
diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php
index d7713b7..2982a3d 100644
--- src/wp-includes/pluggable.php
+++ src/wp-includes/pluggable.php
@@ -211,7 +211,7 @@ function wp_mail( $to, $subject, $message, $headers = '', $attachments = array()
 	// (Re)create it, if it's gone missing
 	if ( ! ( $phpmailer instanceof PHPMailer ) ) {
 		require_once ABSPATH . WPINC . '/class-phpmailer.php';
-		require_once ABSPATH . WPINC . '/class-smtp.php'; 
+		require_once ABSPATH . WPINC . '/class-smtp.php';
 		$phpmailer = new PHPMailer( true );
 	}
 
@@ -1569,6 +1569,8 @@ function wp_notify_moderator($comment_id) {
 			$emails[] = $user->user_email;
 	}
 
+	$switched_locale = switch_to_locale( get_locale() );
+
 	$comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
 	$comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
 
@@ -1664,6 +1666,10 @@ function wp_notify_moderator($comment_id) {
 		@wp_mail( $email, wp_specialchars_decode( $subject ), $notify_message, $message_headers );
 	}
 
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
+
 	return true;
 }
 endif;
@@ -1723,11 +1729,16 @@ function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' )
 	$blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
 
 	if ( 'user' !== $notify ) {
+		$switched_locale = switch_to_locale( get_locale() );
 		$message  = sprintf( __( 'New user registration on your site %s:' ), $blogname ) . "\r\n\r\n";
 		$message .= sprintf( __( 'Username: %s' ), $user->user_login ) . "\r\n\r\n";
 		$message .= sprintf( __( 'Email: %s' ), $user->user_email ) . "\r\n";
 
 		@wp_mail( get_option( 'admin_email' ), sprintf( __( '[%s] New User Registration' ), $blogname ), $message );
+
+		if ( $switched_locale ) {
+			restore_previous_locale();
+		}
 	}
 
 	// `$deprecated was pre-4.3 `$plaintext_pass`. An empty `$plaintext_pass` didn't sent a user notifcation.
@@ -1748,6 +1759,8 @@ function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' )
 	$hashed = time() . ':' . $wp_hasher->HashPassword( $key );
 	$wpdb->update( $wpdb->users, array( 'user_activation_key' => $hashed ), array( 'user_login' => $user->user_login ) );
 
+	$switched_locale = switch_to_locale( $user->locale );
+
 	$message = sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n";
 	$message .= __('To set your password, visit the following address:') . "\r\n\r\n";
 	$message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user->user_login), 'login') . ">\r\n\r\n";
@@ -1755,6 +1768,10 @@ function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' )
 	$message .= wp_login_url() . "\r\n";
 
 	wp_mail($user->user_email, sprintf(__('[%s] Your username and password info'), $blogname), $message);
+
+	if ( $switched_locale ) {
+		restore_previous_locale();
+	}
 }
 endif;
 
diff --git src/wp-includes/pomo/mo.php src/wp-includes/pomo/mo.php
index 6bc44d6..47e9b6a 100644
--- src/wp-includes/pomo/mo.php
+++ src/wp-includes/pomo/mo.php
@@ -16,15 +16,36 @@ class MO extends Gettext_Translations {
 	var $_nplurals = 2;
 
 	/**
+	 * 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;
+	}
+
+	/**
 	 * Fills up with the entries from MO file $filename
 	 *
 	 * @param string $filename MO file to load
 	 */
 	function import_from_file($filename) {
-		$reader = new POMO_FileReader($filename);
-		if (!$reader->is_resource())
+		$reader = new POMO_FileReader( $filename );
+
+		if ( ! $reader->is_resource() ) {
 			return false;
-		return $this->import_from_reader($reader);
+		}
+
+		$this->filename = (string) $filename;
+
+		return $this->import_from_reader( $reader );
 	}
 
 	/**
@@ -299,4 +320,4 @@ class MO extends Gettext_Translations {
 		return $this->_nplurals;
 	}
 }
-endif;
\ No newline at end of file
+endif;
diff --git src/wp-includes/user.php src/wp-includes/user.php
index 22c2c1e..9a3c2a3 100644
--- src/wp-includes/user.php
+++ src/wp-includes/user.php
@@ -1801,8 +1801,12 @@ function wp_update_user($userdata) {
 
 		$blog_name = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
 
-		if ( ! empty( $send_password_change_email ) ) {
+		$switched_locale = false;
+		if ( ! empty( $send_password_change_email ) || ! empty( $send_email_change_email ) ) {
+			$switched_locale = switch_to_locale( isset( $user['locale'] ) ? $user['locale'] : get_locale() );
+		}
 
+		if ( ! empty( $send_password_change_email ) ) {
 			/* translators: Do not translate USERNAME, ADMIN_EMAIL, EMAIL, SITENAME, SITEURL: those are placeholders. */
 			$pass_change_text = __( 'Hi ###USERNAME###,
 
@@ -1910,6 +1914,10 @@ All at ###SITENAME###
 
 			wp_mail( $email_change_email['to'], sprintf( $email_change_email['subject'], $blog_name ), $email_change_email['message'], $email_change_email['headers'] );
 		}
+
+		if ( $switched_locale ) {
+			restore_previous_locale();
+		}
 	}
 
 	// Update the cookies if the password changed.
diff --git src/wp-settings.php src/wp-settings.php
index 21cb4cd..9ba866a 100644
--- src/wp-settings.php
+++ src/wp-settings.php
@@ -131,6 +131,7 @@ if ( SHORTINIT )
 // Load the L10n library.
 require_once( ABSPATH . WPINC . '/l10n.php' );
 require_once( ABSPATH . WPINC . '/class-wp-locale.php' );
+require_once( ABSPATH . WPINC . '/class-wp-locale-switcher.php' );
 
 // Run the installer if WordPress is not installed.
 wp_not_installed();
@@ -401,6 +402,16 @@ unset( $locale_file );
  */
 $GLOBALS['wp_locale'] = new WP_Locale();
 
+/**
+ *  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();
+
 // 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' ) )
diff --git tests/phpunit/tests/l10n.php tests/phpunit/tests/l10n.php
index f1048aa..d7fe894 100644
--- tests/phpunit/tests/l10n.php
+++ tests/phpunit/tests/l10n.php
@@ -85,7 +85,7 @@ class Tests_L10n extends WP_UnitTestCase {
 		$this->assertEmpty( $array );
 
 		$array = get_available_languages( DIR_TESTDATA . '/languages/' );
-		$this->assertEquals( array( 'en_GB', 'es_ES' ), $array );
+		$this->assertEquals( array( 'de_DE', 'en_GB', 'es_ES' ), $array );
 	}
 
 	/**
diff --git tests/phpunit/tests/l10n/loadTextdomainJustInTime.php tests/phpunit/tests/l10n/loadTextdomainJustInTime.php
index f73cfd5..1d39868 100644
--- tests/phpunit/tests/l10n/loadTextdomainJustInTime.php
+++ tests/phpunit/tests/l10n/loadTextdomainJustInTime.php
@@ -141,4 +141,32 @@ class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase {
 		$this->assertSame( 'Das ist ein Dummy Plugin', $expected_output_final );
 		$this->assertTrue( $is_textdomain_loaded_final );
 	}
+
+	/**
+	 * @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();
+
+		$this->assertSame( 'Das ist ein Dummy Theme', $expected );
+	}
 }
diff --git tests/phpunit/tests/l10n/localeSwitcher.php tests/phpunit/tests/l10n/localeSwitcher.php
new file mode 100644
index 0000000..d882df2
--- /dev/null
+++ tests/phpunit/tests/l10n/localeSwitcher.php
@@ -0,0 +1,221 @@
+<?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() {
+		$this->locale = '';
+		$this->previous_locale = '';
+	}
+
+	public function test_switch_to_non_existent_locale_returns_false() {
+		$this->assertTrue( ! 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_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->assertTrue( ! 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->assertTrue( ! 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->assertTrue( ! 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 );
+	}
+}
diff --git tests/phpunit/tests/locale.php tests/phpunit/tests/locale.php
index 1c335f4..79372d6 100644
--- tests/phpunit/tests/locale.php
+++ tests/phpunit/tests/locale.php
@@ -1,7 +1,7 @@
 <?php
 
 /**
- * @group locale
+ * @group l10n
  * @group i18n
  */
 class Tests_Locale extends WP_UnitTestCase {
