Project Description

Simplified DataAnnotations localization using T4 templates.


Localizaed Data Anotations

The main purpose of this Project is to simplify the localization of DataAnnotations driven messages.

For more information see:
Getting started

When using the localization possibilities provided by DataAnnotations out of the box, I notice that the mapping to the localized resources is not very simple. Moreover it's untyped and if done in this way it is unsafe.

public class Person  
    {
        [Display(Name = "FirstName", ResourceType=typeof(DisplayNames))]
        [Required()]
        public string FirstName { get; set; }

        [Display(Name = "LastName", ResourceType = typeof(DisplayNames))]
        [Required]
        public string LastName { get; set; }

        [Display(Name = "Phone", ResourceType = typeof(DisplayNames))]
        public string Phone { get; set; }

        [Display(Name = "Address", ResourceType = typeof(DisplayNames))]
        [MaxLength(30)]
        public string Address { get; set; }



It's getting much more “dirty”, if you need to provide a custom localized message for ValidationAttributes.

 public class Person  
    {
        [Display(Name = "FirstName", ResourceType=typeof(DisplayNames))]
        [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorMessages))]
        public string FirstName { get; set; }

        [Display(Name = "LastName", ResourceType = typeof(DisplayNames))]
        [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(ErrorMessages))]
        public string LastName { get; set; }

        [Display(Name = "Phone", ResourceType = typeof(DisplayNames))]
        public string Phone { get; set; }

        [Display(Name = "Address", ResourceType = typeof(DisplayNames))]
        [Required(ErrorMessageResourceName = "MaxLength", ErrorMessageResourceType = typeof(ErrorMessages))]
        public string Address { get; set; }



The main Idea behind current project is to use T4 templates for generating resource constants based on the resx resource files. Another aspect is setting default ResourceType in a single place, for example in the Application_Start().

Using this approach you can apply localized DataAnnotations in a very simple way using typed constants and still profit from the full localization flexibility.

Example class:

public class Person  
{
        [Display(Name = DisplayNames.Keys.FirstName)]
        [Required()]
        public string FirstName { get; set; }

        [Display(Name = DisplayNames.Keys.LastName)]
        [Required]
        public string LastName { get; set; }

        [Display(Name = DisplayNames.Keys.Phone)]
        public string Phone { get; set; }

        [Display(Name = DisplayNames.Keys.Address)]
        [MaxLength(30)]
        public string Address { get; set; }


Initialization example:

protected void Application_Start()
{

DataAnnotationsLocalizer.SetDefaultResourceType(typeof(Person).Assembly, typeof(DisplayNames), 
typeof(DisplayAttribute));

DataAnnotationsLocalizer.ReplaceDefaultLocalizedMessage<RequiredAttribute>(
    typeof(Person).Assembly, typeof(Person).Namespace, 
    typeof(ErrorMessages), ErrorMessages.Keys.RequiredMessage);
DataAnnotationsLocalizer.ReplaceDefaultLocalizedMessage<MaxLengthAttribute>(
    typeof(Person).Assembly, typeof(Person).Namespace, 
    typeof(ErrorMessages), ErrorMessages.Keys.MaxLengthMessage);



The provides solution can be well used in both MVC and non-MVC scenario, for example behind a WCF service to return localized model validation messages:

Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-de");
Thread.CurrentThread.CurrentCulture = new CultureInfo("de-de");

Person p = new Person {  };

List<ValidationResult> res = new List<ValidationResult>();
Validator.TryValidateObject(p, new ValidationContext(p, null, null), res, true);

foreach (var item in res)
{
          Console.WriteLine(item.ErrorMessage);
}


For more information see:
Getting started



Last edited Sep 4, 2012 at 8:11 AM by Andruha, version 18