当前位置: 首页 > 知识库问答 >
问题:

每个区域设置在JSF 2中的不同面(用于模板)

华锦
2023-03-14

我有一个模板,里面有

这基本上就是问题所在。为了其他正在搜索的人,如果你已经理解我的意思,请跳过下面的上下文。

JSF2中的国际化在很大程度上是非常容易的。创建一个或多个资源包,并在faces配置中声明这些资源包。xml,您就可以使用这些属性了。但我觉得这样的属性文件只适用于短标签文本、列标题、可能包含几个参数的小消息。。。当涉及到大部分文本时,它们似乎很难处理。尤其是如果文本中应该穿插XHTML标记或JSF组件,那么在这种情况下,您需要将其分解得太多。

目前我正在开发一些使用JSF 2的网络应用程序,其中PrimeFaces是组件包,它使用资源包进行常规意义上的国际化。但是各种视图需要一个帮助页面。我也想在这些帮助页面中使用JSF/PrimeFaces组件,这样填充表或对话框的示例看起来就像视图本身一样。

然而,包括基于语言环境的作文内容似乎没有我想象的那么简单。我希望XHTML页面(facelets)带有_en或_fr等区域后缀,并根据活动区域选择正确的页面。如果没有这样的页面,它应该默认为_en页面(或者没有后缀的页面,只包含英文内容)。从facescontext获取区域设置字符串不是问题,但检测页面是否存在似乎更难。有没有办法在JSF中或通过EL实现这一点,还是应该通过托管bean实现?也许为它编写一个自定义标记会很有用,但我不确定这需要做多少工作。

我确实发现了这个相关的问题,但是这似乎只有在我不想注入纯超文本标记语言内容的情况下才有用。我想包括带有JSF内容的页面,这样它们实际上是由JSF servlet处理和呈现的。


共有3个答案

公良莫希
2023-03-14

从这个链接@SO,你可以动态地包含一个内容(检查选中的答案)。在后备文件中,如果你有一个钩子,你可以适当地设置文件名,我认为这可以做到这一点。

对此不确定,您可以检查,如果您可以在EL中传递参数,即方法的部分路径,则可以在方法内部处理rest,例如构造完整路径、附加当前区域设置以及检查文件是否存在。

希望这有帮助。

更新(回答评论):

是的,会的。您可以看看链接JSF2FU,第2部分:模板和复合组件

程招
2023-03-14

例如,您可以定义复合组件,它只是标准ui:include的外观。

资源/myComponents/localeInclude.xhtml:

<cc:interface>
  <cc:attribute name="src" required="true" type="java.lang.String"/>
</cc:interface>

<cc:implementation>
  <ui:include src="#{myResolver.resolve(cc.attrs.src)}">
    <cc:insertChildren/>
  </ui:inclue>
</cc:implementation>

创建名为myResolver的托管bean,它可以被@ApplicationScoped处理,因为它是完全无状态的resolve()方法:

public String resolve(String src) {
  String srcWithoutExt = src.replace(".xhtml", "");
  FacesContext facesContext = FacesContext.getCurrentInstance();
  ServletContext servletContext = (ServletContext) facesContext.getExternalContext().getContext();
  Locale locale = facesContext.getViewRoot().getLocale();
  String localizedSrc = srcWithoutExt + "_" + locale.getLanguage();
  URL url = null;
  if (src.startsWith("/")) {
    url = facesContext.getExternalContext().getResource(localizedSrc + ".xhtml");
  } else {
    try {
      url = new URL((HttpServletRequest) request).getRequestURL(), localizedSrc + ".xhtml");
    } catch (Exception e) { /* Doesn't exist */ }
  }
  if (url != null) {
    return localizedSrc + ".xhtml";
  } else {
    return src;
  }
}

在这种情况下,只需将src放在不带区域设置扩展的页面上,让方法解决这个问题:

<my:localeInclude src="myPage.xhtml/>

由于我包含了children,您可以将ui:param传递给您的include to original。

此外,对于那些只是习惯于根据区域设置(而不仅仅是部分)解析整个页面的人来说,使用Filter更容易。在doFilter()方法中,您可以检查该资源是否存在,如果不将请求转发到另一个页面:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {

  if (request.getServletContext().getResource(request.getRequestURI()) == null) {
    // Here your page doesn't exist so forward user somewhere else...
  }
}

根据您的需要为这个Filter配置映射。

史劲
2023-03-14
匿名用户

下面是我对你问题的解决方案。这本书体积庞大,但内容完整,内容丰富,据我所知,它是完整的。有了它,你将能够在当前语言的基础上,从一系列语言后缀的观点中包含必要的观点。

