Реализация поставщика Locale, который работает в JSF и JAX-RS

Я радостно использовал омнифасы Faces.getLocale() получить языковой стандарт, используемый текущим вошедшим пользователем (который, в свою очередь, получает это от <f:view> определение). Мне действительно нравится резервный подход от представления к клиенту к локали системы по умолчанию, так как он соответствует требованиям для выбора локали в моем приложении:

  1. Если пользователь вошел в систему, используйте его языковые предпочтения (полученные из бэкэнда)
  2. Если пользовательские предпочтения не найдены, используйте язык с самым высоким рейтингом из Accept-Languages Заголовок HTTP
  3. Если языковой стандарт не выбран, используйте системную настройку по умолчанию.

Теперь я начал использовать 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.

Надеюсь, это поможет,

Другие вопросы по тегам