diff --git wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc/cli/class-language-pack.php wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc/cli/class-language-pack.php
index 0252d9fe7..dd811ffcb 100644
--- wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc/cli/class-language-pack.php
+++ wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/inc/cli/class-language-pack.php
@@ -374,20 +374,77 @@ class Language_Pack extends WP_CLI_Command {
 	}
 
 	/**
-	 * Builds a PO file for translations.
+	 * Build a mapping of JS files to translation entries occurring in those files.
+	 * Translation entries occurring in other files are added to the 'po' key.
 	 *
-	 * @param GP_Project         $gp_project The GlotPress project.
-	 * @param GP_Locale          $gp_locale  The GlotPress locale.
-	 * @param GP_Translation_Set $set        The translation set.
-	 * @param string             $dest       Destination file name.
-	 * @return string|WP_Error Last updated date on success, WP_Error on failure.
+	 * @param Translation_Entry[] $entries The translation entries to map.
+	 *
+	 * @return array The mapping of sources to translation entries.
+	 */
+	private function build_mapping( $entries ) {
+		$mapping = array();
+		foreach ( $entries as $entry ) {
+			/** @var Translation_Entry $entry */
+
+			// Find all unique sources this translation originates from.
+			$sources = array_map( function ( $reference ) {
+				$parts = explode( ':', $reference );
+				$file  = $parts[0];
+
+				if ( substr( $file, -3 ) === '.js' ) {
+					return $file;
+				}
+				return 'po';
+			}, $entry->references );
+			$sources = array_unique( $sources );
+
+			foreach ( $sources as $source ) {
+				$mapping[ $source ][] = $entry;
+			}
+		}
+
+		return $mapping;
+	}
+
+	/**
+	 * Builds a mapping of JS file names to translation entries.
+	 *
+	 * @param GP_Project          $gp_project The GlotPress project.
+	 * @param GP_Locale           $gp_locale  The GlotPress locale.
+	 * @param GP_Translation_Set  $set        The translation set.
+	 * @param array               $mapping    A mapping of files to translation entries.
+	 * @param string              $base_dest  Destination file name.
+	 * @return array An array of translation files built, may be empty if no translations in JS files exist.
 	 */
-	private function build_po_file( $gp_project, $gp_locale, $set, $dest ) {
-		$entries = GP::$translation->for_export( $gp_project, $set, [ 'status' => 'current' ] );
-		if ( ! $entries ) {
-			return new WP_Error( 'no_translations', 'No current translations available.' );
+	private function build_json_files(  $gp_project, $gp_locale, $set, $mapping, $base_dest ) {
+		// Export translations for each JS file to a separate translation file.
+		$files  = array();
+		$format = gp_array_get( GP::$formats, 'jed1x' );
+		foreach ( $mapping as $file => $entries ) {
+			$json_content = $format->print_exported_file( $gp_project, $gp_locale, $set, $entries );
+
+			$hash = md5( $file );
+			$dest = "{$base_dest}-{$hash}.json";
+
+			file_put_contents( $dest, $json_content );
+
+			$files[] = $dest;
 		}
 
+		return $files;
+	}
+
+	/**
+	 * Builds a PO file for translations.
+	 *
+	 * @param GP_Project          $gp_project The GlotPress project.
+	 * @param GP_Locale           $gp_locale  The GlotPress locale.
+	 * @param GP_Translation_Set  $set        The translation set.
+	 * @param Translation_Entry[] $entries    The translation entries.
+	 * @param string              $dest       Destination file name.
+	 * @return string|WP_Error Last updated date on success, WP_Error on failure.
+	 */
+	private function build_po_file( $gp_project, $gp_locale, $set, $entries, $dest ) {
 		$format     = gp_array_get( GP::$formats, 'po' );
 		$po_content = $format->print_exported_file( $gp_project, $gp_locale, $set, $entries );
 
@@ -523,6 +580,7 @@ class Language_Pack extends WP_CLI_Command {
 			$export_directory = "{$data->svn_checkout}/{$data->domain}/{$data->version}/{$wp_locale}";
 			$build_directory  = self::BUILD_DIR . "/{$data->type}s/{$data->domain}/{$data->version}";
 			$filename         = "{$data->domain}-{$wp_locale}";
+			$json_file_base   = "{$export_directory}/{$filename}";
 			$po_file          = "{$export_directory}/{$filename}.po";
 			$mo_file          = "{$export_directory}/{$filename}.mo";
 			$zip_file         = "{$export_directory}/{$filename}.zip";
@@ -531,8 +589,24 @@ class Language_Pack extends WP_CLI_Command {
 			// Update/create directories.
 			$this->update_svn_directory( $export_directory );
 
+			$entries = GP::$translation->for_export( $data->gp_project, $set, [ 'status' => 'current' ] );
+			if ( ! $entries ) {
+				WP_CLI::warning( "No current translations available for {$wp_locale}." );
+
+				continue;
+			}
+
+			// Build a mapping based on where the translation entries occur and separate the po entries.
+			$mapping    = $this->build_mapping( $entries );
+			$po_entries = array_key_exists( 'po', $mapping ) ? $mapping['po'] : array();
+
+			unset( $mapping['po'] );
+
+			// Create JED json files for each JS file.
+			$json_files = $this->build_json_files( $data->gp_project, $gp_locale, $set, $mapping, $json_file_base );
+
 			// Create PO file.
-			$last_modified = $this->build_po_file( $data->gp_project, $gp_locale, $set, $po_file );
+			$last_modified = $this->build_po_file( $data->gp_project, $gp_locale, $set, $po_entries, $po_file );
 
 			if ( is_wp_error( $last_modified ) ) {
 				WP_CLI::warning( sprintf( "PO generation for {$wp_locale} failed: %s", $last_modified->get_error_message() ) );
@@ -562,10 +636,11 @@ class Language_Pack extends WP_CLI_Command {
 
 			// Create ZIP file.
 			$result = $this->execute_command( sprintf(
-				'zip -9 -j %s %s %s 2>&1',
+				'zip -9 -j %s %s %s %s 2>&1',
 				escapeshellarg( $zip_file ),
 				escapeshellarg( $po_file ),
-				escapeshellarg( $mo_file )
+				escapeshellarg( $mo_file ),
+				implode( ' ', array_map( 'escapeshellarg', $json_files ) )
 			) );
 
 			if ( is_wp_error( $result ) ) {
