diff --git a/src/js/_enqueues/wp/customize/controls.js b/src/js/_enqueues/wp/customize/controls.js
index bc72f589c7203..8bfcf3912b89d 100644
--- a/src/js/_enqueues/wp/customize/controls.js
+++ b/src/js/_enqueues/wp/customize/controls.js
@@ -2,7 +2,7 @@
* @output wp-admin/js/customize-controls.js
*/
-/* global _wpCustomizeHeader, _wpCustomizeBackground, _wpMediaViewsL10n, MediaElementPlayer, console, confirm */
+/* global _, _wpCustomizeHeader, _wpCustomizeBackground, _wpMediaViewsL10n, MediaElementPlayer, console, confirm */
(function( exports, $ ){
var Container, focus, normalizedTransitionendEventName, api = wp.customize;
@@ -2136,7 +2136,16 @@
}
});
if ( 'local' !== section.params.filter_type ) {
- wp.a11y.speak( api.settings.l10n.themeSearchResults.replace( '%d', data.info.results ) );
+ wp.a11y.speak(
+ wp.i18n.sprintf(
+ wp.i18n._n(
+ '%d theme found',
+ '%d themes found',
+ data.info.results
+ ),
+ data.info.results
+ )
+ );
}
}
@@ -2440,28 +2449,45 @@
*
* @since 4.9.0
*
+ * @param {number} count New theme count.
* @return {void}
*/
updateCount: function( count ) {
- var section = this, countEl, displayed;
+ var section = this, i18n = wp.i18n, countHtml, displayed;
if ( ! count && 0 !== count ) {
count = section.getVisibleCount();
}
displayed = section.contentContainer.find( '.themes-displayed' );
- countEl = section.contentContainer.find( '.theme-count' );
+ countHtml = i18n.sprintf(
+ i18n._n(
+ '%s theme',
+ '%s themes',
+ count
+ ),
+ '' + count + ''
+ );
if ( 0 === count ) {
- countEl.text( '0' );
+ displayed.html( countHtml );
} else {
// Animate the count change for emphasis.
displayed.fadeOut( 180, function() {
- countEl.text( count );
+ displayed.html( countHtml );
displayed.fadeIn( 180 );
} );
- wp.a11y.speak( api.settings.l10n.announceThemeCount.replace( '%d', count ) );
+ wp.a11y.speak(
+ i18n.sprintf(
+ i18n._n(
+ 'Displaying %d theme',
+ 'Displaying %d themes',
+ count
+ ),
+ count
+ )
+ );
}
},
@@ -5519,11 +5545,15 @@
control.setting.notifications.remove( 'csslint_error' );
if ( 0 !== errorAnnotations.length ) {
- if ( 1 === errorAnnotations.length ) {
- message = api.l10n.customCssError.singular.replace( '%d', '1' );
- } else {
- message = api.l10n.customCssError.plural.replace( '%d', String( errorAnnotations.length ) );
- }
+ message = wp.i18n.sprintf(
+ wp.i18n._n(
+ 'There is %d error which must be fixed before you can save.',
+ 'There are %d errors which must be fixed before you can save.',
+ errorAnnotations.length
+ ),
+ errorAnnotations.length
+ );
+
control.setting.notifications.add( new api.Notification( 'csslint_error', {
message: message,
type: 'error'
@@ -7546,7 +7576,14 @@
if ( invalidSettings.length ) {
api.notifications.add( new api.Notification( errorCode, {
- message: ( 1 === invalidSettings.length ? api.l10n.saveBlockedError.singular : api.l10n.saveBlockedError.plural ).replace( /%s/g, String( invalidSettings.length ) ),
+ message: wp.i18n.sprintf(
+ wp.i18n._n(
+ 'Unable to save due to %s invalid setting.',
+ 'Unable to save due to %s invalid settings.',
+ invalidSettings.length
+ ),
+ invalidSettings.length
+ ),
type: 'error',
dismissible: true,
saveFailure: true
diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php
index 6a656808ae5a1..ace59d78f43fc 100644
--- a/src/wp-includes/class-wp-customize-manager.php
+++ b/src/wp-includes/class-wp-customize-manager.php
@@ -4948,15 +4948,17 @@ public function customize_pane_settings() {
'previewableDevices' => $this->get_previewable_devices(),
'l10n' => array(
'confirmDeleteTheme' => __( 'Are you sure you want to delete this theme?' ),
- /* translators: %d: Number of theme search results, which cannot currently consider singular vs. plural forms. */
- 'themeSearchResults' => __( '%d themes found' ),
- /* translators: %d: Number of themes being displayed, which cannot currently consider singular vs. plural forms. */
- 'announceThemeCount' => __( 'Displaying %d themes' ),
/* translators: %s: Theme name. */
'announceThemeDetails' => __( 'Showing details for theme: %s' ),
),
);
+ // These strings are here for backwards compatibility; the translations now occur in JavaScript.
+ /* translators: %d: Number of theme search results. Note there is a newer translation of this string with singular and plural forms. */
+ $settings['l10n']['themeSearchResults'] = __( '%d themes found' );
+ /* translators: %d: Number of themes being displayed. Note there is a newer translation of this string with singular and plural forms. */
+ $settings['l10n']['announceThemeCount'] = __( 'Displaying %d themes' );
+
// Temporarily disable installation in Customizer. See #42184.
$filesystem_method = get_filesystem_method();
ob_start();
diff --git a/src/wp-includes/customize/class-wp-customize-themes-section.php b/src/wp-includes/customize/class-wp-customize-themes-section.php
index 64c36c9099e5c..d57d639dfaf76 100644
--- a/src/wp-includes/customize/class-wp-customize-themes-section.php
+++ b/src/wp-includes/customize/class-wp-customize-themes-section.php
@@ -166,7 +166,7 @@ protected function filter_bar_content_template() {
0' );
+ printf( _n( '%s theme', '%s themes', 0 ), '0' );
?>
diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
index 54193c841c7c3..9ef6b79a97393 100644
--- a/src/wp-includes/script-loader.php
+++ b/src/wp-includes/script-loader.php
@@ -1283,7 +1283,7 @@ function wp_default_scripts( $scripts ) {
$scripts->add( 'customize-preview', "/wp-includes/js/customize-preview$suffix.js", array( 'wp-a11y', 'customize-base' ), false, 1 );
$scripts->add( 'customize-models', '/wp-includes/js/customize-models.js', array( 'underscore', 'backbone' ), false, 1 );
$scripts->add( 'customize-views', '/wp-includes/js/customize-views.js', array( 'jquery', 'underscore', 'imgareaselect', 'customize-models', 'media-editor', 'media-views' ), false, 1 );
- $scripts->add( 'customize-controls', "/wp-admin/js/customize-controls$suffix.js", array( 'customize-base', 'wp-a11y', 'wp-util', 'jquery-ui-core' ), false, 1 );
+ $scripts->add( 'customize-controls', "/wp-admin/js/customize-controls$suffix.js", array( 'customize-base', 'wp-a11y', 'wp-i18n', 'wp-util', 'jquery-ui-core' ), false, 1 );
did_action( 'init' ) && $scripts->localize(
'customize-controls',
'_wpCustomizeControlsL10n',
@@ -1326,31 +1326,30 @@ function wp_default_scripts( $scripts ) {
'videoHeaderNotice' => __( 'This theme does not support video headers on this page. Navigate to the front page or another page that supports video headers.' ),
// Used for overriding the file types allowed in Plupload.
'allowedFiles' => __( 'Allowed Files' ),
+ 'pageOnFrontError' => __( 'Homepage and posts page must be different.' ),
+ 'scheduleDescription' => __( 'Schedule your customization changes to publish ("go live") at a future date.' ),
+ 'themePreviewUnavailable' => __( 'Sorry, you cannot preview new themes when you have changes scheduled or saved as a draft. Please publish your changes, or wait until they publish to preview new themes.' ),
+ 'themeInstallUnavailable' => sprintf(
+ /* translators: %s: URL to Add Themes admin screen. */
+ __( 'You will not be able to install new themes from here yet since your install requires SFTP credentials. For now, please add themes in the admin.' ),
+ esc_url( admin_url( 'theme-install.php' ) )
+ ),
+ 'publishSettings' => __( 'Publish Settings' ),
+ 'invalidDate' => __( 'Invalid date.' ),
+ 'invalidValue' => __( 'Invalid value.' ),
+ // These strings are here for backwards compatibility; the translations now occur in JavaScript.
'customCssError' => array(
/* translators: %d: Error count. */
'singular' => _n( 'There is %d error which must be fixed before you can save.', 'There are %d errors which must be fixed before you can save.', 1 ),
/* translators: %d: Error count. */
'plural' => _n( 'There is %d error which must be fixed before you can save.', 'There are %d errors which must be fixed before you can save.', 2 ),
- // @todo This is lacking, as some languages have a dedicated dual form. For proper handling of plurals in JS, see #20491.
),
- 'pageOnFrontError' => __( 'Homepage and posts page must be different.' ),
'saveBlockedError' => array(
/* translators: %s: Number of invalid settings. */
'singular' => _n( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.', 1 ),
/* translators: %s: Number of invalid settings. */
'plural' => _n( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.', 2 ),
- // @todo This is lacking, as some languages have a dedicated dual form. For proper handling of plurals in JS, see #20491.
),
- 'scheduleDescription' => __( 'Schedule your customization changes to publish ("go live") at a future date.' ),
- 'themePreviewUnavailable' => __( 'Sorry, you cannot preview new themes when you have changes scheduled or saved as a draft. Please publish your changes, or wait until they publish to preview new themes.' ),
- 'themeInstallUnavailable' => sprintf(
- /* translators: %s: URL to Add Themes admin screen. */
- __( 'You will not be able to install new themes from here yet since your install requires SFTP credentials. For now, please add themes in the admin.' ),
- esc_url( admin_url( 'theme-install.php' ) )
- ),
- 'publishSettings' => __( 'Publish Settings' ),
- 'invalidDate' => __( 'Invalid date.' ),
- 'invalidValue' => __( 'Invalid value.' ),
'blockThemeNotification' => sprintf(
/* translators: 1: Link to Site Editor documentation on HelpHub, 2: HTML button. */
__( 'Hurray! Your theme supports site editing with blocks. Tell me more. %2$s' ),