JSF 2.0应用程序中的本地化图像



我有一个JSF 2.0应用程序,它允许用户更改站点的语言,这将影响文本和图像。

当前区域设置是在会话bean中设置的,并且每个页面都具有从该会话bean设置的区域设置。它对文本非常有效。但我在图像方面有困难。目前我们使用的图片是这样的:

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

这会生成以下HTML代码返回给用户代理:

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

假设用户请求英文页面。上面图像的GET请求由ResourceHandler.handleResourceRequest()处理。它使用ViewHandler.calculateLocale()来识别正确的语言环境前缀。我已经用calculateLocale()实现了我自己的ViewHandler,它从用户的会话中检索语言环境。因此,它正确地创建了一个指向"/resources/english/img/flag.gif"的资源实例。然后用户将他/她的区域设置更改为法语。当页面重新加载时,将呈现并请求相同的图像URL。这次ViewHandler.calculateLocale()返回Locale。FRENCH到ResourceHandler,结果创建路径为"/resources/FRENCH/img/flag.gif".

的资源。

在流式传输图像之前,根据规范,ResourceHandler.handleResourceRequest()必须执行以下操作:

•叫Resource.userAgentNeedsUpdate (javax.faces.context.FacesContext)。如果此方法返回false,则HttpServletRequest。SC_NOT_MODIFIED必须传递给HttpServletResponse.setStatus(),然后handleResourceRequest必须立即返回。

它检测到资源在之前的浏览器请求之后没有更新——没有考虑到之前对这个"逻辑"URL的请求会导致服务器上不同的"物理"资源。并返回HTTP 304,这将导致之前的英文图像再次显示给用户。

如果用Shift+F5刷新页面,由于用户代理没有发送"If- modified - since",因此法语图像被正确下载。

总是有可能在库名中手动添加带有EL的区域设置前缀,如下所示:

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

但我仍然认为前一种方法应该有效,而且更简洁。

我在想:

  1. 如果我们使用"name"one_answers"library"属性,为什么JSF不生成一个"src"作为图像的实际路径?JSF拥有在初始页面请求上构建完整路径的所有信息——包括来自UIViewRoot的区域设置(不需要实现我自己的ViewHandler)。我的假设是,这是因为根据规范,资源也可以放在类路径中的JAR中。但是,servlet的url只能用于检索类路径定位的资源,而不能给出直接的url。

  2. 为什么规范声明生成的图像"src"属性应该包括库,但没有说关于语言环境前缀(参见Resource.getReqestPath())?图像src由Resource.getRequestPath()检索。如果前缀包含在URL中,则法语和英语图像将不会被浏览器解释为单个"修改"资源。

欢迎任何想法!

实际上,您也可以使用常规的HTML <img>标记并构建自己的路径。
似乎最好创建自己的控制器来解析路径:

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

本地化控制器可以像这样读取上下文路径(当前应用程序的基础URL):

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

ExternalContext还提供了真实的路径名(即磁盘上的路径名,如果您使用爆炸格式)-如果您需要,请参阅getRealPath()方法。

为什么我更喜欢这种方法?它是非常简单和非常强大的:你可以使用本地化控制器不仅提供路径到本地化对象,如CSS文件(或至少主样式表覆盖),客户端脚本,当然还有图像,而且还提供动态的本地化上下文(即JavaScript中可翻译的字符串数组)。

回答您的具体问题:

  1. 简短的回答是我不知道。我喜欢这样想:设计这个API的人仔细权衡了所有的利弊,选择了最优的解决方案(尽管不能满足每一个可能的用例)。

  2. 我可以给你准确的答案。基本上,正确国际化的应用程序不应该包含任何可能依赖于Locale的图像,即特定于文化的图像。这是非常理想主义的世界观,但老实说,拥有实际上依赖于Locale的图像应该是罕见的情况。
    如果我理解了你的具体问题,你想要基于当前Locale切换一些特定的国家标志。事实上,你也可以在这里使用条件渲染(render="#{someController.someBooleanMethod}"),并一次写入所有的图像引用。我知道这很糟糕,但这是一个可行的解决方案。

最新更新