IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API standards et tierces Java Discussion :

Programme international avec IHM multi-langues [Trucs & Astuces]


Sujet :

API standards et tierces Java

  1. #1
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut Programme international avec IHM multi-langues
    Bonjour à tous,

    Voilà, je me suis penché sur le problème de l'internationalisation d'une
    application JAVA, en m'inspirant du tutoriel de SUN sur la question.

    cf :
    http://java.sun.com/docs/books/tutor...tro/after.html

    Comme je ne suis pas un expert en JAVA, je me permets de vous présenter
    mon programme d'exemple (qui permet donc d'avoir ici la même interface utilisateur
    en anglais, en français et en italien) pour pouvoir profiter de vos commentaires
    dans le but de l'améliorer, si cela n'est pas bon du tout.

    Voici en image l'interface en français :



    Et voici la même interface en italien :



    Voici le fichier langage.properties qu'il faut updater en fonction de la
    langue désirée par l'utilisateur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #Langages
    #Sun Apr 23 20:54:54 CEST 2006
    Pays=US
    Langue=en
    Vous avez donc le choix avec

    Pays=US Langue=en
    Pays=FR Langue=fr
    Pays=IT Langue=it


    Voici le code du programme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    import javax.swing.*;
     
    import java.io.*;
    import java.util.*;
     
    public class MultiLangageApplication extends JFrame
    {
        Locale         contexteLocal;
      ResourceBundle traducteur;
     
      //*************************************************
        // CONSTRUCTEUR
        public MultiLangageApplication()
        {
        initialisationLangue();
     
        setTitle(traducteur.getString("T_titreJFrame"));
        setSize(500, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setJMenuBar( initialiserLeMenu() );
        initialiserJPanel();
        setVisible(true);
        }
     
      //*************************************************    
        public JMenuBar initialiserLeMenu()
        {
            JMenuBar  menuBar;
            JMenu     menu;
            JMenuItem menuItem;
     
            // On crée la barre de menu
            menuBar = new JMenuBar();
     
            // on construit le 1er menu "Fichier"
            menu = new JMenu( traducteur.getString("M_fichier"));
            menuBar.add(menu);
     
            menuItem = new JMenuItem(traducteur.getString("M_ouvrir"));
            menu.add(menuItem);
     
            menuItem = new JMenuItem(traducteur.getString("M_fermer"));
            menu.add(menuItem);
     
            menuItem = new JMenuItem(traducteur.getString("M_quitter"));
            menu.add(menuItem);
     
            // on construit le 2ème menu "Edition"
            menu = new JMenu( traducteur.getString("M_edition"));
            menuBar.add(menu);
     
            menuItem = new JMenuItem( traducteur.getString("M_couper"));
            menu.add(menuItem);
     
            menuItem = new JMenuItem( traducteur.getString("M_copier"));
            menu.add(menuItem);
     
            menuItem = new JMenuItem( traducteur.getString("M_coller"));
            menu.add(menuItem);
     
            menuItem = new JMenuItem( traducteur.getString("M_parametres"));
            menu.add(menuItem);
     
            // on construit le 3ème menu "Aide"
            menu = new JMenu( traducteur.getString("M_aide"));
            menuBar.add(menu);
     
            menuItem = new JMenuItem( traducteur.getString("M_manuel"));
            menu.add(menuItem);
     
            menuItem = new JMenuItem( traducteur.getString("M_aproposde"));
            menu.add(menuItem);
     
            return menuBar;
        }
     
      //*************************************************    
        public void initialiserJPanel()
        {
            String[] entetes = {
                                   traducteur.getString("JTAB_client"),
                                   traducteur.getString("JTAB_adresse"),
                                   traducteur.getString("JTAB_ville"),
                                   traducteur.getString("JTAB_pays")
                               };
            Object[][] contenu =
            {
                    {"01","02","03","04"},
                    {"04","05","06","07"},
                    {"08","09","10","11"},
                    {"12","13","14","15"},
                    {"16","17","18","19"},
                    {"20","21","22","23"},
                    {"24","25","26","27"},
                    {"28","29","30","31"},
                    {"32","34","34","35"}
            };
     
            JTable letableau = new JTable( contenu, entetes);
     
            this.getContentPane().add("Center", new JScrollPane( letableau));
     
            JLabel lelabel = new JLabel(traducteur.getString("JLAB01_message"));
            this.getContentPane().add("South", lelabel);
     
            // les images
            Icon image = new ImageIcon(traducteur.getString("JLAB02_chemin_image"));
            JLabel lab_image = new JLabel(image);
     
            this.getContentPane().add("North", lab_image);
        }
     
      //*************************************************    
        public void initialisationLangue()
        {
            // Création d'un Properties et remplissage à partir du fichier
            Properties prop = new Properties();
            try {
                prop.load(  new FileInputStream( "langage.properties"));
                }
            catch( IOException e)
              {
              System.out.println( "Pb I/O: "+e.getMessage());
              }
     
            String langue = prop.getProperty( "Langue");
            String pays   = prop.getProperty( "Pays");
     
            contexteLocal = new Locale(langue, pays);
            traducteur    = ResourceBundle.getBundle("MessagesBundles", contexteLocal);
        }
     
      //*************************************************
        public static void main(String[] args)
        {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                }
            catch (Exception e) {
                                System.out.println(e);
                                }
     
            // on lance l'application
            new MultiLangageApplication();
        }
     
      //*************************************************
    }
    Et voici un lien vers le ZIP complet contenant tous les fichiers
    nécessaires (traductions comprises), prêt à être intégré tel quel dans Eclipse :

    ZIP

    Y'a-t-il une bonne âme parmis vous qui s'y connait en la question et
    qui peut me dire si c'est la bonne voie à suivre pour un programme de
    plus grande envergure que ce petit programme d'exemple ?

    D'avance merci de vos conseils.

    P.S.: si c'est bon, je vais ajouter tout ça dans la partie du forum
    JAVA : "Partagez vos sources".

  2. #2
    Gfx
    Gfx est déconnecté
    Expert éminent
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Points : 8 178
    Points
    8 178
    Par défaut
    Le seul truc qui pourrait manquer est le support BiDi (affichage de droite a gauche) mais ca depend des langues que tu veux gerer. Swing gere ca bien normalement mais il faut tester.
    Romain Guy
    Android - Mon livre - Mon blog

  3. #3
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Merci pour ton intervention, Gfx.

    Mon programme final sera destiné aux comptables européens.
    Donc, pour la gestion des langues qui vont de la droite vers la gauche, ce ne sera pas vraiment nécessaire pour moi.

    Par contre, mes préoccupations vont plutôt sur le "chargement" des nombreuses phrases des IHM de ma future application comptable (bcp plus grosse que ce petit exemple ci-dessus, écrit juste pour que je comprenne bien le mécanisme).

    Y'a-t-il un risque de ralentissement (vu que le nombre de "libellés" d'une grosse application peut rapidement gonfler au cours de son développement) ?

    Faudra-t-il que je gère le lancement de l'application avec une JProgressBar ? En comptant le nombre final de libellés à importer ?

    Ou alors avec un SplashScreen ?

    Ou est-ce dérisoire comme temps d'attente ? (Au fond, c'est une "bête lecture" d'un fichier texte...)

  4. #4
    Gfx
    Gfx est déconnecté
    Expert éminent
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Points : 8 178
    Points
    8 178
    Par défaut
    Le temps d'attente est derisoire mais je te conseille de placer l'initialisation dans le main plutot que dans le code de la Frame. Essaye aussi d'utiliser une instance statique pour le ResourceBundle. Tu peux meme provoquer le chargement dans un bloc d'initialisation static dans ta classe.
    Romain Guy
    Android - Mon livre - Mon blog

  5. #5
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Attention egalement l'i18n peut ne pas concerner que les chaines de charactere mais aussi les icones* voir les images** utilisees par le programme.

    * certaines icones pouvant ne pas etre comprises dans une langue car contenant du texte (ex : une icone avec marque EXIT) ou representant des dessins pouvant etre "offensant" (ex : une main levee pour representer un stop/arret) dans certains pays.

    **logo de chargement/demarrage avec texte ou nom de l'application, screens de l'ihm pour l'aide en ligne, etc...

    J'en suis venu a utiliser des ResoucesBundle pour : les chaines de characteres, les icones, les images, les curseurs, les sons et l'aide en ligne***. Les access se font a travers un singleton.

    Une autre chose d'interessant est que suivant l'endroit ou doit etre deployer l'application on peut en faire des variantes (avec icones, images,... differentes) rien qu'en fournissant un autre lot de fichiers .properties en remplacement de ceux par defaut.

    *** Mais comme je suis passe a JavaHelp depuis je vais plutot utiliser le support de l'i18n de JavaHelp pour l'aide.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  6. #6
    Membre confirmé Avatar de calogerogigante
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    602
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2003
    Messages : 602
    Points : 497
    Points
    497
    Par défaut
    Citation Envoyé par Gfx
    Je te conseille de placer l'initialisation dans le main plutot que dans le code de la Frame. Essaye aussi d'utiliser une instance statique pour le ResourceBundle.
    OK, je vais voir ça. Je peux faire un tableau static de String, que j'initialise une seule fois dans le main, lors du lancement, et dont je peux accéder alors depuis n'importe quelle autre classe.

    Citation Envoyé par bouye
    Attention egalement l'i18n peut ne pas concerner que les chaines de charactere mais aussi les icones* voir les images** utilisees par le programme.
    Oui, c'est ce à quoi j'ai pensé. Si tu regardes le ZIP de mon petit exemple, tu verras qu'il y a aussi une image propre à chaque langue (ce sont de simples images mais comme c'est juste pour un test).

    Je ne comprends pas bien quand tu dis que tu mets des sons et des images dans un RessourceBundle ?
    Tu veux dire : que tu mets les chemins relatifs et les noms des sons et des images dans le fichier texte *.properties, utilisé par la classe RessourceBundle ?

    Comme je l'ai fait finalement ?

    Bouye, peux-tu m'éclaircir tes propos par rapport au contenu de mon zip ?
    Grand merci d'avance si tu as un peu de temps pour ça !!!

  7. #7
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Citation Envoyé par calogerogigante
    Tu veux dire : que tu mets les chemins relatifs et les noms des sons et des images dans le fichier texte *.properties, utilisé par la classe RessourceBundle ?
    Exact, chaque icone, image ou son a un identificateur. Le fichier .properties contient juste un mapping ID => chemin relatif sur le CLASSPATH (pour que cela puisse fonctionner aussi bien en acces direct que dans un JAR evidement).

    Par exemple, quand on demande a la classe chargee de la gestion des ressources de trouver une icone a partir d'une ID, elle :
    - elle recupere le bundle contenant les definitions des icones (si pas deja charge)
    - trouve le chemin associe a l'ID en fonction de la langue courante (si cette ID existe) via le systeme de resolution propres aux bundles.
    - forme une URL a partir du chemin relatif et getClass().getClassLoader.getResource().
    - charge l'icone suivant les methode habituelles.
    Il y a qq subtilites supplementaires mais c'est en gros ce qui se passe. La meme chose pour les autres types de donnees.

    Sinon pour le reste c'est pratiquement la meme chose que ce que tu as fais. Ex de fichier de definition de chaines de characteres (non-obstant d'eventuelles fautes).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    [...]
    ACTION_INVERT_Y_AXIS=Invert Axis?
    ACTION_INVERT_Y_AXIS.Mnemonic=X
    ACTION_INVERT_Y_AXIS.KeyStroke=
    ACTION_INVERT_Y_AXIS.Tooltip=<html>Inverts the latitudinal axis</html>
    ACTION_Z_AXIS_IS_TIME=Is Time?
    ACTION_Z_AXIS_IS_TIME.Mnemonic=T
    ACTION_Z_AXIS_IS_TIME.KeyStroke=
    ACTION_Z_AXIS_IS_TIME.Tooltip=<html>Indicates whether the Z axis is a <b>time</b> axis instead of a depth axis</html>
    ACTION_Z_AXIS_IS_DEPTH=Is Depth?
    ACTION_Z_AXIS_IS_DEPTH.Mnemonic=D
    ACTION_Z_AXIS_IS_DEPTH.KeyStroke=
    ACTION_Z_AXIS_IS_DEPTH.Tooltip=<html>Indicates whether the Z axis is a <b>depth</b> axis instead of a time axis</html>
    ERROR_DYM_FUNC_DOES_NOT_MATCH=The file does not have the same stretching method than the current selection.
    ERROR_DYM_NLONG_DOES_NOT_MATCH=The file does not have the same number of longitudinal records than the current selection.
    ERROR_DYM_NLAT_DOES_NOT_MATCH=The file does not have the same number of latitudinal records than the current selection.
    ERROR_DYM_NLEVEL_DOES_NOT_MATCH=The file does not have the same number of time/depth records than the current selection.
    ERROR_DYM_START_DATE_DOES_NOT_MATCH=The file does not have the same start date than the current selection.
    ERROR_DYM_END_DATE_DOES_NOT_MATCH=The file does not have the same end date than the current selection.
    LABEL_CONVERSION=Conversion
    LABEL_TASK_CONVERSION_START=Conversion Start...
    MESSAGE_CONVERSION_OPERATION_SUCCESSFUL=The conversion operation was successful.
    PATTERN_CREATING_VARIABLE=Creating {0}
    PATTERN_FILLING_VARIABLE=Filling {0}
    [...]
    J'ai eut qq petits problemes pour reutiliser le code mais ca vient du fait que ca fait tellement longtemps que j'avais fait ma lib que j'avais oublie que le fichier .properties doit etre sur le CLASSPATH pour que le chargement fonctionne et JBuilder m'a plutot mis des batons dans les roues sur ce coup-la...

    Note : pense a fermer le flux qui te permet de lire ton fichier de parametre.

    Tu peux egalement essayer de faire Locale.setDefault(contexteLocal); pour que tous les composants, classes de formattages, etc... charges ulterieurement soient directement a la bonne Locale. Comme Gfx l'a conseille tu peux deplacer le chargement de la locale et du bundle dans un envirronement statique avant la creation de la Frame (comme ca elle aussi aura la bonne Locale a sa creation).
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

Discussions similaires

  1. [Interface] Projet multi-langue sous C++ Builder, message interne en ressource (String Tables)
    Par otacon ghost dans le forum C++Builder
    Réponses: 4
    Dernier message: 03/08/2011, 16h46
  2. Site multi-langue avec masterPage
    Par AghilasB dans le forum ASP.NET
    Réponses: 3
    Dernier message: 05/10/2009, 14h47
  3. Réponses: 4
    Dernier message: 28/05/2009, 10h11
  4. Moteur de recherche interne sur site dynamique et multi-langues
    Par lucimed dans le forum Développement Web en Java
    Réponses: 4
    Dernier message: 30/06/2008, 11h34
  5. [Cookies] multi langue PHP avec cookie
    Par heteroclite dans le forum Langage
    Réponses: 25
    Dernier message: 22/05/2007, 14h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo