web-dev-qa-db-fra.com

Comment utiliser UTF-8 dans les propriétés de ressources avec ResourceBundle

Je dois utiliser UTF-8 dans les propriétés de mes ressources à l'aide de la variable ResourceBundle de Java. Lorsque j'entre le texte directement dans le fichier de propriétés, il s'affiche en tant que mojibake.

Mon application fonctionne sur Google App Engine.

Quelqu'un peut-il me donner un exemple? Je ne peux pas avoir ce travail.

241
nacho

Le ResourceBundle#getBundle() est utilisé sous les couvertures PropertyResourceBundle lorsqu'un fichier _.properties_ est spécifié. Cela utilise par défaut Properties#load(InputStream) pour charger ces fichiers de propriétés. Selon le javadoc , ils sont lus par défaut comme ISO-8859-1.

public void load(InputStream inStream) throws IOException

Lit une liste de propriétés (paires clé/élément) à partir du flux d'octets en entrée. Le flux d'entrée est dans un format simple orienté ligne comme spécifié dans load (Reader) et est supposé utiliser le codage de caractères ISO 8859-1 ; c'est-à-dire que chaque octet est un caractère Latin1. Les caractères qui ne figurent pas dans Latin1 et certains caractères spéciaux sont représentés dans les clés et les éléments à l'aide d'échappements Unicode tels que définis dans la section 3.3 de la spécification du langage Java ™.

Vous devez donc les enregistrer au format ISO-8859-1. Si vous avez des caractères au-delà de la plage ISO-8859-1 et que vous ne pouvez pas utiliser _\uXXXX_ en haut de la tête et que vous êtes donc obligé de sauvegarder le fichier au format UTF-8, vous devrez alors utiliser la commande native2ascii outil permettant de convertir un fichier de propriétés enregistré UTF-8 en un fichier de propriétés enregistré ISO-8859-1 dans lequel tous les caractères non recouverts sont convertis au format _\uXXXX_ format. L'exemple ci-dessous convertit un fichier de propriétés codé UTF-8 _text_utf8.properties_ en un fichier de propriétés codé ISO-8859-1 valide _text.properties_.

natif2ascii -encodant UTF-8 text_utf8.properties text.properties

Lorsque vous utilisez un IDE sain, tel que Eclipse, cette opération est déjà effectuée automatiquement lorsque vous créez un fichier _.properties_ dans un projet basé sur Java et utilisez le propre éditeur d'Eclipse. Eclipse convertira de manière transparente les caractères au-delà de la plage ISO-8859-1 au format _\uXXXX_. Voir également les captures d'écran ci-dessous (notez les onglets "Propriétés" et "Source" en bas, cliquez pour agrandir):

"Properties" tab"Source" tab

Vous pouvez également créer une implémentation personnalisée ResourceBundle.Control dans laquelle vous lisez explicitement les fichiers de propriétés au format UTF-8 à l’aide de InputStreamReader , afin de pouvoir les enregistrer au format. UTF-8 sans avoir à vous soucier de _native2ascii_. Voici un exemple de coup d'envoi:

