JSF Internationalisierungs-Fehler auf Remoteserver

B

Brackelmann

Gast
Hallo,
ich machs kurz:

Die selbe Anwendung, die auf meinem lokalen Rechner läuft, versagt mir in Sachen Internationalisierung auf meinem remote Server den Dienst.

Man klickt auf den jeweiligen Button, der die Sprache wechseln soll, unten im Browser sieht man ne Request-Verarbeitung, aber es tut sich nichts. Der Server-Log ist unauffällig.

Das Seltsame ist, dass die Umgebungen ziemlich identisch sind: Gleiche Glassfish-Version (3.12) Gleiche VM usw.
Der einzige Unterschied ist, dass auf dem Server ein Apache mit mod_ajp vorgeschaltet ist.

Ich suche jetzt verzweifelt nach Erklärungen.

aTemplate.xhtml:

HTML:
   <f:view locale="#{sessionMind.selectedLanguage}" >    
    <h:head>
        <title><h:outputText value="#{titleParam}" /></title>
    </h:head>
    <h:body>
        <h:outputStylesheet library="css" name="ext.css" />
        
        <div id="wrapper">
            
            <div id="header">
                <h:form>
                    <h:commandButton value="Deutsch" action="#{sessionMind.switchLanguage('de')}" />
                    <h:commandButton value="English" action="#{sessionMind.switchLanguage('en')}" />
                </h:form>
                 ......

SessionMind.java (SessionScoped ManagedBean):

Java:
public class SessionMind implements Serializable
{
    private Locale selectedLanguage = FacesContext.getCurrentInstance().getViewRoot().getLocale();
    public Locale getSelectedLanguage() 
    {
        return selectedLanguage;
    }   
    public String switchLanguage(String selectedLanguage)
    {
        this.selectedLanguage = new Locale(selectedLanguage);
        return null;
    }    
}

faces-config:
[XML]
<application>
<resource-bundle>
<base-name>bla.blub</base-name>
<var>pc</var>
</resource-bundle>
<resource-bundle>
<base-name>blabla</base-name>
<var>templatesbla</var>
</resource-bundle>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>de</supported-locale>
</locale-config>
</application>
[/XML]

Ich hoffe, jemand kann mir weiterhelfen! Danke!
 

sence

Bekanntes Mitglied
1)
Debugge mal die Funktion switchLanguage(). ob diese den String Parameter erhält.

Java:
System.out.println("SessionMind :: switchLanguage() -> called :: Param is :: " + selectedLanguage);

2)
ein weiterer Fehler kann sein, dass der Button auf der Startseite ist und die Form auf die Submit Seite:

Java:
<form enctype="application/x-www-form-urlencoded" action="//".....>

zeigt.
Zwei Slashes funktionieren nicht.

3)
Versuch nr 3: aus dem Return Value String ein void zu machen.

4) Hinweis:
wenn du auf einer Prettyurl bist und du den Button betätigst, wirst du in deinem Beispiel von der View:
www.domain.de/content/schoene-url
auf
www.domain.de/viewcontroller.jsf
zurück geleitet.

5)
wo schreibst du die Sprachauswahl zurück in die ViewRoot ?
Java:
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);

Grüße
 
Zuletzt bearbeitet:

sence

Bekanntes Mitglied
<h:command<type> action="view.xhtml" value=""/> // String required
<h:command<type> action="#{elExpression}" value=""/> // Methode Expression

"Use actionListener if you want have a hook before the real business action get executed"

"Use action if you want to execute a business action and if necessary handle navigation. The action method can return a String which will be used as navigation case outcome (the target view)"

Somit kann action bestehen bleiben, es muss eigentlich nur ein Wert zurück gegeben werden, wenn die Navigation auf die Seite verändert werden soll.
Wenn void, dann geht es zurück auf die letzte View.

Greetz

Nachtrag:
gebe kein null zurück, eher einen leeren String ""
 
Zuletzt bearbeitet:
B

Brackelmann

Gast
Danke für die vielen Vorschläge.


