How to interpolate messages using the client Locale

This is are the pieces needed to do message interpolation in a web application based on the client Locale. This is just a suggestion, there are other solutions.

 

Housekeeping

 

Before we get to the actual validation/interpolation part we need to know how to get to the client locale. If we want to use the Locale provided by the browser one way of going about it is to implement a ServletFilter. In the filter we extract the client Locale and store it in a ThreadLocal.

 

The ThreadLocal:

public class ClientLocaleThreadLocal {

  private static ThreadLocal<Locale> tLocal = new ThreadLocal<Locale>();

  public static void set(Locale locale) {
    tLocal.set(locale);
  }

  public static Locale get() {
    return tLocal.get();
  }

  public static void remove() {
    tLocal.remove();
  }
}

 

We set the ThreadLocal in a filter:

public class TimerFilter implements Filter {

  public void destroy() {
  }

  public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
    try {      ClientLocaleThreadLocal.set(req.getLocale());       
      filterChain.doFilter(req, res);
    }
    finally {
      ClientLocaleThreadLocal.remove();
    }
  }


 public void init(FilterConfig arg0) throws ServletException {
}
}






Custom message interpolator

 

Next we need a custom interpolator which will use the client Locale stored in the ThreadLocal. We can use delegation for this task:

public class ClientLocaleMessageInterpolator implements MessageInterpolator {
  private final MessageInterpolator delegate;

  public ResourceBundleMessageInterpolator2(MessageInterpolator delegate) {
    this.delegate = delegate;
  }

  @Override
  public String interpolate(String message, Context context) {
    return this.interpolate(message, context, ClientLocaleThreadLocal.get());
  }

  @Override
  public String interpolate(String message, Context context, Locale locale)
  {
    return delegate.interpolate(message, context, locale);
  }
}

 

Bootstrapping

 

Last but not least, we have to get Hibernate Validator to use the custom message interpolator. There are multiple ways to do this and it depends on the environment (eg depdency injection framework, etc), but here is how it would be done in code:

Configuration config = Validation.byDefaultProvider().configure();
config = config.messageInterpolator( config.getDefaultMessageInterpolator() );
Validator validator = config.buildValidatorFactory().getValidator();