« Flex is a CODiE Award Finalist | Main | ColdFusion MX 7 is available »
January 21, 2005
Localizing Validator Errors
A common request I've seen is a way to localize the Validator error messages. Unfortunately the built-in Validator classes don't make that easy in their current state (something we're hoping to work on in the next version). In the meantime, here is one approach (and I'm sure there are more if you wanted) to changing the error messages using some form of resource file.
First we need a resouce file, I'm gonna format mine to be as close to the validator names as possible:
validatorStrings.xml <validators>
<StringValidator>
<tooLongError>Localized too long</tooLongError>
<tooShortError>Localized too short</tooShortError>
</StringValidator>
</validators>
Note that the validators is just an outer tag to make this valid XML. Inside I would put one tag for every validator. Here I just did StringValidator, but you can imagine a NumberValidator tag sitting right underneath it. Inside the StringValidator tag I put an entry for each error message, the name of the tag is the error name and the body of the tag is the actual value.
Now we need this resource loaded, so I'm just gonna use an HTTPService to do that, then I'm going to store the result in a Model that will be accessible from anywhere.
app.mxml <mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" xmlns="*" initialize="validatorStringsSvc.send()"> <mx:HTTPService id="validatorStringsSvc" url="validatorStrings.xml" />
<mx:Model id="validatorStrings">
{validatorStringsSvc.result.validators}
</mx:Model>
Now we need a Validator to actually use this resource.
StringValidator.as class StringValidator extends mx.validators.StringValidator { private var stringsCopied : Boolean = false; private function copyStrings() : Void { //if for some reason the HTTPService is slow to load this may need to re-execute, hence the extra checks and repeated calls if (!stringsCopied) { var strings : Object = mx.core.Application.application.validatorStrings.StringValidator; if (strings != null) { for (var i in strings) { this[i] = strings[i]; } stringsCopied = true; } } } public function doValidation(value) : Void { copyStrings(); super.doValidation(value); } }
You could basically copy this code and do it for any validator that already exists. I'm sure there is a better way to optimize the copyStrings approach to avoid the repetitive calls (for example you could put the if check in the doValidation method so you pay the price of a compare instead of a function call and THEN a compare), but I think it's not a big deal.
And now finally, how do you use this lovely new Validator? Just use the normal validator tag and change the namespace to point to your local version.
TADA!
The story of why Validators are architected in such a way that this is difficult is a story for another time :-)
Posted by mchotin at January 21, 2005 04:31 PM
Comments
Thanks Matt,
wow - quick solution
thats good support !
I wish you luck with binding 2 validators in flex2.0
;-)
Posted by: stephan at January 22, 2005 10:08 AM
shouldn't it be more appropriate to embed xml file?
I realize we will need to re-compile the app each time we change xml file but i doubt there is any need to change it frequently.
Posted by: Alex at January 23, 2005 11:26 PM
We have separated the localized text into an XML-based resource file. This file is loaded once the flex app is initialized. The app knows which locale specific XML file to load from a flashvar set in the query string (i.e. Index.mxml?locale=en_US). This way the flex app does not need to be recompiled when the XML file or the locale changes.
Posted by: David Ringley at January 24, 2005 07:27 AM