Чтение юникода из messageSource создает проблемы с Java 5 - PullRequest
9 голосов
/ 17 марта 2011

Я сделал веб-приложение Spring (2.5.6) с поддержкой i18n с файлами свойств (например: messages_en_US.properties, messages_de_DE.properties).

Это .properties файлы с уни-кодами.например:

busy = Besch\u00E4ftigt

При чтении busy ключевое слово из messageSource дает такой результат:

...
private static ReloadableResourceBundleMessageSource messageSource;

    /**
     * Gets a message from the resources (.properties) defined in the applicationContext.xml
     *
     * @param input string to hook up
     * @return the the message hooked up from the resources
     */
    public static String getMessage(String input){
        System.out.println(input); //busy
        System.out.println(messageSource.getDefaultEncoding()); //UTF-8
        System.out.println(messageSource.getMessage(input, null, null)); //Beschu00E4ftigt
        return messageSource.getMessage(input, null, null);
    }
...

, поэтому без \

Файлына сервере также находятся UTF-8:

enter image description here

Среды, в которых возникла проблема:

  • Tomcat 5.5.28 (Run jsp-api.jar иservlet-api.jar из common/lib)
  • JDK 1.5.0_22
  • JSTL 1.1.2 (чтение из приложения lib)

  • Tomcat 6.0.32 (Запуск jsp-api.jar и servlet-api.jar из lib)

  • JDK 1.5.0_22
  • JSTL 1.1.2 (чтение из приложения lib)

Среды, в которых проблема решена (точно такой же дистрибутив): - Tomcat 6.0.32 (Запуск jsp-api.jar и servlet-api.jar из lib) - JDK 1.6.0_13 - JSTL 1.1.2 (читать из приложения lib)

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.И не говорите, что мне нужно обновить мой JDK, потому что это невозможно.

Обновление связующего источника сообщений в applicationContext.xml

<b:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <b:property name="defaultEncoding" value="UTF-8"/>
    <b:property name="fallbackToSystemLocale" value="false" />
    <b:property name="basenames">
        <b:list>
            <b:value>classpath:messages</b:value>
            <b:value>/public/custom/i18n/portalmessages</b:value>
        </b:list>
    </b:property>    
    <b:property name="cacheSeconds" value="1"/>
</b:bean>

Обновление2. Поместите файл свойств ресурса в путь к классам и с помощью загрузчика классов:

URLClassLoader cl = (URLClassLoader) IOUtils.class.getClassLoader();
InputStream resourceAsStream = cl.getResourceAsStream("messages_de_DE.properties");
Properties prop = new Properties();
prop.load(resourceAsStream);
System.out.println("From classpath --> " + prop.get("busy")); //Beschäftigt
System.out.println("From i18n folder --> " + I18nFunctions.getMessage("busy")); //Beschu00E4ftigt

Ответы [ 4 ]

10 голосов
/ 27 мая 2011

Я посмотрел на исходный код DefaultPropertiesPersister (он используется ReloadableResourceBundleMessageSource внутри).

Если указано defaultEncoding, свойства загружаются вручную построчно из Reader вместо использования обычного Properties.load() метода.

Перед добавлением пары ключ / значение к объекту Properties на String s

вызывается метод unescape().
protected String unescape(String str) {
    StringBuffer outBuffer = new StringBuffer(str.length());
    for (int index = 0; index < str.length();) {
        char c = str.charAt(index++);
        if (c == '\\') {
            c = str.charAt(index++);
            if (c == 't') {
                c = '\t';
            }
            else if (c == 'r') {
                c = '\r';
            }
            else if (c == 'n') {
                c = '\n';
            }
            else if (c == 'f') {
                c = '\f';
            }
        }
        outBuffer.append(c);
    }
    return outBuffer.toString();
}

Здесь удаляется символ \.

Если вы создаете подкласс DefaultPropertiesPersister следующим образом

package com.something;

import org.apache.commons.lang.StringEscapeUtils;
import org.springframework.util.DefaultPropertiesPersister;

