Skip to content

Latest commit

 

History

History

Spring_part_23

Spring Boot lessons part 23 - Интернационализация и локализация в Spring.

В папке DOC sql-скрипты и др. полезные файлы.

Док. (ссылки) для изучения:



Для начала проведем предварительную подготовку (подгрузим зависимости в build.gradle):

/* 
   Плагин Spring Boot добавляет необходимые задачи в Gradle 
   и имеет обширную взаимосвязь с другими plugin-ами.
*/
id 'org.springframework.boot' version '3.1.3'

/* 
    Менеджер зависимостей позволяет решать проблемы несовместимости 
    различных версий и модулей Spring-а
*/
id "io.spring.dependency-management" version '1.0.11.RELEASE'

/* Подключим Lombok */
id "io.freefair.lombok" version "8.3"

/* 
    Автоматически Gradle создал тестовую зависимость на Junit5, мы можем 
    использовать как Junit4, так и TestNG
*/
test {
    useJUnitPlatform()
}

/*
Подключим Spring Boot Starter он включает поддержку
авто-конфигурации, логирование и YAML
*/
implementation 'org.springframework.boot:spring-boot-starter'

/* Подключим блок для работы с БД (Spring Boot Starter Data Jpa) */
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

/* Для работы с PostgreSQL подключим и его зависимости */
implementation 'org.postgresql:postgresql'

!!! НЕ ЗАБЫВАЕМ !!! У нас есть классы (см. ConnectionPool.java и комментарии), где мы пытаемся внедрить параметры в 
поля через аннотации, с использованием аннатационного же конструктора @RequiredArgsConstructor. Фокус не пройдет без 
создания и настройки файла конфигурации: lombok.config - 'контекст' просто завалится. 

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

implementation 'org.springframework.data:spring-data-envers'

/* Подключим миграционный фреймворк Liquibase */
implementation 'org.liquibase:liquibase-core'

/* Подключаем Wed - Starter */
implementation 'org.springframework.boot:spring-boot-starter-web'

/* Подключим Thymeleaf */
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

/* Подключим валидацию */
implementation 'org.springframework.boot:spring-boot-starter-validation'

/* Подключим стартер безопаности */
implementation 'org.springframework.boot:spring-boot-starter-security'

implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'

/* Зависимости необходимые при тестировании Spring Boot приложения */
testImplementation 'org.springframework.boot:spring-boot-starter-test'

/* Зависимости позволяет тестировать приложение с подключенным Spring Security */
testImplementation 'org.springframework.security:spring-security-test'

testImplementation "org.testcontainers:postgresql:${versions.testcontainers}"

Lesson 116 - i18n-MessageSource.

Как и в Servlet-ах процесс интернационализации идет через ResourceBundle. И конечно в Spring-e это реализуется чуть по-другому, все bundle имеют зарезервированные названия и настройку можно провести за 3-и шага:

  • Шаг 1. - В application.yml добавляем префикс messages из MessageSourceAutoConfiguration, это конфигурационный файл для MessageSource, а значит и для ResourceBundle:

      messages:
          basename: messages
          fallback-to-system-locale: false
    
  • Шаг 2. - Создаем файлы message-ей для разных языков в папке resources нашего приложения:

    • messages.properties - с default настройками (в нашем варианте язык EN);
    • messages_ru.properties - с настройками для русского языка (_ru - указан только язык, если добавить _RU, то мы добавляем намек на регион, хотя это и необязательно и т.д.);

По умолчанию приложение Spring Boot будет искать файлы messages, содержащие ключи и значения интернационализации, в папке src/main/resources. Обычно файлы для каждой локали называются messages_XX.properties, где XX — код локали. Мы также можем определить резервный файл messages.properties.

!!! Однако, резервный файл не следует считать связанным с локалью по умолчанию. Это два отдельных понятия !!!

Языковой стандарт по умолчанию - это языковой стандарт, используемый по умолчанию, когда запрошенный языковой стандарт недоступен или имеет значение NULL. С другой стороны, резервный файл — это место для поиска свойств в случае сбоя перевода локали.

Если ключ не существует в определенном файле локали, приложение просто вернется к резервному файлу. Ключи для значений, которые будут локализованы, должны быть одинаковыми в каждом файле, а значения должны соответствовать языку выбранной локали.

