it-swarm.com.de

Lokalisierung in JSF, wie Sie sich das ausgewählte Gebietsschema pro Sitzung und nicht pro Anforderung/Ansicht merken können

faces-config.xml:

<application>
    <locale-config>
        <default-locale>ru</default-locale>
        <supported-locale>ua</supported-locale>
    </locale-config>
</application> 

In einer Bean-Aktionsmethode ändere ich das Gebietsschema in der aktuellen Ansicht wie folgt:

FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale("ua"));

Das Problem ist, dass ua Locale angewendet wird, jedoch nur pro Anforderung/Ansicht und nicht für die Sitzung. Eine andere Anforderung/Ansicht in derselben Sitzung setzt das Gebietsschema auf den Standardwert ru zurück.

Wie kann ich das Gebietsschema für die Sitzung anwenden?

42
sergionni

Sie müssen das ausgewählte Gebietsschema im Sitzungsbereich speichern und es in der Viewroot an zwei Stellen festlegen: einmal nach UIViewRoot#setLocale() unmittelbar nach dem Ändern des Gebietsschemas (wodurch das Gebietsschema des aktuellen Viewroot geändert wird und somit im Postback wiedergegeben wird; Dieser Teil ist nicht erforderlich, wenn Sie anschließend eine Umleitung durchführen.) und einmal im locale-Attribut des <f:view> (wodurch das Gebietsschema in den nachfolgenden Anforderungen/Ansichten festgelegt wird/bleibt).

Hier ein Beispiel, wie ein solches LocaleBean aussehen sollte:

package com.example.faces;

import Java.util.Locale;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@SessionScoped
public class LocaleBean {

    private Locale locale;

    @PostConstruct
    public void init() {
        locale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
    }

    public Locale getLocale() {
        return locale;
    }

    public String getLanguage() {
        return locale.getLanguage();
    }

    public void setLanguage(String language) {
        locale = new Locale(language);
        FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
    }

}

Und hier sollte ein Beispiel für die Ansicht aussehen:

<!DOCTYPE html>
<html lang="#{localeBean.language}"
    xmlns:f="http://Java.Sun.com/jsf/core"
    xmlns:h="http://Java.Sun.com/jsf/html">
<f:view locale="#{localeBean.locale}">
    <h:head>
        <title>JSF/Facelets i18n example</title>
    </h:head>
    <h:body>
        <h:form>
            <h:selectOneMenu value="#{localeBean.language}" onchange="submit()">
                <f:selectItem itemValue="en" itemLabel="English" />
                <f:selectItem itemValue="nl" itemLabel="Nederlands" />
                <f:selectItem itemValue="es" itemLabel="Español" />
            </h:selectOneMenu>
        </h:form>
        <p><h:outputText value="#{text['some.text']}" /></p>
    </h:body>
</f:view>
</html>

Beachten Sie, dass <html lang> für das Funktionieren von JSF nicht erforderlich ist, aber wie Suchbots Ihre Seite interpretieren müssen. Andernfalls wäre es möglicherweise als doppelter Inhalt gekennzeichnet, was für SEO schlecht ist.

Verbunden:

80
BalusC

Ich sehe, dass das Problem auch mit dem .properties-Dateinamen zusammenhängt. Java-Gebietsschema us-Codes (Kleinbuchstaben) wie: en_gb Das automatisch erstellte Gebietsschema (von Netbeans) ist lowercase_uppercase, dh messages_en_GB.properties : messages_en_gb.properties und es sollte funktionieren - wenn Sie alles versucht haben

4
Sebastian

Diese Komponente f: view ist nicht Ihre JSF-Seite, sie funktioniert nicht und es wird nur die Standardsprache Englisch angezeigt. Ich hatte das gleiche Problem, jetzt funktioniert es gut.

3

Eine kleine Anmerkung zu @BalusCs großartiger Lösung. Wenn wir <f:viewAction> haben, wird eine Methode im Backing Bean ausgeführt. Das vom Aufruf an FacesContext.getCurrentInstance().getViewRoot().getLocale() innerhalb dieser Methode verfügbare Gebietsschema wäre ein Gebietsschema, das vom Benutzerbrowser festgelegt wird, oder das Standardgebietsschema der Anwendung, nicht das Gebietsschema, das von der Benutzerauswahl für das Sitzungs-Bean festgelegt wird (natürlich können sie übereinstimmen, wenn das Gebietsschema des Browsers dem von diesem Benutzer ausgewählten Gebietsschema entspricht ). 

Ich kann korrigiert stehen, weil ich vielleicht bei der Implementierung der von @BalusC bereitgestellten Lösung etwas falsch gemacht habe.

BEARBEITEN. Nach dem Spielen mit JSF-Lebenszyklus hängt dieses Verhalten mit locale nicht mit <f:viewAction> zusammen, da auch bei @PostContruct ein ähnliches Verhalten vorliegt. <f:view locale="#{localeBean.locale}"> in der Anforderung (nach vom Benutzer ausgewähltem Gebietsschema) wird in der Renderantwortphase ausgeführt. <f:viewAction>- und @PostContruct-Methoden werden in der Aufrufanwendungsphase ausgeführt. Aus diesem Grund hat die in dieser Methode ausgeführte Logik keinen Zugriff auf das vom Benutzer ausgewählte Gebietsschema.

Eine Lösung, die wir verwenden, wenn wir das richtige Gebietsschema benötigen, ist (CDI) localeBean in ein anderes Backing Bean zu injizieren, das <f:viewAction>- und @PostContruct-Methoden enthält, und dann am Anfang dieser Methoden das Gebietsschema mit UIViewRoot#setLocale() von localeBean festzulegen.

1
Znas Me

Wenn Sie CDI und Deltaspike ( JSF module ) in Ihrer Umgebung verwenden können, können Sie Ihrer LocaleBean Folgendes hinzufügen, um das Gebietsschema in der aktuellen Ansicht automatisch zurückzusetzen:

@javax.enterprise.context.SessionScoped
public class LocaleBean implements Serializable {

    ...

    public void resetLocale(@Observes @BeforePhase(JsfPhaseId.RENDER_RESPONSE) PhaseEvent event) {
        event.getFacesContext().getViewRoot().setLocale(this.locale);
    }
}
0
Xavier Dury