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' ),