Message Bundles
The most common task of localization is to provide messages depending on the current user locale. To achieve this, messages must be extracted from code and placed in special property files, one file per language. A collection of such files is called a message bundle.
Apart from messages, the message bundle can also contain localized data format strings.
The default message bundle of your project is a set of messages_<language>.properties
files located in the base package under the src/main/resources
folder.
Message bundle files must have the UTF-8 encoding. |
Setting Up Locales
When you create a new project using Studio, you can set up the list of supported locales in the Locales field of the project wizard. This field allows you to select a language code and set its name.
Studio writes the list of language codes to the jmix.core.available-locales
application property and language names to the corresponding messages_<language>.properties
files with localeDisplayName.<language>
key. You can later edit these properties manually or use the Locales tab of the Project Properties window in Studio.
For example, if you have defined two languages for your application: en
- English
and de
- Deutsch
, you have the following file structure in the project (provided that the base package is localization_demo.ex1
):
src/
main/
resources/
localization_demo/
ex1/
messages_en.properties
messages_de.properties
application.properties
And the files have the following contents:
localeDisplayName.en = English
localeDisplayName.de = Deutsch
jmix.core.available-locales = en,de
Creating Messages
Group and Key
Usually, an application contains a single message bundle. Because the number of messages even in a simple application can be quite large, we recommend making property keys of two parts: the group and the message key, separated by the forward slash (/
). It allows you to group related messages and avoid naming conflicts. In the following example, localization_demo.ex1.screen.main
is the group and application.caption
is the message key:
localization_demo.ex1.screen.main/application.caption = Sample application
But you can also define a message without a group, for example:
messageWithoutGroup = Message without a group
Localizing Data Model
Jmix introduces some conventions on localization of the data model elements: entity and attribute names, enumeration values. It allows the framework to find the localized names when displaying entities and enumerations in UI components.
Entity name is localized using the <package>/<class>
format, attribute name - using the <package>/<class>.<attribute>
format. For example:
# entity name
localization_demo.ex1.entity/Customer = Customer
# attribute names
localization_demo.ex1.entity/Customer.id = Id
localization_demo.ex1.entity/Customer.version = Version
localization_demo.ex1.entity/Customer.name = Name
Enumeration name is localized using the <package>/<class>
format, enumeration value - using the <package>/<class>.<value>
format. For example:
# enumeration name
localization_demo.ex1.entity/Status = Status
# enumeration values
localization_demo.ex1.entity/Status.ACTIVE = Active
localization_demo.ex1.entity/Status.SUSPENDED = Suspended
localization_demo.ex1.entity/Status.INACTIVE = Inactive
You can easily create localized names of the data model elements in Studio visual designers. Click the 🌐 (globe) button next to the element name and enter localized values for available locales in the Localized Message dialog. |
Additional Bundles
In a big application with a lot of messages you can maintain a reasonable size of the property files by defining additional message bundles:
-
Create a set of property files with arbitrary name in any directory under
src/main/resources
. In the example below, we createdadditional_messages
files in the same base package as the main message bundle:src/ main/ resources/ localization_demo/ ex1/ additional_messages_en.properties additional_messages_de.properties messages_en.properties messages_de.properties
-
Write localized messages in the additional files in the same way as in the main bundle.
-
Add the
@MessageSourceBasenames
annotation to the application class and set the path and name of the additional bundle in it:@SpringBootApplication @MessageSourceBasenames({"localization_demo/ex1/additional_messages"}) public class LocalizationExampleApplication {
Messages from all bundles of the application are loaded into a single list, so property keys must be unique among all your bundles. |
Using Messages
In Java Code
Messages Interface
To get localized messages from the message bundle, use the Messages
bean. The most common use case is to invoke its getMessage()
method and provide the message group and key. The method will return a message for the current user locale, or the given message key if the message is not found.
In the following example, we define a message in a message bundle and get it using different methods of the Messages
bean:
localization_demo.ex1/someNotification = Something has happened
String message1 = messages.getMessage("localization_demo.ex1/someNotification"); (1)
String message2 = messages.getMessage("localization_demo.ex1", "someNotification"); (2)
String message3 = messages.getMessage(getClass(), "someNotification"); (3)
All three methods return the same value: Something has happened
.
1 | The whole property key is specified. |
2 | The group and the message key are specified separately. |
3 | If the first argument is Class , the method uses the package of the class as the group. |
There is also an overloaded getMessage()
method accepting Enum
. Use it to retrieve a localized enum value, for example:
String message = messages.getMessage(Status.ACTIVE);
MessageBundle Interface
The MessageBundle
interface is available in screen controllers. It provides methods to get localized messages of a single group associated with the screen controller. It differs from the Messages bean in that it can obtain the message group implicitly from the screen controller, so there is no need to pass the group key or the class name.
To use MessageBundle
, inject it in the controller:
@Autowired
private MessageBundle messageBundle;
Now you can use it to get the message by the key:
String someMessage = messageBundle.getMessage("someMessage");
The group of the message is inferred from the screen controller package, as if using Messages.getMessage(getClass(), "someMessage")
.
An arbitrary group can be either defined using the messagesGroup
XML attribute described below, or you can set it in the controller using the setMessageGroup()
method:
messageBundle.setMessageGroup("some.group");
The formatMessage()
method of MessageBundle
retrieves a localized message by the key and then uses it to format the input parameters. The format is defined according to String.format()
method rules. For example:
localization_demo.ex1.screen.user/userInfo=User name: %s
String formattedMessage = messageBundle.formatMessage("userInfo", user.getUsername());
In Screen XML Descriptors
Jmix UI screen descriptors and menu configuration files recognize the msg://
prefix in messages and load such messages from the message bundle.
Let’s consider different options of using msg://
with examples.
-
The group of the message is inferred from the screen’s package.
For example, if you have defined a message with
localization_demo.ex1.screen.user
group:messages_en.propertieslocalization_demo.ex1.screen.user/someMessage = Some message
you can retrieve it in a screen descriptor located in the
localization_demo.ex1.screen.user
package simply by specifying the message key without the group:localization_demo/ex1/screen/user/user-browse.xml<label value="msg://someMessage"/>
-
Getting a message with an arbitrary group.
You can retrieve the message from the previous example in any screen by specifying both the group and the key after the
msg://
prefix, for example:localization_demo/ex1/screen/main/main-screen.xml<label value="msg://localization_demo.ex1.screen.user/someMessage"/>
You can also set an arbitrary message bundle at the screen level using the
messagesGroup
attribute, so that all messages will be retrieved from it by default:localization_demo/ex1/screen/user/user-browse.xml<window xmlns="http://jmix.io/schema/ui/window" caption="msg://UserBrowse.caption" messagesGroup="additional_messages" focusComponent="usersTable">
-
Getting a message without a group.
To retrieve a message without a group, use triple slash in the prefix
msg:///
, followed by the message key.For example, if you have defined a message like this:
messageWithoutGroup = Message without a group
you can get it in any screen descriptor as follows:
<label value="msg:///messageWithoutGroup"/>