public class MyPropertiesPersister extends DefaultPropertiesPersister {
    protected String unescape(String str)
    {
        return StringEscapeUtils.unescapeJava(str);
    }    
}

Установите его в вашем весеннем конфиге так:

<b:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <b:property name="defaultEncoding" value="UTF-8"/>
    <b:property name="fallbackToSystemLocale" value="false" />
    <b:property name="basenames">
        <b:list>
            <b:value>classpath:messages</b:value>
            <b:value>/public/custom/i18n/portalmessages</b:value>
        </b:list>
    </b:property>    
    <b:property name="cacheSeconds" value="1"/>
    <b:property name="propertiesPersister">
        <b:bean class="com.something.MyPropertiesPersister"/>
    </b:property>
</b:bean>

Это сработает .. может потребоваться дополнительная jiggery-pokery, чтобы получить именно то, что вы хотите в отношении других кодировок и т. Д.

3 голосов
/ 17 марта 2011
request.setCharacterEncoding("UTF-8");

Когда вызывается до любого getParameter() вызова, это только указывает API сервлета, какую кодировку использовать для анализа параметров POST (не GET!) request body.

Вам все еще нужно изменить кодировку response , чтобы использовать UTF-8, чтобы API сервлета знал, какую кодировку он должен использовать для передачи символов в байтахна другой конец HTTP-соединения.Вам также все равно придется указывать веб-браузеру по заголовкам HTTP-ответа, в какой кодировке переданы байты, чтобы веб-браузер мог правильно их декодировать в символы.

В JSP обе эти задачи могут быть выполнены с помощью этой простой строкив верхней части файла.Это необходимо применить к всем JSP, а также к включаемым файлам / фрагментам.

<%@ page pageEncoding="UTF-8" %>

В противном случае для отправки будет использоваться кодировка по умолчанию для платформы сервера и кодировка по умолчанию для платформы клиента для чтения.(хотя некоторые умные веб-браузеры, такие как Firefox, могут автоматически определять кодировку, если она не была указана в заголовке ответа HTTP).

См. также:


Обновление : вы уверены, что экранированные символы Юникода сами по себе не экранируются в файлах свойств на компьютере с Linux?То есть, вы видите \u00E и, как и везде, и, следовательно, не \\u00E?Это объяснило бы проблему.

2 голосов
/ 26 мая 2011

Цитирование из javadoc для java.util.Properties,

Методы load (InputStream) / store (OutputStream, String) работают так же, как пара load (Reader) / store (Writer, String), за исключением того, что поток ввода / вывода кодируется в кодировке символов ISO 8859-1 , Символы, которые не могут быть непосредственно представлены в этой кодировке, могут быть написаны с использованием экранирования Unicode; в escape-последовательности допускается только один символ 'u'. Инструмент native2ascii можно использовать для преобразования файлов свойств в другие кодировки и из них.

Возможно, у вас есть какая-то фаза сборки, которая преобразует ваш файл в кодировке UTF-8 в ascii. Попробуйте изменить кодировку файлов свойств на 8859-1. Похоже, ваш файл свойств уже экранирует символы Юникода соответствующим образом.

Также используйте getClassLoader().getResourceAsStream(...), чтобы самостоятельно получить поток в файл свойств и загрузить в файл свойств. Посмотрите, являются ли значения желаемыми строками. Это уменьшит половину проблемы кодирования + упаковки по сравнению с проблемой пружины.

Обновление на основе цепочки комментариев:

Java 1.5 java.util.Properties не не имеет load(Reader) API. Ясно, что это была область улучшения в Java 1.6.

2 голосов
/ 17 марта 2011

Необходимо убедиться, что вы проверяете языковой стандарт как пользователь, выполняющий сервер, или, если быть более точным, вам необходимо проверять языковой стандарт среды, в которой запускается сервер. В целях отладки вы можете отредактировать Запустите сценарии, чтобы записать вывод «locale» в некоторый файл.

...