plugin development – How to get locale within WP REST Request?
Given that I’ve struggled significantly with this, I’d like to share my solution. Note that the solution aims to retrieve the requesting client’s locale within a WP REST Request, incoming from the frontend part of your application, hence from a user who’s not logged in into the WP admin, in a reliable way, such that:
__()
localization functions get the translations in the requesting client’s locale, instead of the default language of your website.- WP core functions like
get_locale()
return the retrieved client’s locale, instead of the default locale of your website.
So here’s my approach:
- Create a Wrapper function in javascript, which you then use to fire all requests to the WP REST API from your frontend application. Within that wrapper function, pass a custom HTTP header that is specific to your plugin, sth like
X-MYPLUGIN-LANG
. I could have usedAccept-Language
, but as you may use a plugin for multilingual functionality already, that header may be affected by that plugin at some stage. So just to avoid any eventual code conflicts, I’ve decided to use a custom HTTP header. - The value of that header is equal to
document.getElementsByTagName("html")[0].lang
; determined once only on page load. - Within the main plugin file of the plugin where your targeted endpoints are registered via
register_rest_route
, you most likely have some code somewhere which loads your plugin’s textdomain. Something like:
add_action(
'init',
function () {
load_plugin_textdomain(
'my-plugin',
false,
dirname(plugin_basename(__FILE__)) . '/languages'
);
}
);
From what I’ve learned, this hook is what loads your localizations from your .mo
files of the concerned plugin in the language represented by the current value of get_locale()
. I’ve tested that by just putting an echo get_locale()
before the load_plugin_textdomain()
call above, and indeed: The translations of all of the __()
all happen in the language represented by the output of get_locale()
. So what must be done is (my thoughts, at least): change the locale for the lifetime of the incoming request, if it’s a custom REST API request, into the one of the requesting client. And as well, for the entire lifetime of the incoming request, do this only once; to avoid repeated calls. This is assured by the fact that you’ll enter your code within the action hooking above, as the init
hook is executed exactly once with every request.
My conclusion was thus to add code that does the following above load_plugin_textdomain()
(I won’t paste the code as your validation may differs, etc.):
- Check if the incoming request has a
X-MYPLUGIN-LANG
HTTP header set. - If so, verify that its value matches a valid locale of your REST API, before doing anything else (input validation).
- If so, remember that the value of your HTTP header is retrieved from the
html
tags’lang
attribute, hence sth likeen-US
. WP locales however seem to work with underscores; hence transform the locale obtained from the client accordingly; hence sth likeen-US
–>en_US
. Although I do not know if that step is strictly necessary. - Simply call
switch_to_locale(<your_transformed_locale>)
.
Doing the above-mentioned within your callback hooked to your init
hook, right above load_plugin_textdomain()
, returned all of my __()
translations in the client’s language, and get_locale()
can also be used for other stuff, now retrieving the correct client locale, too!
UPDATE
As weird as things can get, when using rest_pre_dispatch
and short-circuiting your response to your custom request, the init
hook gets executed, hence the locale gets successfully changed to your client’s locale, but the translations retrieved via __()
calls are still in the root website language. Even if I echo get_locale()
right above echo __('test translation','my-plugin')
, I get test translation
output instead of its translation in the locale described by the output of get_locale()
. The reason so far seems to be that the call to load_plugin_textdomain()
failed; as it returns false
. I’m puzzled.
Leave an answer