Index: src/wp-admin/admin-header.php
===================================================================
--- src/wp-admin/admin-header.php	(revision 31467)
+++ src/wp-admin/admin-header.php	(working copy)
@@ -189,6 +189,8 @@
 }
 ?>
 
+<div id="wp-speak" aria-live="polite" aria-relevant="all" aria-role="status" aria-atomic="true" class="screen-reader-text"></div>
+
 <div id="wpwrap">
 <a tabindex="1" href="#wpbody-content" class="screen-reader-shortcut"><?php _e('Skip to main content'); ?></a>
 <?php require(ABSPATH . 'wp-admin/menu-header.php'); ?>
Index: src/wp-admin/admin.php
===================================================================
--- src/wp-admin/admin.php	(revision 31467)
+++ src/wp-admin/admin.php	(working copy)
@@ -93,6 +93,7 @@
 $time_format = get_option('time_format');
 
 wp_enqueue_script( 'common' );
+wp_enqueue_script( 'a11y' );
 
 // $pagenow is set in vars.php
 // $wp_importers is sometimes set in wp-admin/includes/import.php
Index: src/wp-admin/customize.php
===================================================================
--- src/wp-admin/customize.php	(revision 31467)
+++ src/wp-admin/customize.php	(working copy)
@@ -118,7 +118,7 @@
 <body class="<?php echo esc_attr( $body_class ); ?>">
 <div class="wp-full-overlay expanded">
 	<form id="customize-controls" class="wrap wp-full-overlay-sidebar">
-		<div id="screen-reader-messages" aria-live="polite" aria-relevant="all" aria-role="status" aria-atomic="true" class="screen-reader-text"></div>
+		<div id="wp-speak" aria-live="polite" aria-relevant="all" aria-role="status" aria-atomic="true" class="screen-reader-text"></div>
 
 		<div id="customize-header-actions" class="wp-full-overlay-header">
 			<?php
Index: src/wp-admin/js/customize-widgets.js
===================================================================
--- src/wp-admin/js/customize-widgets.js	(revision 31467)
+++ src/wp-admin/js/customize-widgets.js	(working copy)
@@ -685,10 +685,10 @@
 
 					if ( isMoveUp ) {
 						self.moveUp();
-						$( '#screen-reader-messages' ).text( l10n.widgetMovedUp );
+						wp.speak( l10n.widgetMovedUp );
 					} else {
 						self.moveDown();
-						$( '#screen-reader-messages' ).text( l10n.widgetMovedDown );
+						wp.speak( l10n.widgetMovedDown );
 					}
 
 					$( this ).focus(); // re-focus after the container was moved
@@ -1987,4 +1987,6 @@
 		return settingId;
 	}
 
+	wp.a11y.debug = true;
+
 })( window.wp, jQuery );
Index: src/wp-admin/js/updates.js
===================================================================
--- src/wp-admin/js/updates.js	(revision 31467)
+++ src/wp-admin/js/updates.js	(working copy)
@@ -107,6 +107,7 @@
 
 		$message.addClass( 'updating-message' );
 		$message.text( wp.updates.l10n.updating );
