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
This commit is contained in:
TimothyBlynJacobs 2020-12-01 03:44:05 +00:00
parent b3a952972e
commit c3b40f7f80
11 changed files with 56 additions and 22 deletions

View File

@ -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 );

View File

@ -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("<div></div>").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(i("<p></p>").text(e)).append(i("<button></button>").attr("type","button").addClass("notice-dismiss").append(i("<span></span>").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);
!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("<div></div>").attr("role","alert").attr("tabindex","-1").addClass("is-dismissible notice notice-"+s).append(i("<p></p>").text(e)).append(i("<button></button>").attr("type","button").addClass("notice-dismiss").append(i("<span></span>").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);

View File

@ -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 ) {

View File

@ -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<a.length&&(s.app_id=a),s=wp.hooks.applyFilters("wp_application_passwords_approve_app_request",s,o),wp.apiRequest({path:"/wp/v2/users/me/application-passwords",method:"POST",data:s}).done(function(e,a,s){wp.hooks.doAction("wp_application_passwords_approve_app_request_success",e,a,s);var p,o,t,i=l.success;i?(p=i+(-1===i.indexOf("?")?"?":"&")+"site_url="+encodeURIComponent(l.site_url)+"&user_login="+encodeURIComponent(l.user_login)+"&password="+encodeURIComponent(e.password),window.location=p):(o=wp.i18n.sprintf('<label for="new-application-password-value">'+wp.i18n.__("Your new password for %s is:")+"</label>","<strong></strong>")+' <input id="new-application-password-value" type="text" class="code" readonly="readonly" value="" />',t=r("<div></div>").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(r("<p></p>").addClass("application-password-display").html(o)).append("<p>"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"</p>"),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("<div></div>").attr("role","alert").addClass("notice notice-error").append(r("<p></p>").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);
!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<a.length&&(s.app_id=a),s=wp.hooks.applyFilters("wp_application_passwords_approve_app_request",s,p),wp.apiRequest({path:"/wp/v2/users/me/application-passwords?_locale=user",method:"POST",data:s}).done(function(e,a,s){wp.hooks.doAction("wp_application_passwords_approve_app_request_success",e,a,s);var o,p,t,i=l.success;i?(o=i+(-1===i.indexOf("?")?"?":"&")+"site_url="+encodeURIComponent(l.site_url)+"&user_login="+encodeURIComponent(l.user_login)+"&password="+encodeURIComponent(e.password),window.location=o):(p=wp.i18n.sprintf('<label for="new-application-password-value">'+wp.i18n.__("Your new password for %s is:")+"</label>","<strong></strong>")+' <input id="new-application-password-value" type="text" class="code" readonly="readonly" value="" />',t=r("<div></div>").attr("role","alert").attr("tabindex",-1).addClass("notice notice-success notice-alt").append(r("<p></p>").addClass("application-password-display").html(p)).append("<p>"+wp.i18n.__("Be sure to save this in a safe location. You will not be able to retrieve it.")+"</p>"),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("<div></div>").attr("role","alert").addClass("notice notice-error").append(r("<p></p>").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);

View File

@ -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 ) {

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,7 @@
*
* @since 4.9.0
* @since 5.6.0 Added overriding of the "PUT" and "DELETE" methods with "POST".
* Added an "application/json" Accept header to all requests.
* @output wp-includes/js/api-request.js
*/
@ -26,7 +27,7 @@
var path = options.path;
var method = options.method;
var namespaceTrimmed, endpointTrimmed, apiRoot;
var headers, addNonceHeader, headerName;
var headers, addNonceHeader, addAcceptHeader, headerName;
if (
typeof options.namespace === 'string' &&
@ -55,19 +56,24 @@
// If ?_wpnonce=... is present, no need to add a nonce header.
addNonceHeader = ! ( options.data && options.data._wpnonce );
addAcceptHeader = true;
headers = options.headers || {};
// If an 'X-WP-Nonce' header (or any case-insensitive variation
// thereof) was specified, no need to add a nonce header.
if ( addNonceHeader ) {
for ( headerName in headers ) {
if ( headers.hasOwnProperty( headerName ) ) {
if ( headerName.toLowerCase() === 'x-wp-nonce' ) {
addNonceHeader = false;
break;
}
}
for ( headerName in headers ) {
if ( ! headers.hasOwnProperty( headerName ) ) {
continue;
}
// If an 'X-WP-Nonce' or 'Accept' header (or any case-insensitive variation
// thereof) was specified, no need to add the header again.
switch ( headerName.toLowerCase() ) {
case 'x-wp-nonce':
addNonceHeader = false;
break;
case 'accept':
addAcceptHeader = false;
break;
}
}
@ -78,6 +84,12 @@
}, headers );
}
if ( addAcceptHeader ) {
headers = $.extend( {
'Accept': 'application/json, */*;q=0.1'
}, headers );
}
if ( typeof method === 'string' ) {
method = method.toUpperCase();

View File

@ -1,2 +1,2 @@
/*! This file is auto-generated */
!function(w){var c=window.wpApiSettings;function n(e){return e=n.buildAjaxOptions(e),n.transport(e)}n.buildAjaxOptions=function(e){var n,t,o,r,p,a,i=e.url,d=e.path,s=e.method;if("string"==typeof e.namespace&&"string"==typeof e.endpoint&&(n=e.namespace.replace(/^\/|\/$/g,""),d=(t=e.endpoint.replace(/^\//,""))?n+"/"+t:n),"string"==typeof d&&(o=c.root,d=d.replace(/^\//,""),"string"==typeof o&&-1!==o.indexOf("?")&&(d=d.replace("?","&")),i=o+d),p=!(e.data&&e.data._wpnonce),r=e.headers||{},p)for(a in r)if(r.hasOwnProperty(a)&&"x-wp-nonce"===a.toLowerCase()){p=!1;break}return p&&(r=w.extend({"X-WP-Nonce":c.nonce},r)),"string"==typeof s&&("PUT"!==(s=s.toUpperCase())&&"DELETE"!==s||(r=w.extend({"X-HTTP-Method-Override":s},r),s="POST")),delete(e=w.extend({},e,{headers:r,url:i,method:s})).path,delete e.namespace,delete e.endpoint,e},n.transport=w.ajax,window.wp=window.wp||{},window.wp.apiRequest=n}(jQuery);
!function(w){var l=window.wpApiSettings;function t(e){return e=t.buildAjaxOptions(e),t.transport(e)}t.buildAjaxOptions=function(e){var t,n,a,p,o,r,i,d=e.url,s=e.path,c=e.method;for(i in"string"==typeof e.namespace&&"string"==typeof e.endpoint&&(t=e.namespace.replace(/^\/|\/$/g,""),s=(n=e.endpoint.replace(/^\//,""))?t+"/"+n:t),"string"==typeof s&&(a=l.root,s=s.replace(/^\//,""),"string"==typeof a&&-1!==a.indexOf("?")&&(s=s.replace("?","&")),d=a+s),o=!(e.data&&e.data._wpnonce),r=!0,p=e.headers||{})if(p.hasOwnProperty(i))switch(i.toLowerCase()){case"x-wp-nonce":o=!1;break;case"accept":r=!1}return o&&(p=w.extend({"X-WP-Nonce":l.nonce},p)),r&&(p=w.extend({Accept:"application/json, */*;q=0.1"},p)),"string"==typeof c&&("PUT"!==(c=c.toUpperCase())&&"DELETE"!==c||(p=w.extend({"X-HTTP-Method-Override":c},p),c="POST")),delete(e=w.extend({},e,{headers:p,url:d,method:c})).path,delete e.namespace,delete e.endpoint,e},t.transport=w.ajax,window.wp=window.wp||{},window.wp.apiRequest=t}(jQuery);

View File

@ -171,6 +171,7 @@ class WP_REST_Site_Health_Controller extends WP_REST_Controller {
* @return array
*/
public function test_background_updates() {
$this->load_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.
*

View File

@ -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 );

View File

@ -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.