@Configuration
public class I18nConfig {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
ms.setBasenames("messages", "errors");
ms.setDefaultEncoding("UTF-8");
ms.setFallbackToSystemLocale(false);
ms.setCacheSeconds(3600); // Cache for 1 hour
return ms;
}
// Reloadable version for development
@Bean
public MessageSource reloadableMessageSource() {
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
ms.setBasenames("classpath:messages", "file:/etc/app/messages");
ms.setDefaultEncoding("UTF-8");
ms.setCacheSeconds(60); // Reload every minute
return ms;
}
}# messages.properties (default)
greeting.message=Welcome
user.created=User {0} created successfully
order.total=Order total: {0,number,currency}
event.date=Event on {0,date,long}
# messages_fr.properties
greeting.message=Bienvenue
user.created=Utilisateur {0} créé avec succès
order.total=Total de la commande: {0,number,currency}
event.date=Événement le {0,date,long}
# messages_de.properties
greeting.message=Willkommen
user.created=Benutzer {0} erfolgreich erstellt
order.total=Bestellsumme: {0,number,currency}
event.date=Ereignis am {0,date,long}@Service
public class UserService {
@Autowired
private MessageSource messageSource;
public String createUser(String username, Locale locale) {
// Simple message
String msg = messageSource.getMessage("user.created",
new Object[]{username}, locale);
// With default
String msg2 = messageSource.getMessage("user.welcome",
new Object[]{username}, "Welcome!", locale);
// MessageSourceResolvable
MessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(
new String[]{"user.created", "default.message"},
new Object[]{username},
"User created"
);
String msg3 = messageSource.getMessage(resolvable, locale);
return msg;
}
}@Service
public class NotificationService implements MessageSourceAware {
private MessageSourceAccessor messages;
@Override
public void setMessageSource(MessageSource messageSource) {
this.messages = new MessageSourceAccessor(messageSource, Locale.ENGLISH);
}
public void sendNotification(String username) {
// Simplified access without Locale parameter
String greeting = messages.getMessage("greeting.message");
String userMsg = messages.getMessage("user.created", new Object[]{username});
// With default message
String custom = messages.getMessage("custom.key",
new Object[]{username}, "Default message");
}
}@Component
public class LocaleService {
public void processWithLocale() {
// Get current locale
Locale locale = LocaleContextHolder.getLocale();
// Set locale for current thread
LocaleContextHolder.setLocale(Locale.FRENCH);
try {
// Operations use French locale
doSomething();
} finally {
// Reset locale
LocaleContextHolder.resetLocaleContext();
}
// With timezone
LocaleContextHolder.setLocaleContext(
new TimeZoneAwareLocaleContext() {
@Override
public Locale getLocale() {
return Locale.GERMAN;
}
@Override
public TimeZone getTimeZone() {
return TimeZone.getTimeZone("Europe/Berlin");
}
}
);
}
}@Configuration
public class HierarchicalConfig {
@Bean
public MessageSource parentMessageSource() {
ResourceBundleMessageSource parent = new ResourceBundleMessageSource();
parent.setBasenames("common-messages");
parent.setDefaultEncoding("UTF-8");
return parent;
}
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource child = new ResourceBundleMessageSource();
child.setBasenames("app-messages");
child.setDefaultEncoding("UTF-8");
child.setParentMessageSource(parentMessageSource());
return child;
}
}@Service
public class FormattingService {
@Autowired
private MessageSource messageSource;
public void formattedMessages(Locale locale) {
// Number formatting
String total = messageSource.getMessage("order.total",
new Object[]{new BigDecimal("99.99")}, locale);
// Result: "Order total: $99.99" (US) or "Total: 99,99 €" (FR)
// Date formatting
String event = messageSource.getMessage("event.date",
new Object[]{LocalDate.now()}, locale);
// Result: "Event on January 15, 2024" (US) or "Événement le 15 janvier 2024" (FR)
// Choice formatting
// messages.properties: files.count={0,choice,0#no files|1#one file|1<{0,number,integer} files}
String filesMsg = messageSource.getMessage("files.count",
new Object[]{5}, locale);
// Result: "5 files"
}
}@Configuration
public class ValidationI18nConfig {
@Bean
public LocalValidatorFactoryBean validator(MessageSource messageSource) {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource);
return validator;
}
}
// ValidationMessages.properties
javax.validation.constraints.NotNull.message=Field {0} must not be null
javax.validation.constraints.Size.message=Field {0} must be between {min} and {max} characters
public class User {
@NotNull
@Size(min = 2, max = 50)
private String username;
}