Hi,

I have a need for locale-aware number validation in my app (since Sweden
use comma as decimal-separator instead of dot) and therefor I created my
own DoubleTranslator and FloatTranslator that I contributed to the
TranslatorSource from my module.

Since it would have been nice to also have client validation working in
a locale-aware manner I decided to take it a step further. :-D

Please find attached a patch towards 5.0.19-SNAPSHOT which adds support
for both client- and server-side locale-aware number-validation.

I have the number of decimals fixed to two in the translators since I
need to use it for monetary input. This should be nice to be able to
configure per field in some way.

I have placed the regexp for the client-side validation in the
ValidationMessages.properties-file which might be the wrong place to
have it.

There is probably also a need to look at the regular expressions that
are currently setup to make sure that they are correct for the various
locales.

Best regards,
Joakim

Index: tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java
===================================================================
--- tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java	(revision 733115)
+++ tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClientBehaviorSupportImpl.java	(working copy)
@@ -18,9 +18,12 @@
 import org.apache.tapestry5.Link;
 import org.apache.tapestry5.RenderSupport;
 import org.apache.tapestry5.corelib.data.InsertPosition;
+import org.apache.tapestry5.ioc.Messages;
 import org.apache.tapestry5.ioc.internal.util.Defense;
 import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
+import org.apache.tapestry5.services.PersistentLocale;
+import org.apache.tapestry5.services.ValidationMessagesSource;
 
 public class ClientBehaviorSupportImpl implements ClientBehaviorSupport
 {
@@ -28,9 +31,16 @@
 
     private final JSONObject validations = new JSONObject();
 
-    public ClientBehaviorSupportImpl(RenderSupport renderSupport)
+    private final ValidationMessagesSource validationMessagesSource;
+
+    private final PersistentLocale locale;
+
+    public ClientBehaviorSupportImpl(RenderSupport renderSupport, ValidationMessagesSource validationMessagesSource, PersistentLocale locale)
     {
         this.renderSupport = renderSupport;
+        this.validationMessagesSource = validationMessagesSource;
+        this.locale = locale;
+        
     }
 
     public void addZone(String clientId, String showFunctionName, String updateFunctionName)
@@ -141,5 +151,6 @@
 
             renderSupport.addInit("validate", parameters);
         }
-    }
+        Messages messages = validationMessagesSource.getValidationMessages(locale.get());
+        renderSupport.addInit("localeSpecificFloatRegexp", messages.get("floatRegexp"));    }
 }
Index: tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/FloatTranslator.java
===================================================================
--- tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/FloatTranslator.java	(revision 733115)
+++ tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/FloatTranslator.java	(working copy)
@@ -14,29 +14,40 @@
 
 package org.apache.tapestry5.internal.translator;
 
+import java.text.NumberFormat;
+import java.text.ParseException;
+
 import org.apache.tapestry5.Field;
 import org.apache.tapestry5.ValidationException;
