Discussion:
i18n: Umlaute in ResourceBundle; Events
(zu alt für eine Antwort)
Johannes Schwall
2004-11-26 15:47:44 UTC
Permalink
Hallo!

Ich schreibe ein Programm, das internationalisiert werden soll. Dazu habe
ich nun ein Menü erzeugt, das auch brav die Einträge abhängig vom gewählten
Locale anzeigt. So weit so gut. Zwei Fragen habe ich dabei aber nun:

1. In welcher Form kann ich Umlaute in die Datei schreiben? Derzeit werden
sie falsch dargestellt. Beim Speichern habe ich Emacs gesagt, er solle sie
als UTF-8 speichern.

2. Wie kann ich Events behandeln? Ich erhalte lokalisierte Signale: Wenn ich
z. B. das Programm beenden will, gibt event.getActionCommand() entweder
"Exit" (Locale.ENGLISH) oder "Beenden" (Locale.GERMAN) zurück. Ich weiß im
Moment nicht, wie ich diese Signale auffangen und dann weiter verarbeiten
kann. Ich dachte, es wäre ggf. über event.getID() möglich, aber da erhalte
ich für *alle* Menüpunkte als Antwort "1001".

Schon einmal vielen Dank für Tipps!

Johannes
--
Johannes Schwall
Johannes Schwall
2004-11-26 16:00:36 UTC
Permalink
Ich schiebe noch eine Ergänzung nach: Wie kann ich denn Mnemonics (also
hervorgehobene Buchstaben im Menü) im ResourceBundle speichern? Sie müssen
ja im Quelltext scheinbar mit einfachen Anführungszeichen, also etwa wie
folgt, angeben werden.

fileMenu.setMnemonic('F');

Wenn ich nun aber daraus

