Make WordPress Core

Opened 21 months ago

Last modified 21 months ago

#57945 new defect (bug)

Locale bug in short-circuited WP REST API request via rest_pre_dispatch?

Reported by: joeyojoeyo12's profile joeyojoeyo12 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.1.1
Component: REST API Keywords: reporter-feedback close
Focuses: Cc:

Description

To reproduce the issue: you may register a custom REST endpoint using register_rest_route in your main plugin file of your custom plugin. That endpoint simply produces a response via localization, via a __('sample-string','my-plugin') call and the according .mo/.po files within plugins/my-plugin/languages, as well as in languages/plugins/.. (tested both to be sure).

Next, access your frontend, without being logged in into the admin, in a language which is not the default of the page, e.g. by creating two translations of a page via Polylang. Fire a REST API request to your custom endpoint. __('sample-string','my-plugin') is returned back to the frontend in the site's default language, and not in the (non-default) language of the page.

As a workaround for this, I:

  • send a custom HTTP header along with every WP REST request (e.g. X-MYP-LANG)
  • created custom callback in main plugin file, hooked onto init hook, to get its value and then switch_to_locale accordingly.
  • result: correct translation of __('sample-string','my-plugin') is now output.

PROBLEM:
Whenever I short-circuit a custom REST request's response via rest_pre_dispatch, this stops working. You may return a WP_Error via the rest_pre_dispatch hook for any incoming request to your custom endpoint. The message of that WP_Error being a localization, e.g. __('error message','my-plugin'), it is returned back in the default language, no matter if I switch_to_locale('target_language') explicitly right before returning the WP_Error, reload the plugin textdomain via load_plugin_textdomain() before doing so, or both. Bug?

Change History (3)

#1 @TimothyBlynJacobs
21 months ago

  • Keywords reporter-feedback close added
  • Severity changed from critical to normal

Hi @joeyojoeyo12,

To handle the locale, you can set either ?_locale=user to return the content in the user's locale, or ?_locale=site to return the content in the site's locale.

See #44758.

#2 @joeyojoeyo12
21 months ago

Hi there, thanks for the fast reply.

Adding ?_locale=site to the REST API requests' route from the requesting client did not change anything in the above-mentioned behaviour. Please note that the locale is correct. If I echo get_locale() right before returning the WP_Error instance in my callback hooked onto rest_pre_dispatch, I get the correct locale. But the message of the returned WP_Error, written via ('to be translated','my'plugin'), and having an according translation in the plugins' mo and po files as mentioned above, is not returned in the requests' locale, but in the sites' default locale instead. Please note again that this behaviour only happens for requests which are short-circuited via the rest_pre_dispatch hook.

#3 @joeyojoeyo12
21 months ago

My current workaround is this right before returning a WP_Error instance holding a __('localized message','my-plugin') as its error message, within a callback hooked to rest_pre_dispatch, for the error message to get displayed properly:

$current_locale = get_locale(); // retrieved from the client as explained above, so correct

$mo = new MO();

if ($mo->import_from_file(WP_CONTENT_DIR . "/languages/plugins/my-plugin-$current_locale.mo")) {
    $translations[$current_locale] = $mo->entries;
}
            
echo $translations[$current_locale]['localized message']->translations[0];

But this seems like a horrible hack to me..? https://stackoverflow.com/questions/31778466/get-translations-for-a-string-in-wordpress

Note: See TracTickets for help on using tickets.