_public class UTF8Control extends Control {
    public ResourceBundle newBundle
        (String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
            throws IllegalAccessException, InstantiationException, IOException
    {
        // The below is a copy of the default implementation.
        String bundleName = toBundleName(baseName, locale);
        String resourceName = toResourceName(bundleName, "properties");
        ResourceBundle bundle = null;
        InputStream stream = null;
        if (reload) {
            URL url = loader.getResource(resourceName);
            if (url != null) {
                URLConnection connection = url.openConnection();
                if (connection != null) {
                    connection.setUseCaches(false);
                    stream = connection.getInputStream();
                }
            }
        } else {
            stream = loader.getResourceAsStream(resourceName);
        }
        if (stream != null) {
            try {
                // Only this line is changed to make it to read properties files as UTF-8.
                bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
            } finally {
                stream.close();
            }
        }
        return bundle;
    }
}
_

Ceci peut être utilisé comme suit:

_ResourceBundle bundle = ResourceBundle.getBundle("com.example.i18n.text", new UTF8Control());
_

Voir également:

356
BalusC

Étant donné que vous avez une instance de ResourceBundle et que vous pouvez obtenir String par:

String val = bundle.getString(key); 

J'ai résolu mon problème d'affichage japonais par:

return new String(val.getBytes("ISO-8859-1"), "UTF-8");
125
Rod

regardez ceci: http://docs.Oracle.com/javase/6/docs/api/Java/util/Properties.html#load (Java.io.Reader)

les propriétés acceptent un objet Reader Reader , que vous pouvez créer à partir d'un InputStream.

au moment de la création, vous pouvez spécifier le codage du Reader:

InputStreamReader isr = new InputStreamReader(stream, "UTF-8");

puis appliquez ce Reader à la méthode de chargement:

prop.load(isr);

BTW: récupérez le flux à partir du fichier . Properties :

 InputStream stream = this.class.getClassLoader().getResourceAsStream("a.properties");

BTW: obtenez un groupe de ressources de InputStreamReader:

ResourceBundle rb = new PropertyResourceBundle(isr);

espérons que cela peut vous aider!

46
Chinaxing

ResourceBundle.Control avec UTF-8 et les nouvelles méthodes String ne fonctionne pas, si le fichier de propriétés utilise le jeu de caractères cp1251, par exemple.

J'ai donc recommandé d'utiliser une méthode commune: écrire en symboles Unicode . Pour ça:

IDÉE - a un spécial " conversion transparente native-en-ASCII " option (Paramètres> Codage de fichier).

Eclipse - possède un plugin " Editeur de propriétés " . Cela peut fonctionner comme une application séparée.

20
Kinjeiro
package com.varaneckas.utils;  

import Java.io.UnsupportedEncodingException;  
import Java.util.Enumeration;  
import Java.util.PropertyResourceBundle;  
import Java.util.ResourceBundle;  

/** 
 * UTF-8 friendly ResourceBundle support 
 *  
 * Utility that allows having multi-byte characters inside Java .property files. 
 * It removes the need for Sun's native2ascii application, you can simply have 
 * UTF-8 encoded editable .property files. 
 *  
 * Use:  
 * ResourceBundle bundle = Utf8ResourceBundle.getBundle("bundle_name"); 
 *  
 * @author Tomas Varaneckas <[email protected]> 
 */  
public abstract class Utf8ResourceBundle {  

    /** 
     * Gets the unicode friendly resource bundle 
     *  
     * @param baseName 
     * @see ResourceBundle#getBundle(String) 
     * @return Unicode friendly resource bundle 
     */  
    public static final ResourceBundle getBundle(final String baseName) {  
        return createUtf8PropertyResourceBundle(  
                ResourceBundle.getBundle(baseName));  
    }  

    /** 
     * Creates unicode friendly {@link PropertyResourceBundle} if possible. 
     *  
     * @param bundle  
     * @return Unicode friendly property resource bundle 
     */  
    private static ResourceBundle createUtf8PropertyResourceBundle(  
            final ResourceBundle bundle) {  
        if (!(bundle instanceof PropertyResourceBundle)) {  
            return bundle;  
        }  
        return new Utf8PropertyResourceBundle((PropertyResourceBundle) bundle);  
    }  

    /** 
     * Resource Bundle that does the hard work 
     */  
    private static class Utf8PropertyResourceBundle extends ResourceBundle {  

        /** 
         * Bundle with unicode data 
         */  
        private final PropertyResourceBundle bundle;  

        /** 
         * Initializing constructor 
         *  
         * @param bundle 
         */  
        private Utf8PropertyResourceBundle(final PropertyResourceBundle bundle) {  
            this.bundle = bundle;  
        }  

        @Override  
        @SuppressWarnings("unchecked")  
        public Enumeration getKeys() {  
            return bundle.getKeys();  
        }  

        @Override  
        protected Object handleGetObject(final String key) {  
            final String value = bundle.getString(key);  
            if (value == null)  
                return null;  
            try {  
                return new String(value.getBytes("ISO-8859-1"), "UTF-8");  
            } catch (final UnsupportedEncodingException e) {  
                throw new RuntimeException("Encoding not supported", e);  
            }  
        }  
    }  
}  
19
marcolopes

Ce problème a finalement été résolu dans Java 9: https://docs.Oracle.com/javase/9/intl/internationalization-enhancements-jdk-9

Le codage par défaut pour les fichiers de propriétés est maintenant UTF-8.

La plupart des fichiers de propriétés existants ne doivent pas être affectés: UTF-8 et ISO-8859-1 ont le même encodage pour les caractères ASCII et l'encodage ISO-8859-1 non-ASCII lisible par un humain n'est pas valide. UTF- 8 Si une séquence d'octets UTF-8 non valide est détectée, le moteur d'exécution Java relit automatiquement le fichier dans ISO-8859-1.

18
stenix

Nous créons un fichier resources.utf8 qui contient les ressources dans UTF-8 et avons une règle pour exécuter ce qui suit:

native2ascii -encoding utf8 resources.utf8 resources.properties
17
andykellr

Attention: Les fichiers de propriétés Java doivent être codés selon ISO 8859-1!

ISO 8859-1 encodage de caractères. Les caractères qui ne peuvent pas être directement représentés dans cet encodage peuvent être écrits à l'aide d'échappements Unicode. un seul caractère 'u' est autorisé dans une séquence d'échappement.

@see Properties Java Doc

Si vous voulez toujours faire ceci: regardez: encodage UTF-8 des propriétés Java dans Eclipse - il y a des exemples de code

8
Ralph

http://sourceforge.net/projects/Eclipse-rbe/

comme indiqué précédemment, les fichiers de propriétés doivent être codés dans l'ISO 8859-1

Vous pouvez utiliser le plug-in ci-dessus pour Eclipse IDE pour effectuer la conversion Unicode à votre place.

5
fmucar

Voici une solution Java 7 qui utilise l'excellente bibliothèque de support de Guava et la structure try-with-resources. Il lit et écrit des fichiers de propriétés en utilisant UTF-8 pour une expérience globale des plus simples.

Pour lire un fichier de propriétés au format UTF-8:

File file =  new File("/path/to/example.properties");

// Create an empty set of properties
Properties properties = new Properties();

if (file.exists()) {

  // Use a UTF-8 reader from Guava
  try (Reader reader = Files.newReader(file, Charsets.UTF_8)) {
    properties.load(reader);
  } catch (IOException e) {
    // Do something
  }
}

Pour écrire un fichier de propriétés au format UTF-8:

File file =  new File("/path/to/example.properties");

// Use a UTF-8 writer from Guava
try (Writer writer = Files.newWriter(file, Charsets.UTF_8)) {
  properties.store(writer, "Your title here");
  writer.flush();
} catch (IOException e) {
  // Do something
}
3
Gary Rowe

Comme l’a suggéré un, j’ai traversé la mise en œuvre du regroupement de ressources .. mais cela n’a pas aidé., Car le regroupement a toujours été appelé avec les paramètres régionaux en_US ... j’ai essayé de définir les paramètres régionaux par défaut dans une autre langue tout en mettant en œuvre le regroupement de ressources le contrôle était appelé avec en_US ... j'ai essayé de mettre des messages de journal et d'effectuer une étape de débogage et de voir si un appel local différent était passé après que je change de paramètres régionaux au moment de l'exécution via des appels xhtml et JSF ... qui ne se sont pas produits ... alors j'ai essayé de faire un utf8 par défaut pour la lecture de fichiers par mon serveur (serveur Tomcat) .. mais cela a causé pronlem car toutes mes bibliothèques de classes n'étaient pas compilées sous utf8 et Tomcat a commencé à lire puis au format utf8 et le serveur ne fonctionnait pas correctement ... alors j'ai fini par implémenter une méthode dans mon contrôleur Java à appeler à partir de fichiers xhtml ... dans cette méthode, j'ai fait ce qui suit:

        public String message(String key, boolean toUTF8) throws Throwable{
            String result = "";
            try{
                FacesContext context = FacesContext.getCurrentInstance();
                String message = context.getApplication().getResourceBundle(context, "messages").getString(key);

                result = message==null ? "" : toUTF8 ? new String(message.getBytes("iso8859-1"), "utf-8") : message;
            }catch(Throwable t){}
            return result;
        }

J'étais particulièrement inquiet car cela pourrait ralentir les performances de mon application ... Cependant, après l'avoir implémenté, il semble que mon application soit plus rapide maintenant. Je pense que c'est parce que je suis en train d'accéder directement aux propriétés au lieu de laisser JSF se fraye un chemin dans l'accès aux propriétés ... Je passe spécifiquement l'argument booléen dans cet appel car je sais que certaines propriétés ne seraient pas traduites et n'ont pas besoin d'être au format utf8 ...

Maintenant, j'ai sauvegardé mon fichier de propriétés au format UTF8 et tout fonctionne correctement car chaque utilisateur de mon application a une préférence de lieu de référence par défaut.

2
Masoud
Properties prop = new Properties();
String fileName = "./src/test/resources/predefined.properties";
FileInputStream inputStream = new FileInputStream(fileName);
InputStreamReader reader = new InputStreamReader(inputStream,"UTF-8");

Mon problème, c’est que les fichiers eux-mêmes étaient dans le mauvais encodage. Utiliser iconv a fonctionné pour moi

iconv -f ISO-8859-15 -t UTF-8  messages_nl.properties > messages_nl.properties.new
1
Zack Bartel

Ouvrez la boîte de dialogue Paramètres/Préférences (Ctrl + Alt + S), puis cliquez sur Encodages éditeur et fichier.

Screenshot of window shown

Ensuite, en bas, vous utiliserez les encodages par défaut pour les fichiers de propriétés. Choisissez votre type d'encodage.

Vous pouvez également utiliser des symboles Unicode au lieu de texte dans votre groupe de ressources (par exemple, "ів" est égal à \u0456\u0432).

0

J'ai essayé d'utiliser l'approche fournie par Rod, mais en prenant en considération le souci de BalusC de ne pas répéter le même travail dans toute l'application, je suis venu avec cette classe:

import Java.io.UnsupportedEncodingException;
import Java.util.Locale;
import Java.util.ResourceBundle;

public class MyResourceBundle {

    // feature variables
    private ResourceBundle bundle;
    private String fileEncoding;

    public MyResourceBundle(Locale locale, String fileEncoding){
        this.bundle = ResourceBundle.getBundle("com.app.Bundle", locale);
        this.fileEncoding = fileEncoding;
    }

    public MyResourceBundle(Locale locale){
        this(locale, "UTF-8");
    }

    public String getString(String key){
        String value = bundle.getString(key); 
        try {
            return new String(value.getBytes("ISO-8859-1"), fileEncoding);
        } catch (UnsupportedEncodingException e) {
            return value;
        }
    }
}

La façon de l'utiliser serait très similaire à l'utilisation habituelle de ResourceBundle:

private MyResourceBundle labels = new MyResourceBundle("es", "UTF-8");
String label = labels.getString(key)

Ou vous pouvez utiliser le constructeur alternatif qui utilise UTF-8 par défaut:

private MyResourceBundle labels = new MyResourceBundle("es");
0
carlossierra