I've been joyfully using omnifaces' Faces.getLocale()
to aquire the locale used by the currently logged in user (which in turn gets this from a <f:view>
definition). I really like the fallback approach from view to client to system default locale as it fits the requirements for locale selection in my application:
- If a user is logged in, use his language preference (obtained from the backend entity)
- If no user preference can be found, use the highest ranking language from the
Accept-Languages
HTTP header - If no locale has been selected by now, use the system default.
Now I've started using JAX-RS (resteasy implementation) and find it quite difficult to write a service that will provide my backend code with the current user's locale.
I can't use Faces.getLocale()
, since that requires a FacesContext
which isn't present during JAX-RS request processing.
I can't use the @Context SecurityContext
annotation in a @Provider
(which would give me the user preferred locale) or @Context HttpHeaders
(access to the client locale) since JAX-RS only injects those when it uses the provider itself, not when my backend code instantiates the class.
And I don't want to litter my method signatures with Locale
parameters, since virtually everything requires a locale to be present.
To have a concrete example: I have a vcard generator that generates little NOTE fields depending on the user's preferred locale. I can both call the vcard generating method via JSF/EL:
<h:commandLink action="#{vcfGenerator.forPerson(person)}"
value="Go" target="_blank" />
And via a REST service:
@GET @Path('person/{id:[1-9][0-9]*}/vcard')
@Produces('text/vcard')
String exportVcard(@PathParam('id') Long personId, @Context HttpHeaders headers) {
VcfGenerator exporter = Component.getInstance(VcfGenerator) as VcfGenerator
Person person = entityManager.find(Person, personId)
if (! person)
return Response.noContent().build()
def locale = headers.acceptableLanguages[0] ?: Locale.ROOT
return exporter.generateVCF(person, locale).toString()
}
This works (VcfGenerator
has a set of JSF-only methods that use Faces.getLocale()
), but is a pain to maintain. So instead of passing the Locale
object, I'd like to say:
Vcard generateVCF(Person person) {
Locale activeLocale = LocaleProvider.instance().getContext(VcfGenerator.class)
ResourceBundle bundle = ResourceBundle.getBundle("messages", activeLocale, new MyControl())
// use bundle to construct the vcard
}
Has anyone done similar work and can share insights?