Author: hardy.ferentschik
Date: 2009-02-06 07:20:43 -0500 (Fri, 06 Feb 2009)
New Revision: 15911
Added:
validator/trunk/hibernate-validator/src/test/resources/ValidationMessages_es.properties
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolator.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolatorTest.java
validator/trunk/hibernate-validator/src/test/resources/org/hibernate/validation/ValidationMessages_de.properties
Log:
BVAL-69 made message interpolation work with locales
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolator.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolator.java 2009-02-06
10:38:22 UTC (rev 15910)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolator.java 2009-02-06
12:20:43 UTC (rev 15911)
@@ -17,6 +17,7 @@
*/
package org.hibernate.validation.engine;
+import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
@@ -45,48 +46,64 @@
* Regular expression used to do message interpolation.
*/
private static final Pattern messagePattern = Pattern.compile(
"\\{([\\w\\.]+)\\}" );
- private ResourceBundle defaultResourceBundle;
- private ResourceBundle userResourceBundle;
+ /**
+ * The default locale for the current user.
+ */
+ private final Locale defaultLocale;
+
+ private final Map<Locale, ResourceBundle> userBundlesMap = new HashMap<Locale,
ResourceBundle>();
+
+ private final Map<Locale, ResourceBundle> defaultBundlesMap = new
HashMap<Locale, ResourceBundle>();
+
public ResourceBundleMessageInterpolator() {
- userResourceBundle = getFileBasedResourceBundle();
- defaultResourceBundle = ResourceBundle.getBundle( DEFAULT_VALIDATION_MESSAGES );
+ this( null );
}
public ResourceBundleMessageInterpolator(ResourceBundle resourceBundle) {
+
+ defaultLocale = Locale.getDefault();
+
if ( resourceBundle == null ) {
- userResourceBundle = getFileBasedResourceBundle();
+ ResourceBundle bundle = getFileBasedResourceBundle( defaultLocale );
+ userBundlesMap.put( defaultLocale, bundle );
+
}
else {
- this.userResourceBundle = resourceBundle;
+ userBundlesMap.put( defaultLocale, resourceBundle );
}
- defaultResourceBundle = ResourceBundle.getBundle( DEFAULT_VALIDATION_MESSAGES );
+
+ defaultBundlesMap.put( defaultLocale, ResourceBundle.getBundle(
DEFAULT_VALIDATION_MESSAGES, defaultLocale ) );
}
public String interpolate(String message, ConstraintDescriptor constraintDescriptor,
Object value) {
// probably no need for caching, but it could be done by parameters since the map
// is immutable and uniquely built per Validation definition, the comparaison has to be
based on == and not equals though
- return replace( message, constraintDescriptor.getParameters() );
+ return replace( message, constraintDescriptor.getParameters(), defaultLocale );
}
public String interpolate(String message, ConstraintDescriptor constraintDescriptor,
Object value, Locale locale) {
- throw new UnsupportedOperationException( "Interpolation for Locale. Has to be
done." );
+ return replace( message, constraintDescriptor.getParameters(), locale );
}
/**
* Search current thread classloader for the resource bundle. If not found, search
validator (this) classloader.
*
+ * @param locale The locale of the bundle to load.
+ *
* @return the resource bundle or <code>null</code> if none is found.
*/
- private ResourceBundle getFileBasedResourceBundle() {
+ private ResourceBundle getFileBasedResourceBundle(Locale locale) {
ResourceBundle rb = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if ( classLoader != null ) {
- rb = loadBundle( classLoader, USER_VALIDATION_MESSAGES + " not found by thread
local classloader" );
+ rb = loadBundle( classLoader, locale, USER_VALIDATION_MESSAGES + " not found by
thread local classloader" );
}
if ( rb == null ) {
rb = loadBundle(
- this.getClass().getClassLoader(), USER_VALIDATION_MESSAGES + " not found by
validator classloader"
+ this.getClass().getClassLoader(),
+ locale,
+ USER_VALIDATION_MESSAGES + " not found by validator classloader"
);
}
if ( log.isDebugEnabled() ) {
@@ -100,10 +117,10 @@
return rb;
}
- private ResourceBundle loadBundle(ClassLoader classLoader, String message) {
+ private ResourceBundle loadBundle(ClassLoader classLoader, Locale locale, String
message) {
ResourceBundle rb = null;
try {
- rb = ResourceBundle.getBundle( USER_VALIDATION_MESSAGES, Locale.getDefault(),
classLoader );
+ rb = ResourceBundle.getBundle( USER_VALIDATION_MESSAGES, locale, classLoader );
}
catch ( MissingResourceException e ) {
log.trace( message );
@@ -111,22 +128,25 @@
return rb;
}
- private String replace(String message, Map<String, Object> parameters) {
+ private String replace(String message, Map<String, Object> parameters, Locale
locale) {
Matcher matcher = messagePattern.matcher( message );
StringBuffer sb = new StringBuffer();
while ( matcher.find() ) {
- matcher.appendReplacement( sb, resolveParameter( matcher.group( 1 ), parameters ) );
+ matcher.appendReplacement( sb, resolveParameter( matcher.group( 1 ), parameters,
locale ) );
}
matcher.appendTail( sb );
return sb.toString();
}
- private String resolveParameter(String token, Map<String, Object> parameters) {
+ private String resolveParameter(String token, Map<String, Object> parameters,
Locale locale) {
Object variable = parameters.get( token );
if ( variable != null ) {
return variable.toString();
}
+ ResourceBundle userResourceBundle = findUserResourceBundle( locale );
+ ResourceBundle defaultResourceBundle = findDefaultResourceBundle( locale );
+
StringBuffer buffer = new StringBuffer();
String string = null;
try {
@@ -146,8 +166,28 @@
}
if ( string != null ) {
// call resolve recusively!
- buffer.append( replace( string, parameters ) );
+ buffer.append( replace( string, parameters, locale ) );
}
return buffer.toString();
}
+
+ private ResourceBundle findDefaultResourceBundle(Locale locale) {
+ if ( defaultBundlesMap.containsKey( locale ) ) {
+ return defaultBundlesMap.get( locale );
+ }
+
+ ResourceBundle bundle = ResourceBundle.getBundle( DEFAULT_VALIDATION_MESSAGES, locale
);
+ defaultBundlesMap.put( locale, bundle );
+ return bundle;
+ }
+
+ private ResourceBundle findUserResourceBundle(Locale locale) {
+ if ( userBundlesMap.containsKey( locale ) ) {
+ return userBundlesMap.get( locale );
+ }
+
+ ResourceBundle bundle = getFileBasedResourceBundle( locale );
+ userBundlesMap.put( locale, bundle );
+ return bundle;
+ }
}
Modified:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolatorTest.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolatorTest.java 2009-02-06
10:38:22 UTC (rev 15910)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validation/engine/ResourceBundleMessageInterpolatorTest.java 2009-02-06
12:20:43 UTC (rev 15911)
@@ -20,6 +20,7 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
@@ -57,7 +58,7 @@
@Test
public void testSuccessfulInterpolation() {
- ConstraintDescriptorImpl descriptor = new ConstraintDescriptorImpl(
+ ConstraintDescriptorImpl<NotNull> descriptor = new
ConstraintDescriptorImpl<NotNull>(
notNull, new Class<?>[] { }, new BuiltinConstraints()
);
@@ -80,7 +81,7 @@
@Test
public void testUnSuccessfulInterpolation() {
- ConstraintDescriptorImpl descriptor = new ConstraintDescriptorImpl(
+ ConstraintDescriptorImpl<NotNull> descriptor = new
ConstraintDescriptorImpl<NotNull>(
notNull, new Class<?>[] { }, new BuiltinConstraints()
);
String expected = "foo"; // missing {}
@@ -94,7 +95,7 @@
@Test
public void testUnkownTokenInterpolation() {
- ConstraintDescriptorImpl descriptor = new ConstraintDescriptorImpl(
+ ConstraintDescriptorImpl<NotNull> descriptor = new
ConstraintDescriptorImpl<NotNull>(
notNull, new Class<?>[] { }, new BuiltinConstraints()
);
String expected = "{bar}"; // unkown token {}
@@ -104,20 +105,60 @@
@Test
public void testDefaultInterpolation() {
- ConstraintDescriptorImpl descriptor = new ConstraintDescriptorImpl(
+ ConstraintDescriptorImpl<NotNull> descriptor = new
ConstraintDescriptorImpl<NotNull>(
notNull, new Class<?>[] { }, new BuiltinConstraints()
);
String expected = "may not be null";
String actual = interpolator.interpolate( notNull.message(), descriptor, null );
assertEquals( "Wrong substitution", expected, actual );
- descriptor = new ConstraintDescriptorImpl( size, new Class<?>[] { }, new
BuiltinConstraints() );
+ ConstraintDescriptorImpl<Size> sizeDescriptor = new
ConstraintDescriptorImpl<Size>(
+ size, new Class<?>[] { }, new BuiltinConstraints()
+ );
expected = "size must be between -2147483648 and 2147483647"; // unkown
token {}
- actual = interpolator.interpolate( size.message(), descriptor, null );
+ actual = interpolator.interpolate( size.message(), sizeDescriptor, null );
assertEquals( "Wrong substitution", expected, actual );
}
+ @Test
+ public void testMessageInterpolationWithLocale() {
+ interpolator = new ResourceBundleMessageInterpolator();
+ ConstraintDescriptorImpl<NotNull> descriptor = new
ConstraintDescriptorImpl<NotNull>(
+ notNull, new Class<?>[] { }, new BuiltinConstraints()
+ );
+
+ String expected = "kann nicht null sein";
+ String actual = interpolator.interpolate( notNull.message(), descriptor, null,
Locale.GERMAN );
+ assertEquals( "Wrong substitution", expected, actual );
+ }
+
+ @Test
+ public void testFallbackToDefaultLocale() {
+ interpolator = new ResourceBundleMessageInterpolator();
+
+ ConstraintDescriptorImpl<NotNull> descriptor = new
ConstraintDescriptorImpl<NotNull>(
+ notNull, new Class<?>[] { }, new BuiltinConstraints()
+ );
+
+ String expected = "may not be null";
+ String actual = interpolator.interpolate( notNull.message(), descriptor, null,
Locale.JAPAN );
+ assertEquals( "Wrong substitution", expected, actual );
+ }
+
+ @Test
+ public void testUserResourceBundle() {
+ interpolator = new ResourceBundleMessageInterpolator();
+
+ ConstraintDescriptorImpl<NotNull> descriptor = new
ConstraintDescriptorImpl<NotNull>(
+ notNull, new Class<?>[] { }, new BuiltinConstraints()
+ );
+
+ String expected = "no puede ser null";
+ String actual = interpolator.interpolate( notNull.message(), descriptor, null, new
Locale( "es", "ES" ) );
+ assertEquals( "Wrong substitution", expected, actual );
+ }
+
class TestResources extends ResourceBundle implements Enumeration<String> {
private Map<String, String> testResources;
Iterator<String> iter;
Added:
validator/trunk/hibernate-validator/src/test/resources/ValidationMessages_es.properties
===================================================================
---
validator/trunk/hibernate-validator/src/test/resources/ValidationMessages_es.properties
(rev 0)
+++
validator/trunk/hibernate-validator/src/test/resources/ValidationMessages_es.properties 2009-02-06
12:20:43 UTC (rev 15911)
@@ -0,0 +1 @@
+validator.notNull=no puede ser null
\ No newline at end of file
Modified:
validator/trunk/hibernate-validator/src/test/resources/org/hibernate/validation/ValidationMessages_de.properties
===================================================================
---
validator/trunk/hibernate-validator/src/test/resources/org/hibernate/validation/ValidationMessages_de.properties 2009-02-06
10:38:22 UTC (rev 15910)
+++
validator/trunk/hibernate-validator/src/test/resources/org/hibernate/validation/ValidationMessages_de.properties 2009-02-06
12:20:43 UTC (rev 15911)
@@ -1,11 +1,2 @@
# $Id: ValidationMessages.properties 15846 2009-02-02 11:56:15Z hardy.ferentschik $
-validator.notNull=may not be null
-validator.size=size must be between {min} and {max}
-validator.length=length must be between {min} and {max}
-validator.notEmpty=may not be empty
-validator.pattern=must match "{regex}"
-validator.min=must be greater than {value}
-validator.max=must be less than {value}
-validator.null=must be null
-validator.past=must be in the past
-validator.future=must be in the future
+validator.notNull=kann nicht null sein