我对你的设置的假设

  1. 您正在处理描述语言的区域设置,即区域设置。ENGLISH格式;
  2. 您选择的语言存储在会话范围的bean中;
  3. 您将国际化页面保持以下格式:page.xhtmlpage_en.xhtmlpage_fr.xhtml等;
  4. 默认语言为英语;
  5. 您的FacesServlet映射到*. xhtml

会话范围的bean,包含可用的语言和用户选择:

@ManagedBean
@SessionScoped
public class LanguageBean implements Serializable {

    private List<Locale> languages;//getter
    private Locale selectedLanguage;//getter + setter

    public LanguageBean() {
        languages = new ArrayList<Locale>();
        languages.add(Locale.ENGLISH);
        languages.add(Locale.FRENCH);
        languages.add(Locale.GERMAN);
        selectedLanguage = Locale.ENGLISH;
    }

    public Locale findLocale(String value) {
        for(Locale locale : languages) {
            if(locale.getLanguage().equals(new Locale(value).getLanguage())) {
                return locale;
            }
        }
        return null;
    }

    public void languageChanged(ValueChangeEvent e){
        FacesContext.getCurrentInstance().getViewRoot().setLocale(selectedLanguage);
    }

}

用于区域设置的转换器:

@ManagedBean
@RequestScoped
public class LocaleConverter implements Converter {

    @ManagedProperty("#{languageBean}")
    private LanguageBean languageBean;//setter

    public LocaleConverter() {   }

    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if(value == null || value.equals("")) {
            return null;
        }
        Locale locale = languageBean.findLocale(value);
        if(locale == null) {
            throw new ConverterException(new FacesMessage("Locale not supported: " + value));
        }
        return locale;
    }

    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (!(value instanceof Locale) || (value == null)) {
            return null;
        }
        return ((Locale)value).getLanguage();
    }

}

主视图(Main.xhtml)带有指向国际化页面的链接,并能够通过下拉框更改当前语言:

<f:view locale="#{languageBean.selectedLanguage}">
    <h:head>
        <title>Links to internationalized pages</title>
    </h:head>
    <h:body>
        <h:form>
            <h:selectOneMenu converter="#{localeConverter}" value="#{languageBean.selectedLanguage}" valueChangeListener="#{languageBean.languageChanged}" onchange="submit()">
                <f:selectItems value="#{languageBean.languages}"/>
            </h:selectOneMenu>
        </h:form>
        <br/>
        <h:link value="Show me internationalized page (single)" outcome="/international/page-single"/>
        <br/>
        <h:link value="Show me internationalized page (multiple)" outcome="/international/page-multiple"/>
    </h:body>
</f:view>

通过添加_lang后缀(page multiple.xhtml)进行国际化的基本页面

<f:metadata>
    <f:event type="preRenderView" listener="#{pageLoader.loadPage}"/>
</f:metadata>

国际化页面:

对于英语(page-multiple_en.xhtml):

<h:head>
    <title>Hello - English</title>
</h:head>
<h:body>
    Internationalized page - English
</h:body>

对于法语(page-multiplex_fr.xhtml):

<h:head>
    <title>Hello - Français</title>
</h:head>
<h:body>
    Page internationalisé - Français
</h:body>

德语版(无视图,模拟丢失的文件)。

执行重定向的托管bean:

@ManagedBean
@RequestScoped
public class PageLoader {

    @ManagedProperty("#{languageBean}")
    private LanguageBean languageBean;//setter

    public PageLoader() {   }

    public void loadPage() throws IOException {
        Locale locale = languageBean.getSelectedLanguage();
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext external = context.getExternalContext();
        String currentPath = context.getViewRoot().getViewId();
        String resource = currentPath.replace(".xhtml", "_" + locale.toString() + ".xhtml");
        if(external.getResource(resource) == null) {
            resource = currentPath.replace(".xhtml", "_en.xhtml");
        }
        String redirectedResource = external.getRequestContextPath() + resource.replace(".xhtml", ".jsf");
        external.redirect(redirectedResource);
    }

}

每次请求视图page-multiple.xhtml时,都会重定向到语言后缀视图,或者重定向到英语视图,如果找不到目标语言的视图。当前语言来自会话范围的bean,所有视图都必须位于服务器上的同一个文件夹中。当然,这可以根据视图参数中定义的语言重做。目标页面可以使用组合。默认数据可以在preRenderView监听器不执行重定向的非后缀视图中提供。

作为说明,我的(三)个视图存储在网页的international/文件夹中。

虽然你的问题应该由前一个设置来解决,但我想到了另一个想法,我将在下面描述。

有时,不创建与支持的语言一样多的视图(1用于重定向)可能更容易,而是创建一个基于当前选择的语言有条件地呈现其输出的单个视图。

视图(page single.xhtml,也位于服务器上的同一文件夹中)可能如下所示:

