Localize ASP.NET MVC 2 DataAnnotations validation messages

Edit on GitHub

Living in a country where there are there are three languages being used, almost every application you work on requires some form of localization. In an earlier blog post, I already mentioned ASP.NET MVC 2’s DataAnnotations support for doing model validation. Ever since, I was wondering if it would be possible to use resource files or something to do localization of error messages, since every example that could be found on the Internet looks something like this:

[code:c#]

[MetadataType(typeof(PersonBuddy))]
public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class PersonBuddy
{
    [Required(ErrorMessage = "Name is required.")]
    public string Name { get; set; }

    [Required(ErrorMessage = "E-mail is required.")
    public string Email { get; set; }
}

[/code]

Yes, those are hardcoded error messages. And yes, only in one language. Let’s see how localization of these would work.

1. Create a resource file

Add a resource file to your ASP.NET MVC 2 application. Not in App_GlobalResources or App_LocalResources, just a resource file in a regular namespace. Next, enter all error messages that should be localized in a key/value manner. Before you leave this file, make sure that the Access Modifier property is set to Public.

Access modifier in resource file

2. Update your “buddy classes”

Update your “buddy classes” (or metadata classes or whatever you call them) to use the ErrorMessageResourceType and ErrorMessageResourceName parameters instead of the ErrorMessage parameter that you normally pass. Here’s the example from above:

[code:c#]

[MetadataType(typeof(PersonBuddy))]
public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}

public class PersonBuddy
{
    [Required(ErrorMessageResourceType = typeof(Resources.ModelValidation), ErrorMessageResourceName = "NameRequired")]
    public string Name { get; set; }

    [Required(ErrorMessageResourceType = typeof(Resources.ModelValidation), ErrorMessageResourceName = "EmailRequired")]
    public string Email { get; set; }
}

[/code]

3. See it work!

After creating a resource file and updating the buddy classes, you can go back to work and use model binders, ValidationMessage and ValidationSummary. ASP.NET will make sure that the correct language is used based on the thread culture info.

Localized error messages

kick it on DotNetKicks.com

This is an imported post. It was imported from my old blog using an automated tool and may contain formatting errors and/or broken images.

Leave a Comment

avatar

6 responses

  1. Avatar for Manuel Castro
    Manuel Castro November 5th, 2009

    Simple + Useful = Fantastic !!

  2. Avatar for lehoangdung
    lehoangdung November 9th, 2009

    Great job!

    Besause we I in Vietnam and using vietnamese, so I must write apps that support multiple languages, I've successed in implement localization within SharpArch (NHibernate, ASP.NET MVC 1.0).

    How can you using Localization Resources when you separate your entities, controllers and views in separated assemblies? (You can not use Resources.ModelValidation for example)

    Thanks in advanced!

  3. Avatar for Klenne
    Klenne November 9th, 2009

    All great, there is only one major problem with this. The localized message have to come from a satellite assembly (dll).

    In asp.net one can specify the resource provider factory to use when performing localization. If you use an alternate factory (like a database provider), asp.net uses that factory to pull all resources into memory. DataAnnotations does not use the factory method and you are limited to using the default factory (being satellite assemblies). Big bummer!!!

  4. Avatar for maartenba
    maartenba November 10th, 2009

    I did not test it but I think you can actually use any type that has an indexer on it in which the key can be requested.

  5. Avatar for Fred
    Fred November 26th, 2009

    Hey Maarten,

    How can I access a resource that resides in another assembly which is not being referenced by the project that contains the dataannotation.
    Can I get it through the caller assembly or somehow?

    Thanks,
    Fred

  6. Avatar for maartenba
    maartenba November 26th, 2009

    That would require some plumbing and goes beyond the scope of this blog post and the approach described. Using the approach described, a reference will always have to exist.