以下是我对您的问题的解决方案。它体积庞大,但已经完成,内容丰富,而且据我所知,是完整的。有了它,您将能够根据当前语言,从带有语言后缀的视图系列中引入必要的视图。
我对你的设置的假设
- 您正在处理描述语言的语言环境,即位于
Locale.ENGLISH
format;
- 您选择的语言存储在会话范围的 bean 中;
- 您可以将国际化页面保留为以下格式:
page.xhtml
, page_en.xhtml
, page_fr.xhtml
, etc;
- 默认语言为英语;
- Your
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-multiple_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>
通过此设置,可以呈现以下视图:
查看哪个使用<ui:include>
,其中国际化包含将用创建的//ml/
prefix:
<f:view locale="#{languageBean.selectedLanguage}">
<h:head>
</h:head>
<h:body>
<ui:include src="//ml/international/page-include.xhtml" />
</h:body>
</f:view>
将没有page-include.xhtml
,但会有每种语言的视图,例如:
page-include_en.xhtml
:
<h:outputText value="Welcome" />
page-include_fr.xhtml
:
<h:outputText value="Bienvenue" />
这样,解析器将根据当前区域设置选择正确的国际化包含视图。