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

avec Java Discussion :

Erreur sur ChoiceFormat


Sujet :

avec Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 65
    Par défaut Erreur sur ChoiceFormat
    Bonjour à tous,

    Je suis en train de tester la classe ChoiceFormat pour internationaliser une application.
    J'ai fait l'exemple de la documentation et je pensais l'avoir compris, toutefois, dès que j'essaie de sortir de l'exemple prédéfini. ça bug!
    Ci-dessous, je vous joins mon code. J'essaie simplement de rajouter une chaine de caractère "Toto" à la fin de ma première ligne. Mais rien à faire.
    Je suis obligé d'ajouter un zéro (ou de manière générale une valeur numérique) pour que cela passe et affiche Toto ce qui donne 0Toto alors que je veux juste Toto.
    Qu'est ce que j'ai oublié?

    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
    package fr.localisation.app.Pluriel;
     
    import java.text.ChoiceFormat;
    import java.text.Format;
    import java.text.MessageFormat;
    import java.text.NumberFormat;
    import java.util.Locale;
    import java.util.ResourceBundle;
     
    public class Pluriel {
     
    	public static void mesPluriels() {
     
    		//--------------------------------------------------------//
    		// Gestion des pluriels
    		//--------------------------------------------------------//	
     
    		ResourceBundle traduction_pluriel = ResourceBundle.getBundle("fr.localisation.app.Pluriel.Pluriel", new Locale("fr", "CA"));
     
    		MessageFormat messageForm = new MessageFormat("");
    		messageForm.setLocale(new Locale("fr", "CA"));
     
    		// Création d'un ChoiceFormat
    		// Chaque numéro de fileLimits correspond à un chiffre dans le template
    		double[] fileLimits = {0,1,2};
    		// Les Strings recupérer seront liés à chaque numéro.
    		String [] fileStrings = {
    				traduction_pluriel.getString("noFiles"),
    				traduction_pluriel.getString("oneFile"),
    				traduction_pluriel.getString("multipleFiles")
    		};
    		// Création à proprement dit du ChoiceFormat
    		ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);
     
    		// Appliquer le pattern présent dans le fichier .properties
    		String pattern = traduction_pluriel.getString("pattern");
    		messageForm.applyPattern(pattern);
     
    		// Assigner les formats
    		Format[] formats = {choiceForm, null, NumberFormat.getInstance(), null, null};
    		messageForm.setFormats(formats);
     
    		// Configurer les arguments pour utiliser le bon choix
     
    		Object[] messageArguments = {null, "XDisk", null, 0, "Toto"};
                    // Il m'oblige à ajouter le 0 avant Toto, sinon, plantage!!!
     
    		for (int numFiles = 0; numFiles < 4; numFiles++) {
    		    messageArguments[0] = new Integer(numFiles);
    		    messageArguments[2] = new Integer(numFiles);
    		    String result = messageForm.format(messageArguments);
    		    System.out.println(result);
    		}
     
    	}
     
    }
    Le fichier Pluriel_fr_CA.properties correspondant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    pattern = Il {0} sur {1}. (fichier fr_CA) {3}{4}
    noFiles = n'y a pas de fichiers
    oneFile = y a un fichier
    multipleFiles = y a {2} fichiers
    Le {3} est inutile, mais je l'ajoute à cause de cette fichue valeur numérique qu'il m'impose.
    Curieusement, sur Format[] formats, je ne suis pas obligé de définir le même nombre d'arguments que messageArguments (ça me parait louche ça), du moment que je mets ma valeur numérique.

    Le message d'erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Exception in thread "main" java.lang.IllegalArgumentException: Cannot format given Object as a Number
    	at java.text.DecimalFormat.format(DecimalFormat.java:507)
    	at java.text.Format.format(Format.java:157)
    	at java.text.MessageFormat.subformat(MessageFormat.java:1322)
    	at java.text.MessageFormat.format(MessageFormat.java:865)
    	at java.text.Format.format(Format.java:157)
    	at fr.localisation.app.Pluriel.Pluriel.mesPluriels(Pluriel.java:49)
    	at fr.localisation.app.Main.main(Main.java:23)
    Si quelqu'un arrive me dire ce que j'ai mal fait. Merci d'avance. A bientôt.
    Damien.

    NOTA: Je suis sous Mac OS El Capitan et Java 1.8.0_131. Editeur : Eclipse
    NOTA2 : L'utilisation de MessageText seule fonctionne bien.

    A priori, c'est un bug : https://bugs.openjdk.java.net/browse/JDK-8042551
    J'ai cru comprendre que je dois modifier un des fichiers du JDK?

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    1. Tu es obligé de mettre un nombre en quatrième position parce que tu as mis un format de type "NumberInstance" en quatrième position avec
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      Format[] formats = {choiceForm, null, NumberFormat.getInstance(), null, null};
      Si tu fais :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      Format[] formats = {choiceForm, null, null, null, null};
      plus d'exception parce que le quatrième format est le format par défaut qui admet n'importe quel type, donc "toto" passe si tu n'insères par le 0.

    2. Citation Envoyé par austin57 Voir le message
      Curieusement, sur Format[] formats, je ne suis pas obligé de définir le même nombre d'arguments que messageArguments (ça me parait louche ça), du moment que je mets ma valeur numérique.
      La Javadoc le précise :
      If more formats are provided than needed by the pattern string, the remaining ones are ignored. If fewer formats are provided than needed, then only the first newFormats.length formats are replaced.
      Donc tu peux indiquer autant de formats que tu veux avec setFormats(), il ne remplacera que ceux qu'il y trouve, et au maximum ceux qui existent (dans l'expression du format, soit 5 ({0}...{4})).

    3. Pourquoi utilises-tu ce système d'initialisation qui est plutôt complexe et fastidieux je trouve (en plus, dans le cas professionel, où la traduction est soumise à une agence, c'est problématique d'avoir un seul message en plusieurs morceaux) ? C'est un exercice qui t'y oblige ?

      Il existe une solution simple :
      Dans le fichier properties, tu mets :
      messageNumberOfFile = Il {0,choice,0#n''y a pas de fichier|1#y a un fichier|1<y a {0} fichiers} sur {1}.
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      MessageFormat pluralNumberOfFile = new MessageFormat(traduction_pluriel.getString("messageNumberOfFile"));
      for (int numFiles = 0; numFiles < 4; numFiles++) {
         System.out.println(pluralNumberOfFile.format(new Object[]{numFiles,"XDisk"}));
      }
    4. Normalement, tu ne devrais pas forcer la locale lors de la récupération du bundle ou pour l'instanciation du format. Le programme devrait utiliser la locale par défaut, ce qui permet à chacun d'avoir les messages dans sa langue, si elle supportée bien sûr.
      Tu le fais peut-être juste pour tester. Mais tu peux le faire simplement, soit par la ligne de commande, soit simplement au lancement de ton programme, par :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      		Locale.setDefault(Locale.CANADA_FRENCH);
      Ensuite, tu as juste à faire :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      		ResourceBundle traduction_pluriel = ResourceBundle.getBundle("Pluriel");
      (Le nom complet du bundle n'est pas obligatoire si le fichier est dans le même package que la classe, ce qui sera intéressant si tu dois refactorisé ton code (pas obligé de modifier la chaine dans le code si tu changes le package de la classe)).
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 65
    Par défaut
    Bonjour Joel.drigo


    Quand vous dites que je mets NumberFormat.getInstance() en quatrième position, je ne suis pas sur de comprendre...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Format[] formats = {choiceForm, null, NumberFormat.getInstance(), null};
    0 1 2 3
    Pour moi, c'est bien le 2?
    Sauf si choiceFormat compte pour 3 (car 3 choix) mais dans ce cas, je suis complétement perdu!
    Je vais tenté le correctif proposé sur https://bugs.openjdk.java.net/browse/JDK-8042551
    Enfin, dès que j'aurai compris comment faire pour décompiler le .class et réinjecter le tout sans tout foutre en l'air :p


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Format[] formats = {choiceForm, null, null, null, null};
    Effectivement, si je fais cela, ça fonctionne bien pour un nombre (il prendra même en compte la localisation). Mais si je veux une devise avec NumberFormat.getCurrencyInstance()...crac!


    Pour le point 2. Vous avez totalement raison, c'est écrit noir sur blanc...à force de me faire des noeuds au cerveau, je ne vois que des problèmes!


    3. Pour le système d'initialisation, j'ai suivi la JavaDoc. Mais j'ai effectivement vu ce système de pattern, qui au départ, me semblait très alambiqué, j'ai préféré retarder son étude. Mais je vais y venir. :p

    4. En fait, j'ai voulu testé en utilisant une locale spécifique directement au niveau du ResourceBundle pour permettre à quelqu'un qui veut utiliser l'application, par exemple en Chinois, sur un système français puisse le faire via un menu. Mais à vrai dire, je n'ai pas encore été jusque là. Pour le nom de package...effectivement, je n'avais pas penser à une refactorisation ultérieure! Je vais modifier cela.

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par austin57 Voir le message

    Quand vous dites que je mets NumberFormat.getInstance() en quatrième position, je ne suis pas sur de comprendre...
    Au temps pour moi, je parlais en terme de numéro d'arguments dans le pattern ({3} donc quatrième position). C'est vrai que ça pouvait prêter à confusion et faire penser que je parlais de l'index dans le tableau de formats.

    Le souci avec setFormats() c'est que l'affectation des formats ne se fait pas par rapport à ces positions, mais par rapport à l'ordre de rencontre (à priori). C'est pourquoi il est précisé dans la doc :
    Since the order of format elements in a pattern string often changes during localization, it is generally better to use the setFormatsByArgumentIndex method, which assumes an order of formats corresponding to the order of elements in the arguments array passed to the format methods or the result array returned by the parse methods.
    Si on affiche, dans l'exemple donné dans le ticket de bug :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Format[] formats = { choiceFmt, NumberFormat.getInstance(), null };
    messageFmt.setFormats(formats);
    System.out.println(Arrays.toString(messageFmt.getFormats());
    System.out.println(Arrays.toString(messageFmt.getFormatsByArgumentIndex()));
    On obtient :
    [java.text.ChoiceFormat@43f96e71, java.text.DecimalFormat@674dc]
    [java.text.ChoiceFormat@43f96e71, null, java.text.DecimalFormat@674dc]
    Dans la seconde ligne, on a les formats dans l'ordre correspondant au numéro de paramètres. Dans la première on a le contenu du tableau interne (enfin pas exactement, parce que la méthode getFormats() fait une copie du tableau, en utilisant un int comme limite de nombre de cellules (maxoffset+1), le tableau initial contenant 10 cellules à l'initialisation).

    Lors du parsing des patterns pour déterminer les index d'arguments, MessageFormat parse d'abord son pattern, donc établi un tableau d'index comme ça : [0,2]. Puis parse les sous-format et on obtient [0,2,1]. Du coup, quand on affecte les formats par setFormats() on associe choiceFmt à {0} et NumberFormat.getInstance() à {2} . En gros, setFormats() ne fait que remplir un tableau interne dans l'ordre correspondant au tableau passé. Alors que setFormatsByArgumentIndex utilise bien le tableau interne des numéros de paramètres pour affecter les valeurs dans le tableau de format.
    Si on affiche le pattern final (méthode toPattern), on obtient :
    There {0,choice,0.0#are no files|1.0#is one file|2.0#are {1} files} on {2,number,#,##0.###}.
    Le format de {2} est bien un NumberFormat, donc c:\\ ne peut être formaté, d'où exception.

    C'est étonnant qu'il n'y ait pas de réponse en ce sens dans le ticket. Probablement dû à la disponibilité des intervenants du projet open source.

    Citation Envoyé par austin57 Voir le message
    Mais si je veux une devise avec NumberFormat.getCurrencyInstance()...crac!
    Avec ton programme, utilise alors setFormatsByArgumentsIndex.
    Et avec la solution du pattern unique (si tant est que ça ait un sens d'afficher un nombre de fichiers sous forme de devise ) :
    messageNumberOfFile = Il {0,choice,0#n''y a pas de fichier|1#y a un fichier|1<y a {0,number,currency} fichiers} sur {1}

    Citation Envoyé par austin57 Voir le message
    3. Pour le système d'initialisation, j'ai suivi la JavaDoc. Mais j'ai effectivement vu ce système de pattern, qui au départ, me semblait très alambiqué, j'ai préféré retarder son étude. Mais je vais y venir. :p
    C'est bizarre Moi c'est l'autre qui m'a toujours semblé super alambiqué avec plein de paramètres, dont il faut s'assurer justement la correspondance quand il s'agit de tableaux, sans parler de ne pas oublier d'utiliser ChoiceFormat.nextDouble (ce qui ton cas, d'ailleurs, je ne m'en étais pas aperçu).

    Citation Envoyé par austin57 Voir le message
    4. En fait, j'ai voulu testé en utilisant une locale spécifique directement au niveau du ResourceBundle pour permettre à quelqu'un qui veut utiliser l'application, par exemple en Chinois, sur un système français puisse le faire via un menu.
    Dans ce cas, Locale.setDefault() semble plus approprié parce que ça affectera bien toute l'application (encore faut-il raffraichir l'UI s'il y en a une). A moins que tu veuilles faire quelque chose localement (genre afficher dans une même fenêtre 2 messages de 2 locales différentes, ou afficher dans une fenêtre particulière un message dans une locale différente de la locale système). Mais pour ça, il faut penser à vaiment toutes les instances qui utilisent une Locale (en particulier dans des composants graphiques, il peut y en avoir, les formateurs, dans les Collator aussi, etc, on a vite fait d'en manquer si on ne consulte pas l'ensemble de toutes les docs et/ou le code source). Dans le cas où on veut proposer l'utilsation de l'application dans une langue différente de celle du système, le plus simple est de relancer l'application après changement de la locale (en stockant la locale dans une pref), ou proposer le choix au plus tôt (s'il y a un login par exemple, c'est un bon endroit, car ça en fera la seule gui a gérer en dynamique - d'ailleurs, la locale peut être stockée également dans la table d'utilisateurs dans ce cas).
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    65
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 65
    Par défaut
    Monsieur (avec un grand M) Joel Drigo, je vous remercie pour votre réponse pleine de précision!

    Encore une fois, la solution était dans la documentation. Mais je ne vous cache pas que la petite explication de texte en Français a été le bienvenue!
    Je pense que cette fois-ci, c'est parfaitement clair. La méthode setFormatsByArgumentIndex corrige effectivement le problème et j'ai saisi la subtile différence avec setFormats. Le bug était entre le clavier et la chaise! Une fois encore.
    Mais c'est quand même bizarre que leur exemple ne suivent pas leur recommandation!

    En plus de ça, vous m'avez convaincu, je pense que je vais regarder de plus prés le formatage du pattern avec différent choix, qui en y regardant de plus près ne semble pas si délirant.
    Et enfin, je vais également suivre votre conseil d'utiliser Locale.setDefault() et redémarrer l'application. Ce qui m'éviterai certainement quelques migraines.

    J'ai vraiment appris beaucoup de choses une nouvelle fois grâce à vous.
    Bien cordialement,
    Damien

    NB : Et pour les devises sur le nombre de fichiers, on est bien d'accord, c'était pour le test
    NB2 : J'ai voulu décompiler/recompiler MessageText.class...j'ai tout cassé heureusement, j'avais sauvegardé le rt.jar...je vais laissé ce genre de choses aux pros.

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par austin57 Voir le message
    NB2 : J'ai voulu décompiler/recompiler MessageText.class...j'ai tout cassé heureusement, j'avais sauvegardé le rt.jar...je vais laissé ce genre de choses aux pros.
    Si tu utilises bien un JDK, et non une JRE, pour développer, tu n'as pas besoin de décompiler les classes de Java. Le fichier src.zip (situé à la racine du dossier d'installation) contient les sources et normalement ton IDE devrait l'utiliser directement pour les voir (sinon il suffit de le configurer en lui indiquant l'emplacement de ce fichier).
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Erreur sur une fonction avec des paramètres
    Par Elois dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 05/05/2004, 21h00
  2. [VBS] Erreur sur "AddWindowsPrinterConnection"
    Par Admin dans le forum VBScript
    Réponses: 5
    Dernier message: 27/03/2004, 16h15
  3. Erreur sur serveur lié
    Par k-lendos dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 18/03/2004, 15h21
  4. []Erreur sur second emploi collection binding
    Par jacma dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 08/03/2004, 18h02
  5. Erreur sur le TNSListener après installation de 9iAS
    Par Patmane dans le forum Installation
    Réponses: 4
    Dernier message: 04/02/2004, 11h16

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