Реализация поставщика Locale, который работает в JSF и JAX-RS
Я радостно использовал омнифасы Faces.getLocale()
получить языковой стандарт, используемый текущим вошедшим пользователем (который, в свою очередь, получает это от <f:view>
определение). Мне действительно нравится резервный подход от представления к клиенту к локали системы по умолчанию, так как он соответствует требованиям для выбора локали в моем приложении:
- Если пользователь вошел в систему, используйте его языковые предпочтения (полученные из бэкэнда)
- Если пользовательские предпочтения не найдены, используйте язык с самым высоким рейтингом из
Accept-Languages
Заголовок HTTP - Если языковой стандарт не выбран, используйте системную настройку по умолчанию.
Теперь я начал использовать JAX-RS (реализация resteasy), и мне довольно сложно написать сервис, который будет предоставлять мой бэкэнд-код в соответствии с локалью текущего пользователя.
Я не могу использовать Faces.getLocale()
, поскольку это требует FacesContext
который отсутствует во время обработки запроса JAX-RS.
Я не могу использовать @Context SecurityContext
аннотация в @Provider
(что даст мне предпочтительный язык пользователя) или @Context HttpHeaders
(доступ к языку клиента), поскольку JAX-RS внедряет их только тогда, когда он использует самого провайдера, а не когда мой внутренний код создает экземпляр класса.
И я не хочу засорять мои сигнатуры методов Locale
параметры, так как практически все требует наличия локали.
Чтобы получить конкретный пример: у меня есть генератор vcard, который генерирует небольшие поля NOTE в зависимости от предпочтительного языка пользователя. Я могу оба вызвать метод генерации vcard через JSF/EL:
<h:commandLink action="#{vcfGenerator.forPerson(person)}"
value="Go" target="_blank" />
И через службу REST:
@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()
}
Это работает (VcfGenerator
имеет набор методов только для JSF, которые используют Faces.getLocale()
), но это боль, чтобы поддерживать. Так что вместо прохождения Locale
объект, я хотел бы сказать:
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
}
Кто-нибудь делал подобную работу и может поделиться своими идеями?
1 ответ
Я знаю, что это было опубликовано некоторое время назад, но так как оно не было помечено как решенное, вот как я нашел обходной путь для этого конкретного случая:
- Сначала я получил собственный ResourceBundle, как описано ниже @BalusC: http://balusc.blogspot.fr/2010/10/internationalization-in-jsf-with-utf-8.html
Затем я обновил конструктор, чтобы определить, используется ли FacesContext в данный момент:
public Text() { setParent(ResourceBundle.getBundle(BUNDLE_NAME, FacesContext.getCurrentInstance().getViewRoot().getLocale(), UTF8_CONTROL)); }
К этому:
public Text() { FacesContext ctx = FacesContext.getCurrentInstance(); setParent(ResourceBundle.getBundle(BUNDLE_NAME, ctx != null ? ctx.getViewRoot().getLocale() : Locale.ENGLISH, UTF8_CONTROL)); }
Теперь это работает как в контексте JSF, так и в контексте JAX-RS.
Надеюсь, это поможет,