Come utilizzare UTF-8 nelle proprietà delle risorse con ResourceBundle

Ho bisogno di usare UTF-8 nelle mie proprietà delle risorse usando il ResourceBundle di Java. Quando inserisco il testo direttamente nel file delle proprietà, viene visualizzato come mojibake.

La mia app funziona su Google App Engine.

Qualcuno può darmi un esempio? Non riesco a ottenere questo lavoro.

Il ResourceBundle#getBundle() utilizza sotto le copertine PropertyResourceBundle quando viene specificato un file .properties . Questo a sua volta utilizza per impostazione predefinita Properties#load(InputStream) per caricare quei file di proprietà. Come per la javadoc , sono normalmente letti come ISO-8859-1.

public void load(InputStream inStream) throws IOException

Legge un elenco di proprietà (coppie chiave ed elemento) dal stream di byte di input. Il stream di input è in un semplice formato orientato alla linea come specificato nel caricamento (Reader) e si presume che utilizzi la codifica dei caratteri ISO 8859-1 ; questo è ogni byte è un carattere Latin1. I caratteri non in Latin1 e determinati caratteri speciali sono rappresentati in chiavi ed elementi utilizzando le sequenze di escape Unicode definite nella sezione 3.3 della specifica del linguaggio Java ™.

Quindi, avresti bisogno di salvarli come ISO-8859-1. Se hai caratteri oltre la gamma ISO-8859-1 e non puoi usare \uXXXX in cima alla testa e sei quindi obbligato a salvare il file come UTF-8, allora dovresti usare lo strumento native2ascii per convertire un file di proprietà salvato UTF-8 in un file di proprietà salvato ISO-8859-1 in cui tutti i caratteri scoperti vengono convertiti in formato \uXXXX . L’esempio seguente converte un file di proprietà con codifica UTF-8 text_utf8.properties in un file di proprietà codificato ISO-8859-1 valido text.properties .

  native2ascii -encoding UTF-8 text_utf8.properties text.properties 

Quando si utilizza un IDE sano come Eclipse, questo viene già fatto automaticamente quando si crea un file .properties in un progetto basato su Java e si utilizza l’editor di Eclipse. Eclipse convertirà in modo trasparente i caratteri oltre l’intervallo ISO-8859-1 nel formato \uXXXX . Vedi anche sotto le schermate (nota le tabs “Proprietà” e “Origine” in basso, fai clic per ingrandire):

Scheda Scheda

In alternativa, è ansible anche creare un’implementazione personalizzata ResourceBundle.Control cui si legge esplicitamente i file delle proprietà come UTF-8 utilizzando InputStreamReader , in modo che sia ansible salvarli come UTF-8 senza la necessità di native2ascii con native2ascii . Ecco un esempio di kickoff:

 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; } } 

Questo può essere usato come segue:

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

Guarda anche:

  • Unicode – Come ottenere i caratteri giusto?

Dato che hai un’istanza di ResourceBundle e puoi ottenere String per:

 String val = bundle.getString(key); 

Ho risolto il mio problema con il display giapponese:

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

guarda questo: http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader)

le proprietà accettano un object Reader come argomenti, che è ansible creare da un InputStream.

al momento della creazione, è ansible specificare la codifica del Reader:

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

quindi applica questo Reader al metodo di caricamento:

 prop.load(isr); 

BTW: scarica lo stream dal file .properties :

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

Spero che questo possa aiutarti !

Creiamo un file resources.utf8 che contiene le risorse in UTF-8 e una regola per eseguire quanto segue:

 native2ascii -encoding utf8 resources.utf8 resources.properties 
 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  */ 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); } } } } 

ResourceBundle.Control con UTF-8 e nuovi metodi String non funzionano, ad esempio se il file delle proprietà utilizza il set di caratteri cp1251.

Quindi ho consigliato l’uso di un metodo comune: scrivere in simboli unicode . Per questo:

IDEA – ha una speciale opzione ” Conversione nativa-ASCII trasparente “ (Impostazioni> Codifica file).

Eclipse – ha un plugin ” Proprietà Editor “ . Può funzionare come applicazione separata.

Attenzione: i file di proprietà java devono essere codificati in ISO 8859-1!