fileMenu.setMnemonic(labels.getString("fileMenuMN");

mache und in meiner Resource-Datei natürlich steht

fileMenuMN = F

dann scheint er -- zurecht -- das "F" mit doppelten Anführungszeichen
einzusetzen. Was für eine Lösung gibt es dafür?

Johannes
--
Johannes Schwall
Peter Büttner
2004-11-26 16:15:34 UTC
Permalink
Post by Johannes Schwall
Ich schiebe noch eine Ergänzung nach: Wie kann ich denn Mnemonics (also
hervorgehobene Buchstaben im Menü) im ResourceBundle speichern? Sie müssen
ja im Quelltext scheinbar mit einfachen Anführungszeichen, also etwa wie
folgt, angeben werden.
fileMenu.setMnemonic('F');
Wenn ich nun aber daraus
fileMenu.setMnemonic(labels.getString("fileMenuMN");
mache und in meiner Resource-Datei natürlich steht
fileMenuMN = F
dann scheint er -- zurecht -- das "F" mit doppelten Anführungszeichen
einzusetzen. Was für eine Lösung gibt es dafür?
Kommt darauf an wie du damit umgehst.
Ein Properties-ResourceeBundle (nehme ich mal an) liefert dir nur
Strings. Da musst du dir die Actions draus bauen, also die Strings
interpretieren und dann Menüitems, Buttons daraus bauen.

Ich mach' das meist so das ich im Bundle sowas definiere:

mainWindow.action.connect.name =Connect
mainWindow.action.connect.mnemonic =C
mainWindow.action.connect.accelerator=ENTER
mainWindow.action.connect.tooltip =Connect to server


dann Toolfunktionen/Klassen habe die mir daraus Actions bauen.
z.B. aufruf mit getResAction("conneect") der rest wird dort drinnen
abgehandelt

Es gibt auch was das xml files einliest, mal im Netz suchen.




Grüße
Peter
--
Shell&Jar : Individual icons for jars
jMineSweeper : extended
www.PeterBuettner.de
karlheinz klingbeil
2004-11-26 16:23:56 UTC
Permalink
Johannes Schwall schrub am Freitag, 26. November 2004
Post by Johannes Schwall
dann scheint er -- zurecht -- das "F" mit doppelten
Anführungszeichen einzusetzen. Was für eine Lösung
gibt es dafür?
Johannes
Nur mal als Anregung, hab ich so gelöst:
der lokalisierte String kann irgendwo das Zeichen
MNEMONIC_MARK ( bei mir immer ein "&") enthalten.
Beim Erzeugen einer Action wird dieses Zeichen aus dem
String entfernt und das nachfolgende Zeichen als
Mnemonic genommen.

Beispiel: der STring fürs Datei-Menü lautet "&Datei",
die Action bekommt als Mnemonic ein "D" zugewiesen.

---------------------schnipp----------------------
char mnemonic = '\0';
putValue(NAME,name.replaceAll(MNEMONIC_MARK,""));
if(name.indexOf(MNEMONIC_MARK) != -1) {
String n =
name.substring(name.indexOf(MNEMONIC_MARK)+1,name.indexOf(MNEMONIC_MARK)+2).toUpperCase();
mnemonic=n.charAt(0);
}

putValue(MNEMONIC_KEY, new Integer(mnemonic));
---------------------schnapp----------------------
Ich hoffe, dir geholfen zu haben...
--
greetz Karlheinz Klingbeil (lunqual)
http://www.lunqual.de oder http:www.lunqual.net
Paul Schwann
2004-11-26 17:31:56 UTC
Permalink
Hallo Johannes,

1. Umlaute können allgemeingültig so kodiert werden \uXXXX -> wobei die
X für den Unicode stehen (<http://www.unicode.org>). Dann spielt die
Kodierung der Datei keine Rolle mehr (da nur noch Zeichen aus dem
US-ASCII Satz verwendet werden).
2. Benutze ein ListResourceBundle. Darin kannst Du beliebige *Objekte*
ablegen. Dann nimmst Du für die Wörter Strings und für einzelne Zeichen
(z.B. die Mnemonics) Character.

Gruß Paul
Stefan Matthias Aust
2004-11-26 16:09:35 UTC
Permalink
Post by Johannes Schwall
Ich schreibe ein Programm, das internationalisiert werden soll. Dazu habe
ich nun ein Menü erzeugt, das auch brav die Einträge abhängig vom gewählten
1. In welcher Form kann ich Umlaute in die Datei schreiben? Derzeit werden
sie falsch dargestellt. Beim Speichern habe ich Emacs gesagt, er solle sie
als UTF-8 speichern.
Properties-Dateien haben immer das Encoding ISO-8859-1. Alle nicht
ISO-Zeichen müssen mit \uXXXX kodiert werden. Sie als UTF-8 zu
speichern, ist ein Fehler.
Post by Johannes Schwall
2. Wie kann ich Events behandeln? Ich erhalte lokalisierte Signale: Wenn ich
z. B. das Programm beenden will, gibt event.getActionCommand() entweder
"Exit" (Locale.ENGLISH) oder "Beenden" (Locale.GERMAN) zurück.
ActionCommand sollte gerade ein nicht lokalisierter String sein, der die
Aktion im Programm erkennt. Du benutzt diese Eigenschaft anders als
gedacht.
--
Stefan Matthias Aust // Ngao bo aspar'he, tue bor waba nada
Peter Büttner
2004-11-26 16:18:36 UTC
Permalink
Post by Johannes Schwall
Hallo!
Ich schreibe ein Programm, das internationalisiert werden soll. Dazu habe
ich nun ein Menü erzeugt, das auch brav die Einträge abhängig vom gewählten
1. In welcher Form kann ich Umlaute in die Datei schreiben? Derzeit werden
sie falsch dargestellt. Beim Speichern habe ich Emacs gesagt, er solle sie
als UTF-8 speichern.
Properties-ResourceBundle wollene in iso-8859-1 sein,
siehe Properties.java
Post by Johannes Schwall
2. Wie kann ich Events behandeln? Ich erhalte lokalisierte Signale: Wenn ich
z. B. das Programm beenden will, gibt event.getActionCommand() entweder
"Exit" (Locale.ENGLISH) oder "Beenden" (Locale.GERMAN) zurück. Ich weiß im
Moment nicht, wie ich diese Signale auffangen und dann weiter verarbeiten
kann. Ich dachte, es wäre ggf. über event.getID() möglich, aber da erhalte
ich für *alle* Menüpunkte als Antwort "1001".
Siehe anderes Posting, mach Actions mit einem extra ActionCommand oder
eine eigene Klasse

abstract ResAction extends AbstractAction{
ResAction(String name){
DeinResTool.fillInActionPropertiesFromRes(name);
}

}
in deiner 'Frame/Dialog' Klasse instantiierst du die und musst dann
actionPerformed überschreiben.






Grüße
Peter
--
Shell&Jar : Individual icons for jars
jMineSweeper : extended
www.PeterBuettner.de
Johannes Schwall
2004-12-03 12:38:08 UTC
Permalink
Hallo!
Post by Peter Büttner
Post by Johannes Schwall
2. Wie kann ich Events behandeln? Ich erhalte lokalisierte Signale: Wenn
ich z. B. das Programm beenden will, gibt event.getActionCommand()
entweder "Exit" (Locale.ENGLISH) oder "Beenden" (Locale.GERMAN) zurück.
Ich weiß im Moment nicht, wie ich diese Signale auffangen und dann weiter
verarbeiten kann. Ich dachte, es wäre ggf. über event.getID() möglich,
aber da erhalte ich für *alle* Menüpunkte als Antwort "1001".
Siehe anderes Posting, mach Actions mit einem extra ActionCommand oder
eine eigene Klasse
abstract ResAction extends AbstractAction{
ResAction(String name){
DeinResTool.fillInActionPropertiesFromRes(name);
}
}
in deiner 'Frame/Dialog' Klasse instantiierst du die und musst dann
actionPerformed überschreiben.
Ich habe das jetzt folgendermaßen umgesetzt: In meiner Menü-Klasse gibt es
die Methode actionPerformed:

public void actionPerformed(ResAction event) {
System.out.println(event.getActionCommand());
}

und eine Klasse ResAction habe ich ebenfalls erstellt:

abstract class ResAction extends AbstractAction {
ResAction(String eventName) {
//ResManager.fillInActionPropertiesFromRes(eventName);
}

public String getActionCommand() {
// here: return internationalized ActionString
String cmdString = "anAction";
return cmdString;
}
}

Die Idee dabei war, dass jetzt zum Testen zunächst einmal für jede Action
einfach nur "anAction" zurückgegeben wird. Anschließend wollte ich dann
über das ResourceBundle die "echten" Actions auf die Default-Werte des
ResourceBundle mappen und so bei jeder Sprache die Default-Werte empfangen.
Soweit die Theorie.

Nun komme ich aber nur so weit, dass ich die folgende Fehlermeldung erhalte:

$ javac FGUI.java
./FMenu.java:8: FMenu should be declared abstract; it does not define
actionPerformed(java.awt.event.ActionEvent) in FMenu
public class FMenu extends JMenuBar implements ActionListener {
^
1 error

Aber es *gibt* doch diese Methode actionPerformed! Der Fehler tritt nicht
auf, wenn ich in der Methode statt "ResAction event" "ActionEvent event"
angebe.

Hilfe!? Danke!

Johannes
--
Johannes Schwall
Peter Büttner
2004-12-05 16:23:55 UTC
Permalink
Post by Johannes Schwall
Post by Peter Büttner
Siehe anderes Posting, mach Actions mit einem extra ActionCommand oder
eine eigene Klasse
abstract ResAction extends AbstractAction{
ResAction(String name){
DeinResTool.fillInActionPropertiesFromRes(name);
}
}
in deiner 'Frame/Dialog' Klasse instantiierst du die und musst dann
actionPerformed überschreiben.
Ich habe das jetzt folgendermaßen umgesetzt: In meiner Menü-Klasse gibt es
Welche Menü-Klasse?
Post by Johannes Schwall
public void actionPerformed(ResAction event) {
Wenn du actionPerformed(ActionEvent event) implementieren
willst: das geht so natürlich nicht, die Signatur (hier Parameter)
müssen übereinstimmen
Post by Johannes Schwall
System.out.println(event.getActionCommand());
}
abstract class ResAction extends AbstractAction {
ResAction(String eventName) {
//ResManager.fillInActionPropertiesFromRes(eventName);
}
public String getActionCommand() {
// here: return internationalized ActionString
String cmdString = "anAction";
return cmdString;
}
}
Das machst du besser so:
ResAction#getValue(Action.ACTION_COMMAND_KEY)
liefert dir das eh'. Du musst es halt in deinem
ResManager.fillInActionPropertiesFromRes setzen.

Ich mache das aber eher so:
acCopy = new ResAction("main.copy"){
public void actionPerformed(ActionEvent event) {
doCopy();
}
};

acPaste = new ResAction("main.paste"){
public void actionPerformed(ActionEvent event) {
doPaste();
}
};


menu.add(acEdit);
menu.add(acPaste);


Das erzeugt allerdings eine Menge winziger innerer Klassen, für 10-20
Menüpunkte wär' mir das aber Wurschtegal. Bei 100en von Actions geht es
z.B. so:
(wobei ich das mit den Strings nicht so mag, ich habe die inneren
Klassen lieber, da geht weniger leicht was durch vertippern bei Strings
verloren.

final class AnotherResAction extends AbstractAction{ // nicht abstract!
// fill in ... wie oben
...

public void actionPerformed(ActionEvent event) {
doGrosserDickerActionHander(event);
}
};

}
...
acCopy = new AnotherResAction("main.copy"); // nix überschreib
acPaste = new AnotherResAction("main.paste"); // nix überschreib

doGrosserDickerActionHander(event){
String cmd = event.getActionCommand()
// event.getSource() liefert glaube ich die Action

if (cmd.equals("a")) ...
else if (cmd.equals("b")) ...
// das wird aber auch häßlich, man denke sich was anderes aus.
}


Auf (desktop)java.net gibt es so einen Ansatz, mit menüstruktur und so
fertig mit xml files einlesen.
Post by Johannes Schwall
Die Idee dabei war, dass jetzt zum Testen zunächst einmal für jede Action
einfach nur "anAction" zurückgegeben wird. Anschließend wollte ich dann
über das ResourceBundle die "echten" Actions auf die Default-Werte des
ResourceBundle mappen und so bei jeder Sprache die Default-Werte empfangen.
Soweit die Theorie.
$ javac FGUI.java
./FMenu.java:8: FMenu should be declared abstract; it does not define
actionPerformed(java.awt.event.ActionEvent) in FMenu
public class FMenu extends JMenuBar implements ActionListener {
^
1 error
Aber es *gibt* doch diese Methode actionPerformed! Der Fehler tritt nicht
auf, wenn ich in der Methode statt "ResAction event" "ActionEvent event"
angebe.
Siehe oben du hast was anderes implementiert. Wenn das kein Ausrutscher
war: das ist eine der Grundlagen der Objektorientierung in Java.


Guck dir doch mal das Sun Swing tutorial zu Action an
(ich hoffe das es das gibt:-)
google: site:sun.com swing tutorial action




Grüße
Peter
--
Shell&Jar : Individual icons for jars
jMineSweeper : extended
www.PeterBuettner.de
Loading...