diff --git a/src/wp-includes/class-wp-textdomain-registry.php b/src/wp-includes/class-wp-textdomain-registry.php
index b2cbd72fa5..113ef3bd65 100644
--- a/src/wp-includes/class-wp-textdomain-registry.php
+++ b/src/wp-includes/class-wp-textdomain-registry.php
@@ -314,6 +314,7 @@ class WP_Textdomain_Registry {
if ( $file_path === $mo_path || $file_path === $php_path ) {
$found_location = rtrim( $location, '/' ) . '/';
+ break 2;
}
}
}
diff --git a/src/wp-includes/l10n.php b/src/wp-includes/l10n.php
index 8191b88cee..38c30b84e8 100644
--- a/src/wp-includes/l10n.php
+++ b/src/wp-includes/l10n.php
@@ -1435,19 +1435,20 @@ function translate_user_role( $name, $domain = 'default' ) {
}
/**
- * Gets all available languages based on the presence of *.mo files in a given directory.
+ * Gets all available languages based on the presence of *.mo and *.l10n.php files in a given directory.
*
* The default directory is WP_LANG_DIR.
*
* @since 3.0.0
* @since 4.7.0 The results are now filterable with the {@see 'get_available_languages'} filter.
+ * @since 6.5.0 The initial file list is now cached and also takes into account *.l10n.php files.
*
* @global WP_Textdomain_Registry $wp_textdomain_registry WordPress Textdomain Registry.
*
* @param string $dir A directory to search for language files.
* Default WP_LANG_DIR.
* @return string[] An array of language codes or an empty array if no languages are present.
- * Language codes are formed by stripping the .mo extension from the language file names.
+ * Language codes are formed by stripping the file extension from the language file names.
*/
function get_available_languages( $dir = null ) {
global $wp_textdomain_registry;
@@ -1460,6 +1461,8 @@ function get_available_languages( $dir = null ) {
if ( $lang_files ) {
foreach ( $lang_files as $lang_file ) {
$lang_file = basename( $lang_file, '.mo' );
+ $lang_file = basename( $lang_file, '.l10n.php' );
+
if ( ! str_starts_with( $lang_file, 'continents-cities' ) && ! str_starts_with( $lang_file, 'ms-' ) &&
! str_starts_with( $lang_file, 'admin-' ) ) {
$languages[] = $lang_file;
@@ -1475,7 +1478,7 @@ function get_available_languages( $dir = null ) {
* @param string[] $languages An array of available language codes.
* @param string $dir The directory where the language files were found.
*/
- return apply_filters( 'get_available_languages', $languages, $dir );
+ return apply_filters( 'get_available_languages', array_unique( $languages ), $dir );
}
/**
diff --git a/tests/phpunit/data/languages/admin-en_GB.l10n.php b/tests/phpunit/data/languages/admin-en_GB.l10n.php
new file mode 100644
index 0000000000..ca1d62f663
--- /dev/null
+++ b/tests/phpunit/data/languages/admin-en_GB.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['Thank you for updating! WordPress %s makes your site more connected and responsive.'=>'Thank you for updating! WordPress %s makes your site more connected and responsive.','New %1$s, %2$s, and %3$s objects make interacting with terms, comments, and networks more predictable and intuitive in code.'=>'New %1$s, %2$s, and %3$s objects make interacting with terms, comments, and networks more predictable and intuitive in code.','Comment queries now have cache handling to improve performance. New arguments in %s make crafting robust comment queries simpler.'=>'Comment queries now have cache handling to improve performance. New arguments in %s make crafting robust comment queries simpler.','Term, comment, and network objects'=>'Term, comment, and network objects','Comment query improvements'=>'Comment query improvements'],'language'=>'en_GB','x-generator'=>'Poedit 1.8.10'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/admin-es_ES.l10n.php b/tests/phpunit/data/languages/admin-es_ES.l10n.php
new file mode 100644
index 0000000000..27df773c21
--- /dev/null
+++ b/tests/phpunit/data/languages/admin-es_ES.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['Thank you for updating! WordPress %s makes your site more connected and responsive.'=>'¡Gracias por actualizar! WordPress %s hace que tu sitio esté más conectado y sea más adaptable.','New %1$s, %2$s, and %3$s objects make interacting with terms, comments, and networks more predictable and intuitive in code.'=>'Ahora los objetos %1$s, %2$s y %3$s hacen que interactuar con términos, comentarios y redes sea más predecible y que el código sea más intuitivo.','Comment queries now have cache handling to improve performance. New arguments in %s make crafting robust comment queries simpler.'=>'Las consultas de comentarios ahora tiene una caché que mejora el rendimiento. Nuevos argumentos en %s hacen que sea más fácil crear consultas robustas.','Term, comment, and network objects'=>'Objetos de término, comentario y red','Comment query improvements'=>'Mejoras en las consultas de comentarios'],'language'=>'es_ES','x-generator'=>'Poedit 1.8.10'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/admin-network-en_GB.l10n.php b/tests/phpunit/data/languages/admin-network-en_GB.l10n.php
new file mode 100644
index 0000000000..05171a7e49
--- /dev/null
+++ b/tests/phpunit/data/languages/admin-network-en_GB.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['A password reset link will be sent to the user via email.'=>'A password reset link will be sent to the user via email.','If registration is disabled, please set %1$s in %2$s to a URL you will redirect visitors to if they visit a non-existent site.'=>'If registration is disabled, please set %1$s in %2$s to a URL you will redirect visitors to if they visit a non-existent site.','Site users list'=>'Site users list','Site users list navigation'=>'Site users list navigation','Sites list'=>'Sites list'],'language'=>'en_GB','x-generator'=>'Poedit 1.8.10'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/admin-network-es_ES.l10n.php b/tests/phpunit/data/languages/admin-network-es_ES.l10n.php
new file mode 100644
index 0000000000..0e8f9d4fad
--- /dev/null
+++ b/tests/phpunit/data/languages/admin-network-es_ES.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['A password reset link will be sent to the user via email.'=>'Se te enviará un enlace por email para que puedas cambiar la contraseña.','If registration is disabled, please set %1$s in %2$s to a URL you will redirect visitors to if they visit a non-existent site.'=>'Si el registro de usuarios está desactivado , establece como valor de %1$s en %2$s una URL donde redirigir a los visitantes que accedan a un sitio inexistente.','Site users list navigation'=>'Navegación por la lista de usuarios del sitio','Site users list'=>'Lista de usuarios del sitio','Sites list navigation'=>'Navegación por la lista de sitios'],'language'=>'es_ES','x-generator'=>'Poedit 1.8.10'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/continents-cities-es_ES.l10n.php b/tests/phpunit/data/languages/continents-cities-es_ES.l10n.php
new file mode 100644
index 0000000000..11a692aa5d
--- /dev/null
+++ b/tests/phpunit/data/languages/continents-cities-es_ES.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['Vincennes'=>'Vincennes','Winamac'=>'Winamac','Inuvik'=>'Inuvik','Iqaluit'=>'Iqaluit','Jamaica'=>'Jamaica'],'language'=>'es_ES','x-generator'=>'Poedit 1.8.10'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/de_DE.l10n.php b/tests/phpunit/data/languages/de_DE.l10n.php
new file mode 100644
index 0000000000..8eef01d79c
--- /dev/null
+++ b/tests/phpunit/data/languages/de_DE.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['html_lang_attribute'=>'de-DE','text directionltr'=>'ltr','number_format_decimal_point'=>',','number_format_thousands_sep'=>'.','Update %s now'=>'Jetzt %s aktualisieren','[%1$s] Confirm Action: %2$s'=>'[%1$s] Aktion bestätigen: %2$s','[%s] Erasure Request Fulfilled'=>'[%s] Löschauftrag ausgeführt','[%s] Personal Data Export'=>'[%s] Export personenbezogener Daten'],'language'=>'de_DE','x-generator'=>'Poedit 2.2.1'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/en_GB.l10n.php b/tests/phpunit/data/languages/en_GB.l10n.php
new file mode 100644
index 0000000000..265e1f670f
--- /dev/null
+++ b/tests/phpunit/data/languages/en_GB.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['text directionltr'=>'ltr','ERROR: Sorry, that username is not allowed.'=>'ERROR: Sorry, that username is not allowed.','Invalid parameter.'=>'Invalid parameter.','menu location(Current: %s)'=>'(Current: %s)','menu(Currently set to: %s)'=>'(Currently set to: %s)'],'language'=>'en_GB','x-generator'=>'Poedit 1.8.10'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/es_ES.l10n.php b/tests/phpunit/data/languages/es_ES.l10n.php
new file mode 100644
index 0000000000..827f1f766b
--- /dev/null
+++ b/tests/phpunit/data/languages/es_ES.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['text directionltr'=>'ltr','ERROR: Sorry, that username is not allowed.'=>'ERROR: Lo siento, ese nombre de usuario no está permitido.','Invalid parameter.'=>'Parámetro no válido. ','menu location(Current: %s)'=>'(Actual: %s)','menu(Currently set to: %s)'=>'(Actualmente fijado en: %s)','[%1$s] Confirm Action: %2$s'=>'[%1$s] Confirmar la acción: %2$s','[%s] Erasure Request Fulfilled'=>'[%s] Solicitud de borrado completada','[%s] Personal Data Export'=>'[%s] Exportación de datos personales'],'language'=>'es_ES','x-generator'=>'Poedit 2.3'];
\ No newline at end of file
diff --git a/tests/phpunit/data/languages/ja_JP.l10n.php b/tests/phpunit/data/languages/ja_JP.l10n.php
new file mode 100644
index 0000000000..e8872714ac
--- /dev/null
+++ b/tests/phpunit/data/languages/ja_JP.l10n.php
@@ -0,0 +1,2 @@
+NULL,'plural-forms'=>'nplurals=2; plural=n != 1;','messages'=>['html_lang_attribute'=>'ja','text directionltr'=>'ltr','number_format_decimal_point'=>'number_format_decimal_point','number_format_thousands_sep'=>'number_format_thousands_sep','Update %s now'=>'今すぐ %s を更新','Word count type. Do not translate!words'=>'characters_including_spaces','excerpt_length55'=>'110','comment_excerpt_length20'=>'40','draft_length10'=>'40'],'language'=>'ja_JP','x-generator'=>'Poedit 1.8.10'];
\ No newline at end of file