Уважаемые, почему при явном указании кодировки JSP-страниц UTF-8 в файлай ресурсов строки на разных языках приходится писать как escape-последовательности? Почему файл ресурсов нельзя просто написать в кодировке UTF-8? Так и должно быть, или я чего-то не понимаю?
В MessageResources_ru.properties приходится писать так:
...
welcome.heading=\u0412\u044d\u043b\u043a\u0430\u043c!
...
Неудобно. Приходится файлы ресурсов на разных языках держать в двух экземплярах — в родной для языка кодировке и в ecs-последовательностях.
Если просто написать файлы ресурсов в UTF-8, на страничке сообщения будут крякозябами.
Если contentType явно вообще не указывать, а исходники лежат, например, в Windows-1251, то файл ресурсов можно написать в этой же кодировке, всё будет работать. Но не всякий браузер тогда поймёт, что страничка в Windows-1251, приходится выбирать кодировку вручную (IE понимает, а Firefox — нет).
Вобщем вопрос: есть ли возможность явно указывать кодировку странички как UTF-8 и файлы ресурсов писать в этой же кодировке? Если "да", то что для этого нужно сделать?
Можно антом — вообще прелесть.
Y>Неудобно. Приходится файлы ресурсов на разных языках держать в двух экземплярах — в родной для языка кодировке и в ecs-последовательностях.
Зато переносимо. И никаких проблем с символами завершения строк.
Y>Если просто написать файлы ресурсов в UTF-8, на страничке сообщения будут крякозябами.
Грабли в Properties#load(InputStream). Энтот класс ожидает входной файл в ISO 8859-1, поскольку невозможно (негде) указать кодировку входного файла пропертей.
LCR>Ручками? Это ужасно
Согласен, использую native2ascii . Про ant не знал, не пользуюсь. А в чём прелесть? При сборке сам перекодирует properties в esc?
Но, вернёмся к барашкам: LCR>Грабли в Properties#load(InputStream). Энтот класс ожидает входной файл в ISO 8859-1, поскольку невозможно (негде) указать кодировку входного файла пропертей.
Вынужден повториться:
Если contentType явно вообще не указывать, а исходники лежат, например, в Windows-1251, то файл ресурсов можно написать в этой же кодировке, всё будет работать.
Очевидно, что struts умеет восстанавливать кодировку properties-файла (пишешь файл в Windows-1251, страничка правильно отображается в Windows-1251, не смотря на особенность Properties.load()). Но если явно указать contentType на страничке, то уже не работает, кодировка восстанавливается не правильно.
Вопросы те же: можно ли явно указать кодировку UTF-8 в contentType и держать файлы ресурсов в UTF-8? Если можно, то что для этого нужно сделать?
Yarrow,
LCR>>Ручками? Это ужасно Y>Согласен, использую native2ascii . Про ant не знал, не пользуюсь. А в чём прелесть? При сборке сам перекодирует properties в esc?
Да просто есть соответствующий таск.
Y>Вынужден повториться: Y>Если contentType явно вообще не указывать, а исходники лежат, например, в Windows-1251, то файл ресурсов можно написать в этой же кодировке, всё будет работать.
Будет работать на вашей машине. На машине с другой локалью —
Y>Очевидно, что struts умеет восстанавливать кодировку properties-файла (пишешь файл в Windows-1251, страничка правильно отображается в Windows-1251, не смотря на особенность Properties.load()). Но если явно указать contentType на страничке, то уже не работает, кодировка восстанавливается не правильно.
Это не struts умеет восстанавливать кодировку в properties файле, а поток байтов просасывается через struts в неизменном виде. То есть из properties загружается во внутренний объект Properties, а потом через библиотеку тэгов выводится в HTML (<html:text ... >). А там уже работает автораспознавание кодировки в браузере.
Y>Вопросы те же: можно ли явно указать кодировку UTF-8 в contentType и держать файлы ресурсов в UTF-8? Если можно, то что для этого нужно сделать?
Lazy Cjow Rhrr,
Y>>Вопросы те же: можно ли явно указать кодировку UTF-8 в contentType и держать файлы ресурсов в UTF-8? Если можно, то что для этого нужно сделать?
LCR>есть маленькая идейка...
К сожалению, индейка не прошла Хотел попробовать фильтр прикрутить.
К слову сказать, мне тоже захотелось знать железный способ хранения ресурсов в UTF-8 (железный, то есть не зависящий от локалей и осей).
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>К слову сказать, мне тоже захотелось знать железный способ хранения ресурсов в UTF-8 (железный, то есть не зависящий от локалей и осей).
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>Lazy Cjow Rhrr,
Y>>>Вопросы те же: можно ли явно указать кодировку UTF-8 в contentType и держать файлы ресурсов в UTF-8? Если можно, то что для этого нужно сделать? LCR>>есть маленькая идейка... LCR>К сожалению, индейка не прошла Хотел попробовать фильтр прикрутить. LCR>К слову сказать, мне тоже захотелось знать железный способ хранения ресурсов в UTF-8 (железный, то есть не зависящий от локалей и осей).
Здравствуйте, Lucker, Вы писали:
L>Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>>К слову сказать, мне тоже захотелось знать железный способ хранения ресурсов в UTF-8 (железный, то есть не зависящий от локалей и осей).
L>xml
Struts и интернацонализация будут работать с пропертями в xml формате?
Здравствуйте, Yarrow, Вы писали:
SK>>XML или java файл. Y>А можно подробнее? Struts сам сможет считывать ресурсы из XML?? И что вы имеете ввиду, говоря о java-файле?
С XML, мне кажется, что я погорячился, но все с умным видом промолчали
А с java файлами все просто — пишешь класс, наследуешь от ListResourceBundle, дальше по доке. В файл пишелся все в utf8 и компилятору указывается, что исходники в utf8 и все.
Re: contentType и i18n сообщений Struts
От:
Аноним
Дата:
09.01.06 12:14
Оценка:
Здравствуйте, Yarrow, Вы писали:
Y>Уважаемые, почему при явном указании кодировки JSP-страниц UTF-8 в файлай ресурсов строки на разных языках приходится писать как escape-последовательности? Почему файл ресурсов нельзя просто написать в кодировке UTF-8? Так и должно быть, или я чего-то не понимаю?
.......
Вариант настроиться на базу и хранить в ней ресурсы, т.е.
public final class DBMessageResourceFactory extends MessageResourcesFactory {
public MessageResources createResources(String config) {
return new DBMessageResources(this, config, this.returnNull);
}
}
MaximWirt,
LCR>>К слову сказать, мне тоже захотелось знать железный способ хранения ресурсов в UTF-8 (железный, то есть не зависящий от локалей и осей)
MW>в ant можно указать кодировку
MW><native2ascii encoding="UTF-8" src="src" MW> dest="classes" MW> includes="**/res/Resources*.properties"/>
Человеку (да и мне уже тоже ) интересно, можно ли ресурсы хранить в UTF-8, и подсунуть их Struts? Без native2ascii. То, что хранить xml в UTF-8 можно, это и барану ясно.
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>MaximWirt,
LCR>Человеку (да и мне уже тоже ) интересно, можно ли ресурсы хранить в UTF-8, и подсунуть их Struts? Без native2ascii. То, что хранить xml в UTF-8 можно, это и барану ясно.
полагаю в том виде в котором поставляется стратс сейчас — нет. Однако фича была запланирована аж в 2000 году. Но видно никому так и не понадобилась, или вылилась в нечто более глобальное, пока еще к стратсу не прикрученное. Если поискать в гугле — то можно найти ссылки на некоторые реализации XMLMessageResources, но меня они ни к чему конкретномуне привели. Так что надо или рыть глубже или писать самому.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[2]: contentType и i18n сообщений Struts Windows-1251
Боагодарю, ваша идея была отправной точкой.
Хотелось бы поделиться своим опытом для чтения файла по умолчанию из "Windows-1251":
(Лазил по первоисточникам. Что касается Copyright: привожу код не пренадлежащим
мне код не для корысти, а только для демонстрации )
1. В struts-config.xml в секции message-resources прописал в factory свой класс по загрузке файла установок
Обратите внимание на параметр имени файла "ApplicationResources", у меня их два :
ApplicationResources.properties — для универсальный
ApplicationResources_ru.properties — для RU-локали, здесь у меня сохранен русский текст в кодировке "Windows-1251".
2. Создал свой factory-класс для определения класса обработки файла установок
package ru.narod.bedward70.bevdata.struts;
import org.apache.struts.util.MessageResourcesFactory;
import org.apache.struts.util.MessageResources;
public class MessageResourceFactoryWin
extends MessageResourcesFactory {
public MessageResources createResources(String config) {
return newMessageResourcesWin(this, config, this.returnNull);
}
}
3. Создал свой класс загрузки от PropertyMessageResources, переопределяю конструкторы и метод loadLocale, заменяю только Properties props = new Properties(); на PropertiesCharset props = new PropertiesCharset();
4. Учу читать Prorepties в другой кодировке (делаю класс от Prorepties)
Делаю копию метода load, но с параметром кодировки, и переопределяю первую строку BufferedReader in = new BufferedReader(new InputStreamReader(inStream, "8859_1"));
на BufferedReader in = new BufferedReader(new InputStreamReader(inStream, charsetName));
Но в ошибки вылезли закрытые переменные и методы базового класса — пришлось из переопределить
Вот полный текст:
package ru.narod.bedward70.bevdata.struts;
import java.util.Properties;
import java.io.InputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedReader;
public class PropertiesCharset extends Properties {
private static final String whiteSpaceChars = " \t\r\n\f";
private static final String keyValueSeparators = "=: \t\r\n\f";
private static final String strictKeyValueSeparators = "=:";
private boolean continueLine(String line) {
int slashCount = 0;
int index = line.length() - 1;
while ((index >= 0) && (line.charAt(index--) == '\\'))
slashCount++;
return (slashCount % 2 == 1);
}
public synchronized void load(InputStream inStream, String charsetName) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(inStream, charsetName));while (true) {
// Get next line
String line = in.readLine();
if (line == null)
return;
if (line.length() > 0) {
// Find start of keyint len = line.length();
int keyStart;
for (keyStart=0; keyStart<len; keyStart++)
if (whiteSpaceChars.indexOf(line.charAt(keyStart)) == -1)
break;
// Blank lines are ignoredif (keyStart == len)
continue;
// Continue lines that end in slashes if they are not commentschar firstChar = line.charAt(keyStart);
if ((firstChar != '#') && (firstChar != '!')) {
while (continueLine(line)) {
String nextLine = in.readLine();
if (nextLine == null)
nextLine = "";
String loppedLine = line.substring(0, len-1);
// Advance beyond whitespace on new lineint startIndex;
for (startIndex=0; startIndex<nextLine.length(); startIndex++)
if (whiteSpaceChars.indexOf(nextLine.charAt(startIndex)) == -1)
break;
nextLine = nextLine.substring(startIndex,nextLine.length());
line = new String(loppedLine+nextLine);
len = line.length();
}
// Find separation between key and valueint separatorIndex;
for (separatorIndex=keyStart; separatorIndex<len; separatorIndex++) {
char currentChar = line.charAt(separatorIndex);
if (currentChar == '\\')
separatorIndex++;
else if (keyValueSeparators.indexOf(currentChar) != -1)
break;
}
// Skip over whitespace after key if anyint valueIndex;
for (valueIndex=separatorIndex; valueIndex<len; valueIndex++)
if (whiteSpaceChars.indexOf(line.charAt(valueIndex)) == -1)
break;
// Skip over one non whitespace key value separators if anyif (valueIndex < len)
if (strictKeyValueSeparators.indexOf(line.charAt(valueIndex)) != -1)
valueIndex++;
// Skip over white space after other separators if anywhile (valueIndex < len) {
if (whiteSpaceChars.indexOf(line.charAt(valueIndex)) == -1)
break;
valueIndex++;
}
String key = line.substring(keyStart, separatorIndex);
String value = (separatorIndex < len) ? line.substring(valueIndex, len) : "";
// Convert then store key and value
key = loadConvert(key);
value = loadConvert(value);
put(key, value);
}
}
}
}
private String loadConvert(String theString) {
char aChar;
int len = theString.length();
StringBuffer outBuffer = new StringBuffer(len);
for (int x=0; x<len; ) {
aChar = theString.charAt(x++);
if (aChar == '\\') {
aChar = theString.charAt(x++);
if (aChar == 'u') {
// Read the xxxxint value=0;
for (int i=0; i<4; i++) {
aChar = theString.charAt(x++);
switch (aChar) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
value = (value << 4) + aChar - '0';
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
value = (value << 4) + 10 + aChar - 'a';
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
value = (value << 4) + 10 + aChar - 'A';
break;
default:
throw new IllegalArgumentException(
"Malformed \\uxxxx encoding.");
}
}
outBuffer.append((char)value);
} else {
if (aChar == 't') aChar = '\t';
else if (aChar == 'r') aChar = '\r';
else if (aChar == 'n') aChar = '\n';
else if (aChar == 'f') aChar = '\f';
outBuffer.append(aChar);
}
} else
outBuffer.append(aChar);
}
return outBuffer.toString();
}
}