Internazionalization won't work due to problems w jsf propieties [duplicate] - html

faces-config.xml:
<application>
<locale-config>
<default-locale>ru</default-locale>
<supported-locale>ua</supported-locale>
</locale-config>
</application>
In a bean action method, I'm changing the locale in the current view as follows:
FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale("ua"));
The problem is that ua Locale is applied, but only per request/view and not for session. Another request/view within the same session resets the locale back to default ru value.
How can I apply the locale for session?

You need to store the selected locale in the session scope and set it in the viewroot in two places: once by UIViewRoot#setLocale() immediately after changing the locale (which changes the locale of the current viewroot and thus get reflected in the postback; this part is not necessary when you perform a redirect afterwards) and once in the locale attribute of the <f:view> (which sets/retains the locale in the subsequent requests/views).
Here's an example how such a LocaleBean should look like:
package com.example.faces;
import java.util.Locale;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
#ManagedBean
#SessionScoped
public class LocaleBean {
private Locale locale;
#PostConstruct
public void init() {
locale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
}
public Locale getLocale() {
return locale;
}
public String getLanguage() {
return locale.getLanguage();
}
public void setLanguage(String language) {
locale = new Locale(language);
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}
}
And here's an example of the view should look like:
<!DOCTYPE html>
<html lang="#{localeBean.language}"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view locale="#{localeBean.locale}">
<h:head>
<title>JSF/Facelets i18n example</title>
</h:head>
<h:body>
<h:form>
<h:selectOneMenu value="#{localeBean.language}" onchange="submit()">
<f:selectItem itemValue="en" itemLabel="English" />
<f:selectItem itemValue="nl" itemLabel="Nederlands" />
<f:selectItem itemValue="es" itemLabel="Español" />
</h:selectOneMenu>
</h:form>
<p><h:outputText value="#{text['some.text']}" /></p>
</h:body>
</f:view>
</html>
Which assumes that #{text} is already configured in faces-config.xml as below:
<application>
<resource-bundle>
<base-name>com.example.i18n.text</base-name>
<var>text</var>
</resource-bundle>
</application>
Note that <html lang> is not required for functioning of JSF, but it's mandatory how search bots interpret your page. Otherwise it would possibly be marked as duplicate content which is bad for SEO.
See also:
Maven and JSF webapp structure, where exactly to put JSF resources
Internationalization in JSF, when to use message-bundle and resource-bundle?
i18n with UTF-8 encoded properties files in JSF 2.0 application

I see that the problem is also with .properties file name.
Java Locale us codes (lowercase) like: en_gb
But automaticly created locale (by Netbeans) is lowercase_uppercase i.e.: messages_en_GB.properties
Change name to: messages_en_gb.properties
and it should work - if you tried everything

This component f:view is not there your JSF page it will not work and It will shows only default english language.Provide the localae value for this f:view component then it will work fine. I faced the same problem now its working fine.

One small remark to #BalusC great solution. If we have <f:viewAction> which executes some method in backing bean. Locale available from call to FacesContext.getCurrentInstance().getViewRoot().getLocale() inside that method would be locale that is set by user browser or default application locale, not that locale that is set on session bean by user selection(of course they can match if browser locale equals that locale that user selected).
I can stand corrected, because maybe I did something wrong when implementing solution provided by #BalusC.
EDIT. After playing with JSF lifecycle, this behavior with locale is not related to <f:viewAction>, because there is similar behavior also with #PostContruct. <f:view locale="#{localeBean.locale}"> in request(after user selected locale) is executed in render response phase. <f:viewAction> and #PostContruct methods are executed in invoke application phase. That is why logic that is executed in this method do not have access to user selected locale.
Solution that we using when we need correct locale is to inject(CDI) localeBean in other backing bean that contains <f:viewAction> and #PostContruct methods, and then set locale with UIViewRoot#setLocale() from localeBean in beginning of these methods.

If you can use CDI and deltaspike (JSF module) in your environment, you could add the following to your LocaleBean to automatically reset the locale on the current view:
#javax.enterprise.context.SessionScoped
public class LocaleBean implements Serializable {
...
public void resetLocale(#Observes #BeforePhase(JsfPhaseId.RENDER_RESPONSE) PhaseEvent event) {
event.getFacesContext().getViewRoot().setLocale(this.locale);
}
}