+		wp.speak( wp.updates.l10n.updatingMsg );
 
 		if ( wp.updates.updateLock ) {
 			wp.updates.updateQueue.push( {
@@ -153,6 +154,7 @@
 
 		$message.removeClass( 'updating-message' ).addClass( 'updated-message' );
 		$message.text( wp.updates.l10n.updated );
+		wp.speak( wp.updates.l10n.updatedMsg );
 
 		wp.updates.decrementCount( 'plugin' );
 	};
@@ -173,6 +175,7 @@
 		}
 		$message.removeClass( 'updating-message' );
 		$message.text( wp.updates.l10n.updateFailed );
+		wp.speak( wp.updates.l10n.updateFailed );
 	};
 
 	/**
@@ -198,6 +201,7 @@
 
 		$message.addClass( 'updating-message' );
 		$message.text( wp.updates.l10n.installing );
+		wp.speak( wp.updates.l10n.installingMsg );
 
 		if ( wp.updates.updateLock ) {
 			wp.updates.updateQueue.push( {
@@ -234,6 +238,7 @@
 
 		$message.removeClass( 'updating-message' ).addClass( 'updated-message button-disabled' );
 		$message.text( wp.updates.l10n.installed );
+		wp.speak( wp.updates.l10n.installedMsg );
 	};
 
 	/**
@@ -316,6 +321,8 @@
 			}
 			wp.updates.installPlugin( $button.data( 'slug' ) );
 		} );
+
+		wp.a11y.debug = true;
 	} );
 
 	$( window ).on( 'message', function( e ) {
Index: src/wp-includes/js/wp-a11y.js
===================================================================
--- src/wp-includes/js/wp-a11y.js	(revision 0)
+++ src/wp-includes/js/wp-a11y.js	(working copy)
@@ -0,0 +1,80 @@
+window.wp = window.wp || {};
+
+( function ( wp, $ ) {
+	'use strict';
+
+	var a11y;
+
+	a11y = wp.a11y = wp.a11y || {};
+
+	/**
+	 * Flag to enable debug mode.
+	 * Set this to true in your script on document.ready to have messages
+	 * printed out in your browser's console.
+	 *
+	 * @since 4.2.0
+	 *
+	 * @var bool
+	 */
+	a11y.debug = false;
+
+	/**
+	 * wp.a11y.log
+	 *
+	 * A debugging utility. Works only when the debug flag is on and the browser
+	 * supports it.
+	 *
+	 * @since 4.2.0
+	 */
+	a11y.log = function() {
+		if ( window.console && a11y.debug ) {
+			window.console.log.apply( window.console, arguments );
+		}
+	};
+
+	/**
+	 * wp.a11y.speak
+	 *
+	 * Update the ARIA live notification area text node.
+	 *
+	 * @since 4.2.0
+	 *
+	 * @param {string} message
+	 */
+	a11y.speak = function( message ) {
+
+		if ( 0 === a11y.liveContainer.length ) {
+			// No need to make this translatable, it's just for debugging.
+			a11y.log( 'WP speak can\'t speak: no live notification area present' );
+			return;
+		}
+
+		// Log messages to the console when debugging.
+		a11y.log( 'WP speak: ' + message );
+
+		// Make messages available to screen readers.
+		a11y.liveContainer.text( message );
+
+	};
+
+	/**
+	 * Give developers an easy, handy, shortcut to send messages to screen readers.
+	 *
+	 * Usage: wp.speak( 'your text string here' );
+	 *
+	 * @since 4.2.0
+	 */
+	wp.speak = a11y.speak;
+
+	/**
+	 * Initialize wp.a11y and define ARIA live notification area.
+	 *
+	 * @since 4.2.0
+	 */
+	a11y.init = function() {
+		a11y.liveContainer = $( '#wp-speak' );
+	};
+
+	$( document ).ready( a11y.init );
+
+} ( window.wp, jQuery ) );
Index: src/wp-includes/script-loader.php
===================================================================
--- src/wp-includes/script-loader.php	(revision 31467)
+++ src/wp-includes/script-loader.php	(working copy)
@@ -82,6 +82,8 @@
 		'warnDelete' => __("You are about to permanently delete the selected items.\n  'Cancel' to stop, 'OK' to delete.")
 	) );
 
+	$scripts->add( 'a11y', "/wp-includes/js/wp-a11y$suffix.js", array( 'jquery' ), false, 1 );
+
 	$scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array(), '1.6.1', 1 );
 
 	$scripts->add( 'quicktags', "/wp-includes/js/quicktags$suffix.js", array(), false, 1 );
@@ -379,7 +381,7 @@
 
 	$scripts->add( 'hoverIntent', "/wp-includes/js/hoverIntent$suffix.js", array('jquery'), 'r7', 1 );
 
-	$scripts->add( 'customize-base',     "/wp-includes/js/customize-base$suffix.js",     array( 'jquery', 'json2', 'underscore' ), false, 1 );
+	$scripts->add( 'customize-base',     "/wp-includes/js/customize-base$suffix.js",     array( 'jquery', 'json2', 'underscore', 'a11y' ), false, 1 );
 	$scripts->add( 'customize-loader',   "/wp-includes/js/customize-loader$suffix.js",   array( 'customize-base' ), false, 1 );
 	$scripts->add( 'customize-preview',  "/wp-includes/js/customize-preview$suffix.js",  array( 'customize-base' ), false, 1 );
 	$scripts->add( 'customize-models',   "/wp-includes/js/customize-models.js", array( 'underscore', 'backbone' ), false, 1 );
@@ -511,6 +513,10 @@
 				'installing'    => __( 'Installing...' ),
 				'installed'     => __( 'Installed!' ),
 				'installFailed' => __( 'Installation failed' ),
+				'updatingMsg'   => __( 'Updating... please wait.' ),
+				'installingMsg' => __( 'Installing... please wait.' ),
+				'updatedMsg'    => __( 'Update completed successfully.' ),
+				'installedMsg'  => __( 'Installation completed successfully.' ),
 			)
 		) );
 
