6

I made an application with hibernate and use annotations to do the validation. I realized that to translate the message into my language I have to put in the resources folder a file called ValidationMessage_xx.properties. The problem is that what should be the default language but I have to give visitors the option to change the language of the website and thus also that of the validation

This is code of class where I use validator:

    class Example {
    
            @NotEmpty
            private String fieldOne;
            @NotEmpty
            private String fieldTwo;
            
            public String getFieldOne(){
                return fieldOne;
            }
            
            public void setFieldOne(String fieldOne){
                this.fieldOne = fieldOne
            }
            
            ....
        }

SternK
  • 11,649
  • 22
  • 32
  • 46
ciro
  • 771
  • 1
  • 8
  • 30

2 Answers2

3

The default locale ( e.g. ValidationMessage.properties ) can be any language you want it to be, this is entirely application specific. Because I speak English, I tend to prefer making that file contain English based translations and I extend to other languages as needed.

As for selecting the appropriate locale choice, you will need to provide a way of passing that value downstream from your application tier to the validation framework.

For example, your application could setup a thread local variable or use LocalContextHolder if you're using spring, that will allow you to set a thread specific Locale that you can access statically downstream in code.

In my past experience, we typically have a single resource bundle that we want to use in bean validation that is shared with the controllers and services. We provide bean validation a resolver implementation that loads that resource bundle based on the thread local variable and exposes internationalization messages this way.

A provided example:

// This class uses spring's LocaleContextHolder class to access the requested
// application Locale instead a ThreadLocal variable.  See spring's javadocs
// for details on how to use LocaleContextHolder.
public class ContextualMessageInterpolator 
   extends ResourceBundleMessageInterpolator {
  private static final String BUNDLE_NAME = "applicationMessages";

  @Override
  public ContextualMessageInterpolator() {
    super( new PlatformResourceBundleLocator( BUNDLE_NAME ) );
  }

  @Override
  public String interpolate(String template, Context context) {
    return super.interpolate( template, context, LocaleContextHolder.getLocale() );
  }

  @Override
  public String interpolate(String template, Context context, Locale locale) {
    return super.interpolate( template, context, LocaleContextHolder.getLocale() );
  }
}

The next step is you need to provide the ContextualMessageInterpolator instance to Hibernate Validator. This can be done by createing a validation.xml and placing in META-INF under the root of the classpath. In a web application, this would be WEB-INF/classes/META-INF.

<validation-config
    xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration"
    version="1.1">
  <message-interpolator>com.company.ContextualMessageInterpolator</message-interpolator>
</validation-config>

Since I used applicationMessages as my bundle name, just create a default applicationMessages.properties file and subsequent locale-specific versions and add your validation message strings to those property files.

javax.validation.constraints.NotNull.message=Field must not be empty.
javax.validation.constraints.Max.message=Field must be less-than or equal-to {value}.
javax.validation.constraints.Min.message=Field must be greater-than or equal-to {value}.

Hope that helps.

Naros
  • 19,928
  • 3
  • 41
  • 71
  • please can you add link to example? i have a class with private field and getter and setter. I apply constraints to field. How i set locale? I edit my question and add simple class. thanks – ciro Aug 07 '16 at 09:27
0

You can use the Accept-Language header to change the validation language. To do so, you need to implement LocaleResolver. A good example of how to do it is available here.

If you are using JAX-RS, you can also refer to this code sample:

@POST
@Path("example")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Map<String, String> setExample(Example example,
                                      @HeaderParam("Accept-Language") String acceptLanguage) {
    var validator = Validation
            .byDefaultProvider()
            .configure()
            .messageInterpolator(new ParameterMessageInterpolator(Set.of(Locale.FRANCE, Locale.ITALY, Locale.US), // supported locales
                    Locale.FRANCE, // default locale
                    context -> {
                        if (Objects.nonNull(acceptLanguage)) {
                            var acceptedLanguages = Locale.LanguageRange.parse(acceptLanguage);
                            var resolvedLocales = Locale.filter(acceptedLanguages, context.getSupportedLocales());
                            if (resolvedLocales.size() > 0) {
                                return resolvedLocales.get(0);
                            }
                        }
                        return context.getDefaultLocale();
                    }, false))
            .buildValidatorFactory()
            .getValidator();
    var violations = validator.validate(example);
    Map<String, String> violationsMap = new LinkedHashMap<>();
    for (var violation : violations)
        violationsMap.put(violation.getPropertyPath().toString(), violation.getMessage());
    return violationsMap;
}
sbrajchuk
  • 48
  • 6