diff --git src/wp-includes/class.wp-scripts.php src/wp-includes/class.wp-scripts.php
index a9299f0b91..873985cc9e 100644
--- src/wp-includes/class.wp-scripts.php
+++ src/wp-includes/class.wp-scripts.php
@@ -463,6 +463,81 @@ class WP_Scripts extends WP_Dependencies {
 		return parent::set_group( $handle, $recursion, $grp );
 	}
 
+	/**
+	 * Register a translation textdomain.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param string $handle Name of the script to register a translation domain to.
+	 * @param string $domain The textdomain.
+	 * @param string $path   Optional. The full file path to the directory containing translation files.
+	 *
+	 * @return bool True if the textdomain was registered, false if not.
+	 */
+	public function set_translations( $handle, $domain, $path = null ) {
+		if ( ! isset( $this->registered[ $handle ] ) ) {
+			return false;
+		}
+
+		/** @var \_WP_Dependency $obj */
+		$obj = $this->registered[ $handle ];
+
+		/** This filter is documented in wp-includes/class.wp-scripts.php */
+		$src = esc_url( apply_filters( 'script_loader_src', $obj->src, $handle ) );
+
+		$relative          = false;
+		$languages_path    = WP_LANG_DIR;
+		$json_translations = false;
+
+		// First see if the script is from the content directory.
+		$content_url = content_url();
+		if ( strpos( $content_url, $src ) === 0 ) {
+			// Make the src relative the specific plugin or theme.
+			$relative = trim( substr( $src, strlen( $content_url ) ), '/' );
+			$relative = explode( '/', $relative );
+
+			$languages_path = WP_LANG_DIR . '/' . $relative[0];
+
+			$relative = array_slice( $relative, 2 );
+			$relative = implode( '/', $relative );
+		} else {
+			// Otherwise check if it's from another WP directory.
+			$site_url = site_url();
+			if ( strpos( $site_url, $src ) === 0 ) {
+				// Make the src relative to the WP root.
+				$relative = substr( $src, strlen( $site_url ) );
+				$relative = trim( $relative, '/' );
+			}
+		}
+
+		// If the source is not from WP.
+		if ( false === $relative ) {
+			return false;
+		}
+
+		$locale = is_admin() ? get_locale() : get_user_locale();
+
+		$filename = $domain . '-' . $locale . '-' . md5( $relative ) . '.json';
+
+		// If a registered path was given check if a translation exists.
+		if ( $path && file_exists( $path . '/' . $filename ) ) {
+			$json_translations = file_get_contents( $path . '/' . $filename );
+		}
+
+		// Otherwise check if the translation exists in the languages path.
+		if ( ! $json_translations && file_exists( $languages_path . '/' . $filename ) ) {
+			$json_translations = file_get_contents( $languages_path . '/' . $filename );
+		}
+
+		if ( ! $json_translations ) {
+			return false;
+		}
+
+		$obj->deps[] = 'wp-i18n';
+
+		return $this->add_inline_script( $handle, 'wp.i18n.setLocaleData( ' . $json_translations . ', ' . $domain . ' );', 'before' );
+	}
+
 	/**
 	 * Determines script dependencies.
      *
diff --git src/wp-includes/functions.wp-scripts.php src/wp-includes/functions.wp-scripts.php
index dccaaf262a..dee66014d9 100644
--- src/wp-includes/functions.wp-scripts.php
+++ src/wp-includes/functions.wp-scripts.php
@@ -192,6 +192,33 @@ function wp_localize_script( $handle, $object_name, $l10n ) {
 	return $wp_scripts->localize( $handle, $object_name, $l10n );
 }
 
+/**
+ * Register translated strings for a script.
+ *
+ * Works only if the script has already been added.
+ *
+ * @see WP_Scripts::register_textdomain()
+ * @link https://core.trac.wordpress.org/ticket/45103
+ * @global WP_Scripts $wp_scripts The WP_Scripts object for printing scripts.
+ *
+ * @since 5.0.0
+ *
+ * @param string $handle Script handle the textdomain will be attached to.
+ * @param string $domain The textdomain.
+ * @param string $path   Optional. The full file path to the directory containing translation files.
+ *
+ * @return bool True if the textdomain was successfully localized, false otherwise.
+ */
+function wp_set_script_translations( $handle, $domain, $path = null ) {
+	global $wp_scripts;
+	if ( ! ( $wp_scripts instanceof WP_Scripts ) ) {
+		_wp_scripts_maybe_doing_it_wrong( __FUNCTION__ );
+		return false;
+	}
+
+	return $wp_scripts->set_translations( $handle, $domain, $path );
+}
+
 /**
  * Remove a registered script.
  *
