Пакеты ресурсов Java содержат локализуемый текст. Один тип пакета - это PropertyResourceBundle. Этот пакет представляет собой текстовый файл, содержащий простые пары ключ-значение, например:

HELLO=I'm just a string, nothing special here.
CAVEAT=But my encoding is LATIN-1!

Хотя файлы свойств Java эффективны и широко используются, они ужасно неудобны в одном значительном смысле: они должны быть закодированы как ISO-8859–1.

Это означает, что вы не можете представить большинство символов Юникода без специальных методов экранирования, если вы используете JDK 8 или более ранние версии.

Возня с кодировками ASCII

В JDK 8 и ранее вы должны использовать escape-символы ASCII, отличные от Latin-1, если вы хотите использовать PropertyResourceBundle. В Java Development Kit (JDK) есть инструмент под названием native2ascii для облегчения преобразования. Это дополнительное экранирование делает переведенные пакеты ресурсов практически невозможными для визуального чтения. Например, слово «книга» по-японски - «本» (хон). Используя механизм загрузки пакета свойств по умолчанию, вам нужно будет экранировать файл свойств ASCII. Формат ASCII-escape - \uXXXX, где XXXX представляет шестнадцатеричное значение единицы кода UTF-16:

BOOK=\u672C

На мой взгляд, это просто недопустимо. Мы предпочитаем видеть правильный персонаж в его естественной визуальной форме:

BOOK=本

Создание элемента управления ResourceBundle с поддержкой UTF-8

К счастью, вам не нужно жертвовать удобством использования и удобочитаемостью. Мы можем создать наш собственный класс ResourceBundle.Control, чтобы переопределить стратегию загрузки по умолчанию, используемую методом ResourceBundle.getBundle. Перегрузив метод newBundle, мы можем легко указать загрузчику пакета использовать UTF-8 для кодировки кодировки файла свойств.

Создайте PropertyResourceBundle, используя UTF-8 InputStreamReader вместо InputStream, который ограничен Latin-1:

InputStream stream = classLoader.getResourceAsStream(resourceName);
Reader reader = new InputStreamReader(stream, “UTF-8”);
ResourceBundle bundle = new PropertyResourceBundle(reader);

Полный исходный код UTF8ResourceBundleControl находится в моем проекте Github Enhanced Resources. Ознакомьтесь с полной информацией о том, как реализовать подкласс ResourceBundle.Control.

Использование элемента управления UTF 8 ResourceBundle

Использовать новый UTF8ResourceBundleControl так же просто, как передать его методу ResourceBundle.getBundle. В этом тесте я создаю пакет японского языка и получаю строку в кодировке UTF-8:

ResourceBundle.Control utf8Control = 
    new Utf8ResourceBundleControl();
ResourceBundle bundle =
    ResourceBundle.getBundle(“com.joconner.i18n.res.Utf8Resources”,
    Locale.JAPANESE, utf8Control);
String hello = bundle.getString(“HELLO”);
assertEquals(“こんにちは!”, hello);

С нетерпением жду JDK 9

В JDK 9 добавлена ​​поддержка файлов свойств UTF-8. Вы можете прочитать больше об этом долгожданном дополнении в этой заметке OpenJDK JEP. Вы сможете пользоваться ресурсами UTF-8 без лишних усилий. А пока, однако, если вы собираетесь продолжать использовать JDK 8 еще какое-то время, пожалуйста, попробуйте мою реализацию.

Загрузите исходный код для UTF8ResourceBundleControl и других из моего репозитория Расширенные ресурсы на Github. Получайте удовольствие от поддержки UTF-8 в PropertyResourceBundle файлах без кодировки ASCII.