Codifica dei caratteri ISO 8859-1. I caratteri che non possono essere rappresentati direttamente in questa codifica possono essere scritti utilizzando gli escape Unicode; solo un singolo carattere ‘u’ è permesso in una sequenza di escape.

@see Proprietà Java Doc

Se vuoi davvero farlo: dai un’occhiata a: Proprietà Java Codifica UTF-8 in Eclipse – ci sono alcuni esempi di codice

Questo problema è stato finalmente risolto in Java 9: https://docs.oracle.com/javase/9/intl/internationalization-enhancements-jdk-9

La codifica predefinita per i file delle proprietà è ora UTF-8.

La maggior parte dei file di proprietà esistenti non dovrebbe essere interessata: UTF-8 e ISO-8859-1 hanno la stessa codifica per i caratteri ASCII e la codifica ISO-8859-1 non ASCII leggibile dall’uomo non è UTF-8 valida. Se viene rilevata una sequenza byte UTF-8 non valida, il runtime Java rilegge automaticamente il file in ISO-8859-1.

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

come già dichiarato i file di proprietà dovrebbero essere codificati in ISO 8859-1

Puoi utilizzare il plug-in precedente per eclipse IDE per rendere la conversione Unicode per te.

Ecco una soluzione Java 7 che utilizza l’eccellente libreria di supporto di Guava e il costrutto try-with-resources. Legge e scrive i file delle proprietà usando UTF-8 per la più semplice esperienza complessiva.

Per leggere un file di proprietà come 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 } } 

Per scrivere un file di proprietà come 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 } 

Come suggerito, sono passato all’attuazione del bundle di risorse .. ma questo non ha aiutato .. dato che il bundle è sempre stato chiamato in locale locale en_US … ho provato a impostare le mie impostazioni internazionali predefinite in una lingua diversa e ancora la mia implementazione del pacchetto di risorse il controllo veniva chiamato con en_US … Ho provato a mettere i messaggi di log e fare un passo attraverso il debug e vedere se veniva effettuata una chiamata locale diversa dopo aver cambiato le impostazioni locali in fase di esecuzione attraverso chiamate xhtml e JSF … che non erano accadute … poi ho provato a fare un default di sistema a un utf8 per leggere i file dal mio server (server tomcat) .. ma questo ha causato pronlem come tutte le mie librerie di classi non sono state compilate sotto utf8 e tomcat ha iniziato a leggere in formato utf8 e il server non funzionava correttamente … poi ho finito con l’implementazione di un metodo nel mio controller java per essere chiamato da file xhtml .. in quel metodo ho fatto quanto segue:

  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; } 

Ero particolarmente nervoso perché questo potrebbe rallentare le prestazioni della mia applicazione … tuttavia, dopo averlo implementato, sembra che la mia applicazione sia più veloce ora … penso che sia perché, ora sto direttamente accedendo alle proprietà invece di lasciarle JSF analizza la sua strada per accedere alle proprietà … in particolare, passo l’argomento booleano in questa chiamata perché so che alcune proprietà non verrebbero tradotte e non avrebbero bisogno di essere nel formato utf8 …

Ora ho salvato il mio file delle proprietà in formato UTF8 e sta funzionando bene poiché ogni utente nella mia applicazione ha una preferenza di locale di riferimento.

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

Per quello che vale il mio problema è stato che i file stessi erano nella codifica sbagliata. Usando iconv ha funzionato per me

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

Ho provato a utilizzare l’approccio fornito da Rod, ma prendendo in considerazione la preoccupazione di BalusC di non ripetere lo stesso work-around in tutte le applicazioni ed è arrivato con questa class:

 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; } } } 

Il modo per utilizzare questo sarebbe molto simile al normale utilizzo di ResourceBundle:

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

Oppure puoi utilizzare il costruttore alternativo che usa UTF-8 per impostazione predefinita:

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

Apri la finestra di dialogo Impostazioni / Preferenze ( Ctrl + Alt + S ), quindi fai clic su Editor e File Encodings.

Screenshot della finestra mostrata

Quindi, in basso, verranno codificate le codifiche predefinite per i file delle proprietà. Scegli il tuo tipo di codifica.

In alternativa puoi utilizzare i simboli unicode invece del testo nel tuo gruppo di risorse (ad esempio "ів" equivale a \u0456\u0432 )