IDEA сразу объединила оба свойства в ассоциированный комплект: Resource Bundle 'messages'. Теперь необходимо удостовериться, что в настройках среды разработки, кодирование файлов идет в UTF-8 см. DOC/IDEASettingFileEncodingUTF-8.jpg

  • Шаг 3. - Фактически уже все готово, но нам нужно убедиться, что интернационализация работает. Для этого создадим REST endpoint позволяющий тестировать работу нашей - Internationalization (i18n) - MessageRestController.java см. комментарии в коде класса.

Теперь проверяем работу наших настроек на REST контроллере, запускаем приложение, переходим по http://localhost:8080/swagger-ui/index.html и тестируем *.getMessage() метод. Например, 'key' у нас это 'login.username', тогда 'lang' это 'ru', 'fr' или 'en', см. DOC/message-rest-controller-ru-test.jpg и DOC/message-rest-controller-fr-test.jpg.


Lesson 117 - i18n и внедрение его в HTML страницы с Thymeleaf.

На HTML страницах для использования интернационализации применяется тег #{.....} см. пример:

<span th:text="#{login.username}">Username:</span>

Т.е. нам необходимо по данному шаблону интернационализировать все наши страницы. Однако у нас нет возможности выбора языка ни на одной странице, нужно это исправить. Добавим блок выбора языка в папку fragment - language_selection.html.

И так повторим, что необходимо сделать для внедрения интернационализации и локализации в Spring приложение:

  • Шаг 1. - Настроить application.yml см. выше предыдущий Lesson 116.
  • Шаг 2. - Создать файлы message-ей для разных языков в папке resources нашего приложения см. выше предыдущий Lesson 116.
  • Шаг 3. - Предоставить пользователю возможность изменять язык интерфейса, желательно, на всех доступных страницах. Для этого создаем отдельную страницу language_selection.html, которая будет интегрироваться в другие HTML страницы.
  • Шаг 4. - Используя синтаксис Thymeleaf описанный выше внесем изменения в файлы: language_selection.html, logout.html и user.html (только в них, другие можно изменить по данному же принципу, но тут мы этого делать не будем)

И вот тут начинается самое интересное. Нам необходимо отслеживать запрос генерируемый language_selection.html на нашем сервере (в нашем приложении). Т.е. наше приложение должно увидеть что параметр lang=en изменился на lang=ru или другой язык. Для этого нам нужно внести изменения в WebConfiguration.java:

  • Шаг 5. - Создаем bean метод перехватчик изменений локали *.localeChangeInterceptor(), который будет возвращать LocaleChangeInterceptor. Однако Spring не внедряет LocaleChangeInterceptor автоматически, мы должны это прописать в коде сами.
  • Шаг 6. - Создаем метод *.addInterceptors() и уже через него добавляем наш перехватчик изменений локали в реестр перехватчиков - InterceptorRegistry. Только в этом случае, каждый запрос на смену локали (языка) будет обрабатываться приложением (сервером), еще раз см. language_selection.html.
  • Шаг 7. - Теперь нам нужно хранить выбранную пользователем локаль (в healers, в cookies, т.е. в параметрах сессии). Для этого нам нужен еще один bean метод *.localeResolver(), который будет возвращать реализацию LocaleResolver, а их несколько, т.е. мы можем выбрать, где хранить состояние локали (языка), например:

В cookies мы храним сессию, поэтому (на данном этапе), затолкаем туда и сведение о выбранном языке. Теперь можно проверить работу локализации в приложении - запускаем и смотрим что получилось см. SelectLanguageMenu.jpg.


См. официальные Guides:

  • Getting Started Guides - Эти руководства, рассчитанные на 15–30 минут, содержат быстрые практические инструкции по созданию «Hello World» для любой задачи разработки с помощью Spring. В большинстве случаев единственными необходимыми требованиями являются JDK и текстовый редактор.
  • Topical Guides - Тематические руководства предназначенные для прочтения и понимания за час или меньше, содержит более широкий или субъективный контент, чем руководство по началу работы.
  • Tutorials - Эти учебники, рассчитанные на 2–3 часа, обеспечивают более глубокое контекстное изучение тем разработки корпоративных приложений, что позволяет вам подготовиться к внедрению реальных решений.