Capítulo 3. Archivos de propiedades y temas
- Internacionalización y Localización de Aplicaciones
- Creación de los archivos properties
- Creación de las etiquetas para los campos de las Entity
- Listado de propiedades en application.properties
- Ahora crearemos el CDI Beans ResourcesFiles, para manejar los archivos properties.
- Editar template.xhtml
- Editamos menu.xhtml
- Editar EstatusController.java
- CREAR UN SelectOneMenu
- TEMAS DE PRIMEFACES
Internacionalización y Localización de Aplicaciones
En este capítulo se mostrará como crear aplicaciones con soporte para múltiples idiomas.
Esté será el estándar que se usarán para las propiedades de la aplicación
messages.properties --> contendrá las etiquetas y nombre de tablas
application.properties --> mensajes del sistema, botones , mensajes de error.
Formato
sistema
|
application.
| |
botones
|
boton.
| |
idioma
|
language.
| |
elementos de menu
|
menu.
| |
elementos menuitem
|
menuitem.
| |
formularios
|
form.
|
form.entidad, form.entidadnew, form.entidadedit, form.entidadlist, form.entidadsearch, form.entidadprint
|
mensajes de error
|
error.
| |
mensajes warning
|
warning.
|
warning.ATRIBUTOcomplemento
warning.idexist
existe un registro con ese id
|
mensajes de información
|
info.
| |
dialogos
|
dialog.
|
Para agregar el soporte para múltiples idiomas en nuestra aplicacion web, debemos seguir los siguientes pasos
Creación de los archivos properties
En Other Sources hacemos clic derecho sobre src/main/resources y seleccionamos New→ Java Package
Seguidamente, indicamos el nombre del paquete: com.avbravo.scrumweb.properties
Ahora, seguimos:
- Desde menú File, seleccionamos New
- en Categories, escogemos Other
- y en File Types, seleccionamos Properties File
Seguimos indicando el nombre: messages
Ahora le damos clic derecho y seleccionamos Add→ Locale para crear compatibilidad con otros idiomas:
Indicamos la compatibilidad para el idioma inglés colocando en Language Code: en
Repetimos el procedimiento y agregamos soporte para el idioma español colocando en Language Code: es
Con esto se generarán los archivos messages_en.properties, y messages_es.properties
Creación de las etiquetas para los campos de las Entity
Abrimos el Entity Estatus
y observamos los atributos, que son los que usaremos para agregar al archivo de propiedades.
- idestatus
- estatus
- esinicial
Agregaremos propiedades con el mismo nombre de cada atributo en el archivo messages.properties. Para ello, seleccionaremos el archivo messages.properties dar con el clic derecho y seleccionamos Open , luego hacemos clic en New Property
Indicamos los valores para los campos key y value correspondientes a los atributos del Entity
De esta manera agregamos todas las propiedades del Entity para los idiomas que establecimos(predeterminado, inglés, español)
Creamos un archivo properties para el manejo de los mensajes, etiquetas, botones de la aplicacion, lo llamaremos application.properties y agregamos el soporte para el idioma español e inglés.
Listado de propiedades en application.properties
application.title=Scrum Web
application.shorttitle=Scrum Web
boton.all=Todos
boton.cerrar=Cerrar
boton.changetheme=Cambiar
boton.new=Nuevo
boton.save=Guardar
boton.delete=Eliminar
boton.update=Actualizar
boton.ayuda=Ayuda
boton.filter=Filtrar
boton.search=Buscar
boton.home=Inicio
boton.query=Consultar
boton.clear=Limpiar
boton.yes=Si
boton.no=No
boton.list=Listar
boton.print=Imprimir
boton.login=Login
boton.logout=Salir
boton.menu=Menu
boton.return=Regresar
dialog.edit=Editar
dialog.search=Busqueda
dialog.delete=Eliminar
error.title=Error
form.estatus=Estatus
form.estatusnew=Crear Estatus
form.estatusedit=Editar Estatus
form.estatuslist=Listar Estatus
form.estatussearch=Buscar Estatus
form.estatusprint= Imprimir Estatus
label.similar=Similar
info.message=Mensaje
info.save=Guardado exitosamente
info.theme=Tema
info.required=es requerido
info.update=Editado exitosamente
info.delete=Eliminado
info.notnull=No nulo
info.sinrolasignado=No tiene rol asignado
info.title=Informacion
language.spanish=Espanol
language.english=Ingles
language.language=Idiomas
login.username=Username
login.password=Password
login.passwordnotvalid=Password no es correcto
login.usernamenotvalid=Nombre de usuario no valido
login.inactive=Usuario inactivo
login.logout=Salir
login.accesodenegado=Acceso Denegado
login.accesodenegadoDetalle=No cuenta con los privilegios para accesar esta pagina
menu.edit=Editar
menu.options=Opciones
menu.search=Buscar
menu.insert=Insertar
menu.list=Listar
menu.estatus=Estatus
menu.records=Registros
menu.themes=Temas
warning.title=Advertencia
warning.idnotexist=No existe un registro con ese id
warning.idexist=Existe registro con ese id
Nota:
Recuerde colocar el valor de las etiquetas en inglés y otros idiomas que desee agregar.
Ahora crearemos el CDI Beans ResourcesFiles, para manejar los archivos properties.
Crear el CDI llamado ResourcesFiles.java en el paquete generales
- Desde menú File, seleccione New
- Categories, seleccione Java Server Faces
- File Types, seleccione JSF ManagedBeans
- Class Name: ResourcesFiles
- Package: com.avbravo.scrumweb.generales
- Scope: Session
Nota:
Recuerde eliminar import javax.faces.bean.ManagedBean; ,
import javax.faces.bean.SessionScoped; y @ManagedBean
Codigo completo ResourcesFiles.java
Definiremos dos atributos ResourceBundle mrb para el manejo de message.properties y arb para el manejo de application.properties, en el método asignar() establecemos el idioma que el usuario seleccione. Locale usamos para obtener el objeto Locale correspondiente al idioma. Creamos losmétodoss set/get para arb, mrb.
import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
/**
*
* @author avbravo
*/
@Named
@SessionScoped
public class ResourcesFiles implements Serializable{
private static final long serialVersionUID = 1L;
Locale currentLocale;
ResourceBundle mrb; //for messages
ResourceBundle arb; //for application
public ResourcesFiles() {
}
@PostConstruct
public void init() {
saveLocale();
}
public void saveLocale() {
currentLocale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
mrb = ResourceBundle.getBundle("com.avbravo.scrumweb.properties.messages", currentLocale);
arb = ResourceBundle.getBundle("com.avbravo.scrumweb.properties.application", currentLocale);
}
public Locale getCurrentLocale() {
return currentLocale;
}
public void setCurrentLocale(Locale currentLocale) {
this.currentLocale = currentLocale;
}
public ResourceBundle getMrb() {
return mrb;
}
public void setMrb(ResourceBundle mrb) {
this.mrb = mrb;
}
public ResourceBundle getArb() {
return arb;
}
public void setArb(ResourceBundle arb) {
this.arb = arb;
}
/*
*Devuelve el mensaje Mrb
*/
public String getMensajeMrb(String mensaje) {
return mrb.getString(mensaje);
}
/*
*Devuelve el mensaje Arb
*/
public String getMensajeArb(String mensaje) {
return arb.getString(mensaje);
}
}
Crear el CDI Idiomas.java ,obtenemos el objeto locale y se define los métodos para cambiar el idioma a español inglés y se llama al método saveLocale() para guardar el idioma y establecerlo para la sesión del usuario.
- Desde menú File, seleccione New
- Categories, seleccione Java Server Faces
- File Types, seleccione JSF ManagedBeans
- Class Name: Idiomas
- Package: com.avbravo.scrumweb.generales
- Scope: Session
Codigo completo Idiomas.java
import java.io.Serializable;
import java.util.Locale;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
/**
*
* @author avbravo
*/
@Named
@SessionScoped
public class Idiomas implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
ResourcesFiles rf;
private String locale = Locale.getDefault().getDisplayLanguage();
public void setLocale(String locale) {
this.locale = locale;
}
public synchronized String getLocale() {
return locale;
}
public synchronized String changeLanguage() {
return "changed";
}
public Idiomas() {
}
public String englishAction() {
FacesContext context = FacesContext.getCurrentInstance();
context.getViewRoot().setLocale(Locale.ENGLISH);
this.locale = "en";
rf.saveLocale();
return null;
}
public String spanishAction() {
FacesContext context = FacesContext.getCurrentInstance();
context.getViewRoot().setLocale(new Locale("es"));
this.locale = "es";
rf.saveLocale();
return null;
}
}
Editar template.xhtml
colocamos dentro de las etiquetas <h:head>, el <f:view locale="#{idiomas.locale}"> indicaremos el CDI Beans que contiene el locale.
y para indicar el archivo de propiedades mediante <f:loadBundle> y el valor de var como variable de referencia.
<h:head>
<f:facet name="first">
<meta content='text/html; charset=UTF-8' http-equiv="Content-Type"/>
Agregamos
<f:view locale="#{idiomas.locale}"></f:view>
<f:loadBundle basename="com.avbravo.scrumweb.properties.messages" var="msg" />
<f:loadBundle basename="com.avbravo.scrumweb.properties.application" var="app" />
con esto podemos utilizar msg para referirnos a los archivos message y app para application.
Ahora usaremos los valores establecidos en los archivos de propiedades dentro de template.xhtml, haremos referencia mediante "#{app['application.title']}"
<title><h:outputText value="Scrum web"/></title>
por
<title><h:outputText value="#{app['application.title']}"/></title>
en donde app hace referencia a la variable para application.properties, y usamos ['aplication.title'] ya que la propiedad esta compuesta de application.title
y cambiar en bottom para agregar <h:outputText value="#{app['application.foot']}"/>
<p:layoutUnit position="south" size="50" closable="true" collapsible="true">
<ui:insert name="bottom">
Footer
</ui:insert>
</p:layoutUnit>
por
<p:layoutUnit position="south" size="50" closable="true" collapsible="true">
<ui:insert name="bottom">
<h:outputText value="#{app['application.footer']}"/>
</ui:insert>
</p:layoutUnit>
Editamos menu.xhtml
Cambiamos las etiquetas de los menús
<p:submenu label="#{app['menu.records']}" icon="ui-icon-check">
<p:column>
<p:submenu label="#{app['menu.estatus']}">
<p:menuitem value="#{app['menu.insert']}" url="/faces/page/estatus/estatusinsert.xhtml" />
<p:menuitem value="#{app['menu.list']}" url="/faces/page/estatus/estatuslist.xhtml"/>
</p:submenu>
y agregamos las etiquetas para los idiomas
<p:submenu label="#{app['menu.options']}" icon="ui-icon-check">
<p:column>
<p:submenu label="#{app['language.language']}" >
<p:menuitem action="#{idiomas.englishAction}" value="#{app['language.english']}" immediate = "true" ajax = "false" icon="ui-icon-flag"/>
<p:menuitem action="#{idiomas.spanishAction}" value="#{app['language.spanish']}" immediate = "true" ajax = "false" icon="ui-icon-flag" />
</p:submenu>
</p:column>
</p:submenu>
codigo de menu.xhtml
<h:form id="menuForm" >
<p:megaMenu>
<p:submenu label="#{app['menu.records']}" icon="ui-icon-check">
<p:column>
<p:submenu label="#{app['menu.estatus']}">
<p:menuitem value="#{app['menu.insert']}" url="/faces/page/estatus/estatusinsert.xhtml" />
<p:menuitem value="#{app['menu.list']}" url="/faces/page/estatus/estatuslist.xhtml"/>
</p:submenu>
</p:column>
</p:submenu>
<p:submenu label="#{app['menu.options']}" icon="ui-icon-check">
<p:column>
<p:submenu label="#{app['language.language']}" >
<p:menuitem action="#{idiomas.englishAction}" value="#{app['language.english']}" immediate = "true" ajax = "false" icon="ui-icon-flag"/>
<p:menuitem action="#{idiomas.spanishAction}" value="#{app['language.spanish']}" immediate = "true" ajax = "false" icon="ui-icon-flag" />
</p:submenu>
</p:column>
</p:submenu>
</p:megaMenu>
</h:form>
Si observamos el browser
Dar clic en ingles y cambia el idioma
Editamos estatusinsert.xhtml para agregar las etiquetas de los archivos de propiedades usar app. para archivos application.properties y msg para messages.properties .
Usamos msg.idestatus para las etiquetas y el nombre del formulario
Cambiar
<h1><h:outputText value="Create/Edit"/></h1>
por
<h1><h:outputText value="#{app['form.estatusnew']}"/> </h1>
Cambiar
value="Idestatus:" for="idestatus" />
por
<h:outputLabel value="#{msg.idestatus}" for="idestatus" />
Esto lo hacemos para cada atributo del CDI Beans que se encuentra en el JSF
Importante, crear las propiedades para title y para requiredMessage
En los inputText cambiamos title y requiredMessage agregamos la etiqueta con el atributo #{app['info.required']}" para enviar el mensaje que es requerido.
<h:inputText id="idestatus" value="#{estatusController.estatus.idestatus}" title="#{msg.idestatus}" required="true" requiredMessage="#{msg.idestatus} #{app['info.required']}"/>
Cambiamos todas las etiquetas.
Cambiar el botón save
<p:commandButton value="#{app['boton.save']}" update="panel,growl" action="#{estatusController.save()}"/>
Código que implementa las etiquetas
<h1><h:outputText value="#{app['form.estatusnew']}"/></h1>
<h:panelGrid id="panel" columns="2">
<h:outputLabel value="#{msg.idestatus}" for="idestatus" />
<h:inputText id="idestatus" value="#{estatusController.estatus.idestatus}" title="#{msg.idestatus}" required="true" requiredMessage="#{msg.idestatus} #{app['info.required']}"/>
<h:outputLabel value="#{msg.estatus}" for="estatus" />
<h:inputText id="estatus" value="#{estatusController.estatus.estatus}" title="#{msg.estatus}" required="true" requiredMessage="#{msg.estatus} #{app['info.required']}"/>
<h:outputLabel value="#{msg.esinicial}" for="esinicial" />
<h:inputText id="esinicial" value="#{estatusController.estatus.esinicial}" title="#{msg.esinicial}" required="true" requiredMessage="#{msg.esinicial} #{app['info.required']}"/>
<f:facet name="footer">
<p:commandButton value="#{app['boton.save']}" update="panel,growl" action="#{estatusController.save()}"/>
</f:facet>
</h:panelGrid>
Formulario con idioma español
seleccionar el idioma inglés para cambiar los valores de los atributos
Mensajes de campos requeridos en español
Mensajes de campos requeridos en inglés
title, se mostrará una ayuda al colocar el cursor sobre el componente.
Editar EstatusController.java
Cambiaremos los mensajes en el CDI para utilizar los de los archivos messages.properties y application.properties, y en los métodos.
Inyectar ResourcesFiles
@Inject
ResourcesFiles rf;
usamos rf.getMensajeArb(etiqueta)para obtener las etiquetas del archivo application.properties.
usamos rf.getMensajeMrb(etiqueta)para obtener las etiquetas del archivo messages.properties.
Modificar el codigo del método save(), para utilizar las etiquetas de los archivos properties.
@Named
@SessionScoped
public class EstatusController implements Serializable {
@Inject
EstatusFacade estatusFacade;
Estatus estatus = new Estatus();
@Inject
ResourcesFiles rf;
private List<Estatus> items;
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
public Estatus getEstatus() {
return estatus;
}
public void setEstatus(Estatus estatus) {
this.estatus = estatus;
}
public List<Estatus> getEstatusList() {
return estatusFacade.getEstatusList();
}
public String save() {
try {
if (estatusFacade.find(estatus.getIdestatus()) != null) {
JSFUtil.warningDialog(rf.getMensajeArb("info.message"), rf.getMensajeArb("warning.idexist"));
return null;
}
estatusFacade.create(estatus);
JSFUtil.addSuccessMessage(rf.getMensajeArb("info.save"));
estatus = new Estatus();
} catch (Exception e) {
JSFUtil.addErrorMessage(e.getLocalizedMessage());
}
return null;
}
public String edit() {
try {
estatusFacade.edit(estatus);
JSFUtil.addSuccessMessage(rf.getMensajeArb("info.update"));
} catch (Exception e) {
JSFUtil.addErrorMessage(e.getLocalizedMessage());
}
return null;
}
public String delete() {
try {
estatusFacade.remove(estatus);
JSFUtil.addSuccessMessage(rf.getMensajeArb("info.delete"));
encontrado = false;
estatus = new Estatus();
} catch (Exception e) {
JSFUtil.addErrorMessage(e.getLocalizedMessage());
}
return null;
}
public List<Estatus> getItems() {
if (items == null) {
items = estatusFacade.findAll();
}
return items;
}
Muestra el mensaje en Espanol
o en inglés dependiendo del idioma seleccionado
CREAR UN SelectOneMenu
Ahora crearemos un selectOneMenu para desplegar las opciones para el atributo esinicial, con los valores de si/no.
Utilizamos el componente <p:selectOneMenu/> de primefaces, el valor para value se indicará el atributo del Entity
<p:selectOneMenu id="esinicial" value="#{estatusController.estatus.esinicial}" required="true" requiredMessage="#{msg.esinicial} #{app['info.notnull']}">
<f:selectItem itemLabel="#{app['boton.yes']}" itemValue="si" />
<f:selectItem itemLabel="#{app['boton.no']}" itemValue="no" />
</p:selectOneMenu>
Genera el selectOneMenu con los valores en diversos idiomas.
en Español
Cambiamos el idioma a ingles.
TEMAS DE PRIMEFACES
Primefaces ofrece una serie de temas que podemos implementar en nuestra aplicación web y cambiar su aspecto de manera sencilla.
Primero crearemos un CDI de tipo @SessionScoped para que contenga durante la sesión del usuario el tema seleccionado, modificaremos el archivo web.xml para establecer el soporte para el tema y se mostrará una lista de temas para seleccionarlo.
- Desde menú File, seleccione New
- en Categories, seleccione Java Server Faces
- en File Types, seleccione JSF ManagedBeans
- Class Name: ManagementThemes
- Package com.avbravo.scrumweb.generales
- Scope: Session
import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
/**
*
* @author avbravo
*/
@Named
@SessionScoped
public class ManagementThemes implements Serializable {
private static final long serialVersionUID = 1L;
private String tema = "home";
private String temaPredeterminado = "home";
private Map<String, String> themes;
public Map<String, String> getThemes() {
themes = new TreeMap<String, String>();
themes.put("afterdark", "afterdark");
themes.put("afternoon", "afternoon");
themes.put("afterwork", "afterwork");
themes.put("aristo", "aristo");
themes.put("black-tie", "black-tie");
themes.put("blitzer", "blitzer");
themes.put("bluesky", "bluesky");
themes.put("casablanca", "casablanca");
themes.put("cupertino", "cupertino");
themes.put("cruze", "cruze");
themes.put("dark-hive", "dark-hive");
themes.put("dot-luv", "dot-luv");
themes.put("eggplant", "eggplant");
themes.put("excite-bike", "excite-bike");
themes.put("flick", "flick");
themes.put("glass-x", "glass-x");
themes.put("home", "home");
themes.put("hot-sneaks", "hot-sneaks");
themes.put("humanity", "humanity");
themes.put("le-frog", "le-frog");
themes.put("midnight", "midnight");
themes.put("mint-choc", "mint-choc");
themes.put("none", "none");
themes.put("overcast", "overcast");
themes.put("pepper-grinder", "pepper-grinder");
themes.put("redmond", "redmond");
themes.put("rocket", "rocket");
themes.put("sam", "sam");
themes.put("smoothness", "smoothness");
themes.put("south-street", "south-street");
themes.put("start", "start");
themes.put("sunny", "sunny");
themes.put("swanky-purse", "swanky-purse");
themes.put("trontastic", "trontastic");
themes.put("ui-darkness", "ui-darkness");
themes.put("ui-lightness", "ui-lightness");
themes.put("vader", "vader");
return themes;
}
public String getTemaPredeterminado() {
return temaPredeterminado;
}
public void setTemaPredeterminado(String temaPredeterminado) {
this.temaPredeterminado = temaPredeterminado;
}
public void setThemes(Map<String, String> themes) {
this.themes = themes;
}
public String getTema() {
return tema;
}
public void setTema(String tema) {
this.tema = tema;
}
public String cambiar(){
return null;
}
}
Editar el archivo web.xml ubicado en la carpeta WEB-INF
Agregar en <context-param> referencia al CDI ManagementThemes
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>#{managementThemes.tema}</param-value>
</context-param>
Editar menu.xhtml
Agregar dentro del <p:column> en el submenú option
<p:submenu label="#{app['menu.themes']}">
<p:menuitem icon="ui-icon-star" onclick="PF('dlgTheme').show();"
value="#{app['info.theme']}" immediate = "true" />
</p:submenu>
y colocamos el menuitem para salir
<p:menuitem value="#{app['login.logout']}" title="#{app['login.logout']}" icon="ui-icon-power"/>
y agregamos el <p:dialog> debajo del </p:megaMenu>
<p:dialog header="#{app['info.theme']}" widgetVar="dlgTheme"
showEffect="bounce" hideEffect="explode" width="400"
height="200">
<h:panelGrid columns="2">
<h:panelGroup>
<p:outputLabel value="#{app['info.theme']}"/>
<p:selectOneMenu value="#{managementThemes.tema}" immediate
= "true" editable="true">
<f:selectItems value="#{managementThemes.themes}" />
</p:selectOneMenu>
<p:commandButton value="#{app['boton.changetheme']}"
action="#{managementThemes.cambiar}" ajax="false"/>
</h:panelGroup>
</h:panelGrid>
</p:dialog>
Codigo de menu.xhtml
<h:form id="menuForm" >
<p:megaMenu rendered="#{loginBean.logeado}">
<p:submenu label="#{app['menu.records']}" rendered="#{menuBeans.barraRegistros}" icon="uiiconcheck">
<p:column>
<p:submenu label="#{app['menu.estatus']}" rendered="#{menuBeans.estatusMenu}">
<p:menuitem value="#{app['menu.insert']}" rendered="#{menuBeans.estatusCrear}" url="/faces/page/estatus/estatusinsert.xhtml" />
<p:menuitem value="#{app['menu.list']}" rendered="#{menuBeans.estatusListar}" url="/faces/page/estatus/estatuslist.xhtml"/>
</p:submenu>
</p:column>
</p:submenu>
<p:submenu label="#{app['menu.options']}">
<p:column>
<p:submenu label="#{app['menu.themes']}">
<p:menuitem icon="ui-icon-star" onclick="PF('dlgTheme').show();"
value="#{app['info.theme']}" immediate = "true" />
</p:submenu>
<p:submenu label="#{app['language.language']}">
<p:menuitem action="#{idiomas.englishAction}" value="#{app['language.english']}"
immediate = "true" ajax = "false" icon="ui-icon-flag"/>
<p:menuitem action="#{idiomas.spanishAction}" value="#{app['language.spanish']}"
immediate = "true" ajax = "false" icon="ui-icon-flag" />
</p:submenu>
</p:column>
</p:submenu>
<p:menuitem value="#{app['login.logout']}" title="#{app['login.logout']}" icon="ui-icon-power"/>
</p:megaMenu>
<p:dialog header="#{app['info.theme']}" widgetVar="dlgTheme"
showEffect="bounce" hideEffect="explode" width="400"
height="200">
<h:panelGrid columns="2">
<h:panelGroup>
<p:outputLabel value="#{app['info.theme']}"/>
<p:selectOneMenu value="#{managementThemes.tema}" immediate
= "true" editable="true">
<f:selectItems value="#{managementThemes.themes}" />
</p:selectOneMenu>
<p:commandButton value="#{app['boton.changetheme']}"
action="#{managementThemes.cambiar}" ajax="false"/>
</h:panelGroup>
</h:panelGrid>
</p:dialog>
</h:form>
Tenemos un ejemplo cambiando el tema a hot-sneaks
se muestra la aplicación con el tema aplicado
primefaces ofrece el componente <p:themeSwitcher> que realiza la misma función.
<h:outputText value="#{app['info.theme']}" />
<p:themeSwitcher style="width:165px" id="defaultSwitcher">
<f:selectItem itemLabel="Choose Theme" itemValue="" />
<f:selectItems value="#{managementThemes.themes}" />
</p:themeSwitcher>
Comments
(Do que eu li) É isso que você está usando no seu blog?