Better support for localization in ASP.NET.

If you’ve tried the built in localization features in ASP.NET you’ll probably written cluttered view models like:

 public class UserViewModel
{
    [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    [LocalizedDisplayName(ErrorMessageResourceName = "UserId", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    [LocalizedDescription(ErrorMessageResourceName = "UserIdDescription", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    public int Id { get; set; }

    [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    [LocalizedDisplayName(ErrorMessageResourceName = "UserFirstName", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    [LocalizedDescription(ErrorMessageResourceName = "UserFirstNameDescription", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    public string FirstName { get; set; }

    [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    [LocalizedDisplayName(ErrorMessageResourceName = "UserLastName", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    [LocalizedDescription(ErrorMessageResourceName = "UserLastNameDescription", ErrorMessageResourceType = typeof(Resources.LocalizedStrings))]
    public string LastName { get; set; }
}

I’ve solved that with my Griffin.MvcContrib project. But the solution is more of an hack than a solid approach.

The problem is really that there is no way to inject your own custom strings into the localization process of the DataAnnotation attributes. They use their own string tables (resource files) and that’s it. Well, unless you use attribute properties as shown above.

A much cleaner approach would be if the attributes asked a central class about the strings. Something like:

public static class LocalizationStringProvider
{
    public static string GetValidationMessage(Type attributeType, string text)
    {
        // scan registered providers after the text
    }
    
    public static string GetModelText(Type model, string propertyName, string metadataName)
    {
        // scan registered providers after the text
    }
    
    // add a new one
    public void Register(ILocalizationStringProvider provider)
    {
    }
    
    // remove all providers
    public void Clear()
    {}
}

Which in turn will get it’s text from a registered provider:

public interface ILocalizationStringProvider
{
    string GetValidationMessage(Type attributeType, string text);
    string GetModelText(Type model, string propertyName, string metadataName);
}

In this way we can by ourself choose if we want to use string tables, a SQL database, flat files or any other source. It will also work for attributes like the ASP.NET MVC CompareAttribute which requires to get a localized version of the property name which it’s compared to.

Hence to customize the localization of model and validation strings would simply be:

LocalizationStringProvider.Clear();
LocalizationStringProvider.Add(new MySqlProvider());

Summary

Vote at uservoice.com if you like this idea and want it implemented in ASP.NET.

Disclaimer: The decision of using a static class in this example was chosen since it’s how the other extension points of ASP.NET is made.