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: [email protected]
For additional commands, e-mail: [email protected]