Database aware i18n messages — SpringBoot

Nakul Pant
TechCret Software
Published in
3 min readMay 2, 2020

Continuing from my last story where we migrated the messages stored in the properties file to the database, let’s put them to use now.

In this story, we will set up a Message Source that will pick all the i18n messages from the database.

Often we keep our i18n messages in a properties file and use the messages from there. But, what if the user wants the control to make changes to the content at runtime, we cannot ask the user to change the properties file manually. In these scenario usually database comes to our help where we can open up a rest API to update the message content.

Locale Resolver

Let’s walk through the locale resolver first before diving into the message source. LocaleResolver is required to correctly decide which local is currently used in the application. LocaleResolver interface allows for implementations based on a request, session, cookies, etc. The default implementation in spring-boot is AcceptHeaderLocaleResolver. The locale should be passed in the header called “Accept-Language”. We will stick to the default LocalResolver in our sample code. Please read LocaleResolver for more details.

Message Source

MessageSource interface is used for resolving messages, with support for the parameterization and internationalization of the messages. Spring contains two built-in MessageSource implementations: ResourceBundleMessageSource and ReloadableResourceBundleMessageSource. The latter is able to reload message definitions without restarting the Virtual Machine.

More on message source here.

Basically every Spring application needs a message source that is responsible for resolving messages based on some parameters. This can be achieved by getMessage() method of the MessageSource which has three variants that can be consulted on the official spring documentation here.

We need to set up our message source and the strategy to resolve the messages from the database. We do so by declaring a bean named ‘messageSource’. The name is specific to the Spring ecosystem and should be used as it is, however, the implementations can differ obviously.

Our DatabaseAwareMessageSource is marked with @Component(“messageSource”) which marks the class as a spring component bean named ‘messageSource’. Remember to stick to the name :P

Our message source class implements AbstractMessageSource which provides us with a method resolveCode(String messageKey, Locale locale) that needs to be overridden. Our main logic to retrieve the messages based on locales from the database will be implemented here. This method returns a MessageFormat.

Here I am getting the current tenant in the current request with the help of a utility class TenantContext which obviously am not going to cover here :P

MessageRepository helps us to find the message content by the message key and locale passed along with the tenantId we fetched above.

Next, we create and return an instance of MessageFormat which takes in the content based on the message key and the locale.

That is all for messageSource configuration.

Next, let's use this message source. The usage of getting the messages from messageSource is the same.

Let's say we have a message in the database with the above key and value. This message accepts an argument and is replaced by {0} as the first argument, which is resolved by using getMessage() from the messageSource bean. The database record looks like this in our database.

Usage —

throw new UserNotFoundException(messageSource.getMessage("not.found.admin", new String[]{adminCO.getUniqueId()}, Locale.getDefault()))

results in throwing an exception with the message that is provided from the database. The getMessage() method takes the message key as the first argument, an array of string objects that will be resolved as placeholders in the message content, and a locale. The placeholder arguments can be accessed based on the index, meaning {0} will be replaced by the element at the 0th index, and {2} will be replaced by the element at 2nd index of the array.

--

--