Visualizzazione dei risultati da 1 a 6 su 6

Discussione: [Java] i18n

  1. #1

    [Java] i18n

    Salve, ho creato 1 programmino e ora sto cercando di inserire la possibilità di cambiare lingua con scelta da parte dell'utente tramite bottone.

    Ho creato 2 file .properties chiamati WowAbsoluteCoords_ENG e WowAbsoluteCoords_ITA dove vi sono le coppie chiave/valore per la traduzione
    codice:
    YOU_HAVENT_INSERT_COORDINATES=You haven't insert coordinates.
    CREATE_GAMEOBJECT=Create gameobject
    CREATE_CREATURE=Create creature
    CLEAN_TEXTAREA=Clean textareas
    SAVE_AS_SQL=Save in sql file
    PASTE_GUI_RESULT=Paste here .gps command result
    RESULT=Result
    ...
    Al momento il codice è il seguente
    codice:
        private Locale locale;
        private ResourceBundle resources;
        private static String defaultLanguage;
    
        .....
    
        //Imposta la lingua di default
        locale = Locale.getDefault();
        if (locale.toString().equals("en_US")){
            defaultLanguage="wowabsolutecoords/WowAbsoluteCoords_ENG";
        }
        else if (locale.toString().equals("it_IT")){
            defaultLanguage="wowabsolutecoords/WowAbsoluteCoords_ITA";    
        }
            
        resources = ResourceBundle.getBundle(defaultLanguage, locale);
    
        ....
    Ogni stringa del programma è settata come segue
    codice:
            gameobjectJButton.setToolTipText(resources.getString("CREATE_GAMEOBJECT").toString());
    Questo per tutti i componenti della GUI.

    Ora, creato il bottone per il cambio della lingua e il suo ActionListener, come potrei fare a cambiare dinamicamente sfruttando i file di properties tutte le label con poche righe di codice?
    Esiste sicuramente un metodo rapido che non conosco, non credo si debba usare un .setText per tutti gli elementi della GUI, anche perché alcuni si trovano su file diversi da quello della GUI, quindi non potrei usare i .setText

    Grazie mille per gli aiuti

  2. #2
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320

    Moderazione

    Java ha il suo bel forum dedicato.

    Sposto.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  3. #3
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: [Java] i18n

    Originariamente inviato da mishima
    codice:
        //Imposta la lingua di default
        locale = Locale.getDefault();
        if (locale.toString().equals("en_US")){
            defaultLanguage="wowabsolutecoords/WowAbsoluteCoords_ENG";
        }
        else if (locale.toString().equals("it_IT")){
            defaultLanguage="wowabsolutecoords/WowAbsoluteCoords_ITA";    
        }
            
        resources = ResourceBundle.getBundle(defaultLanguage, locale);
    Giusto per chiarire, generalmente i ResourceBundle non si usano in questo modo. Nel senso che a meno di dover fare cose davvero fuori dall'ordinario, non c'è bisogno di fare "a mano" lo switch tra i nomi dei bundle! Sa già farlo il framework! E se i nomi sono scritti nel formato appropriato.

    Backing a ResourceBundle with Properties Files
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  4. #4
    hai ragione andbin

    ho modificato il codice

    Ho rinominato i file .properties in language (default in inglese) e language_it (l'italiano) secondo gli standard usati.
    Li ho spostati nella giusta posizione del progetto. Ora il codice è

    codice:
    ResourceBundle resources = ResourceBundle.getBundle("language", Locale.getDefault());
    E il programma parte in italiano.

    Tuttavia il mio problema resta. Se l'utente sceglie di cambiare lingua, diciamo vuole passare all'inglese del file language

    Come posso cambiare con poco codice tutti i testi presenti nelle JLabel, le JTextArea, i JTextField, i JMenuItem, i JButton etc.. ?
    Non voglio credere di essere costretto a fare un .setText per ognuno di questi elementi nel listener del bottone per il cambio della lingua. Ora la mia interfaccia è semplice, saranno 20 voci... Ma in caso di interfacce complesse con 200 voci? O anche di più?

  5. #5
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da mishima
    Tuttavia il mio problema resta. Se l'utente sceglie di cambiare lingua, diciamo vuole passare all'inglese del file language

    Come posso cambiare con poco codice tutti i testi presenti nelle JLabel, le JTextArea, i JTextField, i JMenuItem, i JButton etc.. ?
    Non voglio credere di essere costretto a fare un .setText per ognuno di questi elementi nel listener del bottone per il cambio della lingua. Ora la mia interfaccia è semplice, saranno 20 voci... Ma in caso di interfacce complesse con 200 voci? O anche di più?
    Partiamo dalla questione sul java.util.Locale. Le soluzioni sono 2 (almeno .. ho in mente queste adesso):

    1) Settare il Locale di default (setDefault di Locale) in modo che tutto il resto che si basa sul locale di "default" vada automaticamente a posto. Questo sarebbe positivo non solo per il ResourceBundle ma anche quando, ad esempio, da qualche parte prendi es. un NumberFormat o un DateFormat per il locale predefinito.

    2) Usare una tua variabile Locale (globale in qualche modo), inizialmente settata con il locale di default. Quindi una gestione "a monte" di quella del framework, dove tutto nella tua applicazione girerebbe in funzione di questa tua variabile. Non mi piace molto come soluzione ma l'ho detta giusto per completezza.

    Passiamo alla questione del "cambio" della interfaccia utente. Questa è più "spinosa".

    Se hai pochi componenti "localizzabili", potresti anche fare una gestione specializzata e veloce. Anche con dei banali setText ma intendo dire che potresti anche non voler "generalizzare" la cosa (spiego dopo).
    C'è solo un problema se vuoi cambiare i testi nella interfaccia "al volo" mantenendo la interfaccia "viva" senza ricostruirla: i testi potrebbero essere più lunghi o più corti e a seconda del/dei layout manager che hai usato, un banale cambio dei testi potrebbe portare ad una interfaccia un po' "sballata".
    Certo ... si potrebbe sempre fare un pack() sul frame (ammesso, ripeto, che ci siano i layout manager) ma in ogni caso è da valutare.

    Le altre soluzioni sono almeno tre:

    1) Notificare all'utente che il cambio di lingua avverrà al prossimo avvio della applicazione (ovviamente la lingua devi salvarla in modo persistente da qualche parte, es. file di configurazione o altro). Non è una soluzione tanto brutta quanto sembra. Molte applicazioni multi-lingua fanno così.

    2) Senza dover terminare l'applicazione, semplicemente "distruggere" il/i frame/dialog della applicazione (che vuol solo dire chiuderli e farli diventare non più raggiungibili) e poi ricrearli con la nuova lingua.
    Chiaramente ci vuole un po' di "logica", nel senso che si tratta di predisporre un possibile "loop" per ricreare la GUI. Ma nulla di complicato.

    3) Mantenere la interfaccia viva e cambiare solo i testi localizzabili. A patto poi di fare in modo che la interfaccia si presenti bene dal punto di vista visivo.
    Questo tecnicamente si può fare in svariati modi: dal modo più diretto in cui avendo i riferimenti ai componenti fai tanti setText di fila in un tuo metodo a modi più generici in cui magari crei i tuoi componenti es. MyLabel che estende JLabel, ecc... che hanno in più la informazione sul "id" da usare per il testo e magari implementano una interfaccia es. Localizzabile. A quel punto basta una scansione in profondità partendo da un contenitore per trovare tutti i "Localizzabile" invocando su ognuno es. localizza().
    Questa sarebbe una architettura più "generica" ma va pensata e strutturata prima di partire "in quinta" marcia con lo sviluppo della applicazione!
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  6. #6
    Originariamente inviato da andbin
    Le altre soluzioni sono almeno tre:

    1) Notificare all'utente che il cambio di lingua avverrà al prossimo avvio della applicazione (ovviamente la lingua devi salvarla in modo persistente da qualche parte, es. file di configurazione o altro). Non è una soluzione tanto brutta quanto sembra. Molte applicazioni multi-lingua fanno così.

    2) Senza dover terminare l'applicazione, semplicemente "distruggere" il/i frame/dialog della applicazione (che vuol solo dire chiuderli e farli diventare non più raggiungibili) e poi ricrearli con la nuova lingua.
    Chiaramente ci vuole un po' di "logica", nel senso che si tratta di predisporre un possibile "loop" per ricreare la GUI. Ma nulla di complicato.
    Interessante, hai previsto tutti i casi possibili, tralasciamo la 3 che è un po' complicata e oltre le mie necessità.
    Il primo caso in effetti è semplice da fare e mi risolverebbe numerosi problemi. L'ho già implementato e funziona

    Il secondo caso, che era quello che cercavo, l'ho fatto così (bottone per settare inglese)
    codice:
                    frame.dispose();
                    ConfigurationProperties.setProperty("LANGUAGE", "en_US");
                    createAndShowGUI();
    In pratica distruggo la finestra, memorizzo la nuova lingua nel mio file di proprietà, ConfigurationProperties è una classe che ho creato con il metodo statico setProperty e infine richiamo la funzione che mi crea la GUI, presente su questo stesso file dove è presente questo codice.

    Tuttavia solo la JMenuBar cambia lingua (aggiunta col il codice)
    codice:
    frame.setJMenuBar(myJMenuBar);
    Il resto è tutta una serie di .add tra elementi.
    E' come se il dispose non eliminasse tutto ciò che è interno al frame, restano elementi quali JTextArea, JLabel etc.. contenenti testo in italiano. Il dispose non dovrebbe eliminare anche i sottocomponenti del frame?

    Altra idea, provo con il codice
    codice:
                    frame.dispose();
                    ConfigurationProperties.setProperty("LANGUAGE", "en_US");
                    new MyGUI();
    Dove MyGUI è il nome della classe che crea la GUI. Ottengo l'effetto di avere tutti i testi in inglese, ma mi rendo conto di non aver fatto una cosa pulita, essendo ancora vivo il vecchio oggetto MyGUI. Provo allora
    codice:
                        this.finalize();
                    } catch (Throwable ex) {
                        Logger.getLogger(MyGUI.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    ConfigurationProperties.setProperty("LANGUAGE", "en_US");
                    new MyGUI();
    Il codice funziona, ma non so quanto possa essere corretto. In un oggetto chiamo un finalize su se stesso, e il codice successivo viene eseguito? All'inizio credevo si fermasse il thread che gestisce la GUI nel punto della chiamata a finalize().

    Dunque le mie domande sono, perché il dispose non elimina tutto ciò che è interno al frame?
    L'ultimo codice postato, con il finalize, è una soluzione corretta?

    Ti ringrazio

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.