From c3b40f7f80daceb2d4d80251d1d09a4fdd84e0e5 Mon Sep 17 00:00:00 2001 From: TimothyBlynJacobs Date: Tue, 1 Dec 2020 03:44:05 +0000 Subject: [PATCH] Site Health, App Passwords: Ensure REST API responses are properly translated. The REST API requests in Site Health and App Passwords now include `_locale=user` in the request URL to ensure the user's locale is used instead of the site locale. Additionally, the `apiRequest` library now sends a JSON `Accept` header which is required by `determine_locale()` to respect the `_locale` query parameter. The Site Health REST API controllers now manually load the default admin textdomain if not `is_admin()`. This allows for the Site Health tests to be translated even though the translations are part of the administration project and the REST API is not. Props oglekler, kebbet, Clorith, TimothyBlynJacobs, ocean90, SergeyBiryukov, adamsilverstein. Fixes #51871. Built from https://develop.svn.wordpress.org/trunk@49716 git-svn-id: http://core.svn.wordpress.org/trunk@49439 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/js/application-passwords.js | 6 ++-- wp-admin/js/application-passwords.min.js | 2 +- wp-admin/js/auth-app.js | 2 +- wp-admin/js/auth-app.min.js | 2 +- wp-admin/js/site-health.js | 2 +- wp-admin/js/site-health.min.js | 2 +- wp-includes/js/api-request.js | 34 +++++++++++++------ wp-includes/js/api-request.min.js | 2 +- .../class-wp-rest-site-health-controller.php | 22 ++++++++++++ wp-includes/script-loader.php | 2 +- wp-includes/version.php | 2 +- 11 files changed, 56 insertions(+), 22 deletions(-) diff --git a/wp-admin/js/application-passwords.js b/wp-admin/js/application-passwords.js index 09e4434e2f..b1a20ceb8e 100644 --- a/wp-admin/js/application-passwords.js +++ b/wp-admin/js/application-passwords.js @@ -47,7 +47,7 @@ request = wp.hooks.applyFilters( 'wp_application_passwords_new_password_request', request, userId ); wp.apiRequest( { - path: '/wp/v2/users/' + userId + '/application-passwords', + path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user', method: 'POST', data: request } ).always( function() { @@ -94,7 +94,7 @@ $submitButton.prop( 'disabled', true ); wp.apiRequest( { - path: '/wp/v2/users/' + userId + '/application-passwords/' + uuid, + path: '/wp/v2/users/' + userId + '/application-passwords/' + uuid + '?_locale=user', method: 'DELETE' } ).always( function() { $submitButton.prop( 'disabled', false ); @@ -123,7 +123,7 @@ $submitButton.prop( 'disabled', true ); wp.apiRequest( { - path: '/wp/v2/users/' + userId + '/application-passwords', + path: '/wp/v2/users/' + userId + '/application-passwords?_locale=user', method: 'DELETE' } ).always( function() { $submitButton.prop( 'disabled', false ); diff --git a/wp-admin/js/application-passwords.min.js b/wp-admin/js/application-passwords.min.js index 0cef7eb19e..95389326ae 100644 --- a/wp-admin/js/application-passwords.min.js +++ b/wp-admin/js/application-passwords.min.js @@ -1,2 +1,2 @@ /*! This file is auto-generated */ -!function(i){var a=i("#application-passwords-section"),o=a.find(".create-application-password"),n=o.find(".input"),t=o.find(".button"),p=a.find(".application-passwords-list-table-wrapper"),r=a.find("tbody"),d=r.find(".no-items"),e=i("#revoke-all-application-passwords"),l=wp.template("new-application-password"),c=wp.template("application-password-row"),w=i("#user_id").val();function u(e,s,a){var o=a;e.responseJSON&&e.responseJSON.message&&(o=e.responseJSON.message),f(o,"error")}function f(e,s){var a=i("
").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(i("

").text(e)).append(i("").attr("type","button").addClass("notice-dismiss").append(i("").addClass("screen-reader-text").text(wp.i18n.__("Dismiss this notice."))));return o.after(a),a}function v(){i(".notice",a).remove()}t.click(function(e){if(e.preventDefault(),!t.prop("aria-disabled")){var s=n.val();if(0!==s.length){v(),t.prop("aria-disabled",!0).addClass("disabled");var a={name:s};a=wp.hooks.applyFilters("wp_application_passwords_new_password_request",a,w),wp.apiRequest({path:"/wp/v2/users/"+w+"/application-passwords",method:"POST",data:a}).always(function(){t.removeProp("aria-disabled").removeClass("disabled")}).done(function(e){n.val(""),t.prop("disabled",!1),o.after(l({name:s,password:e.password})),i(".new-application-password-notice").focus(),r.prepend(c(e)),p.show(),d.remove(),wp.hooks.doAction("wp_application_passwords_created_password",e,a)}).fail(u)}else n.focus()}}),r.on("click",".delete",function(e){if(e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke this password? This action cannot be undone."))){var s=i(this),a=s.closest("tr"),o=a.data("uuid");v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+w+"/application-passwords/"+o,method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(0===a.siblings().length&&p.hide(),a.remove(),f(wp.i18n.__("Application password revoked."),"success").focus())}).fail(u)}}),e.on("click",function(e){if(e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke all passwords? This action cannot be undone."))){var s=i(this);v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+w+"/application-passwords",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(r.children().remove(),a.children(".new-application-password").remove(),p.hide(),f(wp.i18n.__("All application passwords revoked."),"success").focus())}).fail(u)}}),a.on("click",".notice-dismiss",function(e){e.preventDefault();var s=i(this).parent();s.removeAttr("role"),s.fadeTo(100,0,function(){s.slideUp(100,function(){s.remove(),n.focus()})})}),0===r.children("tr").not(d).length&&p.hide()}(jQuery); \ No newline at end of file +!function(i){var a=i("#application-passwords-section"),o=a.find(".create-application-password"),n=o.find(".input"),t=o.find(".button"),p=a.find(".application-passwords-list-table-wrapper"),r=a.find("tbody"),d=r.find(".no-items"),e=i("#revoke-all-application-passwords"),l=wp.template("new-application-password"),c=wp.template("application-password-row"),u=i("#user_id").val();function w(e,s,a){var o=a;e.responseJSON&&e.responseJSON.message&&(o=e.responseJSON.message),f(o,"error")}function f(e,s){var a=i("
").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(i("

").text(e)).append(i("").attr("type","button").addClass("notice-dismiss").append(i("").addClass("screen-reader-text").text(wp.i18n.__("Dismiss this notice."))));return o.after(a),a}function v(){i(".notice",a).remove()}t.click(function(e){if(e.preventDefault(),!t.prop("aria-disabled")){var s=n.val();if(0!==s.length){v(),t.prop("aria-disabled",!0).addClass("disabled");var a={name:s};a=wp.hooks.applyFilters("wp_application_passwords_new_password_request",a,u),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"POST",data:a}).always(function(){t.removeProp("aria-disabled").removeClass("disabled")}).done(function(e){n.val(""),t.prop("disabled",!1),o.after(l({name:s,password:e.password})),i(".new-application-password-notice").focus(),r.prepend(c(e)),p.show(),d.remove(),wp.hooks.doAction("wp_application_passwords_created_password",e,a)}).fail(w)}else n.focus()}}),r.on("click",".delete",function(e){if(e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke this password? This action cannot be undone."))){var s=i(this),a=s.closest("tr"),o=a.data("uuid");v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords/"+o+"?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(0===a.siblings().length&&p.hide(),a.remove(),f(wp.i18n.__("Application password revoked."),"success").focus())}).fail(w)}}),e.on("click",function(e){if(e.preventDefault(),window.confirm(wp.i18n.__("Are you sure you want to revoke all passwords? This action cannot be undone."))){var s=i(this);v(),s.prop("disabled",!0),wp.apiRequest({path:"/wp/v2/users/"+u+"/application-passwords?_locale=user",method:"DELETE"}).always(function(){s.prop("disabled",!1)}).done(function(e){e.deleted&&(r.children().remove(),a.children(".new-application-password").remove(),p.hide(),f(wp.i18n.__("All application passwords revoked."),"success").focus())}).fail(w)}}),a.on("click",".notice-dismiss",function(e){e.preventDefault();var s=i(this).parent();s.removeAttr("role"),s.fadeTo(100,0,function(){s.slideUp(100,function(){s.remove(),n.focus()})})}),0===r.children("tr").not(d).length&&p.hide()}(jQuery); \ No newline at end of file diff --git a/wp-admin/js/auth-app.js b/wp-admin/js/auth-app.js index 4af3a05fa8..ad4403032d 100644 --- a/wp-admin/js/auth-app.js +++ b/wp-admin/js/auth-app.js @@ -54,7 +54,7 @@ request = wp.hooks.applyFilters( 'wp_application_passwords_approve_app_request', request, context ); wp.apiRequest( { - path: '/wp/v2/users/me/application-passwords', + path: '/wp/v2/users/me/application-passwords?_locale=user', method: 'POST', data: request } ).done( function( response, textStatus, jqXHR ) { diff --git a/wp-admin/js/auth-app.min.js b/wp-admin/js/auth-app.min.js index cd2fd9dabe..6695f4dc1a 100644 --- a/wp-admin/js/auth-app.min.js +++ b/wp-admin/js/auth-app.min.js @@ -1,2 +1,2 @@ /*! This file is auto-generated */ -!function(r,l){var p=r("#app_name"),i=r("#approve"),e=r("#reject"),d=p.closest("form"),o={userLogin:l.user_login,successUrl:l.success,rejectUrl:l.reject};i.click(function(e){var n=p.val(),a=r('input[name="app_id"]',d).val();if(e.preventDefault(),!i.prop("aria-disabled"))if(0!==n.length){i.prop("aria-disabled",!0).addClass("disabled");var s={name:n};0'+wp.i18n.__("Your new password for %s is:")+"","")+' ',t=r("
").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(r("

").addClass("application-password-display").html(o)).append("

"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"

"),r("strong",t).text(n),r("input",t).val(e.password),d.replaceWith(t),t.focus())}).fail(function(e,a,s){var p=s,o=null;e.responseJSON&&(o=e.responseJSON).message&&(p=o.message);var t=r("
").attr("role","alert").addClass("notice notice-error").append(r("

").text(p));r("h1").after(t),i.removeProp("aria-disabled",!1).removeClass("disabled"),wp.hooks.doAction("wp_application_passwords_approve_app_request_success",o,a,e)})}else p.focus()}),e.click(function(e){e.preventDefault(),wp.hooks.doAction("wp_application_passwords_reject_app",o),window.location=l.reject}),d.on("submit",function(e){e.preventDefault()})}(jQuery,authApp); \ No newline at end of file +!function(r,l){var o=r("#app_name"),i=r("#approve"),e=r("#reject"),d=o.closest("form"),p={userLogin:l.user_login,successUrl:l.success,rejectUrl:l.reject};i.click(function(e){var n=o.val(),a=r('input[name="app_id"]',d).val();if(e.preventDefault(),!i.prop("aria-disabled"))if(0!==n.length){i.prop("aria-disabled",!0).addClass("disabled");var s={name:n};0'+wp.i18n.__("Your new password for %s is:")+"","")+' ',t=r("
").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(r("

").addClass("application-password-display").html(p)).append("

"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"

"),r("strong",t).text(n),r("input",t).val(e.password),d.replaceWith(t),t.focus())}).fail(function(e,a,s){var o=s,p=null;e.responseJSON&&(p=e.responseJSON).message&&(o=p.message);var t=r("
").attr("role","alert").addClass("notice notice-error").append(r("

").text(o));r("h1").after(t),i.removeProp("aria-disabled",!1).removeClass("disabled"),wp.hooks.doAction("wp_application_passwords_approve_app_request_success",p,a,e)})}else o.focus()}),e.click(function(e){e.preventDefault(),wp.hooks.doAction("wp_application_passwords_reject_app",p),window.location=l.reject}),d.on("submit",function(e){e.preventDefault()})}(jQuery,authApp); \ No newline at end of file diff --git a/wp-admin/js/site-health.js b/wp-admin/js/site-health.js index d91b75e90a..9bba750094 100644 --- a/wp-admin/js/site-health.js +++ b/wp-admin/js/site-health.js @@ -271,7 +271,7 @@ jQuery( document ).ready( function( $ ) { if ( 'undefined' !== typeof( this.has_rest ) && this.has_rest ) { wp.apiRequest( { - url: this.test, + url: wp.url.addQueryArgs( this.test, { _locale: 'user' } ), headers: this.headers } ) .done( function( response ) { diff --git a/wp-admin/js/site-health.min.js b/wp-admin/js/site-health.min.js index 18295a79da..cc617fedb5 100644 --- a/wp-admin/js/site-health.min.js +++ b/wp-admin/js/site-health.min.js @@ -1,2 +1,2 @@ /*! This file is auto-generated */ -jQuery(document).ready(function(c){var a,t,s,h=wp.i18n.__,n=wp.i18n._n,o=wp.i18n.sprintf,i=new ClipboardJS(".site-health-copy-buttons .copy-button"),d=c(".health-check-body.health-check-debug-tab").length,r=c("#health-check-accordion-block-wp-paths-sizes");function l(e){var t,s,a=wp.template("health-check-issue"),i=c("#health-check-issues-"+e.status);if(!function(e){var t,s,a,i,n={test:"string",label:"string",description:"string"},o=!0;if("object"!=typeof e)return!1;for(t in n)if("object"==typeof(s=n[t]))for(a in s)i=s[a],void 0!==e[t]&&void 0!==e[t][a]&&i===typeof e[t][a]||(o=!1);else void 0!==e[t]&&s===typeof e[t]||(o=!1);return o}(e))return!1;SiteHealth.site_status.issues[e.status]++,s=SiteHealth.site_status.issues[e.status],void 0===e.test&&(e.test=e.status+s),"critical"===e.status?t=o(n("%s critical issue","%s critical issues",s),''+s+""):"recommended"===e.status?t=o(n("%s recommended improvement","%s recommended improvements",s),''+s+""):"good"===e.status&&(t=o(n("%s item with no issues detected","%s items with no issues detected",s),''+s+"")),t&&c(".site-health-issue-count-title",i).html(t),c(".issues","#health-check-issues-"+e.status).append(a(e))}function u(){var e,t,s=c(".site-health-progress"),a=s.closest(".site-health-progress-wrapper"),i=c(".site-health-progress-label",a),n=c(".site-health-progress svg #bar"),o=parseInt(SiteHealth.site_status.issues.good,0)+parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),r=.5*parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),l=100-Math.ceil(r/o*100);0!==o?(a.removeClass("loading"),e=n.attr("r"),l<0&&(l=0),100"+e+"

"+t+"

",actions:""},l(wp.hooks.applyFilters("site_status_test_result",s))}i.on("success",function(e){var t=c(e.trigger),s=c(".success",t.closest("div"));e.clearSelection(),t.focus(),clearTimeout(a),s.removeClass("hidden"),a=setTimeout(function(){s.addClass("hidden"),i.clipboardAction.fakeElem&&i.clipboardAction.removeFake&&i.clipboardAction.removeFake()},3e3),wp.a11y.speak(h("Site information has been copied to your clipboard."))}),c(".health-check-accordion").on("click",".health-check-accordion-trigger",function(){"true"===c(this).attr("aria-expanded")?(c(this).attr("aria-expanded","false"),c("#"+c(this).attr("aria-controls")).attr("hidden",!0)):(c(this).attr("aria-expanded","true"),c("#"+c(this).attr("aria-controls")).attr("hidden",!1))}),c(".site-health-view-passed").on("click",function(){var e=c("#health-check-issues-good");e.toggleClass("hidden"),c(this).attr("aria-expanded",!e.hasClass("hidden"))}),"undefined"==typeof SiteHealth||d||(0===SiteHealth.site_status.direct.length&&0===SiteHealth.site_status.async.length?u():SiteHealth.site_status.issues={good:0,recommended:0,critical:0},0'+s+""):"recommended"===e.status?t=o(n("%s recommended improvement","%s recommended improvements",s),''+s+""):"good"===e.status&&(t=o(n("%s item with no issues detected","%s items with no issues detected",s),''+s+"")),t&&c(".site-health-issue-count-title",i).html(t),c(".issues","#health-check-issues-"+e.status).append(a(e))}function u(){var e,t,s=c(".site-health-progress"),a=s.closest(".site-health-progress-wrapper"),i=c(".site-health-progress-label",a),n=c(".site-health-progress svg #bar"),o=parseInt(SiteHealth.site_status.issues.good,0)+parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),r=.5*parseInt(SiteHealth.site_status.issues.recommended,0)+1.5*parseInt(SiteHealth.site_status.issues.critical,0),l=100-Math.ceil(r/o*100);0!==o?(a.removeClass("loading"),e=n.attr("r"),l<0&&(l=0),100"+e+"

"+t+"

",actions:""},l(wp.hooks.applyFilters("site_status_test_result",s))}i.on("success",function(e){var t=c(e.trigger),s=c(".success",t.closest("div"));e.clearSelection(),t.focus(),clearTimeout(a),s.removeClass("hidden"),a=setTimeout(function(){s.addClass("hidden"),i.clipboardAction.fakeElem&&i.clipboardAction.removeFake&&i.clipboardAction.removeFake()},3e3),wp.a11y.speak(h("Site information has been copied to your clipboard."))}),c(".health-check-accordion").on("click",".health-check-accordion-trigger",function(){"true"===c(this).attr("aria-expanded")?(c(this).attr("aria-expanded","false"),c("#"+c(this).attr("aria-controls")).attr("hidden",!0)):(c(this).attr("aria-expanded","true"),c("#"+c(this).attr("aria-controls")).attr("hidden",!1))}),c(".site-health-view-passed").on("click",function(){var e=c("#health-check-issues-good");e.toggleClass("hidden"),c(this).attr("aria-expanded",!e.hasClass("hidden"))}),"undefined"==typeof SiteHealth||d||(0===SiteHealth.site_status.direct.length&&0===SiteHealth.site_status.async.length?u():SiteHealth.site_status.issues={good:0,recommended:0,critical:0},0load_admin_textdomain(); return $this->site_health->get_test_background_updates(); } @@ -182,6 +183,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { * @return array */ public function test_dotorg_communication() { + $this->load_admin_textdomain(); return $this->site_health->get_test_dotorg_communication(); } @@ -193,6 +195,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { * @return array */ public function test_loopback_requests() { + $this->load_admin_textdomain(); return $this->site_health->get_test_loopback_requests(); } @@ -204,6 +207,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { * @return array */ public function test_authorization_header() { + $this->load_admin_textdomain(); return $this->site_health->get_test_authorization_header(); } @@ -219,6 +223,8 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { require_once ABSPATH . 'wp-admin/includes/class-wp-debug-data.php'; } + $this->load_admin_textdomain(); + $sizes_data = WP_Debug_Data::get_sizes(); $all_sizes = array( 'raw' => 0 ); @@ -256,6 +262,22 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller { return $all_sizes; } + /** + * Loads the admin textdomain for Site Health tests. + * + * The {@see WP_Site_Health} class is defined in WP-Admin, while the REST API operates in a front-end context. + * This means that the translations for Site Health won't be loaded by default in {@see load_default_textdomain()}. + * + * @since 5.6.0 + */ + protected function load_admin_textdomain() { + // Accounts for inner REST API requests in the admin. + if ( ! is_admin() ) { + $locale = determine_locale(); + load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" ); + } + } + /** * Gets the schema for each site health test. * diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index f3ad2de05c..a0da5a0c4d 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -1286,7 +1286,7 @@ function wp_default_scripts( $scripts ) { $scripts->add( 'plugin-install', "/wp-admin/js/plugin-install$suffix.js", array( 'jquery', 'jquery-ui-core', 'thickbox' ), false, 1 ); $scripts->set_translations( 'plugin-install' ); - $scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-api-request' ), false, 1 ); + $scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-api-request', 'wp-url' ), false, 1 ); $scripts->set_translations( 'site-health' ); $scripts->add( 'privacy-tools', "/wp-admin/js/privacy-tools$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 ); diff --git a/wp-includes/version.php b/wp-includes/version.php index db316fc067..2cb7334735 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.7-alpha-49713'; +$wp_version = '5.7-alpha-49716'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.