Skip to content

Commit 582db15

Browse files
committed
HV-1748 HV-1749 Add some documentation about the localization support
1 parent c4dfc46 commit 582db15

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

documentation/src/main/asciidoc/ch12.asciidoc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ Note that when a package is part of the public API this is not necessarily true
5151
`org.hibernate.validator.spi.constraintdefinition`::
5252
An SPI for registering additional constraint validators programmatically, see <<section-constraint-definition-contribution>>.
5353

54+
`org.hibernate.validator.spi.messageinterpolation`::
55+
An SPI that can be used to tweak the resolution of the locale when interpolating the constraint violation messages. See <<section-locale-resolver>>.
56+
5457
`org.hibernate.validator.spi.nodenameprovider`::
5558
An SPI that can be used to alter how the names of properties will be resolved when the property path is constructed. See <<section-property-node-name-provider>>.
5659

@@ -443,6 +446,55 @@ error messages from other resource bundles than _ValidationMessages_ while still
443446
interpolation algorithm as defined by the specification. Refer to
444447
<<section-resource-bundle-locator>> to learn how to make use of that SPI.
445448

449+
[[section-locale-resolver]]
450+
=== Customizing the locale resolution
451+
452+
[WARNING]
453+
====
454+
These contracts are marked as `@Incubating` so they might be subject to change in the future.
455+
====
456+
457+
Hibernate Validator provides several extension points to build a custom locale resolution strategy.
458+
The resolved locale is used when interpolating the constraint violation messages.
459+
460+
The default behavior of Hibernate Validator is to always use the system default locale (as obtained via `Locale.getDefault()`).
461+
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.
462+
463+
The following example shows how to set the Hibernate Validator default locale to `fr-FR`:
464+
465+
[[example-configure-default-locale]]
466+
.Configure the default locale
467+
====
468+
[source, JAVA, indent=0]
469+
----
470+
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter12/localization/LocalizationTest.java[tags=default-locale]
471+
----
472+
====
473+
474+
While this is already a nice improvement, in a fully internationalized application, this is not sufficient:
475+
you need Hibernate Validator to select the locale depending on the user context.
476+
477+
Hibernate Validator provides the `org.hibernate.validator.spi.messageinterpolation.LocaleResolver` SPI
478+
which allows to fine-tune the resolution of the locale.
479+
Typically, in a JAX-RS environment, you can resolve the locale to use from the `Accept-Language` HTTP header.
480+
481+
In the following example, we use a hardcoded value but, for instance, in the case of a RESTEasy application,
482+
you could extract the header from the `ResteasyContext`.
483+
484+
[[example-locale-resolver]]
485+
.Fine tune the locale used to interpolate the messages via a `LocaleResolver`
486+
====
487+
[source, JAVA, indent=0]
488+
----
489+
include::{sourcedir}/org/hibernate/validator/referenceguide/chapter12/localization/LocalizationTest.java[tags=locale-resolver]
490+
----
491+
====
492+
493+
[NOTE]
494+
====
495+
When using the `LocaleResolver`, you have to define the list of supported locales via the `locales()` method.
496+
====
497+
446498
=== Custom contexts
447499

448500
The Jakarta Bean Validation specification offers at several points in its API the possibility to unwrap a
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package org.hibernate.validator.referenceguide.chapter12.localization;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import java.util.List;
6+
import java.util.Locale;
7+
import java.util.Locale.LanguageRange;
8+
import java.util.Set;
9+
10+
import javax.validation.ConstraintViolation;
11+
import javax.validation.Validation;
12+
import javax.validation.Validator;
13+
import javax.validation.constraints.AssertTrue;
14+
15+
import org.hibernate.validator.HibernateValidator;
16+
import org.hibernate.validator.spi.messageinterpolation.LocaleResolver;
17+
import org.hibernate.validator.spi.messageinterpolation.LocaleResolverContext;
18+
import org.junit.Test;
19+
20+
public class LocalizationTest {
21+
22+
@Test
23+
public void changeDefaultLocale() {
24+
// tag::default-locale[]
25+
Validator validator = Validation.byProvider( HibernateValidator.class )
26+
.configure()
27+
.defaultLocale( Locale.FRANCE )
28+
.buildValidatorFactory()
29+
.getValidator();
30+
31+
Set<ConstraintViolation<Bean>> violations = validator.validate( new Bean() );
32+
assertEquals( "doit avoir la valeur vrai", violations.iterator().next().getMessage() );
33+
// end::default-locale[]
34+
}
35+
36+
@Test
37+
public void localeResolver() {
38+
// tag::locale-resolver[]
39+
LocaleResolver localeResolver = new LocaleResolver() {
40+
41+
@Override
42+
public Locale resolve(LocaleResolverContext context) {
43+
// get the locales supported by the client from the Accept-Language header
44+
String acceptLanguageHeader = "it-IT;q=0.9,en-US;q=0.7";
45+
46+
List<LanguageRange> acceptedLanguages = LanguageRange.parse( acceptLanguageHeader );
47+
List<Locale> resolvedLocales = Locale.filter( acceptedLanguages, context.getSupportedLocales() );
48+
49+
if ( resolvedLocales.size() > 0 ) {
50+
return resolvedLocales.get( 0 );
51+
}
52+
53+
return context.getDefaultLocale();
54+
}
55+
};
56+
57+
Validator validator = Validation.byProvider( HibernateValidator.class )
58+
.configure()
59+
.defaultLocale( Locale.FRANCE )
60+
.locales( Locale.FRANCE, Locale.ITALY, Locale.US )
61+
.localeResolver( localeResolver )
62+
.buildValidatorFactory()
63+
.getValidator();
64+
65+
Set<ConstraintViolation<Bean>> violations = validator.validate( new Bean() );
66+
assertEquals( "deve essere true", violations.iterator().next().getMessage() );
67+
// end::locale-resolver[]
68+
}
69+
70+
private static class Bean {
71+
72+
@AssertTrue
73+
private boolean invalid = false;
74+
}
75+
}

0 commit comments

Comments
 (0)