Multi-lingual form validation using MVC DataAnnotation attributes and Sitecore – Part 1 (Custom attributes)

So you wanna use MVC data annotations for form validation in a multi-lingual Sitecore site?

internationalWith Sitecore wrapping a firm grip around MVC, it is important to have a solid validation strategy for your data models.  From home-grown controller action validation to fluent validation (new post coming soon …), there are a variety of ways to tackle it.  Making the site multi-lingual and with client validation adds some layers of complexity.

Much of the functionality has been around since MVC 3.  So, why create a new post about it now?  … as I was working on a time-sensitive project, I wasn’t able to find all of the answers to my translation questions in one (or two or three) spots.  I’m striving to knit all that’s out there together when one questions is asked.

Prerequisites:

In this post, I’ll be providing tips and tricks for using MVC DataAnnotation attributes to decorate your data model properties for validation while writing the error messages in the user’s chosen language using Sitecore.Globalization.Translate.Text().

1) Create your data model with desired DataAnnotation attributes

[DisplayName("Email Address")]
[Required(ErrorMessage = "Email address is required.")]
public string EmailAddress {get; set;}

[DisplayName("Password")]
[MinLength(6, ErrorMessage = "Password must be a minimum of 6 characters.")]
public string Password {get; set;}

[DisplayName("Verify Password")]
[Compare("Password", ErrorMessage = "Verify Password must match Password.")]
public string VerifyPassword {get; set;}

2) Create your form that supports your data model

@using (Html.BeginForm()) {

   @Html.ValidationSummary()
   @Html.LabelFor(x=>x.EmailAddress) 
   @Html.TextBoxFor(x => x.EmailAddress) 
   @Html.ValidationMessageFor(x => x.EmailAddress) 

   @Html.LabelFor(x=>x.Password) 
   @Html.PasswordFor(x => x.Password) 
   @Html.ValidationMessageFor(x => x.Password) 

   @Html.LabelFor(x=>x.VerifyPassword) 
   @Html.PasswordFor(x => x.VerifyPassword) 
   @Html.ValidationMessageFor(x => x.VerifyPassword) 

   @Html.ActionLink("Save", "SaveAction", "MainController")
}

screen1

Nice! Server validation works well, however, we want multi-lingual and the attribute argument (in this case, the ErrorMessage) “must be a constant expression, typeof expression, or array creation expression of an attribute parameter type”. It must be a compile-time constant … Sitecore.Globalization.Translate.Text() or any method cannot be used as a replacement for the string within the attribute argument.

3) Create custom attributes to support translating text for multi-lingual sites. Creating custom attributes provide the ability to override and customize methods of the attribute from which you are inheriting.

public class RequiredTranslated : RequiredAttribute
    {
        public override string FormatErrorMessage(string name)
        {
            return Translate.Text(base.FormatErrorMessage(name));
        }
    }

public class MinLengthTranslated : MinLengthAttribute
    {
        public MinLengthTranslated(int length) : base(length) { }

        public override string FormatErrorMessage(string name)
        {
            return Translate.Text(base.FormatErrorMessage(name));
        }
    }

public class CompareTranslated : CompareAttribute
    {
        public CompareTranslated(string otherProperty) : base(otherProperty) { }

        public override string FormatErrorMessage(string name)
        {
            return Translate.Text(base.FormatErrorMessage(name));
        }
    }

These classes inherit from their ‘non-translated’ equivalents, “Required”, “MinLength”, and “Compare.”

4) Decorate your data model properties with your custom attributes. Please make sure that you swap out the message for a translated key that matches your message from your domain dictionary.

For example, “EmailAddressRequired” is my domain dictionary key for the string, “Email Address is required” (and its various other language versions).

[RequiredTranslated(ErrorMessage = "EmailAddressRequired")]
public string EmailAddress {get; set;}

[MinLengthTranslated(6, ErrorMessage = "PasswordMinLength")]
public string Password {get; set;}

[CompareTranslated("Password", ErrorMessage = "VerifyPasswordInvalid")]
public string VerifyPassword {get; set;}

With this small step of adding custom attributes, you have an easy way to handle multi-lingual server validation.

If you’d like to see how you can use these custom attributes with client validation, see part 2.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s