skip to content

MessageSource & i18n

MessageSource resolves message codes plus arguments against a Locale, backed by resource bundles that may or may not reload at runtime. Asked when the role involves multi-language products or user-facing error text.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is Spring's MessageSource, and how do you use getMessage to resolve a localized message with arguments?

level: juniorimportance: must knowfreq 55%

answer

  1. code + args + Locale
  2. {0} = MessageFormat placeholder
  3. bean must be named messageSource
  4. 3 overloads: default / throws / Resolvable
  5. messages_fr.properties fallback chain

basics

~20 s

MessageSource is Spring's interface for resolving text by a code for a given Locale. You call getMessage(code, args, locale); args fill placeholders like {0} in the properties file, so one code renders in different languages.

solid answer

~30 s

MessageSource is Spring's abstraction for internationalized (i18n) text lookup. You resolve a message by a String code, passing an Object[] of arguments and a java.util.Locale; Spring finds the matching properties file (e.g. messages_fr.properties) and substitutes arguments into MessageFormat placeholders {0}, {1}. Three overloads exist: one taking a defaultMessage (returned on a miss), one that throws NoSuchMessageException on a miss, and one taking a MessageSourceResolvable. The ApplicationContext itself implements MessageSource, delegating to a bean that must be named exactly 'messageSource'. In Spring Boot a ResourceBundleMessageSource over the 'messages' basename is auto-configured, so you add messages.properties files per locale and inject MessageSource.

code

java · 22 lines
java
@Configuration
public class I18nConfig {
    @Bean
    public MessageSource messageSource() {
        var ms = new ResourceBundleMessageSource();
        ms.setBasename("messages");           // messages.properties, messages_fr.properties...
        ms.setDefaultEncoding("UTF-8");
        return ms;
    }
}

@Service
public class Greeter {
    private final MessageSource messages;
    public Greeter(MessageSource messages) { this.messages = messages; }

    public String greet(String name, Locale locale) {
        // messages.properties:    greeting=Hello, {0}!
        // messages_fr.properties: greeting=Bonjour, {0} !
        return messages.getMessage("greeting", new Object[]{name}, locale);
    }
}

go deeper

for a junior

Knows getMessage(code, args, locale) and per-locale properties files.

for a middle

Understands the three overloads, the fallback chain, and the messageSource bean-name requirement.

for a senior

Explains MessageFormat quoting, default-message vs exception semantics, and Boot auto-configuration.

for a principal

Frames i18n as an externalization/ops concern; standardizes codes, encoding, and missing-key policy across services.

**What it is.** `org.springframework.context.MessageSource` is Spring's core interface for *internationalization* (i18n) — resolving human-readable text by a symbolic **code** instead of hard-coding strings, so one application can render French, German, etc. based on a **Locale** (`java.util.Locale`). **The three getMessage overloads:** - `getMessage(String code, Object[] args, String defaultMessage, Locale locale)` — returns `defaultMessage` (may be `null`) if the code is not found; never throws. - `getMessage(String code, Object[] args, Locale locale)` — throws `NoSuchMessageException` if the code is missing. - `getMessage(MessageSourceResolvable resolvable, Locale locale)` — resolves an object that carries its own codes/args/default (used by validation errors). **How lookup works.** Messages live in `.properties` files keyed by a **basename** plus a locale suffix: `messages.properties` (default), `messages_fr.properties`, `messages_fr_FR.properties`. For `Locale.FRANCE` Spring tries the most specific file first (`_fr_FR`), then `_fr`, then the base file. Each file holds `code=text` pairs, e.g. `greeting=Hello, {0}!`. **Arguments and placeholders.** When you pass a non-empty `args` array, Spring runs the text through `java.text.MessageFormat`. `{0}` is replaced by `args[0]`, `{1}` by `args[1]`, and typed formats like `{0,number,currency}` or `{0,date,long}` are supported. Gotcha: with args present, a literal single quote must be **doubled** (`''`) because `MessageFormat` treats `'` as an escape. **Wiring.** The `ApplicationContext` *is* a `MessageSource` — but it only works if you register a bean literally named **`messageSource`**; `AbstractApplicationContext` looks that bean up by name during refresh. In Spring Boot, `MessageSourceAutoConfiguration` creates a `ResourceBundleMessageSource` from the `messages` basename automatically (configurable via `spring.messages.*`). You then inject either the `MessageSource` bean or the `ApplicationContext`. **When to use.** Any user-facing text that must vary by language or that you want centralized/externalized: validation messages, emails, UI labels, error responses.

  • What happens if the code isn't found?
    The overload with a defaultMessage returns that default (or null); the overload without one throws NoSuchMessageException. You can also set useCodeAsDefaultMessage=true to return the code itself instead of throwing.
  • Why must the bean be named 'messageSource'?
    AbstractApplicationContext.initMessageSource() looks up a bean by that exact name to back the context's own MessageSource; a differently-named bean is ignored and a DelegatingMessageSource with no parent is used, so lookups fail.

saying these in an interview costs you the question

  • Thinking getMessage always throws when a code is missing (the defaultMessage overload doesn't)
  • Naming the bean anything other than 'messageSource' and expecting it to work
  • Forgetting that placeholders use MessageFormat {0} indexing, not named tokens

context

open as a page

Compare ResourceBundleMessageSource and ReloadableResourceBundleMessageSource. When would you choose one over the other?

level: middleimportance: should knowfreq 45%

basics

~10 s

ResourceBundleMessageSource wraps java.util.ResourceBundle and caches bundles for the JVM's life. ReloadableResourceBundleMessageSource loads via Spring Resources and can re-read files on a timer (cacheSeconds), so you can change messages without a restart.

open as a page

In a Spring MVC web app, how is the Locale for a request determined, and what is the role of LocaleResolver?

level: seniorimportance: should knowfreq 40%

basics

~10 s

A LocaleResolver decides which Locale a request uses. Spring MVC's DispatcherServlet calls it, then MessageSource lookups and LocaleContextHolder use that Locale. The default is AcceptHeaderLocaleResolver, which reads the browser's Accept-Language header.

open as a page

What is MessageSourceResolvable, and how does it connect Spring's validation errors (FieldError/ObjectError) to MessageSource?

level: seniorimportance: should knowfreq 32%

basics

~20 s

MessageSourceResolvable is an object carrying candidate codes, arguments, and a default message. MessageSource tries the codes in order and returns the first that resolves. Validation errors (FieldError, ObjectError) implement it, so getMessage(error, locale) produces localized error text.

open as a page

What are the key production pitfalls with MessageSource around MessageFormat quoting, encoding, missing keys, and the parent hierarchy?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Watch four things: single quotes must be doubled ('') only when a message has arguments; set defaultEncoding to UTF-8; decide missing-key behavior (throw vs default vs useCodeAsDefaultMessage); and set fallbackToSystemLocale=false so missing files fall back to the base bundle, not the server's locale.

open as a page