Related

Can't apply plain HTML class to a Blazor component

I've tried to use this code in my .NET 5 Blazor project, in .razor file:
<SignedLabel class="some-css-class" Price=123 Currency=Currency.Usd />
where SignedLabel - is a Blazor component and Price, Currency is the component's input parameters. I expect Blazor to treat the class word as an html property and apply the plain HTML class to this component so that I can style this component later on. But Blazor actually treats it as another input parameter for component and crashes whole app rendering with error:
Object of type 'SignedLabel' does not have a property matching the name 'class'
So the questions is
Is it possible to use the class property in a such way?
If yes, how should I do this?
PS: project settings:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>9</LangVersion>
</PropertyGroup>
...
</Project >
You cannot apply a class to a Component. You can use splatting to capture attributes placed on a Component to pass as parameter to one of the components elements.
SomeComponent.razor
<div #attributes="#CapturedAttributes">
Hello
</div>
#code {
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string,object> CapturedAttributes { get; set; }
}
##Usage
<SomeComponent id="fred" class="some-css-class" style="width:100vh" />
Will render:
<div id="fred" class="some-css-class" style="width:100vh" >
Hello
</div>
Docs
You just have to create a Parameter in your component. For example, this works fine. In a Tree component, TopDivClass parameter has been added an used.
In the markup of the component:
<div class="#TopDivClass">
In the code behind of the component:
[Parameter]
public string TopDivClass { get; set; }
In the markup using the component:
<Components.Tree TopDivClass="TreeView" />
The result in the HTML is
<div class="TreeView" ...
I've encountered a similar issue and Google led me here, so I share it for anyone who might hit this as well.
My project setup is .NET 7 and Teams App project template (Blazor Server).
The problem was similar to OP's - I wanted to apply CSS class to Web Component. In my case it was FluentTextField, so I couldn't modify its code.
Although doing this:
<FluentTextField
class="w-100"
Placeholder="Provide the URL"
Required="true"/>
wasn't producing any errors and in browser Dev Tools I could see the class added the element, i.e. <fluent-text-field class='w-100'>, the CSS defined in parent component wasn't applied.
Turns out, it's enough to change "Blazor syntax" to "JS syntax" and everything works fine:
<fluent-text-field
class="w-100"
Placeholder="Provide the URL"
Required="true"/>

How to let JSF pass through HTML attributes [duplicate]