+import org.apache.tapestry5.services.PersistentLocale;
 
 public class FloatTranslator extends DecimalNumberTranslator<Float>
 {
-    public FloatTranslator()
+    private final PersistentLocale locale;
+
+    public FloatTranslator(PersistentLocale locale)
     {
         super("float", Float.class);
+        this.locale = locale;
     }
 
     public String toClient(Float value)
     {
-        return value.toString();
+        NumberFormat formatter = NumberFormat.getNumberInstance(this.locale.get());
+        formatter.setMinimumFractionDigits(2);
+        formatter.setMaximumFractionDigits(2);
+        return formatter.format(value);
     }
 
-    public Float parseClient(Field field, String clientValue, String message)
-            throws ValidationException
+    public Float parseClient(Field field, String clientValue, String message) throws ValidationException
     {
+        NumberFormat formatter = NumberFormat.getNumberInstance(this.locale.get());
+
         try
         {
-            return new Float(clientValue.trim());
+            return formatter.parse(clientValue.trim()).floatValue();
         }
-        catch (NumberFormatException ex)
+        catch (ParseException ex)
         {
             throw new ValidationException(message);
         }
Index: tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/DoubleTranslator.java
===================================================================
--- tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/DoubleTranslator.java	(revision 733115)
+++ tapestry-core/src/main/java/org/apache/tapestry5/internal/translator/DoubleTranslator.java	(working copy)
@@ -14,24 +14,32 @@
 
 package org.apache.tapestry5.internal.translator;
 
+import java.text.NumberFormat;
+import java.text.ParseException;
+
 import org.apache.tapestry5.Field;
 import org.apache.tapestry5.ValidationException;
+import org.apache.tapestry5.services.PersistentLocale;
 
 public class DoubleTranslator extends DecimalNumberTranslator<Double>
 {
-    public DoubleTranslator()
+    private final PersistentLocale locale;
+
+    public DoubleTranslator(PersistentLocale locale)
     {
         super("double", Double.class);
+        this.locale = locale;
     }
 
-    public Double parseClient(Field field, String clientValue, String message)
-            throws ValidationException
+    public Double parseClient(Field field, String clientValue, String message) throws ValidationException
     {
+        NumberFormat formatter = NumberFormat.getNumberInstance(this.locale.get());
+
         try
         {
-            return new Double(clientValue.trim());
+            return formatter.parse(clientValue.trim()).doubleValue();
         }
-        catch (NumberFormatException ex)
+        catch (ParseException ex)
         {
             throw new ValidationException(message);
         }
@@ -39,6 +47,9 @@
 
     public String toClient(Double value)
     {
-        return value.toString();
+        NumberFormat formatter = NumberFormat.getNumberInstance(this.locale.get());
+        formatter.setMinimumFractionDigits(2);
+        formatter.setMaximumFractionDigits(2);
+        return formatter.format(value);
     }
 }
Index: tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
===================================================================
--- tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java	(revision 733115)
+++ tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java	(working copy)
@@ -644,15 +644,15 @@
      * Contributes the basic set of named translators: <ul>  <li>string</li>  <li>byte</li> <li>integer</li>
      * <li>long</li> <li>float</li> <li>double</li> <li>short</li> </ul>
      */
-    public static void contributeTranslatorSource(Configuration<Translator> configuration)
+    public static void contributeTranslatorSource(Configuration<Translator> configuration, PersistentLocale locale)
     {
 
         configuration.add(new StringTranslator());
         configuration.add(new ByteTranslator());
         configuration.add(new IntegerTranslator());
         configuration.add(new LongTranslator());
-        configuration.add(new FloatTranslator());
-        configuration.add(new DoubleTranslator());
+        configuration.add(new FloatTranslator(locale));
+        configuration.add(new DoubleTranslator(locale));
         configuration.add(new ShortTranslator());
     }
 
@@ -1479,6 +1479,8 @@
 
                                          final ValidationMessagesSource validationMessagesSource,
 
+                                         final PersistentLocale  persistentLocale,
+                                         
                                          final SymbolSource symbolSource,
 
                                          final AssetSource assetSource)
@@ -1535,7 +1537,7 @@
             {
                 RenderSupport renderSupport = environment.peekRequired(RenderSupport.class);
 
-                ClientBehaviorSupportImpl clientBehaviorSupport = new ClientBehaviorSupportImpl(renderSupport);
+                ClientBehaviorSupportImpl clientBehaviorSupport = new ClientBehaviorSupportImpl(renderSupport, validationMessagesSource, persistentLocale);
 
                 environment.push(ClientBehaviorSupport.class, clientBehaviorSupport);
 
@@ -1609,7 +1611,9 @@
 
                                                 final AssetSource assetSource,
 
-                                                final ValidationMessagesSource validationMessagesSource)
+                                                final ValidationMessagesSource validationMessagesSource,
+                                                
+                                                final PersistentLocale persistentLocale)
     {
         PartialMarkupRendererFilter documentLinker = new PartialMarkupRendererFilter()
         {
@@ -1659,7 +1663,7 @@
             {
                 RenderSupport renderSupport = environment.peekRequired(RenderSupport.class);
 
-                ClientBehaviorSupportImpl support = new ClientBehaviorSupportImpl(renderSupport);
+                ClientBehaviorSupportImpl support = new ClientBehaviorSupportImpl(renderSupport, validationMessagesSource, persistentLocale);
 
                 environment.push(ClientBehaviorSupport.class, support);
 
Index: tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js	(working copy)
@@ -761,6 +761,11 @@
         });
     },
 
+    localeSpecificFloatRegexp : function(specs)
+    {
+    	Tapestry.Validator.FLOAT_REGEXP = new RegExp(specs);
+    },
+    
     validate : function (field, specs)
     {
         field = $(field);
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_da.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_da.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_da.properties	(working copy)
@@ -28,3 +28,4 @@
 
 # This is where the translator messages go.
 
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ru.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ru.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ru.properties	(working copy)
@@ -28,4 +28,4 @@
 
 # This is where the translator messages go.
 
-
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_PT.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_PT.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_PT.properties	(working copy)
@@ -27,3 +27,4 @@
 
 # This is where the translator messages go.
 
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_de.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_de.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_de.properties	(working copy)
@@ -31,3 +31,4 @@
 integer-format-exception=Sie müssen für %s einen ganzzahligen Wert angeben.
 number-format-exception=Sie müssen für %s einen numerischen Wert angeben.
 
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ja.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ja.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_ja.properties	(working copy)
@@ -31,3 +31,4 @@
 integer-format-exception=%s\u306b\u306f\u6574\u6570\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002
 number-format-exception=%s\u306b\u306f\u6570\u5024\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002
 
+floatRegexp=^(\\+|-)?((\\.\\d+)|(\\d+(\\.\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr_FR.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr_FR.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fr_FR.properties	(working copy)
@@ -28,3 +28,4 @@
 
 # This is where the translator messages go.
 
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_el.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_el.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_el.properties	(working copy)
@@ -31,3 +31,4 @@
 integer-format-exception=\u03a0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b4\u03ce\u03c3\u03b5\u03c4\u03b5 \u03b1\u03ba\u03ad\u03c1\u03b1\u03b9\u03b1 \u03c4\u03b9\u03bc\u03ae \u03b3\u03b9\u03b1 \u03c4\u03bf \u03c0\u03b5\u03b4\u03af\u03bf %s.
 number-format-exception=\u03a0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b4\u03ce\u03c3\u03b5\u03c4\u03b5 \u03b1\u03c1\u03b9\u03b8\u03bc\u03b7\u03c4\u03b9\u03ba\u03ae \u03c4\u03b9\u03bc\u03ae \u03b3\u03b9\u03b1 \u03c4\u03bf \u03c0\u03b5\u03b4\u03af\u03bf %s.
 
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_zh_CN.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_zh_CN.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_zh_CN.properties	(working copy)
@@ -25,3 +25,5 @@
 # as the first parameter, and the field's label as the second parameter. Occasionally
 # we must use specific indexing when that's not the best order.
 required = \u8BF7\u8F93\u5165%s\u7684\u5185\u5BB9\u3002
+
+floatRegexp=^(\\+|-)?((\\.\\d+)|(\\d+(\\.\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_BR.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_BR.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_pt_BR.properties	(working copy)
@@ -30,3 +30,5 @@
 
 integer-format-exception=Você deve fornecer um número inteiro para %s.
 number-format-exception=Você deve fornecer um número para %s.
+
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_es.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_es.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_es.properties	(working copy)
@@ -30,3 +30,5 @@
 
 integer-format-exception='%s' tiene que ser un valor entero.
 number-format-exception='%s' tiene que ser un valor num\u00e9rico.
+
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_hr.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_hr.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_hr.properties	(working copy)
@@ -28,4 +28,4 @@
 
 # This is where the translator messages go.
 
-
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_it.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_it.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_it.properties	(working copy)
@@ -27,3 +27,4 @@
 
 # This is where the translator messages go.
 
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fi_FI.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fi_FI.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_fi_FI.properties	(working copy)
@@ -27,3 +27,5 @@
 invalid-email='%s' ei ole s\u00E4hk\u00F6postiosoite.
 
 # This is where the translator messages go.
+
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_sv_SE.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_sv_SE.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages_sv_SE.properties	(working copy)
@@ -28,3 +28,4 @@
 
 # This is where the translator messages go.
 
+floatRegexp=^(\\+|-)?((,\\d+)|(\\d+(,\\d*)?))$
\ No newline at end of file
Index: tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties
===================================================================
--- tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties	(revision 733115)
+++ tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties	(working copy)
@@ -31,3 +31,4 @@
 integer-format-exception=You must provide an integer value for %s.
 number-format-exception=You must provide a numeric value for %s.
 
+floatRegexp=^(\\+|-)?((\\.\\d+)|(\\d+(\\.\\d*)?))$
\ No newline at end of file

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org

Reply via email to