Index: src/js/_enqueues/admin/privacy-tools.js
===================================================================
--- src/js/_enqueues/admin/privacy-tools.js	(revision 47433)
+++ src/js/_enqueues/admin/privacy-tools.js	(working copy)
@@ -259,10 +259,14 @@
 		doNextErasure( 1, 1 );
 	});
 
-	// Privacy policy page, copy button.
+	// Privacy Policy page, copy action.
 	$( document ).on( 'click', function( event ) {
-		var $target = $( event.target );
-		var $parent, $container, range;
+		var $parent,
+			$container,
+			range,
+			__ = wp.i18n.__,
+			$target = $( event.target ),
+			copiedNotice = $target.siblings( '.success' );
 
 		if ( $target.is( 'button.privacy-text-copy' ) ) {
 			$parent = $target.parent().parent();
@@ -277,22 +281,35 @@
 					var documentPosition = document.documentElement.scrollTop,
 						bodyPosition     = document.body.scrollTop;
 
+					// Setup copy.
 					window.getSelection().removeAllRanges();
+
+					// Hide tutorial content to remove from copied content.
 					range = document.createRange();
 					$container.addClass( 'hide-privacy-policy-tutorial' );
 
+					// Copy action.
 					range.selectNodeContents( $container[0] );
 					window.getSelection().addRange( range );
 					document.execCommand( 'copy' );
 
+					// Reset section.
 					$container.removeClass( 'hide-privacy-policy-tutorial' );
 					window.getSelection().removeAllRanges();
 
+					// Return scroll position - see #49540
 					if ( documentPosition > 0 && documentPosition !== document.documentElement.scrollTop ) {
 						document.documentElement.scrollTop = documentPosition;
 					} else if ( bodyPosition > 0 && bodyPosition !== document.body.scrollTop ) {
 						document.body.scrollTop = bodyPosition;
 					}
+
+					// Display and speak notice to indicate action complete.
+					copiedNotice.addClass( 'visible' );
+					wp.a11y.speak( __( 'The section has been copied to your clipboard.' ) );
+
+					// Delay notice dismissal
+					setTimeout( function(){ copiedNotice.removeClass( 'visible' ); }, 3000 );
 				} catch ( er ) {}
 			}
 		}
Index: src/wp-admin/css/edit.css
===================================================================
--- src/wp-admin/css/edit.css	(revision 47433)
+++ src/wp-admin/css/edit.css	(working copy)
@@ -728,6 +728,18 @@
 	padding-bottom: 6px;
 }
 