sence hat gesagt.:
Debugge mal die Funktion switchLanguage(). ob diese den String Parameter erhält.[

Der Parameter kommt an. Habe SessionMind um getter für selectedLangugae erweitert.

Code:
<h:outputText value="#{sessionMind.selectedLanguage}" />

Der Wert wird durch die Buttons geändert, die Sprache der Inhalte aber bleibt gleich.

sence hat gesagt.:
gebe kein null zurück, eher einen leeren String ""

Ich meine mal gelesen zu haben, dass null der Anweisung "Bleibe auf derzeitigem View" entspricht. Egal, habe es entsprechend geändert, keine Verhaltensänderung :(

sence hat gesagt.:
wo schreibst du die Sprachauswahl zurück in die ViewRoot ?
Code:
private Locale selectedLanguage = FacesContext.getCurrentInstance().getViewRoot().getLocale();


Ich betone nochmal: Die selbe Anwendung, also tatsächlich ein und dieselbe .war verhalten sich unterschiedlich. Lokal funktioniert alles sehr gut, auf dem Remote-Server nicht.

sence hat gesagt.:
wenn du auf einer Prettyurl bist und du den Button betätigst

Ich verwende PrettyFaces, aber wie gesagt, in einem Fall läufts, im anderen nicht. Es gelten auch keine besonderen Regeln für die beiden Umgebungen, zum Testen laufen sowohl die entfernte, als auch die lokale Anwendung im selben context-root.

Könnte etwas auf dem Server anders konfiguriert sein?
 
B

Brackelmann

Gast
Update:

Habe gerade noch etwas Interessamtes gemerkt:

Die automatische Spracherkennung, also die Sprache, die angezeigt wird, bevor, ein Button gedrückt wird, funktioniert auf dem Remote-Server auch nicht (lokal klappts).

Default-Sprache ist Englisch. Das scheint der remote-umgebung egal zu sein. Es wird immer alles auf deutsch angezeigt.
Man muss die property-datei mit den deutschen Inhalten explizit löschen, sonst zeugt er die englische nicht an...

Ich dachte erst, es könnte daran liegen, dass die englische bei einigen Schlüsseln noch keinen Wert stehen hat und habe sie vervollständigt, aber damit hatte es scheinbar nichts zu tun.
 

sence

Bekanntes Mitglied
private Locale selectedLanguage = FacesContext.getCurrentInstance().getViewRoot().getLocale();

damit holst du dir nur die aktuelle Sprache.
Die neue vom Benutzer ausgewählte Sprache muss doch noch zurück ins System (ViewRoot) geschrieben werden, damit jsf weiß welche
Sprachedatei er verwenden soll.


Java:
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);



Anbei mal meine Message Klasse...
lass dich nicht von den anderen Methoden verwirren, getResourceText() und getFacesMessage(), die sind für die Programmierte Ausgabe von Texten in der aktuellen Sprache.

Die Sprache ändere ich via dropdown Listene und dem ajax listener.
Dort ist auch die Beachtung der aktuellen URL enthalten (SEO - Prettyfaces)

Java:
@SessionScoped
@ManagedBean
public class Locales {


	private String userSelectedLanguage;

	private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();

	public void setLocale(String language) {
		if(language.equals("en"))			
			this.locale = new Locale("en");
		if(language.equals("de"))
			this.locale = new Locale("de");
		if(language.equals("fr"))
			this.locale = new Locale("fr");		
			        
		FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);	
		System.out.println("View id ist: " + FacesContext.getCurrentInstance().getViewRoot().getViewId());		
		// return ;
	}
	
	public void ajaxPageRefresh() {
		setLocale(userSelectedLanguage);
		
		FacesContext fc = FacesContext.getCurrentInstance();
		HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
		String url = request.getContextPath();
		try {
			FacesContext.getCurrentInstance().getExternalContext().redirect(url);
		} catch (IOException e) {			
			e.printStackTrace();
		}
	}
	
	public Locale getLocale() {
		return locale;
	}
	
	public String getLocaleAsString() {		
		
		return locale.getLanguage();
	}
	
	public void setUserSelectedLanguage(String userSelectedLanguage) {
		this.userSelectedLanguage = userSelectedLanguage;
	}

	public String getUserSelectedLanguage() {
		return userSelectedLanguage;
	}

	public String getResourceText(FacesContext ctx, String key,Object args) {
		String text;		
		try{
			Application app = ctx.getApplication();
			ResourceBundle bundle = app.getResourceBundle(ctx, "msgs");
			text = bundle.getString(key);
			if(args != null) text = MessageFormat.format(text, args);
			
			return text;				
		}catch(Exception e) {}
		return "";
	}
	public static FacesMessage getFacesMessage(FacesContext ctx, FacesMessage.Severity serverity, String msgKey, Object args){
		Locale loc = ctx.getViewRoot().getLocale();
		ResourceBundle bundle = ResourceBundle.getBundle(ctx.getApplication().getMessageBundle(), loc);
		String msg = bundle.getString(msgKey);
		if(args != null) {
			MessageFormat format = new MessageFormat(msg);
			msg = format.format(args);
		}
		return new FacesMessage(serverity, msg,null);
	}
}
 
B

Brackelmann

Gast
sence hat gesagt.:
Anbei mal meine Message Klasse...
lass dich nicht von den anderen Methoden verwirren,

Gut gesprochen :)

sence hat gesagt.:
damit holst du dir nur die aktuelle Sprache.
Die neue vom Benutzer ausgewählte Sprache muss doch noch zurück ins System (ViewRoot) geschrieben werden, damit jsf weiß welche
Sprachedatei er verwenden soll.

