Локализация JSF 2 (управляемый компонент) - PullRequest
7 голосов
/ 13 августа 2010

У меня есть файл свойств для локализации:

foo=Bar
title=Widget Application

Это связано как resource-bundle в файле face-config:

<resource-bundle>
    <base-name>com.example.messages.messages</base-name>
    <var>msgs</var>
</resource-bundle>

Я могу получить доступ к этому просто отличнов представлении Facelets с использованием EL:

<title>#{msgs.title}</title>

Однако, если есть такие вещи, как SQLExceptions, мне нужно иметь возможность писать сообщения из управляемого компонента.Это все также работает:

FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "There was an error saving this widget.", null);
FacesContext.getCurrentInstance().addMessage(null, message);

Вот проблема: я хочу, чтобы эти сообщения приходили из файла свойств, чтобы их тоже можно было изменять в зависимости от локали.Есть ли простой способ получить доступ к файлу свойств с помощью инъекции?

Ответы [ 5 ]

16 голосов
/ 09 сентября 2010

Я задал довольно похожий вопрос по SO: Как внедрить несериализуемый класс (например, java.util.ResourceBundle) с помощью Weld

А внутри шовного форума: http://seamframework.org/Community/HowToCreateAnInjectableResourcebundleWithWeld

Подведем итог: Я реализовал инъекционный ResourceBundle с 3 продюсерами. Сначала вам нужен FacesContextProducer. Я взял один из источников Альфа Шва 3.

public class FacesContextProducer {
   @Produces @RequestScoped
   public FacesContext getFacesContext() {
      FacesContext ctx = FacesContext.getCurrentInstance();
      if (ctx == null)
         throw new ContextNotActiveException("FacesContext is not active");
      return ctx;
   }
}

Тогда вам нужен LocaleProducer, который использует FacesContextProducer. Я также взял это из Шва 3 Альфа.

public class FacesLocaleResolver {
   @Inject
   FacesContext facesContext;

   public boolean isActive() {
      return (facesContext != null) && (facesContext.getCurrentPhaseId() != null);
   }

   @Produces @Faces
   public Locale getLocale() {
      if (facesContext.getViewRoot() != null) 
         return facesContext.getViewRoot().getLocale();
      else
         return facesContext.getApplication().getViewHandler().calculateLocale(facesContext);
   }
}

Теперь у вас есть все для создания ResourceBundleProducer, который может выглядеть следующим образом:

public class ResourceBundleProducer {
  @Inject       
  public Locale locale;

  @Inject       
  public FacesContext facesContext;

  @Produces
  public ResourceBundle getResourceBundle() {
   return ResourceBundle.getBundle("/messages", facesContext.getViewRoot().getLocale() );
  }
}

Теперь вы можете @ Вставить ResourceBundle в ваши bean-компоненты. Обратите внимание, что он должен быть вставлен во временный атрибут, иначе вы получите исключение, сообщающее, что ResourceBundle не сериализуем.

@Named
public class MyBean {
  @Inject
  private transient ResourceBundle bundle;

  public void testMethod() {
    bundle.getString("SPECIFIC_BUNDLE_KEY");
  }
}
2 голосов
/ 11 ноября 2011

Вы можете сделать это только с помощью JSF.

Начните с определения управляемого свойства в вашем компоненте поддержки.В конфигурации JSF вы можете установить значение управляемого свойства для выражения EL, которое ссылается на ваш пакет ресурсов.

Я сделал что-то вроде следующего, используя Tomcat 6. Единственное предостережение - вы не можете получить доступэто значение из конструктора вашего компонента поддержки, поскольку JSF еще не инициализировал его.Используйте @PostConstruct в методе инициализации, если значение необходимо в начале жизненного цикла компонента.

<managed-bean>
  ...
  <managed-property>
    <property-name>messages</property-name>
    <property-class>java.util.ResourceBundle</property-class>
    <value>#{msgs}</value>
  </managed-property>
  ...
</managed-bean>

<application>
  ...
  <resource-bundle>
    <base-name>com.example.messages.messages</base-name>
    <var>msgs</var>
  </resource-bundle>
  ...
</application>

Это дает преимущество, заключающееся в том, что ваши методы компонента поддержки в меньшей степени зависят от технологии представления, поэтому это должно быть прощетестировать.Он также отделяет ваш код от таких деталей, как имя, данное пакету.

Некоторые тесты с использованием Mojarra 2.0.4-b09 действительно показывают небольшое несоответствие, когда пользователь меняет локаль в середине сеанса.В выражениях EL на странице используется новая локаль, но компоненту поддержки не дается новая ссылка ResourceBundle.Чтобы сделать это согласованным, вы можете использовать значение свойства bean в выражениях EL, например, использовать #{backingBean.messages.greeting} вместо #{msgs.greeting}.Тогда страница EL и компонент поддержки всегда будут использовать локаль, которая была активной в начале сеанса.Если бы у пользователей было , чтобы переключать локали в середине сеанса и получать новые сообщения, вы могли бы попытаться создать bean-объект в области запроса и дать ему ссылки как на сессионный компонент, так и на пакет ресурсов.

2 голосов
/ 29 ноября 2010

Проще использовать, например, модуль сообщений MyFaces CODI !

0 голосов
/ 05 сентября 2012

Это старый вопрос, но я добавляю другой способ сделать это. Я искал что-то еще и наткнулся на это. Методы здесь все казались запутанными для чего-то, что не кажется мне настолько сложным. Играю с блеском, потому что это мило, если вы спросите меня.

Данный файл:

/com/full/package/path/to/messages/errormessages.properties

Внутри файла:

SOME_ERROR_STRING=Your App Just Cratered

Я создаю метод getBundle (), так как мне нравится ловить среду выполнения и добавлять значимое сообщение, чтобы я мог понять, откуда оно приходит. Не сложно и может помочь, если вы по какой-то причине получаете прихоть, чтобы поиграть с файлами свойств и не обновлять все правильно. Я иногда делаю это приватным, так как иногда это вспомогательный метод в классе (для меня). Это удерживает бесполезный беспорядок в значимом коде.

Использование полного пути к файлу позволяет поместить его где-то, кроме расположения / каталога по умолчанию, если у вас есть другие идеи по организации.

public/private ResourceBundle getMessageResourceBundle(){
    String messageBundle = "com.full.package.path.to.messages.errormessages";
    ResourceBundle bundle = null;
    try{
        bundle = ResourceBundle.getBundle(messageBundle);
    }catch(MissingResourceException ex){
        Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
                    "Unable to find message bundle in XYZ Class", ex);
        throw ex;
    }

}

public void doSomethingWithBundle(){

    ResourceBundle bundle = getMessageResourceBundle();
    String someString = bundle.getString("SOME_ERROR_STRING");
    ...
}
0 голосов
/ 13 августа 2010

Вот пример того, как это сделать: http://www.laliluna.de/articles/javaserver-faces-message-resource-bundle-tutorial.html

Вы хотите взглянуть на деталь ResourceBundle.getBundle().

Привет, Lars

...