+.privacy-text-actions .success {
+	display: none;
+	color: #40860a;
+	float: right;
+	padding-right: 1em;
+}
+
+.privacy-text-actions .success.visible {
+	display: inline-block;
+	height: 32px;
+}
+
 .wp-privacy-policy-guide .policy-text h2 {
 	margin: 1.2em 0 1em;
 	padding: 0;
Index: src/wp-admin/includes/class-wp-privacy-policy-content.php
===================================================================
--- src/wp-admin/includes/class-wp-privacy-policy-content.php	(revision 47433)
+++ src/wp-admin/includes/class-wp-privacy-policy-content.php	(working copy)
@@ -372,12 +372,9 @@
 	public static function privacy_policy_guide() {
 
 		$content_array = self::get_suggested_policy_text();
-
 		$content       = '';
 		$toc           = array( '<li><a href="#wp-privacy-policy-guide-introduction">' . __( 'Introduction' ) . '</a></li>' );
 		$date_format   = __( 'F j, Y' );
-		$copy          = __( 'Copy this section to clipboard' );
-		$return_to_top = '<a href="#" class="return-to-top">' . __( '&uarr; Return to Top' ) . '</a>';
 
 		foreach ( $content_array as $section ) {
 			$class   = '';
@@ -385,7 +382,7 @@
 			$removed = '';
 
 			if ( ! empty( $section['removed'] ) ) {
-				$class = ' text-removed';
+				$class = 'text-removed';
 				$date  = date_i18n( $date_format, $section['removed'] );
 				/* translators: %s: Date of plugin deactivation. */
 				$meta = sprintf( __( 'Removed %s.' ), $date );
@@ -394,7 +391,7 @@
 				$removed = __( 'You deactivated this plugin on %s and may no longer need this policy.' );
 				$removed = '<div class="error inline"><p>' . sprintf( $removed, $date ) . '</p></div>';
 			} elseif ( ! empty( $section['updated'] ) ) {
-				$class = ' text-updated';
+				$class = 'text-updated';
 				$date  = date_i18n( $date_format, $section['updated'] );
 				/* translators: %s: Date of privacy policy text update. */
 				$meta = sprintf( __( 'Updated %s.' ), $date );
@@ -408,36 +405,37 @@
 			$toc_id      = 'wp-privacy-policy-guide-' . sanitize_title( $plugin_name );
 			$toc[]       = sprintf( '<li><a href="#%1$s">%2$s</a>' . $meta . '</li>', $toc_id, $plugin_name );
 
-			$content .= '<div class="privacy-text-section' . $class . '">';
+			$content .= '<div class="privacy-text-section ' . $class . '">';
 			$content .= '<a id="' . $toc_id . '">&nbsp;</a>';
 			/* translators: %s: Plugin name. */
 			$content .= '<h2>' . sprintf( __( 'Source: %s' ), $plugin_name ) . '</h2>';
 			$content .= $removed;
 
 			$content .= '<div class="policy-text">' . $section['policy_text'] . '</div>';
-			$content .= $return_to_top;
+			$content .= '<a href="#" class="return-to-top">' . __( '&uarr; Return to Top' ) . '</a>';
 
 			if ( empty( $section['removed'] ) ) {
-				$content         .= '<div class="privacy-text-actions">';
-					$content     .= '<button type="button" class="privacy-text-copy button">';
-						$content .= $copy;
-						$content .= '<span class="screen-reader-text">';
-						/* translators: %s: Plugin name. */
-						$content .= sprintf( __( 'Copy suggested policy text from %s.' ), $plugin_name );
-						$content .= '</span>';
-					$content     .= '</button>';
-				$content         .= '</div>';
+				$content .= '<div class="privacy-text-actions">';
+				$content .= '<button type="button" class="privacy-text-copy button">';
+				$content .= __( 'Copy this section to clipboard' );
+				$content .= '<span class="screen-reader-text">';
+				/* translators: %s: Plugin name. */
+				$content .= sprintf( __( 'Copy suggested policy text from %s.' ), $plugin_name );
+				$content .= '</span>';
+				$content .= '</button>';
+				$content .= '<span class="success" aria-hidden="true">' . __( 'Copied!' ) . '</span>';
+				$content .= '</div>';
 			}
 
-			$content .= "</div>\n"; // End of .privacy-text-section.
+			$content .= "</div>"; // End of .privacy-text-section.
 		}
 
 		if ( count( $toc ) > 2 ) {
 			?>
-			<div  class="privacy-text-box-toc">
+			<div class="privacy-text-box-toc">
 				<p><?php _e( 'Table of Contents' ); ?></p>
 				<ol>
-					<?php echo implode( "\n", $toc ); ?>
+					<?php echo implode( $toc ); ?>
 				</ol>
 			</div>
 			<?php
Index: src/wp-includes/script-loader.php
===================================================================
--- src/wp-includes/script-loader.php	(revision 47433)
+++ src/wp-includes/script-loader.php	(working copy)
@@ -1417,7 +1417,7 @@
 		$scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-i18n' ), false, 1 );
 		$scripts->set_translations( 'site-health' );
 
-		$scripts->add( 'privacy-tools', "/wp-admin/js/privacy-tools$suffix.js", array( 'jquery' ), false, 1 );
+		$scripts->add( 'privacy-tools', "/wp-admin/js/privacy-tools$suffix.js", array( 'jquery', 'wp-a11y', 'wp-i18n' ), false, 1 );
 		did_action( 'init' ) && $scripts->localize(
 			'privacy-tools',
 			'privacyToolsL10n',