Ich bin irritiert. Was du sagst, ergibt durchaus Sinn, anfangs habe ich das auch explizit über setLocale() geregelt, aber dann wollte ich diese FacesContext.get().get().get()-Geschichte etwas wegrationalisieren.

Schließlich funktioniert es ja auch (lokal)!

Ich erkläre mir das so, dass JSF den Wert in der update-model-values-phase aktualisiert, könnte natürlich auch anders funktionieren. Bin noch nicht so lange mit JSF zugange...

Wie gesagt: Ich sehe ja, dass es geht, das Problem ist ja auch nicht, dass es generell nicht geht, sondern, dass es in einer bestimmten Umgebng nicht mehr geht...
 
B

Brackelmann

Gast
Soooo, ich habe es jetzt doch ziemlich eingrenzen können:

HTML:
<f:view locale="en" >    
                 ......

Es wird trotz allem die deutsche Variante ausgegeben.

Wenn ich
Code:
<f:loadBundle />
benutze, funktioniert die lokale Variante weiterhin, die auf dem externen Server weiterhin nicht...
Irgendwas wird da nicht unterstützt.
 
B

Brackelmann

Gast
Gefixt!

Es hatte etwas mit der Benennung der .properties für die "Sprachfetzen" zu tun.

Die Dateien hießen ursprünglich

xyz.properties
und xyz_de.properties

In der faces-config wurde das dann so eingebunden:

[XML]
<resource-bundle>
<base-name>content.xyz</base-name>
<var>xyz</var>
</resource-bundle>
[/XML]

Die Datei ohne Locale-Anhängsel war immer die mit den englischen Inhalten. Ich dachte immer, man meint damit die Sprache, die in der faces-config unter default-locale eingetragen ist (in meinem Fall eben englisch), aber anscheinend lag ich falsch.

Auf dem externen Server muss eine andere System-Spracheinstellung vorliegen als auf dem lokalen Rechner (auch wenn ich bisher noch keinen Unterschied gefunden habe, alles englisch)

Deswegen habe ich jetzt drei .properties: Eine xyz_de, eine xyz_en und eine xyz, wobei letztere einfach nur eine Kopie der alten xyz_en ist, die gebraucht wird, damit die basename-deklaration aufgelöst werden kann.

Wie genau der Mechanismus funktioniert weiß ich nicht. Ich kann nur spekulieren, dass die dahinterstehende Logik in der Datei ohne Locale-Endung die Werte für die Sprache vermutet, mit der das Host-System konfiguriert ist (und eben nicht die Sprache, die in faces-config als default-wert angegeben ist.)

Wenn jemand weiß, wonach genau sich das Auswahlverfahren richtet, wäre ich für eine Erklärung sehr dankbar!

Läuft, läuft, läuft! ;)
 

sence

Bekanntes Mitglied
Anhand des HTTP Headers beim Request, wird im Request die vom Client bevorzugte Sprache übersendet.
Dementsprechend nimmt die Anwendung die bevorzugte Sprache.
Wenn man dies nicht haben möchte, kann man in <f:view locale="en" > die Sprache vorgeben.

anbei ein Link wenn du dich weiter reinarbeiten möchtest:

JSFAtWork, JSF 2.0 und Apache MyFaces

Grüße
 
B

Brackelmann

Gast
Sorry, ich glaube das da oben habe ich etwas holprig formuliert. Tut mir Leid, dass du dir jetzt unnötigerweise Arbeit gemacht hast, Sence.

Es ging mir darum, wie JSF ermittelt, auf welches Locale sich bundle-xyz.properties bezieht - also der Dateibezeichner, ohne _en _de _fr usw.

Eigentlich bin ich davon ausgegangen, dass mit der Datei ohne besondere Sprachenrweiterung immer diejenige gemeint ist, die in der faces-context als Default-Sprache angegeben wird. Aber das scheiont ja nicht der Fall zu sein.
 
B

Brackelmann

Gast
Hab was Neues rausgefunden (sorry wegen der Zuspammerei):

In so ziemlich jeder Quelle, die ich eingesehen habe (auch jsfatwork) gibt es immer eine datei bundle.properties, auf die man sich in der faces-config bezieht. Was in dieser Datei zu stehen hat, wird nirgendwo erläutert...

ABER:

Es muss sie überhaupt gar nicht geben!

Steht in der faces-config:
[XML]
<resource-bundle>
<base-name>content.xyz</base-name>
<var>xyz</var>
</resource-bundle>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>de</supported-locale>
</locale-config>
[/XML]

In diesem Fall wird der Base-Name (der Name sagt ja eigentlich schon alles) als erste Hälfte des Dateinamens genommen und die gewünschten Locale-Endungen einfach ergänzt.

Wenn das für euch selbstverständlich war, lacht mich aus, ich war überrascht, als ichs zufälligerweise bemerkt habe...
 

Ähnliche Java Themen

Neue Themen


Oben