Localized Images in JSF 2.0

I have a JSF 2.0 application that allows the user to change the language of the site, which should affect both texts and images.

Currently, the locale is set up in a bean session, and each page has a locale set from that bean session. It works great for texts. But I have image problems. We currently use these images:

<h:graphicImage name="flag.gif" library="img"> 

This results in the following HTML being returned to the user agent:

 <img src="/AppRoot/faces/javax.faces.resource/flag.gif?ln=img" .... /> 

Suppose a user requests a page in English. The GET request for the image above is processed by ResourceHandler.handleResourceRequest (). It uses ViewHandler.calculateLocale () to determine the correct language prefix. I implemented my own ViewHandler using calculateLocale (), which retrieves the locale from a user session. As a result, it correctly creates an instance of the resource that points to "/resources/english/img/flag.gif" . The user then changes his language to French. When the page reloads, the same image URL is displayed and requested. This time, ViewHandler.calculateLocale () returns Locale.FRENCH in the ResourceHandler, which results in the creation of the resource using the path "/resources/french/img/flag.gif" .

Before streaming an image according to the ResourceHandler.handleResourceRequest () specification, it must do the following:

• Call Resource.userAgentNeedsUpdate (javax.faces.context.FacesContext). If this method returns false, HttpServletRequest.SC_NOT_MODIFIED should be passed to HttpServletResponse.setStatus (), then handleResourceRequest should return immediately.

It discovers that the resource has not been updated since the previous browser request - not taking into account that the previous request to this “logical” URL leads to a different “physical” resource on the server. And it returns HTTP 304, which results in the previous English image being displayed again to the user.

If the page is refreshed using Shift + F5, the French-language image will load correctly because the user agent sends an "If-Modified-Since" message.

It is always possible to add a local prefix manually using EL in the library name, for example:

 <h:graphicImage library="#{userContext.locale}/img" name="flag.gif" /> 

But I still think the old approach should work cleaner.

I am wondering:

  • Why doesn't JSF create "src", which is the actual path to the image if we use the attributes "name" and "library"? JSF has all the information to build the full path on the initial page request, including the local UIViewRoot form (there is no need to implement my own ViewHandler). My guess is that this is due to the fact that, according to the specification, resources can also be placed in the JAR in the class path. However, the servlet URL could only be displayed to get the path to the cluster for which the direct URL could not be specified.

  • Why does the specification indicate that the "src" attribute of the generated image should contain a library, but does not say anything about the locale prefix (see Resource.getReqestPath ())? The src image is retrieved by Resource.getRequestPath (). If the prefix was included in the URL, French and English images will not be interpreted by the browser as one “changed” resource.

Any ideas are welcome!

+8
image jsf jsf-2 localization
source share
1 answer

In fact, you can use the regular HTML <img> and create your own path.
It seems best to create your own controller for path resolution:

 <img alt="#{i18n['some.image.title']}" src="#{localizationController.someImage}" /> 

The localization controller could read the context path (the base URL of the current application) as follows:

 String basePath = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath(); 

ExternalContext also provides a real path name (that is, one on disk if you are using an exploded format) - see the getRealPath() method if you ever need to.

Why do I prefer this method? This is extremely simple and quite effective: you can use the localization controller not only to provide paths to localized objects, for example, CSS files (or at least to basic overrides of the stylesheet), client scripts, and, of course, images, but also to provide a dynamic localizable context (i.e., arrays of translatable strings in JavaScript).

To answer your specific questions:

  • Short answer: I do not know. I would like to think about it, that someone who developed this API carefully weighed the pros and cons and chose the optimal solution (although it did not satisfy all possible use cases).

  • For this I can give you an exact answer. In principle, a properly internationalized application should not contain images that may depend on Locale, i.e. Depend on the specific culture. This is a completely idealistic view of the world, but honestly, an image that actually depends on Locale should be a rare case.
    If I understand your specific problem, you want to switch a specific country flag based on the current locale. In fact, you can simply use conditional rendering here ( render="#{someController.someBooleanMethod}" ) and actually write all the image links at once. I know this sucks, but this is one viable solution.

+2
source share

All Articles