【问题标题】:Localized images in JSF 2.0 applicationJSF 2.0 应用程序中的本地化图像
【发布时间】:2011-10-25 14:09:47
【问题描述】:

我有一个 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”,因此正确下载了法国图像。

总是可以在库名称中手动添加语言环境前缀,如下所示:

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

但我仍然认为前一种方法应该有效并且更清洁。

我想知道:

  1. 如果我们为 . JSF 具有在初始页面请求上构建完整路径的所有信息 - 包括 UIViewRoot 的语言环境(无需实现我自己的 ViewHandler)。我的假设是,这是因为根据规范,资源也可以放在类路径中的 JAR 中。 servlet 的 url 仍然可以仅用于检索无法提供直接 url 的位于类路径的资源。

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

欢迎提出任何想法!

【问题讨论】:

    标签: image jsf localization jsf-2


    【解决方案1】:

    实际上,您也可以使用普通的 HTML &lt;img&gt; 标记并构建自己的路径。
    似乎最好创建自己的控制器来解析路径:

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

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

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

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

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

    回答您的具体问题:

    1. 简短的回答是我不知道。我很乐意考虑设计此 API 的人仔细权衡了所有优缺点并选择了最佳解决方案(尽管不能满足所有可能的用例)。

    2. 为此,我可以给你准确的答案。基本上,正确的国际化应用程序不应包含任何可能依赖于语言环境的图像,即特定于文化的图像。这是一种相当理想化的世界观,但说实话,拥有实际依赖于语言环境的图像应该很少见。
      如果我了解您的具体问题,您想根据当前的语言环境切换一些特定的国家标志。事实上,您也可以在此处使用条件渲染 (render="#{someController.someBooleanMethod}") 并实际一次写入所有图像引用。我知道这很糟糕,但这是一种可行的解决方案。

    【讨论】:

    • 您在上面提供的解决方案非常强大且易于应用。但如果我错了,请纠正我:引入库并将大部分演示数据描述(图像、css、元信息等)移动到 JSF 标记中,使我们能够创建演示的良好抽象。在阅读了 JSR 314 之后,我感觉图像、css 等现在也是 JSF 2.0 中国际化的一部分。那么这应该是在 i18n 中包含图像的一种新趋势,并且在 JSF 中实现得不好,或者只是不适合使用该技术?
    • JSF 组件绝对是更好的做事方式。也就是说,如果您要重新使用它们。至于 JSF 2.0,我真的希望它能够提供简单的机制来本地化 CSS、JS、图像等文件。我可能不知道某些事情,我希望有人能启发我,但我不知道如何使此类文件依赖于语言环境(上述解决方案除外)。现在,我不建议使用许多依赖于语言环境的图像。它们很难本地化,因此应该避免。如果原始设计师提供它们没有问题,但祝你好运......
    • >"如果我理解你的具体问题,你想根据当前的语言环境切换一些特定的国家标志。"其实这是一个书本的例子。我试图 i18n 图像,如“下一个”、“上一个”等。>“基本上,正确的国际化应用程序不应包含任何可能依赖于区域设置的图像,即特定于文化的图像。”在这里我要争论。根据 JSF 2.0 Specification 的“2.6.1.3 Resource Identifiers”部分: > 由几个段组成,具体如下。 >[localePrefix/][libraryName/][libraryVersion/]resourceName[/resourceVersion]
    • 另外:>function derivedResourceId(prefix, resourceLoader, resourceName, libraryName) { var localePrefix = getLocalePrefix();规范中有一个用于派生客户端语言环境的算法。所以我认为每个 JSF 实现都应该小心切换语言环境。如果切换了区域设置,那么绝对应该将图像重新发送给客户端。
    • 我尝试了以下方法:我使用了带有名称和库属性的 ​​h:graphicImage。它生成到 FacesServlet 的链接。我调试了 calculateLocale() 方法——它返回“en”,因为它是我在浏览器中的主要语言环境。它正确地返回了我的英文图像。然后我在浏览器中打开我的语言设置并将“fr”区域设置放在“en”区域设置之上。在这种情况下,MyFaces 正确识别出图像的语言环境是“fr”,但它没有返回新图像,因为“en”图像比“fr”图像新!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2011-05-11
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多