This question already has an answer here:
Custom HTML tag attributes are not rendered by JSF
(1 answer)
Closed 2 years ago.
I am using Primefaces 3 in JSF 2 to make a search box. I need to add a non-standard attribute (x-webkit-speech) to the control so you would have something like this...
<p:autoComplete x-webkit-speech="x-webkit-speech" ... />
Since this attribute isn't part of the autoComplete control JSF gives me a 500 error. But when I remove it, the page renders fine. In general, how do you specify pass through attributes on a JSF tag so they are ignored?
JSF by design ignores all custom attributes when rendering HTML.
If you're already on JSF 2.2+, simply specify it as passthrough attribute:
<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<p:autoComplete a:x-webkit-speech="x-webkit-speech" ... />
If you're not on JSF 2.2 yet, then you need a custom renderer. This is in case of PrimeFaces <p:autoComplete> (and all other components) fortunately relatively simple. It's sufficient to override just the renderPassThruAttributes() method wherein you add the new attribute which you'd like to render to the attrs argument and finally delegate to the super method.
E.g.
package com.example;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.primefaces.component.autocomplete.AutoCompleteRenderer;
public class MyAutoCompleteRenderer extends AutoCompleteRenderer {
#Override
protected void renderPassThruAttributes(FacesContext facesContext, UIComponent component, String[] attrs) throws IOException {
String[] newAttrs = new String[attrs.length + 1];
System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
newAttrs[attrs.length] = "x-webkit-speech";
super.renderPassThruAttributes(facesContext, component, newAttrs);
}
}
To get it to run, register it as follows in your webapp's faces-config.xml:
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.AutoCompleteRenderer</renderer-type>
<renderer-class>com.example.MyAutoCompleteRenderer</renderer-class>
</renderer>
</render-kit>
(you can find out the component family and renderer type by looking at the source code of AutoComplete class, they're specified as COMPONENT_FAMILY and RENDERER_TYPE constants in there)
No, the #FacesRenderer annotation simply won't work when the purpose is to override custom renderers which are by itselves already registered in a faces-config.xml.
The most Tags can be extended, using the Attribute-Tag from JSF-Ext.
<html xmlns:h="http://java.sun.com/jsf/html" xmlns:e="http://java.sun.com/jsf/ext">
<!-- ... -->
<h:inputText id="name" value="#{bean.name}">
<e:attribute name="placeholder" value="My Name"/>
</h:inputText>
<!-- ... -->
</html>
You can configure it via maven:
<dependency>
<groupId>com.intersult</groupId>
<artifactId>jsf-ext</artifactId>
<version>2.2.0.1</version>
</dependency>
JSF-Ext is a library from http://www.intersult.com/wiki/page/JSF%20Ext
I am not sure if this is possible at all. I would add those attributes on the client side using javascript or jQuery.
You can put el expressions into your javascript code if you want to integrate server-side stuff.

Primefaces AJAX event not working inside tabView

How can I use an AJAX listener inside a tabview. Whenever the tab opened(or for a mouse click anywhere), the listener need to execute. I tried with event=click,change,blur etc, but not worked.
<p:tabView activeIndex="#{backingbean.tanIndex}">
<p:ajax event="?" listener="#{backingbean.setTabIndex}" />
in view.jsf:
<p:tabView>
<p:ajax event="tabChange" listener="#{employeeEdit.onTabChange}">
in edit.jsf:
<p:tabView activeIndex="#{employeeEdit.tabIndex}">
in backingBean:
private int tabIndex;
public int onTabChange(TabChangeEvent event)
{
// Here I'm getting event.getTab().getId() and set it to `tabIndex` property.
}
When editing I need redirect to the that tab which is active in view. So if I didn't change the tab onTabChange() will not execute and tabIndex has its old value only.
I'm using Primefaces version-3.0.M3.
It looks like this was a Primefaces bug that was fixed in the newest 3.0.1 release:
http://forum.primefaces.org/viewtopic.php?f=3&t=17288
I had a similar problem with Primefaces 5.1
As long as i put the tabview into a form everything worked fine.
But because i wanted to use seperate forms in my tabs i had to remove the surrounding form of the tabview to avoid nested forms.
Without the surrounding form the ajax event didn´t get triggered any more when changing the tab.
My solution was to use a remotecommand in a form parallel to the tabview.
The remotecommand is triggered by the onTabChange attribute of the tabview element.
At that call i forwarded the index parameter to the global request parameters.
<p:tabView id="rootTabMenu" styleClass="tabcontainer" prependId="false"
activeIndex="#{sessionData.activeTabIndex}" widgetVar="rootTabMenu"
onTabChange="tabChangeHelper([{name: 'activeIndex', value: index}])">
// Tabs...
</p:tabView>
<h:form id="tabChangeHelperForm">
<p:remoteCommand name="tabChangeHelper" actionListener="#{sessionData.onTabChange()}" />
</h:form>
In the backing bean i catched the value again from the request parameter map and set the active index.
public void onTabChange()
{
FacesContext context = FacesContext.getCurrentInstance();
Map<String, String> paramMap = context.getExternalContext().getRequestParameterMap();
String paramIndex = paramMap.get("activeIndex");
setActiveTabIndex(Integer.valueOf(paramIndex));
System.out.println("Active index changed to " + activeTabIndex);
}
Hope that can help you
Not sure if what I am writing is true for ver 3.0.M3. I have in front of the documentation of ver 3.0RC2 and there is a paragraph about this, with explaination and sample code (chapter TabView, paragraph Ajax Behaviour Events). You should have a look at that.
This is the part of the sample code that should help most:
<p:tabView>
<p:ajax event=”tabChange” listener=”#{bean.onChange}” />
</p:tabView>
Jaron has an answer that the 3.0.1 release fixed this but I had this all the way up to 3.5 i believe i was still having this problem. on firefox and IE, the javascript handler for the Tabs weren't firing the ajax event. On google chrome, for whatever reason, it actually worked.
I moved up to Primefaces 5.0 today and this does NOT have the problem any longer. So at the very worst-case, go to Primefaces 5.0 and you'll be all good in the hood

collapsing p:tree

I have a tree that is used as menu, so every node is clickable and opens another *.xhtml file. The tree is displayed on every *.xhtml file with templates.
Problem: the tree collapses if redirect to a *.xhtml file. Surprisingly, the selected node stays selected (it is colored as selected). The tree shouldn't collapse!
The tree is generated dynamic, but it is only generated once.
Tested with Primefaces 2.2.1 and 3.0.M2
How can I solve this problem? At primefaces showcase this works.
My code:
<h:form id="formTreeStudents">
<p:tree id="treeGroups"
value="#{studentTree.root}"
var="node"
cache="true"
selectionMode="single"
nodeSelectListener="#{studentTree.onNodeSelect}"
selection="#{studentrTree.selectedNode}"
onselectComplete="ajaxDialog.show();"
update="statusbar userbar">
<p:treeNode>
<h:outputText value="#{node.treeString}" styleClass="treeNodeParent"/>
</p:treeNode>
</p:tree>
<p:ajax event="load" onstart="ajaxDialog.hide();"/>
</h:form>
The bakingBean is sessionScoped. It has getter and setter similar to the example at primefaces showcase and a listener function.
#ManagedBean
#SessionScoped
public class StudentTree implements Serializable{
...
public void onNodeSelect(NodeSelectEvent event) {
...
}
}
The tree node stays selected because the property #{studentrTree.selectedNode} of the managed bean has a value.
Your managed bean is #SessionScoped so it will live in session even after you navigate away from and back to the page. If you were to change it to #ViewScoped then the managed bean will die when navigating away from the page, and when you navigate back to the page the property selectedNode will be its default value again.
solved it.
it works with Primefaces 3.0.M2. Something was wrong with my libraries or with cached data.
Some changes had to be done to use 3.0.M2.
f.e.:
nodeSelectListener="#{studentTree.onNodeSelect}"
is now replaced with
<p:ajax event="select" listener="#{studentTree.onNodeSelect}"/>

richfaces dataOrderedList and custom back-end list [edit: browser caching !!!]

I have a backing bean containing this object:
List<Session> sessions;
and a Session is an class that has some standard fields but also this:
List<Entry> entries;
An Entry is a class that contains several fields but all of them standard java objects.
So it's like this..
List<Session>
|-Session
|-List<Entry>
|-Entry
I have tried accessing the List<Entry> directly with success.
But when I try to access the List<Session> I get the following error:
javax.faces.FacesException:
javax.el.PropertyNotFoundException:
/pages/console.jspx #75,109
value="#{session.sessionID}": The
class 'org.apache.cata
lina.session.StandardSessionFacade'
does not have the property
'sessionID'.
(sessionID is a String field of Session class)
Is there any way to fix this ?? (could a converter solve this ?)
the jspx code is:
<rich:dataOrderedList id="sessions" var="session" value="#{backEnd.sessions}" style="position:relative;top:40px">
<rich:togglePanel switchType="client" stateOrder="closed, opened" initialState="#{backEnd.sessionsState}">
<f:facet name="closed">
<rich:toggleControl style="font-weight:bold;" value="#{session.sessionID}" switchToState="opened" />
</f:facet>
Thanks in advance !!
You are using 'session' keyword as a variable and it seems like there is another bean named 'session'. To solve the problem, change your var property. Use something like
<rich:dataOrderedList id="sessions" var="mySession" value="#{backEnd.sessions}" style="position:relative;top:40px">
instead of
<rich:dataOrderedList id="sessions" var="session" value="#{backEnd.sessions}" style="position:relative;top:40px">
It appears the problem had nothing to do with code, config, deploy or anything related to that.
There is a meta parameter in the header of html documents called "Pragma" and it is used by the browsers to cache pages for the back/forward navigation. Maybe for refresh too because this was my case. (clearing cache on firefox had no effect).
So if you want to fix this while developing there is a firefox addon called "Modify Headers" which allows you to include parameters in the headers of the requested websites.
If you want to remove this feature from your html for some reason you have to add the following in the header:
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">
and I haven't investigated this one which may be needed as well:
<META HTTP-EQUIV="Cache-control" CONTENT="no-cache">