Пакеты сообщений

Наиболее частой задачей локализации является обеспечение сообщений, соответствующих текущему языку пользователя. Для этого сообщения должны быть извлечены из кода и помещены в специальные файлы свойств, по одному файлу на каждый язык. Коллекция таких файлов называется пакетом сообщений.

Помимо сообщений, пакет сообщений также может содержать локализованные строки форматов.

Пакет сообщений проекта по умолчанию представляет собой набор файлов messages_<language>.properties, расположенных в базовом пакете в папке src/main/resources.

Файлы пакетов сообщений должны иметь кодировку UTF-8.

Настройка локалей

При создании нового проекта в Studio вы можете настроить список поддерживаемых языков в поле Locales мастера проекта. Это поле позволяет выбрать языки и их коды.

Studio записывает список кодов языков в свойство приложения jmix.core.available-locales, а названия языков - в соответствующие файлы messages_<language>.properties с ключом localeDisplayName.<language>. Позже вы можете отредактировать эти свойства вручную или использовать вкладку Locales окна Project Properties в Studio.

Например, если для приложения определено два языка: English (en) and Русский (ru), в проекте будет следующая структура файлов (при условии, что базовым пакетом является com.company.demo):

src/main/resources/
    com/company/demo/
        messages_en.properties
        messages_ru.properties
    application.properties

И файлы будут иметь следующее содержимое:

messages_en.properties
localeDisplayName.en=English
messages_ru.properties
localeDisplayName.ru=Русский
application.properties
jmix.core.available-locales = en,ru

Создание сообщений

Группа и ключ

Обычно приложение содержит один пакет сообщений. Поскольку количество сообщений даже в простом приложении может быть довольно большим, рекомендуется создавать ключи свойств из двух частей: группы и ключа сообщения, разделенных косой чертой (/). Это позволяет группировать связанные сообщения и избегать конфликтов имен. В следующем примере com.company.demo.view.main - это группа, а applicationTitle.text - это ключ сообщения:

com.company.demo.view.main/applicationTitle.text=Demo App

Также можно определить сообщение без группы, например:

messageWithoutGroup = Message without a group

Локализация модели данных

Jmix вводит некоторые правила локализации элементов модели данных, таких как имена сущностей и атрибутов, значения перечисления. Это позволяет фреймворку находить локализованные имена при отображении сущностей и перечислений в компонентах UI.

Имя сущности локализуется в формате <package>/<class>, имя атрибута - в формате <package>/<class>.<attribute>. Например:

# entity name
com.company.demo.entity/User=User
# attribute names
com.company.demo.entity/User.id=ID
com.company.demo.entity/User.username=Username
com.company.demo.entity/User.firstName=First name
com.company.demo.entity/User.lastName=Last name
com.company.demo.entity/User.password=Password
com.company.demo.entity/User.email=Email

Имя перечисления локализуется в формате <package>/<class>, значение перечисления - в формате <package>/<class>.<value>. Например:

# enumeration name
com.company.demo.entity/Status=Status
# enumeration values
com.company.demo.entity/Status.ACTIVE=Active
com.company.demo.entity/Status.INACTIVE=Inactive
com.company.demo.entity/Status.SUSPENDED=Suspended
Локализованные имена элементов модели данных можно легко создавать в визуальных дизайнерах Studio. Нажмите кнопку 🌐 (глобус) рядом с именем элемента и введите локализованные значения для доступных языков в диалоговом окне Localized Message.

Дополнительные пакеты

