以下は、あなたの問題に対する私の解決策です。かさばりますが、完成しており、有益であり、私が見る限り完全です。それを使用すると、現在の言語に基づいて、言語接尾部のビューのファミリーから必要なビューを含めることができます。
あなたのセットアップに関する私の仮定
- 言語を記述するロケールを扱っています。つまり、
Locale.ENGLISH
形式があります。
- 選択した言語は、セッション スコープ Bean に格納されます。
- 国際化されたページは
page.xhtml
、page_en.xhtml
、page_fr.xhtml
、 などの形式で保持します。
- デフォルトの言語は英語です。
- あなた
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>
複数のページに基づくソリューション - 言語ごとに 1 つ
_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
リスナーがリダイレクトを実行しないサフィックスのないビューで提供できます。
備考として、私の(3つの)ビューはinternational/
Webページのフォルダーに保存されていました。
すべての言語の単一ページに基づくソリューション
あなたの問題は以前のセットアップでカバーされるはずですが、別のアイデアが頭に浮かびました。それについては以下で説明します。
サポートされている言語と同じ数のビュー (リダイレクトの場合は +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/
プレフィックスで定義されます。
<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" />
このようにして、リゾルバーは現在のロケールに基づいて、適切な国際化されたインクルード ビューを選択します。