Files

4.9 KiB

i18n

Companion project for the article Internationalization (i18n) in Spring Boot 4: MessageSource, LocaleResolver and Localized ProblemDetail on ankurm.com.

One small web application that answers in English, Marathi and Hindi, plus the test suite that starts it on a real port and records what it says. Every console block quoted in the article came out of output/. Transcripts 01-11 are written by the test suite (so a claim that stops being true turns the build red); 12 is read out of the Spring Boot jar by scripts/capture-facts.sh.

There is deliberately no docs/ folder: the deeper material lives in collapsible "going deeper" sections inside the article itself, next to the paragraph each one extends.

Versions

Spring Boot 4.1.1
Spring Framework 7.0.9
JDK 25 (Temurin 25.0.4.1+1)
Maven 3.9

Quickstart

export JAVA_HOME=/path/to/jdk-25
mvn test                  # runs every scenario and rewrites output/01-11
./scripts/run-all.sh      # everything, including 12 (needs python3)

The tests pin the JVM to -Duser.language=en -Duser.country=US -Dfile.encoding=UTF-8 (see pom.xml) so the transcripts do not depend on the machine they were generated on, and run each test class in its own JVM (reuseForks=false) because a test that changes the JVM's default locale once leaked it into another test's transcript.

Profiles

Profile What it turns on
(none) Spring Boot's defaults: AcceptHeaderLocaleResolver, basename messages, UTF-8
cookie CookieLocaleResolver("lang") named localeResolver, plus a LocaleChangeInterceptor for ?lang=
cookiewrongname the same resolver under the bean name cookieLocaleResolver, which Spring MVC ignores
interceptoronly the LocaleChangeInterceptor with Spring Boot's default resolver

Endpoints

Endpoint What it shows
GET /api/greeting?name= MessageSource with a Locale controller argument
GET /api/cart?items= a number formatted by MessageFormat in the request locale
GET /api/cart-latin?items= the same sentence with the number pre-formatted as text
GET /api/orders/{id} ErrorResponseException: problemDetail.* keys translate it automatically
POST /api/customers Bean Validation messages and a localized MethodArgumentNotValidException
GET /api/pay an ordinary exception translated in the @ExceptionHandler
GET /api/legacy an ordinary exception whose handler hard-codes English

Source layout

Path What it holds
src/main/resources/messages*.properties English, Marathi (_mr) and Hindi (_hi), UTF-8
web/ShopController the endpoints above
web/CustomerRequest Bean Validation with {message.key} placeholders
web/OrderNotFoundException an ErrorResponseException with a message-code argument
web/ApiExceptionHandler ResponseEntityExceptionHandler subclass
config/LocaleConfig one nested configuration per profile
src/test/.../LocaleResolutionTests transcripts 01, 03, 11
src/test/.../SystemLocaleFallbackTests transcript 02 (own JVM)
src/test/.../MessagesTests transcripts 04-07 and 10
src/test/.../ProblemDetailTests transcripts 08, 09

Index of captured output

File Written by What it shows
01-accept-language.txt LocaleResolutionTests which locale each Accept-Language header resolves to, and what a missing header gives
02-fallback-to-system-locale.txt SystemLocaleFallbackTests a French or English request served in Hindi because the JVM default is Hindi
03-cookie-locale-resolver.txt LocaleResolutionTests ?lang=mr, the Set-Cookie, the cookie honoured later; and the two wiring mistakes
04-messageformat-apostrophes.txt MessagesTests '' vs ', with and without arguments
05-devanagari-digits.txt MessagesTests Marathi renders 1234567 in Devanagari digits, Hindi does not; two ways to keep Latin digits
06-missing-keys.txt MessagesTests a key present only in English, and a key present nowhere
07-properties-encoding.txt MessagesTests the same file read as UTF-8 and as ISO-8859-1
08-validation-messages.txt ProblemDetailTests a 400 in four languages, validation messages and all
09-problemdetail-localized.txt ProblemDetailTests three kinds of exception, translated or not
10-always-use-message-format.txt MessagesTests the apostrophe lookups with spring.messages.always-use-message-format=true
11-spring-web-locale.txt LocaleResolutionTests spring.web.locale and spring.web.locale-resolver=fixed
12-configuration-metadata.txt capture-facts.sh every spring.messages.* and spring.web.locale* property, type and default