Для того, чтобы придерживаться разумного размера файлов свойств в масштабном приложении с большим количеством сообщений, можно определить дополнительные пакеты:

  1. Создайте набор файлов свойств с произвольным именем в любом каталоге раздела src/main/resources. В приведенном ниже примере файлы additional_messages созданы в том же базовом пакете приложения, что и основной пакет сообщений:

    src/main/resources/com/company/demo/
        additional_messages_en.properties
        additional_messages_ru.properties
        messages_en.properties
        messages_ru.properties
  2. Запишите локализованные сообщения в дополнительные файлы так же, как и в основном пакете.

  3. Добавьте аннотацию @MessageSourceBasenames к классу приложения и укажите в ней путь и имя дополнительного пакета:

    @SpringBootApplication
    @MessageSourceBasenames({"com/company/demo/additional_messages"})
    public class DemoApplication implements AppShellConfigurator {
Сообщения из всех пакетов приложения загружаются в единый список, поэтому ключи свойств должны быть уникальными среди всех пакетов.

Использование сообщений

В коде Java

Интерфейс Messages

Чтобы получать локализованные сообщения из пакета сообщений, используйте бин Messages. Наиболее распространенным вариантом использования является вызов его метода getMessage() и предоставление группы сообщений и ключа. Метод вернет сообщение для текущего пользовательского языка или заданного ключа, если сообщение не найдено.

В следующем примере определим сообщение в пакете сообщений и получим его, используя различные методы бина Messages:

messages_en.properties
com.company.demo/someNotification = Something has happened
String message1 = messages.getMessage("com.company.demo/someNotification"); (1)

String message2 = messages.getMessage("com.company.demo", "someNotification"); (2)

String message3 = messages.getMessage(getClass(), "someNotification"); (3)

Все три метода возвращают одно и то же значение: Something has happened.

1 Ключ свойства задан целиком.
2 Группа и ключ сообщения заданы отдельно.
3 Если первым аргументом является Class, метод использует пакет класса как группу.

Существует также перегруженный метод getMessage(), принимающий Enum. Используйте его для извлечения локализованного значения перечисления, например:

String message = messages.getMessage(Status.ACTIVE);

Интерфейс MessageBundle

Интерфейс MessageBundle доступен в контроллерах экрана. Он предоставляет методы для получения локализованных сообщений одной группы, связанных с контроллером экрана. Он отличается от бина Messages тем, что может неявно получать группу сообщений от контроллера экрана, поэтому нет необходимости передавать ключ группы или имя класса.

Чтобы использовать MessageBundle, инжектируйте его в контроллер:

@Autowired
private MessageBundle messageBundle;

Теперь его можно использовать, чтобы получить сообщение по ключу:

String someMessage = messageBundle.getMessage("someMessage");

Группа сообщения выводится из пакета контроллера экрана, как при использовании Messages.getMessage(getClass(), "someMessage").

Произвольную группу можно либо определить с помощью XML-атрибута messagesGroup, описанного ниже, либо задать ее в контроллере с помощью метода setMessageGroup():

messageBundle.setMessageGroup("some.group");

Метод formatMessage() интерфейса MessageBundle извлекает локализованное сообщение по ключу, а затем использует его для форматирования входных параметров. Формат определяется в соответствии с правилами метода String.format(). Например:

messages_en.properties
com.company.demo.view.user/userInfo=User name: %s
String formattedMessage = messageBundle.formatMessage("userInfo", user.getUsername());

В XML-дескрипторах экранов

Дескрипторы экрана и файлы конфигурации меню UI распознают префикс msg:// в сообщениях и загружают их из пакета сообщений.

Рассмотрим различные варианты использования msg:// с примерами.

  1. Группа сообщения выводится из пакета экрана.

    Например, если сообщение определено с группой com.company.demo.view.user:

    messages_en.properties
    com.company.demo.view.user/someMessage = Some message

    Его можно получить в дескрипторе экрана, расположенном в пакете com.company.demo.view.user, просто указав ключ сообщения без группы:

    com/company/demo/view/user/user-list-view.xml
    <span text="msg://someMessage"/>
  2. Получение сообщения с произвольной группой.

    Сообщение из предыдущего примера можно получить на любом экране, указав группу и ключ после префикса msg://, например:

    com/company/demo/view/main/main-view.xml
    <span text="msg://com.company.demo.view.user/someMessage"/>

    Также можно установить произвольную группу на уровне экрана с помощью атрибута messagesGroup, чтобы все сообщения извлекались по умолчанию с этой группой:

    com/company/demo/view/sample/sample-view.xml
    <view xmlns="http://jmix.io/schema/flowui/view"
          messagesGroup="some.common.messages"
          title="msg://sampleView.title">
  3. Получение сообщения без группы.

    Чтобы получить сообщение без группы, следует поставить тройную косую черту в префиксе msg:///, за которым следует ключ сообщения.

    Например, если сообщение определено так:

    messageWithoutGroup = Message without a group

    То его можно получить в любом дескрипторе экрана следующим образом:

    <span text="msg:///messageWithoutGroup"/>