[Java] Sprache ändern zur laufzeit

Dieses Thema im Forum "Programmierung & Entwicklung" wurde erstellt von 5p34k, 17. Mai 2013 .

  1. 17. Mai 2013
    Sprache ändern zur laufzeit

    Hey
    ich hab ein großes java programmiertes spiel.
    jetzt wollen wir (freunde, die mitprogrammiert haben) das ganze auch in andere Sprache übersetzten.
    das ganz soll auch zur laufzeit möglich sein.

    Wir starten in einem Frame, dass fragt ob wir ein neues Spiel starten wollen oder laden wollen und sowas...
    Danach kommen andere Frames, die jeweils nacheinander aufgebaut werden und angezeigt werden mit JPanels und Buttons und scroller und allem drum und dran.
    nun hab ich gelesen, dass das ganze wohl mit dem RessourceBundle gehen soll. hab mir auch das tut von sun durchgelesen und so weiter und ich hab jetzt ein propertie-file erstellt.
    So nun weiß ich aber nicht genau, wo ich das einbinden soll...

    Das spiel startet in main (logischerweise :lol: ) so dann kriegen wir ne neue instanz vom hauptmenü, von da aus eine neue instanz vom Spiel.
    Ich hab eine Klasse Internalization erstellt, die so aussieht:

    Code:
    package controller;
    
    import java.util.Locale;
    import java.util.MissingResourceException;
    import java.util.ResourceBundle;
    
    import javax.swing.JOptionPane;
    
    public class Internalization {
     private static ResourceBundle message;
     private static String language = "en";
     
     public Internalization(String lang) {
     Internalization.language = lang;
     setLanguage();
     }
     
     public static void setLanguage() {
     Locale currentLocale;
     currentLocale = new Locale(language);//what language
     try {
     message = ResourceBundle.getBundle("controller.MessageBundle", currentLocale);
     } catch (MissingResourceException e) {
     e.printStackTrace();
     JOptionPane.showConfirmDialog(null, "Could not find the language file!", "Error",
     JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
     }
     }
     
     public static ResourceBundle getMessage() {
     return message;
     }
    
    }
    
    der konstruktor bekommt die sprache übergeben und darüber selektieren wir das file, wo wir die Strings auslesen. so das funktioniert auch, allerdings wenn ich die sprache ändern will, macht er genau nix. wäre cool, wenn ihr eine idee hättet...
    THX
     
  2. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    Du musst denke ich die Aktualisierung der Labels etc. manuell vornehmen, eine andere Lösung gibt es meines Wissens nach nicht. Aĺso einen EventListener auf dein Steuerelement für die Sprache packen und darin die Labels neu setzen.
     
  3. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    also ich habs jetzt so (in meiner menubar):

    Code:
     JMenu menuFile = new JMenu(Internalization.getMessage().getString("menuFile"));// Create new DropDown file 
    
    ich hab das jetzt nur auf einem gemacht.
    Ich habe außerdem ein menüpunkt, um die sprache anzuwählen und wenn ich den klick wird Internalization("en") bzw. mit ("de") aufgerufen.
    der code oben funktioniert so, denn er zeigt auch wirklich den string, den ich angegeben hab.

    Ich habe jetzt ganz am anfang von meinem programm einmal
    Code:
    new Internalization("en");
    aufgerufen, denn wenn ich das nicht mache, dann krieg ich ne NullPointerException (is mir klar, weil die variablen sind ja uninitialisiert)..

    Was du jetzt meinst ist, dass wenn ich meine Sprache ändern will, dass ich einen eventhandler schreiben muss, der erstmal meine ganze GUI up-to-date bringt und alle labels, buttons etc neu initialisiert??? Also praktisch meine ganze GUI neu laden???
     
  4. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    Deine UI wird nicht neu geladen/initialisiert, es werden lediglich die Textelemente geändert.
    Anschließend ein .repaint() und die Sache hat sich erledigt.
     
    1 Person gefällt das.
  5. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    ok das problem ist fürn .repaint brauch ich ja die instanz der GUI.

    wir haben uns er game so aufgebaut:
    wir haben eine GUI und zwar nach dem MVC - modell.
    die GUI observt also die Instanz von Game, die einfach nur die spielregeln macht und die spieler und sowas alles hat.

    also wenn wir ein neues Spiel erstellen, brauchen wir erst eine Instanz vom game, dann erstellen wir eine Instanz unserer GUI und dann eine Instanz vom Controller (der nur im prinzip ein paar actionlistener und so hat)

    Code:
     IGame game = new Game((int)dialog.getNumberOfCards().getValue(),hardcoreMode);//create game
     this.game=game;//new reference
     for(int i = 0; i <= 5; i++) {//i = 0 to 5
     if (dialog.getOpenSlots()[i] == true)
     if (loop(i)) {//check for same color
     game.addPlayer(dialog.getPlayers()[i], colorConstants.get(dialog.getPlayerColor()[i]));//add player
     if (colorsAreEqual == true)//dont need to add any more player
     break;//exit for loop
     }
     }
     // If there are no or only one player, do nothing.
     if (game.getPlayers().size()<2) {
     dialog.onePlayer();//display information
     return;
     } else if (colorsAreEqual==true) {//two players have the same color
     dialog.twoColorsAreEqual();//display information
     colorsAreEqual=false;
     return;
     }
     MainFrame frame = new MainFrame(game);
     new Controller(game, frame);
    Das ist im prinzip der code abschnitt, der uns ein neues Game und ne neue GUI erstellt.
    wir machen ein paar abfragen, stellen fest, das wir genügend spieler haben und blabla
    die letzten beiden zeilen sind eigentlich die interessanten:
    wir erstellen unser neues Frame mit ner referenz von unserem neuen Modell game
    und dann machen wir nene Controller, der ne referenz hat zu dem Modell und der GUI...
    wenn ich jetzt meine Klasse Internalization einfüge, dann kann ich das ja frühstens nach der deklaration von MainFrame machen oder nicht??? Weil ich brauch ja eine Referenz von der Gui um .repaint() aufzurufen... :angry:
     
  6. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    Stimmt, mit repaint ists natürlich easy.

    Du kannst bzw. musst doch initial die Standardsprache mit der Internationalization-Klasse laden, damit der MainFrame überhaupt gebaut werden kann. Wo kommen sonst die Textteile der GUI her? Und wenn der User eine andere Sprache einstellt wird im Controller der Listener getriggert und ruft auf dem Frame repaint auf.
     
  7. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    genau das hab ich auch gedacht...
    also ich muss doch erstmal meine klasse Internationalization laden, damit ich meine static variablen initialisiere...
    ich hab das jetzt so versucht zu lösen:

    Code:
    package controller;
    
    import java.util.Locale;
    import java.util.MissingResourceException;
    import java.util.ResourceBundle;
    
    import javax.swing.JOptionPane;
    
    import view.MainFrame;
    
    public class Internalization {
     private static Locale currentLocale = new Locale("en");
     private static ResourceBundle message = ResourceBundle.getBundle("controller.MessageBundle", currentLocale);
     
     public Internalization() {
     
     }
     
     public static void changeLanguage(String lang, MainFrame frame) {
     currentLocale = new Locale(lang);//what language
     try {
     message = ResourceBundle.getBundle("controller.MessageBundle", currentLocale);
     frame.repaint();
     } catch (MissingResourceException e) {
     e.printStackTrace();
     JOptionPane.showConfirmDialog(null, "Could not find the language file!", "Error",
     JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
     }
     }
     
     
     public static ResourceBundle getMessage() {
     return message;
     }
    
    }
    
    und in main:

    Code:
     public static void main(String[] args) {
     new Internalization();
     new MainMenuController(new MainMenuFrame());
     
     }
    
    und dann mein mainframe:

    Code:
    package view;
    
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.Toolkit;
    import java.awt.event.ActionListener;
    
    import java.util.Observable;
    import java.util.Observer;
    
    import javax.swing.*;
    
    import model.*;
    import net.miginfocom.swing.MigLayout;
    
    public class MainFrame extends JFrame implements Observer{
     
     private static final long serialVersionUID = 1L;
     private MapScrollPane mapPanel;
     private MultifunctionalPanel multiPanel;
     private CardPreviewPanel cardPanel;
     private PlayerPane players;
     private Container content;
     private MenuBar menuBar;
     private MigLayout ml;
     private int playerNo;
     // This is the screen's size.
     private Dimension screen;
     // This is the ContentPane's size.
     private Dimension paneSize;
     private int cellHeight;
     // This is the ratio between the ContentPane's height
     // and the screen's height. Default is 0.9.
     private final double paneToScreen = 0.9;
    
     public MainFrame(IGame game) {
     this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
     content = new JPanel();
     ml =new MigLayout("gap 0 0,ins 0");
     this.setLayout(ml);
     content.setLayout(ml);
     setUpFrame();
     
     // The JPanel containing all the info about the players
     players = new PlayerPane(game);
     // A panel showing the currently drawn card
     cardPanel = new CardPreviewPanel(game);
     // A JScrollPane containing the map
     // It needs game to observe player and zombie movements.
     // It needs cardPanel to get the image of the last drawn card.
     // It needs the cardNo to determine the map's size.
     mapPanel = new MapScrollPane(game,cardPanel, game.getCardNo());
     // A multifunctional JPanel which gets changed depending on game phase
     multiPanel = new MultifunctionalPanel(game);
     
     int paneWidth=getContentPane().getWidth();
     int paneHeight=getContentPane().getHeight();
     
     String mapS="w "+(paneWidth-cellHeight)+"px!,h "+(paneHeight-cellHeight)+"!";
     String previewS="w "+cellHeight+"px!,h "+cellHeight+"px!";
     String playerS="w "+(paneWidth-cellHeight)+"px!,h "+cellHeight+"px!";
     String multiS="w "+cellHeight+"px!,h "+(paneHeight-cellHeight)+"px!";
     
     // The map's width is the ContentPane width minus one Cell width.
     content.add(mapPanel, "cell 0 0 6 3, "+mapS);
     //The multiPanel is the rest.
     content.add(multiPanel, "cell 6 0 1 3, "+multiS);
     // The PlayerPanels are under the map, all in one row
     content.add(players,"cell 0 3 6 1, "+playerS);
     // The preview panel is a square.
     content.add(cardPanel,"cell 6 3 1 1, "+previewS);
     game.addObserver(this);
     pack();
     players.load();
     if (game.getPlayers().isEmpty()) {
     mapPanel.scrollToField(game.getBoard().getCenter());
     } else if (game.getPhase()==Constants.SETCARD_PLACE_ZAL) {
     Pos lastCard = game.getBoard().getLastPos();
     mapPanel.scrollToField(new Pos(lastCard.getY()*3+1,lastCard.getX()*3+1));
     } else {
     mapPanel.scrollToField(game.getActivePlayer().getPos());
     }
     
     // Center this window on the screen
     setLocationRelativeTo(null);
     // Do not allow resizing as it would make the 3 standardS panels not square
     setResizable(false);
     setVisible(true);
     }
     
     /**
     * Sets up the frame and the content pane.
     */
     private void setUpFrame() {
     // Get the screen size.
     Toolkit toolkit = Toolkit.getDefaultToolkit();
     screen = toolkit.getScreenSize();
     menuBar = new MenuBar();
     setJMenuBar(menuBar);
     // Sets up this frame's ContentPane.
     int paneHeight = (int)(float)(screen.height*paneToScreen);
     int paneWidth = (int)(float)(paneHeight*screen.width/screen.height);
     paneSize = new Dimension(paneWidth,paneHeight);
     content.setSize(paneSize);
     // The height and width that every square component of this has.
     cellHeight = (int)((float)paneHeight/4)/3*3;
     setContentPane(content);
     this.setTitle("Zombie Invasion -- TEST");
     }
    
     /**
     * Getter for the ScrollPane.
     * @return The JScrollPane containing the map.
     */
     public MapScrollPane getScrollPane() {
     return mapPanel;
     }
     
     /**
     * Getter for the multifunctional panel.
     * @return
     */
     public MultifunctionalPanel getMultiPanel() {
     return multiPanel;
     }
     
     /**
     * Getter for the panel showing the last drawn card.
     * @return
     */
     public CardPreviewPanel getPreviewPanel() {
     return cardPanel;
     }
     
     /**
     * Add a new player to the GUI. Adds a PlayerPanel and a PlayerIcon.
     * @param player The player that gets added.
     */
     public void addPlayer(IPlayer player) {
     if (playerNo<6) {
     players.addPanel(player);
     mapPanel.getMap().addPlayer(player);
     playerNo++;
     pack();
     }
     }
     
     public void update(Observable obs, Object arg) {
     // Notified by game when a player is added.
     if (arg instanceof IPlayer) {
     IPlayer a = (IPlayer)arg;
     addPlayer(a);
     }else if(arg.equals("GAME_WON")){
     Game g = (Game)obs;
     if(g.getWinner()!=null){
     JOptionPane.showMessageDialog(this, g.getWinner().getName()+" wins the game");
     }
     }
     }
     
     public void addMenuActionListener(ActionListener l) {
     /*
     * Since getMenuBar is a method of JPanel (with the wrong MenuBar type),
     * we can not use this getter approach like we did with other Listeners :-(. 
     */
     menuBar.addActionListener(l);
     }
    }
    naja aber das .repaint will nicht so wirklich ?(
     
  8. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    Sorry, aber die Internationalization Klasse ist super häßlich. Wozu ist alles static mit public Konstruktor? Wenn das ein Singleton sein soll, lies die mal auf Wikipedia durch wie das geht.

    Was heißt will nicht so wirklich? Tritt ne Exception auf, wenn ja, welche und wo? Poste bitte die Exception und den Codeabschnitt wo sie auftritt. So blickt da keiner durch.
     
  9. 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    ja das stimmt... ne an singleton hab ich jetzt gar nicht gedacht aber gute idee...
    ich schreib die mal ein bisschen um...


    ne es passiert einfach gar nichts.. keine exception, keine meldung... einfach nichts...
     
  10. 17. Mai 2013
    Zuletzt bearbeitet: 17. Mai 2013
    AW: Sprache ändern zur laufzeit

    Hast du dir malo die API von ResourceBundle durchgelesen?
    http://docs.oracle.com/javase/6/docs/api/java/util/ResourceBundle.html

    Du machst die Strings hardcoded:
    Code:
    String multiS = "w " + cellHeight + "px!,h " + (paneHeight - cellHeight) + "px!";
    [...]
    content.add(multiPanel, "cell 6 0 1 3, " + multiS);
    
    Ansonsten ist da nicht ein String bzw. Zugriff auf deine Inter. Klasse drin.

    Was soll da nach nem repaint() deiner Meinung nach passieren?
     
    1 Person gefällt das.
  11. 17. Mai 2013
    Zuletzt von einem Moderator bearbeitet: 18. Mai 2013
    AW: Sprache ändern zur laufzeit

    der string den du da hast ist doch nur fürs miglayout...

    ich hab erstmal nur einen string, den ich neu machen will (im menü)

    und den hab ich eigentlich so realisiert:

    Code:
    JMenu menuFile = new JMenu(Internalization.getMessage().getString("menuFile"));
    deshalb ist das ding auch statisch und hat nen getter, weil sonst krieg ich keine referenz dadrauf...

    -----------

    ok also die Datei Internationalization heißt jetzt einfach I18N

    Code:
    package controller;
    
    import java.util.Locale;
    import java.util.MissingResourceException;
    import java.util.ResourceBundle;
    
    import javax.swing.JOptionPane;
    
    public class I18N {
     private static ResourceBundle message;
     
     public I18N(String lang) {
     Locale currentLocale = null;
     if (lang != null)
     currentLocale = new Locale(lang);
     try {
     I18N.message = ResourceBundle.getBundle("controller.MessageBundle", currentLocale);
     } catch (MissingResourceException e) {
     e.printStackTrace();
     JOptionPane.showConfirmDialog(null, "Could not find file!",
     "ERROR", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
     }
     }
     
     public static ResourceBundle getMessage() {
     return I18N.message;
     }
    
    }
    
    so das funktioniert auch soweit.
    jetzt haben wir das problem mit repaint() nur gehabt, denn wenn wir die instanz der gui zersört haben und neu aufgebaut haben, hat er die sprache geändert...
    wir haben jetzt einfach paint() überschrieben...
    jetzt klappt das mit repaint()
     
  12. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.