diff --git a/documentation/src/main/asciidoc/ch12.asciidoc b/documentation/src/main/asciidoc/ch12.asciidoc index 6d6e205f68..6abbddc995 100644 --- a/documentation/src/main/asciidoc/ch12.asciidoc +++ b/documentation/src/main/asciidoc/ch12.asciidoc @@ -51,6 +51,9 @@ Note that when a package is part of the public API this is not necessarily true `org.hibernate.validator.spi.constraintdefinition`:: An SPI for registering additional constraint validators programmatically, see <>. +`org.hibernate.validator.spi.messageinterpolation`:: + An SPI that can be used to tweak the resolution of the locale when interpolating the constraint violation messages. See <>. + `org.hibernate.validator.spi.nodenameprovider`:: An SPI that can be used to alter how the names of properties will be resolved when the property path is constructed. See <>. @@ -443,6 +446,55 @@ error messages from other resource bundles than _ValidationMessages_ while still interpolation algorithm as defined by the specification. Refer to <> to learn how to make use of that SPI. +[[section-locale-resolver]] +=== Customizing the locale resolution + +[WARNING] +==== +These contracts are marked as `@Incubating` so they might be subject to change in the future. +==== + +Hibernate Validator provides several extension points to build a custom locale resolution strategy. +The resolved locale is used when interpolating the constraint violation messages. + +The default behavior of Hibernate Validator is to always use the system default locale (as obtained via `Locale.getDefault()`). +This might not be the desired behavior if, for example, you usually set your system locale to `en-US` but want your application to provide messages in French. + +The following example shows how to set the Hibernate Validator default locale to `fr-FR`: + +[[example-configure-default-locale]] +.Configure the default locale +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/org/hibernate/validator/referenceguide/chapter12/localization/LocalizationTest.java[tags=default-locale] +---- +==== + +While this is already a nice improvement, in a fully internationalized application, this is not sufficient: +you need Hibernate Validator to select the locale depending on the user context. + +Hibernate Validator provides the `org.hibernate.validator.spi.messageinterpolation.LocaleResolver` SPI +which allows to fine-tune the resolution of the locale. +Typically, in a JAX-RS environment, you can resolve the locale to use from the `Accept-Language` HTTP header. + +In the following example, we use a hardcoded value but, for instance, in the case of a RESTEasy application, +you could extract the header from the `ResteasyContext`. + +[[example-locale-resolver]] +.Fine tune the locale used to interpolate the messages via a `LocaleResolver` +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/org/hibernate/validator/referenceguide/chapter12/localization/LocalizationTest.java[tags=locale-resolver] +---- +==== + +[NOTE] +==== +When using the `LocaleResolver`, you have to define the list of supported locales via the `locales()` method. +==== + === Custom contexts The Jakarta Bean Validation specification offers at several points in its API the possibility to unwrap a diff --git a/documentation/src/test/java/org/hibernate/validator/referenceguide/chapter12/localization/LocalizationTest.java b/documentation/src/test/java/org/hibernate/validator/referenceguide/chapter12/localization/LocalizationTest.java new file mode 100644 index 0000000000..76b3edc7a6 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/validator/referenceguide/chapter12/localization/LocalizationTest.java @@ -0,0 +1,75 @@ +package org.hibernate.validator.referenceguide.chapter12.localization; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Locale; +import java.util.Locale.LanguageRange; +import java.util.Set; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.constraints.AssertTrue; + +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.spi.messageinterpolation.LocaleResolver; +import org.hibernate.validator.spi.messageinterpolation.LocaleResolverContext; +import org.junit.Test; + +public class LocalizationTest { + + @Test + public void changeDefaultLocale() { + // tag::default-locale[] + Validator validator = Validation.byProvider( HibernateValidator.class ) + .configure() + .defaultLocale( Locale.FRANCE ) + .buildValidatorFactory() + .getValidator(); + + Set> violations = validator.validate( new Bean() ); + assertEquals( "doit avoir la valeur vrai", violations.iterator().next().getMessage() ); + // end::default-locale[] + } + + @Test + public void localeResolver() { + // tag::locale-resolver[] + LocaleResolver localeResolver = new LocaleResolver() { + + @Override + public Locale resolve(LocaleResolverContext context) { + // get the locales supported by the client from the Accept-Language header + String acceptLanguageHeader = "it-IT;q=0.9,en-US;q=0.7"; + + List acceptedLanguages = LanguageRange.parse( acceptLanguageHeader ); + List resolvedLocales = Locale.filter( acceptedLanguages, context.getSupportedLocales() ); + + if ( resolvedLocales.size() > 0 ) { + return resolvedLocales.get( 0 ); + } + + return context.getDefaultLocale(); + } + }; + + Validator validator = Validation.byProvider( HibernateValidator.class ) + .configure() + .defaultLocale( Locale.FRANCE ) + .locales( Locale.FRANCE, Locale.ITALY, Locale.US ) + .localeResolver( localeResolver ) + .buildValidatorFactory() + .getValidator(); + + Set> violations = validator.validate( new Bean() ); + assertEquals( "deve essere true", violations.iterator().next().getMessage() ); + // end::locale-resolver[] + } + + private static class Bean { + + @AssertTrue + private boolean invalid = false; + } +}