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 System.Globalization.CultureInfo("de-de"); Thread.CurrentThread.CurrentCulture = new System.Globalization.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