it-swarm.dev

Como usar o UTF-8 nas propriedades do recurso com ResourceBundle

Eu preciso usar o UTF-8 em minhas propriedades de recurso usando o ResourceBundle do Java. Quando eu insiro o texto diretamente no arquivo de propriedades, ele é exibido como mojibake.

Meu aplicativo é executado no Google App Engine.

Alguém pode me dar um exemplo? Eu não posso conseguir este trabalho.

238
nacho

O ResourceBundle#getBundle() usa sob as cobertas PropertyResourceBundleNAME _ quando um arquivo .properties é especificado. Por sua vez, isso usa por padrão Properties#load(InputStream) para carregar esses arquivos de propriedades. Conforme o o javadoc , eles são, por padrão, lidos como ISO-8859-1.

public void load(InputStream inStream) throws IOException

Lê uma lista de propriedades (pares de chaves e elementos) do fluxo de bytes de entrada. O fluxo de entrada está em um formato simples orientado por linha, conforme especificado em load (Reader) e é assumido que usa a codificação de caracteres ISO 8859-1 ; isto é, cada byte é um caractere Latin1. Os caracteres que não estão no Latin1 e determinados caracteres especiais são representados em chaves e elementos usando escapes Unicode, conforme definido na seção 3.3 de The Java ™ Language Specification.

Então, você precisa salvá-los como ISO-8859-1. Se você tiver qualquer caractere além do intervalo ISO-8859-1 e não puder usar \uXXXX off top of head e for forçado a salvar o arquivo como UTF-8, será necessário usar o native2ascii ferramenta para converter um arquivo de propriedades salvo UTF-8 em um arquivo de propriedades salvo ISO-8859-1, no qual todos os caracteres descobertos são convertidos no formato \uXXXX. O exemplo a seguir converte um arquivo de propriedades codificado em UTF-8 text_utf8.properties em um arquivo de propriedades codificado ISO-8859-1 válido text.properties.

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

Ao usar um sane IDE como o Eclipse, isso já é feito automaticamente quando você cria um arquivo .properties em um projeto baseado em Java e usa o próprio editor do Eclipse. O Eclipse converterá de forma transparente os caracteres além do intervalo ISO-8859-1 para o formato \uXXXX. Veja também as capturas de tela abaixo (observe as guias "Propriedades" e "Origem" na parte inferior, clique para grandes):

"Properties" tab"Source" tab

Alternativamente, você também pode criar uma implementação customizada ResourceBundle.Control onde você lê explicitamente os arquivos de propriedades como UTF-8 usando InputStreamReaderNAME _ , para que você possa salvá-los como UTF-8 sem a necessidade de lidar com native2ascii. Aqui está um exemplo de 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;
    }
}

Isso pode ser usado da seguinte maneira:

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

Veja também:

352
BalusC

Dado que você tem uma instância de ResourceBundle e você pode obter String por:

String val = bundle.getString(key); 

Eu resolvi meu problema de exibição em japonês por:

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

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

as propriedades aceitam um objeto Reader como argumentos, que você pode criar a partir de um InputStream.

no momento da criação, você pode especificar a codificação do Reader:

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

em seguida, aplique este Reader ao método load:

prop.load(isr);

BTW: obtenha o fluxo de . Propriedades arquivo:

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

BTW: get pacote de recursos de InputStreamReader:

ResourceBundle rb = new PropertyResourceBundle(isr);

espero que isso possa ajudá-lo!

45
Chinaxing

ResourceBundle.Control com UTF-8 e novos métodos String não funcionam, se o arquivo de propriedades usar o conjunto de caracteres cp1251, por exemplo.

Então eu recomendo usar um método comum: escrever em símbolos unicode . Por esta:

IDEA - tem um especial " Conversão nativa transparente para ASCII " opção (Configurações> Codificação de Arquivo).

O Eclipse - possui um plugin " Editor de Propriedades " . Pode funcionar como aplicativo separado.

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

Criamos um arquivo resources.utf8 que contém os recursos em UTF-8 e temos uma regra para executar o seguinte:

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

Este problema foi finalmente corrigido no Java 9: ​​ https://docs.Oracle.com/javase/9/intl/internationalization-enhancements-jdk-9

