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