นี่เป็นคำถามเก่า แต่ฉันคิดว่านี่เป็นปัญหาที่พบบ่อยมากและนี่คือคำตอบของฉันใน MVC 3
ประการแรกต้องใช้เทมเพลต T4 เพื่อสร้างค่าคงที่เพื่อหลีกเลี่ยงสตริงที่น่ารังเกียจ เรามีไฟล์ทรัพยากร 'Labels.resx' เก็บสตริงป้ายกำกับทั้งหมด ดังนั้นเทมเพลต T4 จึงใช้ไฟล์ทรัพยากรโดยตรง
<#@ 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#>";                    
<#
           }    
#>
    }
}
จากนั้นวิธีการขยายจะถูกสร้างขึ้นเพื่อโลคัลไลซ์ '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;
        }
    }
}
แอตทริบิวต์ "DisplayName" ถูกแทนที่ด้วยแอตทริบิวต์ "DisplayLabel" เพื่อให้อ่านจาก "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;
            }
        }
    }
}
หลังจากดำเนินการเตรียมการทั้งหมดแล้วให้ใช้เวลาแตะแอตทริบิวต์การตรวจสอบความถูกต้องเริ่มต้นเหล่านั้น ฉันกำลังใช้แอตทริบิวต์ "จำเป็น" เป็นตัวอย่าง
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());
        }
    }
}
ตอนนี้เราสามารถใช้คุณลักษณะเหล่านั้นในแบบจำลองของเรา
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; }
    }
}
โดยค่าเริ่มต้นชื่อคุณสมบัติจะใช้เป็นคีย์ในการค้นหา "Label.resx" แต่ถ้าคุณตั้งค่าผ่าน "DisplayLabel" จะใช้ชื่อนั้นแทน