I use MVCContrib library on one of my ASP.NET MVC 2 projects. That project should have multi-language support. I use InputBuilders quite much but InputBuilders don’t support the multilanguage features for i.e. Labels, Descriptions, etc..
So I realized to extend it.
So to fully understand this blog entry you nee to be familiar with MvcContrib InputBuilders and the way how the default multi-language support is done in ASP.NET MVC.
There is quite nice article written about the localization here. There are several ways how to store the multi-language texts but I like Adam’s guide because it’s quite easy.
My MVCContrib-multi-language extension
In my project I have the source code of MVCContrib, so it was easy to extend. I demonstrate my extension on Labels.
I created 2 classes:
1 namespace MvcContrib.UI.InputBuilder.Attributes
2 {
3 public class LabelAttribute : Attribute
4 {
5 public Type LabelResourceType { get; set; }
6 public string LabelResourceName { get; set; }
7
8 private string _label;
9
10 public string Label
11 {
12 get
13 {
14 if (!string.IsNullOrEmpty(_label))
15 {
16 return _label;
17 }
18
19 if (LabelResourceType != null && !string.IsNullOrEmpty(LabelResourceName))
20 {
21 PropertyInfo property = LabelResourceType.GetProperty(LabelResourceName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
22 if (property != null)
23 {
24 var txt = property.GetValue(null, null) as string;
25 return txt;
26 }
27 return "Default:" + LabelResourceName;
28 }
29
30 return "";
31 }
32 set
33 {
34 _label = value;
35 }
36 }
37
38 public LabelAttribute()
39 {
40 }
41
42 public LabelAttribute(string text)
43 {
44 Label = text;
45 }
46
47 public LabelAttribute(Type textResourceType, string textResourceName)
48 {
49 LabelResourceType = textResourceType;
50 LabelResourceName = textResourceName;
51 }
52
53 }
54
55 [AttributeUsage(AttributeTargets.Class)]
56 public class LabelConventionAttribute : Attribute
57 {
58 public Type ResourceType { get; set; }
59 public string Pattern { get; set; }
60
61 public LabelConventionAttribute(Type resourceType, string pattern)
62 {
63 ResourceType = resourceType;
64 Pattern = pattern;
65 }
66
67 public string GetLabelFor(string propertyName)
68 {
69 return new LabelAttribute(ResourceType, string.Format(Pattern, propertyName)).Label;
70 }
71 }
72 }
Class LabelAttribute
is to add the multilanguage support for the particular property. But because I’m lazy to write it on all properties of my model which is sent to the view, I create LabelConventionAttribute
.
I like Convetion-over-Configuration style so using this attribute it is possible to setup the convention that the labels will be named by the convention Pattern.FormatWith(propetyName)
.
Next change was to change DefaultProperyConvention class to be partial. It’s due to the have my extensions in a separate class. I had to add there a method Lable
So here it’s
1 namespace MvcContrib.UI.InputBuilder.Conventions
2 {
3 public partial class DefaultProperyConvention
4 {
5
17
18 public virtual string LabelForPropertyConvention(PropertyInfo propertyInfo)
19 {
20 if (propertyInfo.AttributeExists<LabelAttribute>())
21 {
22 return propertyInfo.GetAttribute<LabelAttribute>().Label;
23 }
24 if (propertyInfo.ReflectedType.AttributeExists<LabelConventionAttribute>())
25 {
26 return propertyInfo.ReflectedType.GetAttribute<LabelConventionAttribute>().GetLabelFor(propertyInfo.Name);
27 }
28 return propertyInfo.Name.ToSeparatedWords();
29 }
30 }
31 }
32
And in the original DefaultPropertyConvention
class I had to remove the method LabelForPropertyConvention.
That’s all. The similar steps can be done also for Description
, but it’s necessary to extend PropertyViewModel
class with new property.
The usage is:
1 [DescriptionConvention(typeof(Descriptions), "Car_{0}")]
2 [LabelConvention(typeof(Labels), "Car_{0}")]
3 public class CarInput
4 {
5 [Required]
6 [Example("BMW")]
7 public virtual string Name { get; set; }
8 }
Based on Adam’s guidance, I also had to create a resource file for the labels and the VS.NET created me the class Labels.
If you use MVCContrib builders then i.e. their Field.Master contains code like this: Html.Encode(Model.Label)
to display the model’s label. Using the previously described extension it will be translated into the culture set in Thread.CurrentThread.CurrentUICulture
.
That’s all for now …