ASP.NET MVC localization DisplayNameAttribute alternatives: a better way
- by Brian Schroer
In my last post, I talked bout creating a custom class inheriting from System.ComponentModel.DisplayNameAttribute to retrieve display names from resource files: [LocalizedDisplayName("RememberMe")]
public bool RememberMe { get; set; }
That’s a lot of work to put an attribute on all of my model properties though. It would be nice if I could intercept the ASP.NET MVC code that analyzes the model metadata to retrieve display names to make it automatically get localized text from my resource files. That way, I could just set up resource file entries where the keys are the property names, and not have to put attributes on all of my properties.
That’s done by creating a custom class inheriting from System.Web.Mvc.DataAnnotationsModelMetadataProvider:
1: public class LocalizedDataAnnotationsModelMetadataProvider :
2: DataAnnotationsModelMetadataProvider
3: {
4: protected override ModelMetadata CreateMetadata(
5: IEnumerable<Attribute> attributes,
6: Type containerType,
7: Func<object> modelAccessor,
8: Type modelType,
9: string propertyName)
10: {
11: var meta = base.CreateMetadata
12: (attributes, containerType, modelAccessor, modelType, propertyName);
13:
14: if (string.IsNullOrEmpty(propertyName))
15: return meta;
16:
17: if (meta.DisplayName == null)
18: GetLocalizedDisplayName(meta, propertyName);
19:
20: if (string.IsNullOrEmpty(meta.DisplayName))
21: meta.DisplayName = string.Format("[[{0}]]", propertyName);
22:
23: return meta;
24: }
25:
26: private static void GetLocalizedDisplayName(ModelMetadata meta, string propertyName)
27: {
28: ResourceManager resourceManager = MyResource.ResourceManager;
29: CultureInfo culture = Thread.CurrentThread.CurrentUICulture;
30:
31: meta.DisplayName = resourceManager.GetString(propertyName, culture);
32: }
33: }
Line 11 calls the base CreateMetadata method.
Line 17 checks whether the metadata DisplayName property has already been populated by a DisplayNameAttribute (or my LocalizedDisplayNameAttribute). If so, it respects that and doesn’t use my custom localized text lookup.
The GetLocalizedDisplayName method checks for the property name as a resource file key. If found, it uses the localized text from the resource files.
If the key is not found in the resource file, as with my LocalizedDisplayNameAttribute, I return a formatted string containing the property name (e.g. “[[RememberMe]]”) so I can tell by looking at my web pages which resource keys I haven’t defined yet.
It’s hooked up with this code in the Application_Start method of Global.asax:
ModelMetadataProviders.Current = new LocalizedDataAnnotationsModelMetadataProvider();