Index: /trunk/src/wp-includes/class-wp-locale.php
===================================================================
--- /trunk/src/wp-includes/class-wp-locale.php	(revision 64231)
+++ /trunk/src/wp-includes/class-wp-locale.php	(revision 64232)
@@ -443,4 +443,6 @@
 	 * @return string Localized word count type. Possible values are `characters_excluding_spaces`,
 	 *                `characters_including_spaces`, or `words`. Defaults to `words`.
+	 *
+	 * @phpstan-return 'characters_excluding_spaces'|'characters_including_spaces'|'words'
 	 */
 	public function get_word_count_type() {
Index: /trunk/src/wp-includes/l10n.php
===================================================================
--- /trunk/src/wp-includes/l10n.php	(revision 64231)
+++ /trunk/src/wp-includes/l10n.php	(revision 64232)
@@ -333,4 +333,7 @@
  *                       Default 'default'.
  * @return string Translated text.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $domain
  */
 function __( $text, $domain = 'default' ) {
@@ -349,4 +352,7 @@
  *                       Default 'default'.
  * @return string Translated text on success, original text on failure.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $domain
  */
 function esc_attr__( $text, $domain = 'default' ) {
@@ -366,4 +372,7 @@
  *                       Default 'default'.
  * @return string Translated text.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $domain
  */
 function esc_html__( $text, $domain = 'default' ) {
@@ -379,4 +388,7 @@
  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
  *                       Default 'default'.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $domain
  */
 function _e( $text, $domain = 'default' ) {
@@ -397,4 +409,7 @@
  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
  *                       Default 'default'.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $domain
  */
 function esc_attr_e( $text, $domain = 'default' ) {
@@ -415,4 +430,7 @@
  * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
  *                       Default 'default'.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $domain
  */
 function esc_html_e( $text, $domain = 'default' ) {
@@ -436,4 +454,8 @@
  *                        Default 'default'.
  * @return string Translated context string without pipe.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $context
+ * @phpstan-param literal-string $domain
  */
 function _x( $text, $context, $domain = 'default' ) {
@@ -450,4 +472,8 @@
  * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
  *                        Default 'default'.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $context
+ * @phpstan-param literal-string $domain
  */
 function _ex( $text, $context, $domain = 'default' ) {
@@ -468,4 +494,8 @@
  *                        Default 'default'.
  * @return string Translated text.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $context
+ * @phpstan-param literal-string $domain
  */
 function esc_attr_x( $text, $context, $domain = 'default' ) {
@@ -486,4 +516,8 @@
  *                        Default 'default'.
  * @return string Translated text.
+ *
+ * @phpstan-param literal-string $text
+ * @phpstan-param literal-string $context
+ * @phpstan-param literal-string $domain
  */
 function esc_html_x( $text, $context, $domain = 'default' ) {
@@ -510,4 +544,8 @@
  *                       Default 'default'.
  * @return string The translated singular or plural form.
+ *
+ * @phpstan-param literal-string $single
+ * @phpstan-param literal-string $plural
+ * @phpstan-param literal-string $domain
  */
 function _n( $single, $plural, $number, $domain = 'default' ) {
@@ -569,4 +607,9 @@
  *                        Default 'default'.
  * @return string The translated singular or plural form.
+ *
+ * @phpstan-param literal-string $single
+ * @phpstan-param literal-string $plural
+ * @phpstan-param literal-string $context
+ * @phpstan-param literal-string $domain
  */
 function _nx( $single, $plural, $number, $context, $domain = 'default' ) {
@@ -634,4 +677,16 @@
  *     @type null        $context  Context information for the translators.
  *     @type string|null $domain   Text domain.
+ * }
+ *
+ * @phpstan-param literal-string $singular
+ * @phpstan-param literal-string $plural
+ * @phpstan-param literal-string|null $domain
+ * @phpstan-return array{
+ *     0: literal-string,
+ *     1: literal-string,
+ *     singular: literal-string,
+ *     plural: literal-string,
+ *     context: null,
+ *     domain: literal-string|null,
  * }
  */
@@ -680,4 +735,18 @@
  *     @type string      $context  Context information for the translators.
  *     @type string|null $domain   Text domain.
+ * }
+ *
+ * @phpstan-param literal-string $singular
+ * @phpstan-param literal-string $plural
+ * @phpstan-param literal-string $context
+ * @phpstan-param literal-string|null $domain
+ * @phpstan-return array{
+ *     0: literal-string,
+ *     1: literal-string,
+ *     2: literal-string,
+ *     singular: literal-string,
+ *     plural: literal-string,
+ *     context: literal-string,
+ *     domain: literal-string|null,
  * }
  */
@@ -720,4 +789,13 @@
  *                              a text domain passed to _n_noop() or _nx_noop(), it will override this value. Default 'default'.
  * @return string Either $singular or $plural translated text.
+ *
+ * @phpstan-param array{
+ *     singular: literal-string,
+ *     plural: literal-string,
+ *     context: literal-string|null,
+ *     domain: literal-string|null,
+ *     ...
+ * } $nooped_plural
+ * @phpstan-param literal-string $domain
  */
 function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {
@@ -745,7 +823,7 @@
  * @since 6.1.0 Added the `$locale` parameter.
  *
- * @global MO[]                   $l10n                   An array of all currently loaded text domains.
- * @global MO[]                   $l10n_unloaded          An array of all text domains that have been unloaded again.
- * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
+ * @global array<string, WP_Translations|NOOP_Translations|MO> $l10n                   An array of all currently loaded text domains.
+ * @global array<string, true>                                 $l10n_unloaded          An array of all text domains that have been unloaded again.
+ * @global WP_Textdomain_Registry                              $wp_textdomain_registry WordPress Textdomain Registry.
  *
  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
@@ -755,5 +833,4 @@
  */
 function load_textdomain( $domain, $mofile, $locale = null ) {
-	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
 	global $l10n, $l10n_unloaded, $wp_textdomain_registry;
 
@@ -900,6 +977,6 @@
  * @since 6.1.0 Added the `$reloadable` parameter.
  *
- * @global MO[] $l10n          An array of all currently loaded text domains.
- * @global MO[] $l10n_unloaded An array of all text domains that have been unloaded again.
+ * @global array<string, WP_Translations|NOOP_Translations|MO> $l10n          An array of all currently loaded text domains.
+ * @global array<string, true>                                 $l10n_unloaded An array of all text domains that have been unloaded again.
  *
  * @param string $domain     Text domain. Unique identifier for retrieving translated strings.
@@ -1017,6 +1094,6 @@
  * @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
  *
- * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
- * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
+ * @global WP_Textdomain_Registry                              $wp_textdomain_registry WordPress Textdomain Registry.
+ * @global array<string, WP_Translations|NOOP_Translations|MO> $l10n                   An array of all currently loaded text domains.
  *
  * @param string       $domain          Unique identifier for retrieving translated strings
@@ -1030,6 +1107,4 @@
  */
 function load_plugin_textdomain( $domain, $deprecated = false, $plugin_rel_path = false ) {
-	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
-	/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
 	global $wp_textdomain_registry, $l10n;
 
@@ -1064,6 +1139,6 @@
  * @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
  *
- * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
- * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
+ * @global WP_Textdomain_Registry                              $wp_textdomain_registry WordPress Textdomain Registry.
+ * @global array<string, WP_Translations|NOOP_Translations|MO> $l10n                   An array of all currently loaded text domains.
  *
  * @param string $domain             Text domain. Unique identifier for retrieving translated strings.
@@ -1073,6 +1148,4 @@
  */
 function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
-	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
-	/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
 	global $wp_textdomain_registry, $l10n;
 
@@ -1105,6 +1178,6 @@
  * @since 6.7.0 Translations are no longer immediately loaded, but handed off to the just-in-time loading mechanism.
  *
- * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
- * @global array<string, WP_Translations|NOOP_Translations> $l10n An array of all currently loaded text domains.
+ * @global WP_Textdomain_Registry                              $wp_textdomain_registry WordPress Textdomain Registry.
+ * @global array<string, WP_Translations|NOOP_Translations|MO> $l10n                   An array of all currently loaded text domains.
  *
  * @param string       $domain Text domain. Unique identifier for retrieving translated strings.
@@ -1114,6 +1187,4 @@
  */
 function load_theme_textdomain( $domain, $path = false ) {
-	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
-	/** @var array<string, WP_Translations|NOOP_Translations> $l10n */
 	global $wp_textdomain_registry, $l10n;
 
@@ -1239,5 +1310,4 @@
  */
 function _load_script_textdomain_from_src( string $handle, string $src, string $domain, string $path, bool $is_module ) {
-	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
 	global $wp_textdomain_registry;
 
@@ -1447,5 +1517,5 @@
  * @access private
  *
- * @global MO[]                   $l10n_unloaded          An array of all text domains that have been unloaded again.
+ * @global array<string, true>    $l10n_unloaded          An array of all text domains that have been unloaded again.
  * @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
  *
@@ -1454,5 +1524,4 @@
  */
 function _load_textdomain_just_in_time( $domain ) {
-	/** @var WP_Textdomain_Registry $wp_textdomain_registry */
 	global $l10n_unloaded, $wp_textdomain_registry;
 
@@ -1506,8 +1575,8 @@
  * @since 2.8.0
  *
- * @global MO[] $l10n An array of all currently loaded text domains.
+ * @global array<string, WP_Translations|NOOP_Translations|MO> $l10n An array of all currently loaded text domains.
  *
  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
- * @return Translations|NOOP_Translations A Translations instance.
+ * @return WP_Translations|Translations|NOOP_Translations A Translations instance.
  */
 function get_translations_for_domain( $domain ) {
@@ -1532,5 +1601,5 @@
  * @since 3.0.0
  *
- * @global MO[] $l10n An array of all currently loaded text domains.
+ * @global array<string, WP_Translations|NOOP_Translations|MO> $l10n An array of all currently loaded text domains.
  *
  * @param string $domain Text domain. Unique identifier for retrieving translated strings.
@@ -1624,5 +1693,18 @@
  *
  * @param string $type What to search for. Accepts 'plugins', 'themes', 'core'.
- * @return array Array of language data.
+ * @return array<string, array<string, array<string, string>>> Array of language data, keyed by text domain
+ *                                                             and then by locale, each value being the
+ *                                                             translation file headers.
+ *
+ * @phpstan-return (
+ *     $type is 'plugins'|'themes'|'core'
+ *         ? array<string, array<string, array{
+ *             'POT-Creation-Date': string,
+ *             'PO-Revision-Date': string,
+ *             'Project-Id-Version': string,
+ *             'X-Generator': string,
+ *         }>>
+ *         : array{}
+ * )
  */
 function wp_get_installed_translations( $type ) {
@@ -1684,5 +1766,12 @@
  *
  * @param string $po_file Path to PO file.
- * @return string[] Array of PO file header values keyed by header name.
+ * @return array<string, string> Array of PO file header values keyed by header name.
+ *
+ * @phpstan-return array{
+ *     'POT-Creation-Date': string,
+ *     'PO-Revision-Date': string,
+ *     'Project-Id-Version': string,
+ *     'X-Generator': string,
+ * }
  */
 function wp_get_pomo_file_data( $po_file ) {
@@ -1696,9 +1785,27 @@
 		)
 	);
-	foreach ( $headers as $header => $value ) {
-		// Remove possible contextual '\n' and closing double quote.
-		$headers[ $header ] = preg_replace( '~(\\\n)?"$~', '', $value );
-	}
-	return $headers;
+
+	$result = array(
+		'POT-Creation-Date'  => '',
+		'PO-Revision-Date'   => '',
+		'Project-Id-Version' => '',
+		'X-Generator'        => '',
+	);
+
+	foreach ( array_keys( $result ) as $header ) {
+		$value = $headers[ $header ];
+
+		// Remove possible closing double quote and the contextual '\n' preceding it.
+		if ( str_ends_with( $value, '"' ) ) {
+			$value = substr( $value, 0, -1 );
+			if ( str_ends_with( $value, '\n' ) ) {
+				$value = substr( $value, 0, -2 );
+			}
+		}
+
+		$result[ $header ] = $value;
+	}
+
+	return $result;
 }
 
@@ -1709,5 +1816,12 @@
  *
  * @param string $php_file Path to a `.l10n.php` file.
- * @return string[] Array of file header values keyed by header name.
+ * @return array<string, string> Array of file header values keyed by header name.
+ *
+ * @phpstan-return array{
+ *     'POT-Creation-Date': string,
+ *     'PO-Revision-Date': string,
+ *     'Project-Id-Version': string,
+ *     'X-Generator': string,
+ * }
  */
 function wp_get_l10n_php_file_data( $php_file ) {
@@ -1730,5 +1844,5 @@
 
 	foreach ( $headers as $po_header => $php_header ) {
-		if ( isset( $data[ $php_header ] ) ) {
+		if ( isset( $data[ $php_header ] ) && is_string( $data[ $php_header ] ) ) {
 			$result[ $po_header ] = $data[ $php_header ];
 		}
@@ -2099,4 +2213,6 @@
  * @return string Locale-specific word count type. Possible values are `characters_excluding_spaces`,
  *                `characters_including_spaces`, or `words`. Defaults to `words`.
+ *
+ * @phpstan-return 'characters_excluding_spaces'|'characters_including_spaces'|'words'
  */
 function wp_get_word_count_type() {
