Как использовать UTF-8 в свойствах ресурсов с помощью ResourceBundle

Мне нужно использовать UTF-8 в свойствах ресурса с помощью Java ResourceBundle. Когда я ввожу текст непосредственно в файл свойств, он отображается как mojibake.

Мое приложение работает в Google App Engine.

Может ли кто-нибудь дать мне пример? Я не могу получить эту работу.

Ответ 1

ResourceBundle#getBundle() использует под обложками PropertyResourceBundle когда указан файл .properties. Это, в свою очередь, использует по умолчанию Properties#load(InputStream) для загрузки этих файлов свойств. Согласно javadoc, они по умолчанию читаются как ISO-8859-1.

public void load(InputStream inStream) throws IOException

Считывает список свойств (пары ключей и элементов) из потока входных байтов. Входной поток находится в простом линейно-ориентированном формате, как указано в load (Reader) , и предполагается использовать кодировку символов ISO 8859-1; то есть каждый байт является одним латинским символом. Символы не в Latin1 и некоторые специальные символы представлены в ключах и элементах, используя escape-последовательности Unicode, как определено в разделе 3.3 Спецификации языка Java ™.

Итак, вам нужно сохранить их как ISO-8859-1. Если у вас есть символы за пределами диапазона ISO-8859-1, и вы не можете использовать \uXXXX с верхней части головы, и поэтому вы должны сохранить файл как UTF-8, тогда вам нужно будет использовать native2ascii, чтобы преобразовать файл сохраненных свойств UTF-8 в файл сохраненных свойств ISO-8859-1, в котором все непокрытые символы преобразуются в \uXXXX формат. В приведенном ниже примере преобразуется файл свойств кодированного UTF-8 text_utf8.properties в действительный файл свойств кодированного ISO-8859-1 text.properties.

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

При использовании надежной среды IDE, такой как Eclipse, это уже выполняется автоматически при создании файла .properties в Java-проекте и использовании собственного редактора Eclipse. Eclipse будет прозрачно преобразовывать символы за пределы ISO-8859-1 в формат \uXXXX. См. Также ниже скриншоты (обратите внимание на вкладки "Свойства" и "Источник" внизу, нажмите для увеличения):

"Properties" tab "Source" tab

В качестве альтернативы вы также можете создать пользовательскую ResourceBundle.Control реализацию, в которой вы явно читаете файлы свойств как UTF-8, используя InputStreamReader, так что вы можете просто сохранить их как UTF-8 без необходимости хлопоты с помощью native2ascii. Вот пример запуска:

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

Это можно использовать следующим образом:

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

См. также:

Ответ 2

Учитывая, что у вас есть экземпляр ResourceBundle, вы можете получить String:

String val = bundle.getString(key); 

Я решил проблему с японским дисплеем:

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

Ответ 3

посмотрите на это: http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#load(java.io.Reader)

свойства принимают объект Reader в качестве аргументов, которые вы можете создать из InputStream.

в момент создания, вы можете указать кодировку Reader:

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

затем примените этот Reader к методу загрузки:

prop.load(isr);

BTW: получить поток из файла .properties:

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

надеюсь, что это может вам помочь!

Ответ 4

Мы создаем файл resources.utf8, который содержит ресурсы в UTF-8 и имеет правило для запуска следующего:

native2ascii -encoding utf8 resources.utf8 resources.properties

Ответ 5

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

Ответ 6

ResourceBundle.Control с UTF-8 и новые методы String не работают, например, если файл свойств использует charset cp1251.

Поэтому я рекомендую использовать общий метод: писать в символах unicode. Для этого:

IDEA - имеет специальный параметр Transparent native-to-ASCII conversion" (Настройки > Файл Кодирование).

Eclipse - есть плагин Редактор свойств". Он может работать как отдельное приложение.

Ответ 7

Внимание: файлы свойств java должны быть закодированы в ISO 8859-1!

кодировка символов ISO 8859-1. Персонажи, которые не могут быть напрямую представленный в этой кодировке, может быть с использованием Unicode-экранов; только один символ "u" разрешен escape-последовательность.

@see Свойства Java Doc

Если вы все еще действительно хотите это сделать, посмотрите: Свойства Java UTF-8 в Eclipse - есть примеры кода

Ответ 8

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

поскольку уже указанные файлы свойств должны быть закодированы в ISO 8859-1

Вы можете использовать приведенный выше плагин для Eclipse IDE, чтобы преобразовать Юникод для вас.

Ответ 9

Здесь решение Java 7, которое использует превосходную библиотеку поддержки Guava и конструкцию try-with-resources. Он читает и записывает файлы свойств с использованием UTF-8 для простейшего общего опыта.

Чтобы прочитать файл свойств как 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
  }
}

Чтобы записать файл свойств как 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
}

Ответ 10

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

Ответ 11

Эта проблема, наконец, была исправлена ​​в Java 9: https://docs.oracle.com/javase/9/intl/internationalization-enhancements-jdk-9

Кодировка по умолчанию для файлов свойств теперь UTF-8.

Большинство существующих файлов свойств не должны быть затронуты: UTF-8 и ISO-8859-1 имеют одинаковую кодировку для символов ASCII и кодируемая человеком кодировка не-ASCII ISO-8859-1 недействительна UTF-8. Если обнаружена некорректная последовательность байтов UTF-8, среда выполнения Java автоматически перечитывает файл в ISO-8859-1.

Ответ 12

Для чего стоит моя проблема в том, что сами файлы были в неправильной кодировке. Использование iconv сработало для меня

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

Ответ 13

Как я уже сказал, я рассмотрел реализацию пакета ресурсов.. но это не помогло... поскольку пакет всегда вызывался под en_US locale... Я попытался установить языковой стандарт по умолчанию на другой язык, и все же моя реализация управления связью ресурсов вызывается с помощью en_US... я попытался поместить сообщения журнала и сделать шаг отладки и посмотреть, был ли произведен другой локальный вызов после того, как я изменил локаль во время выполнения через вызовы xhtml и JSF... что did not happend... тогда я попытался сделать системный набор по умолчанию для utf8 для чтения файлов на моем сервере (tomcat server).. но это вызвало пролема, поскольку все мои библиотеки классов не были скомпилированы под utf8, а tomcat начал читать тогда в формате utf8 и сервере не работает должным образом... тогда я закончил реализацию метода в моем java-контроллере, который вызывается из xhtml файлов.. в этом методе я сделал следующее:

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

Я особенно нервничал, так как это могло замедлить работу моего приложения... однако, после реализации этого, похоже, что мое приложение работает быстрее. Я думаю, что это потому, что теперь я прямо обращаюсь к свойствам вместо того, чтобы позволить JSF разобраться в доступе к свойствам... я специально передаю логический аргумент в этом вызове, потому что я знаю, что некоторые из свойств не будут переведены и не должны быть в формате utf8...

Теперь я сохранил файл свойств в формате UTF8, и он отлично работает, поскольку каждый пользователь в моем приложении имеет предпочтение языковой референции.

Ответ 14

Я попытался использовать подход, предоставленный Родом, но с учетом заботы BalusC о том, чтобы не повторять одну и ту же работу во всем приложении и не приходил с этим классом:

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

Способ использования этого будет очень похож на обычное использование ResourceBundle:

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

Или вы можете использовать альтернативный конструктор, который по умолчанию использует UTF-8:

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