1. Обзор
Исключения в Java используются для того, чтобы сигнализировать о том, что в программе что-то пошло не так. В дополнение к исключению, мы даже можем добавить сообщение для предоставления дополнительной информации.
В этой статье мы воспользуемся методом getLocalizedMessage для предоставления сообщений об исключениях как на английском, так и на французском языках.
2. Пакет ресурсов
Нам нужен способ поиска сообщений с помощью ключа message для идентификации сообщения и Локали для определения того, какой перевод обеспечит значение для messageKey . Мы создадим простой класс для абстрактного доступа к нашему ResourceBundle для получения переводов сообщений на английский и французский языки:
public class Messages { public static String getMessageForLocale(String messageKey, Locale locale) { return ResourceBundle.getBundle("messages", locale) .getString(messageKey); } }
Наш класс Messages использует ResourceBundle для загрузки файлов свойств в ваш пакет, который находится в корне вашего пути к классу. У нас есть два файла – один для наших английских сообщений и один для наших французских сообщений:
# messages.properties message.exception = I am an exception.
# messages_fr.properties message.exception = Je suis une exception.
3. Локализованный класс исключений
Наш подкласс Exception будет использовать стандарт Locale по умолчанию, чтобы определить, какой перевод использовать для наших сообщений. Мы получим Locale по умолчанию, используя Locale#getDefault .
Если бы ваше приложение работало на сервере, мы бы использовали заголовки HTTP-запросов для определения Locale для использования вместо установки по умолчанию. Для этой цели мы создадим конструктор, который будет принимать локаль .
Давайте создадим наш подкласс Exception . Для этого мы могли бы расширить либо RuntimeException , либо Exception . Давайте расширим Исключение и переопределим getLocalizedMessage :
public class LocalizedException extends Exception { private final String messageKey; private final Locale locale; public LocalizedException(String messageKey) { this(messageKey, Locale.getDefault()); } public LocalizedException(String messageKey, Locale locale) { this.messageKey = messageKey; this.locale = locale; } public String getLocalizedMessage() { return Messages.getMessageForLocale(messageKey, locale); } }
4. Собрать Все Это Воедино
Давайте создадим несколько модульных тестов, чтобы убедиться, что все работает. Мы создадим тесты для переводов на английский и французский языки, чтобы проверить передачу пользовательского Locale исключению во время построения:
@Test public void givenUsEnglishProvidedLocale_whenLocalizingMessage_thenMessageComesFromDefaultMessage() { LocalizedException localizedException = new LocalizedException("message.exception", Locale.US); String usEnglishLocalizedExceptionMessage = localizedException.getLocalizedMessage(); assertThat(usEnglishLocalizedExceptionMessage).isEqualTo("I am an exception."); } @Test public void givenFranceFrenchProvidedLocale_whenLocalizingMessage_thenMessageComesFromFrenchTranslationMessages() { LocalizedException localizedException = new LocalizedException("message.exception", Locale.FRANCE); String franceFrenchLocalizedExceptionMessage = localizedException.getLocalizedMessage(); assertThat(franceFrenchLocalizedExceptionMessage).isEqualTo("Je suis une exception."); }
Наше исключение также может использовать стандарт Locale по умолчанию. Давайте создадим еще два теста, чтобы проверить, работает ли функциональность по умолчанию Locale :
@Test public void givenUsEnglishDefaultLocale_whenLocalizingMessage_thenMessageComesFromDefaultMessages() { Locale.setDefault(Locale.US); LocalizedException localizedException = new LocalizedException("message.exception"); String usEnglishLocalizedExceptionMessage = localizedException.getLocalizedMessage(); assertThat(usEnglishLocalizedExceptionMessage).isEqualTo("I am an exception."); } @Test public void givenFranceFrenchDefaultLocale_whenLocalizingMessage_thenMessageComesFromFrenchTranslationMessages() { Locale.setDefault(Locale.FRANCE); LocalizedException localizedException = new LocalizedException("message.exception"); String franceFrenchLocalizedExceptionMessage = localizedException.getLocalizedMessage(); assertThat(franceFrenchLocalizedExceptionMessage).isEqualTo("Je suis une exception."); }
5. Предостережения
5.1. Ведение журнала выбрасываемых материалов
Нам нужно будет иметь в виду структуру ведения журнала, которую мы используем для отправки Исключение экземпляры в журнал.
Log4J, Log4J2 и Log back используйте GetMessage для получения сообщения для записи в приложение журнала. Если мы используем java.util.logging , содержимое поступает из getLocalizedMessage .
Возможно, мы захотим рассмотреть возможность переопределения GetMessage для вызова getLocalizedMessage , чтобы нам не пришлось беспокоиться о том, какая реализация ведения журнала используется.
5.2. Серверные приложения
Когда мы локализуем наши сообщения об исключениях для клиентских приложений, нам нужно беспокоиться только о текущей Локали одной системы . Однако, если мы хотим локализовать сообщения об исключениях в серверном приложении, мы должны иметь в виду, что переключение Locale по умолчанию повлияет на все запросы на нашем сервере приложений.
Если мы решим локализовать сообщения об исключениях, мы создадим конструктор для нашего исключения, чтобы принять Locale . Это даст нам возможность локализовать наши сообщения без обновления Locale по умолчанию .
6. Резюме
Локализация сообщений об исключениях довольно проста. Все, что нам нужно сделать, это создать ResourceBundle для наших сообщений, а затем реализовать getLocalizedMessage в наших подклассах Exception .
Как обычно, примеры доступны на GitHub .