<ui:param name="lang" value="#{languageBean.selectedLanguage}"/>
<ui:fragment rendered="#{lang == 'en'}">
    <h:head>
        <title>Hello - English</title>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF8" />
    </h:head>
    <h:body>
        Internationalized page - English
    </h:body>
</ui:fragment>
<ui:fragment rendered="#{lang == 'fr'}">
    <h:head>
        <title>Hello - Français</title>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF8" />
    </h:head>
    <h:body>
        Page internationalisé - Français
    </h:body>
</ui:fragment>
<ui:fragment rendered="#{(lang ne 'en') and (lang ne 'fr')}">
    <h:head>
        <title>Hello - Default</title>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF8" />
    </h:head>
    <h:body>
        Internationalized page - Default
    </h:body>
</ui:fragment>

使用此视图,您可以指定其中的所有数据,有条件地仅呈现所需语言或默认数据所需的数据。

资源解析程序将根据视图的当前区域设置包含所需的文件。

资源解析器:

public class InternalizationResourceResolver extends ResourceResolver {

    private String baseLanguage;
    private String delimiter;
    private ResourceResolver parent;

    public InternalizationResourceResolver(ResourceResolver parent) {
        this.parent = parent;
        this.baseLanguage = "en";
        this.delimiter = "_";
    }

    @Override
    public URL resolveUrl(String path) {
        URL url = parent.resolveUrl(path);
        if(url == null) {
            if(path.startsWith("//ml")) {
                path = path.substring(4);
                Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
                URL urlInt = parent.resolveUrl(path.replace(".xhtml", delimiter + locale.toString() + ".xhtml"));
                if(urlInt == null) {
                    URL urlBaseInt = parent.resolveUrl(path.replace(".xhtml", delimiter + baseLanguage + ".xhtml"));
                    if(urlBaseInt != null) {
                        url = urlBaseInt;
                    }
                } else {
                    url = urlInt;
                }
            }
        }
        return url;
    }

}

web.xml中启用解析器:

<context-param>
    <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
    <param-value>i18n.InternalizationResourceResolver</param-value>
</context-param>

使用此设置,可以渲染以下视图:

使用

<f:view locale="#{languageBean.selectedLanguage}">
    <h:head>
    </h:head>
    <h:body>
        <ui:include src="//ml/international/page-include.xhtml" />
    </h:body>
</f:view>

没有页面包含。xhtml,但会有每种语言的视图,如:

page-include\n。xhtml

<h:outputText value="Welcome" />

page-include\u fr.xhtml

<h:outputText value="Bienvenue" />

这样,解析器将根据当前区域设置选择正确的国际化包含视图。

 类似资料:
  • 我试图在Symfony中设置一个区域设置,除了我试图在布局文件中翻译或生成路线的地方,一切都很好。我创建了一个侦听器,这样我就可以在每个请求上设置区域设置。 } 如果在树枝模板中,我试图使用app.session.get('_locale')访问会话变量,该变量存储了它应该是的语言环境-我得到了所需的结果。但是当我尝试app.request.locale我得到默认的语言环境,而不是在网址。正因为如

  • 我想强制我的Symfony 2.5应用程序的区域设置为。我希望这个区域设置用于strftime()函数。 我的: 我正在我的一个控制器中使用以下代码来调试: 当这样执行时,它显示:。 但是,当第一行未注释时,它会显示:,因此区域设置已安装在系统中并正常工作。 我如何使Symfony始终使用配置中指定的语言环境? $locale-a:

  • 我有一个问题返回日期在法语在我laravel项目, 在我的模型中,我有以下方法: 但日期仍然是英文的, 我也试过了 但日期仍然是英文的。我也尝试过使用php日期函数和Carbon的localizedFormat方法,但结果总是一样的:英语中的日期, 你知道这个问题吗?(我使用区域设置进行了检查-我的计算机上有a和fr_fr) 谢谢你

  • 我已经研究了如何更改Angulal-Chart.js的颜色,但它涉及整个(数据集)的颜色,而不是特定的条。 我要寻找的是一种在条形图中为每个条形应用不同颜色的方法;从图表到角度。 所以,我有一个条形图: 使用以下角度代码(当然是在控制器中) 其中将返回随机颜色。 现在,字段将此颜色应用于所有条: 当我真的想为每个酒吧不同的颜色: 柱塞

  • 在本机构建时,我对可用区域设置有一个意想不到的行为。在纯模式下,我只有一个区域设置可用。 我的应用程序很简单: 签出后,如果我在开发模式下启动应用程序: 您可以调用endpoint:http://localhost:8080/api/locales 此endpoint返回许多区域设置: 如果在纯模式下执行相同操作: 我只获得一个区域设置: 如何获取所有可用的区域设置? 而且,由于这种行为,我还有另