To stare pytanie, ale myślę, że jest to bardzo powszechny problem, a oto moje rozwiązanie w MVC 3.
Po pierwsze, szablon T4 jest potrzebny do generowania stałych, aby uniknąć nieprzyjemnych ciągów znaków. Mamy plik zasobów „Labels.resx” zawierający wszystkie ciągi etykiet. Dlatego szablon T4 używa bezpośrednio pliku zasobów,
<#@ template debug="True" hostspecific="True" language="C#" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="C:\Project\trunk\Resources\bin\Development\Resources.dll" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Resources" #>
<#
var resourceStrings = new List<string>();
var manager = Resources.Labels.ResourceManager;
IDictionaryEnumerator enumerator = manager.GetResourceSet(CultureInfo.CurrentCulture, true, true)
.GetEnumerator();
while (enumerator.MoveNext())
{
resourceStrings.Add(enumerator.Key.ToString());
}
#>
// This file is generated automatically. Do NOT modify any content inside.
namespace Lib.Const{
public static class LabelNames{
<#
foreach (String label in resourceStrings){
#>
public const string <#=label#> = "<#=label#>";
<#
}
#>
}
}
Następnie zostaje utworzona metoda rozszerzenia, aby zlokalizować „DisplayName”,
using System.ComponentModel.DataAnnotations;
using Resources;
namespace Web.Extensions.ValidationAttributes
{
public static class ValidationAttributeHelper
{
public static ValidationContext LocalizeDisplayName(this ValidationContext context)
{
context.DisplayName = Labels.ResourceManager.GetString(context.DisplayName) ?? context.DisplayName;
return context;
}
}
}
Atrybut „DisplayName” zostaje zastąpiony atrybutem „DisplayLabel” w celu automatycznego odczytu z „Labels.resx”,
namespace Web.Extensions.ValidationAttributes
{
public class DisplayLabelAttribute :System.ComponentModel.DisplayNameAttribute
{
private readonly string _propertyLabel;
public DisplayLabelAttribute(string propertyLabel)
{
_propertyLabel = propertyLabel;
}
public override string DisplayName
{
get
{
return _propertyLabel;
}
}
}
}
Po tych wszystkich przygotowaniach czas na dotknięcie domyślnych atrybutów walidacji. Jako przykładu używam atrybutu „Wymagane”,
using System.ComponentModel.DataAnnotations;
using Resources;
namespace Web.Extensions.ValidationAttributes
{
public class RequiredAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute
{
public RequiredAttribute()
{
ErrorMessageResourceType = typeof (Errors);
ErrorMessageResourceName = "Required";
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return base.IsValid(value, validationContext.LocalizeDisplayName());
}
}
}
Teraz możemy zastosować te atrybuty w naszym modelu,
using Web.Extensions.ValidationAttributes;
namespace Web.Areas.Foo.Models
{
public class Person
{
[DisplayLabel(Lib.Const.LabelNames.HowOldAreYou)]
public int Age { get; set; }
[Required]
public string Name { get; set; }
}
}
Domyślnie nazwa właściwości jest używana jako klucz do wyszukiwania „Label.resx”, ale jeśli ustawisz ją za pomocą „DisplayLabel”, użyje go zamiast tego.