A codificação padrão para arquivos de propriedades é agora UTF-8.

A maioria dos arquivos de propriedades existentes não deve ser afetada: UTF-8 e ISO-8859-1 têm a mesma codificação para caracteres ASCII, e a codificação ISO-8859-1 não-ASCII legível não é válida UTF- 8 Se uma sequência de bytes UTF-8 inválida for detectada, o tempo de execução Java relê automaticamente o arquivo em ISO-8859-1.

15
stenix

Atenção: Os arquivos de propriedade Java devem ser codificados em ISO 8859-1!

Codificação de caracteres ISO 8859-1. Caracteres que não podem ser representados diretamente nesta codificação podem ser gravados usando escapes Unicode; somente um único caractere 'u' é permitido em uma seqüência de escape.

@see Propriedades Java Doc

Se você ainda quer realmente fazer isso: dê uma olhada em: Propriedades Java codificação UTF-8 no Eclipse - existem algumas amostras de código

8
Ralph

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

como os arquivos de propriedade já mencionados devem ser codificados em ISO 8859-1

Você pode usar o plug-in acima para o Eclipse IDE para fazer a conversão Unicode para você.

5
fmucar

Aqui está uma solução Java 7 que usa a excelente biblioteca de suporte do Guava e a construção try-with-resources. Ele lê e grava arquivos de propriedades usando UTF-8 para a experiência geral mais simples.

Para ler um arquivo de propriedades como 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
  }
}

Para gravar um arquivo de propriedades como 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

Como um sugerido, eu passei pela implementação do pacote de recursos .. mas isso não ajudou .. como o pacote sempre foi chamado em en_US locale ... eu tentei definir o meu local padrão para um idioma diferente e ainda a minha implementação do pacote de recursos controle estava sendo chamado com en_US ... eu tentei colocar mensagens de log e fazer um passo através de depuração e ver se uma chamada local diferente estava sendo feita depois de eu mudar locale em tempo de execução através de chamadas xhtml e JSF ... que não aconteceu ... então eu tentei fazer um sistema definir o padrão para um utf8 para ler arquivos pelo meu servidor (servidor Tomcat) .. mas isso causou pronome como todas as minhas bibliotecas de classes não foram compiladas sob utf8 e Tomcat começou a ler então no formato utf8 e servidor não estava funcionando corretamente ... então eu acabei com a implementação de um método no meu controlador Java para ser chamado de arquivos xhtml .. nesse método eu fiz o seguinte:

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

Eu estava particularmente nervoso, pois isso poderia atrasar o desempenho do meu aplicativo ... no entanto, após implementá-lo, parece que meu aplicativo está mais rápido agora. Acho que é porque, agora estou acessando diretamente as propriedades, em vez de deixar O JSF analisa seu caminho para acessar propriedades ... Eu especificamente passo o argumento booleano nesta chamada porque eu sei que algumas das propriedades não seriam traduzidas e não precisam estar no formato utf8 ...

Agora salvei meu arquivo de propriedades no formato UTF8 e ele está funcionando bem, pois cada usuário do meu aplicativo tem uma preferência de código de idioma de referência.

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");

Pois o que valeu a pena foi que os próprios arquivos estavam na codificação errada. Usando iconv trabalhou para mim

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

Abra o diálogo Configurações/Preferências (Ctrl + Alt + S), depois clique em Editor e Codificações de arquivo.

Screenshot of window shown

Em seguida, na parte inferior, você terá codificações padrão para os arquivos de propriedades. Escolha o seu tipo de codificação.

Como alternativa, você pode usar símbolos unicode em vez de texto em seu pacote de recursos (por exemplo, "ів" equals \u0456\u0432)

0
Юра Чорнота

Eu tentei usar a abordagem fornecida por Rod, mas levando em consideração a preocupação da BalusC em não repetir a mesma solução em toda a aplicação e veio com esta 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;
        }
    }
}

A maneira de usar isso seria muito semelhante ao uso regular do ResourceBundle:

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

Ou você pode usar o construtor alternativo que usa o UTF-8 por padrão:

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