4

How can I i18n a spring @RestController property on javax.validation constraints?

I thought I could just add /src/main/resources/messages.properties and messages_de.properties, and then spring would detect them and enable proper i18n? But that seems not to be the case:

@RestController
public void TestController {
       @PostMapping
       public void post(@Valid @RequestBody Person p) {
       }
}

public class Person {
       private String firstname;

       @javax.validation.constraints.NotBlank(message = "{errors.person.lastname}")
       private String lastname;
}

messages.properties:
errors.person.lastname=person should provide a lastname

messages_de.properties:
errors.person.lastname=Person ohne Nachnamen

Problem: if I now send a POST request:

{
    "exception": "org.springframework.web.bind.MethodArgumentNotValidException",
    "message": "'lastname': {errors.person.lastname}"
}

Question 1: do I really have to tell spring explicit to apply i18n as follows? Or can I somehow rely on auto-detect features?

Next step was adding the following configuration. Now the default message is resolved properly. But is it necessary to really add this whenever I want to have validation i18n?

@Configuration
public class MessageSourceConfig {
    @Bean
    public LocalValidatorFactoryBean localValidatorFactoryBean() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setValidationMessageSource(messageSource());
        return bean;
    }

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource bundle = new ResourceBundleMessageSource();
        bundle.setBasenames("messages");
        return bundle;
    }
}

Question 2: I those beans are required: how can I now send a post request to switch the language? I tried adding get-query parameters like ?local=de, locale=de, ?lang=de, language=de, but none of them worked...

membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • 3
    Spring Boot autoconfigures the `MessageSource` it doesn't however integrate automatically with the `LocalValidatorFactoryBean`. For changing the locale you need to configure a `LocaleResolver` which allows this (default configured is the `AcceptHeaderLocaleResolver` which doens't allow changing the `Locale`. And you need to properly configure the `LocaleChangeInterceptor`. – M. Deinum Mar 18 '19 at 11:46
  • Ok I see, so having a http header `Accept-Language=de` would be fine too. But why do I still need the `LocalValidatorFactoryBean` and `MessageSource` then? Can't spring autodetect my bundles for `javax.validation`? – membersound Mar 18 '19 at 11:47
  • 1
    The bundles are the default Spring `MessageSource` bundles, Spring Boot already autoconfigures the `MessageSource` BUT (as stated earlier) doesn't bind that to the `LocalValidatorFactory`. – M. Deinum Mar 18 '19 at 11:49
  • One more question: can I tell spring to initialize the default `MessageSource` with `fallbackToSystemLocale=false`? Or would I then have to create my own `@Bean` configuration overriding the default message source? – membersound Mar 18 '19 at 11:52
  • 1
    I suggest a read of the Spring Boot Reference g uide. Especially the [appendix](https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html), hint look for `spring.messages`. – M. Deinum Mar 18 '19 at 12:28

1 Answers1

5

With the help of @M. Deinum above, this is the missing peace:

    @Bean
    public LocalValidatorFactoryBean localValidatorFactoryBean(MessageSource messageSource) {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setValidationMessageSource(messageSource);
        return bean;
    }

Then having to send a web request with http header Accept-Language=de.

membersound
  • 81,582
  • 193
  • 585
  • 1,120