[c#] DisplayNameAttribute का स्थानीयकरण



Answers

हम कई भाषाओं का समर्थन करने के लिए कई विशेषताओं के लिए ऐसा कर रहे हैं। हमने माइक्रोसॉफ्ट के लिए एक समान दृष्टिकोण लिया है, जहां वे अपने मूल गुणों को ओवरराइड करते हैं और वास्तविक स्ट्रिंग के बजाय संसाधन नाम पास करते हैं। संसाधन स्ट्रिंग का उपयोग वास्तविक स्ट्रिंग के लिए डीएलएल संसाधनों में एक लुकअप करने के लिए किया जाता है।

उदाहरण के लिए:

class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
    private readonly string resourceName;
    public LocalizedDisplayNameAttribute(string resourceName)
        : base()
    {
      this.resourceName = resourceName;
    }

    public override string DisplayName
    {
        get
        {
            return Resources.ResourceManager.GetString(this.resourceName);
        }
    }
}

वास्तव में विशेषता का उपयोग करते समय आप इसे एक कदम आगे ले सकते हैं, और अपने संसाधन नामों को स्थिर वर्ग में स्थिरांक के रूप में निर्दिष्ट कर सकते हैं। इस तरह, आपको घोषणाएं मिलती हैं।

[LocalizedDisplayName(ResourceStrings.MyPropertyName)]
public string MyProperty
{
  get
  {
    ...
  }
}

अद्यतन करें
ResourceStrings कुछ ऐसा दिखाई देगा (नोट, प्रत्येक स्ट्रिंग संसाधन के नाम को संदर्भित करेगी जो वास्तविक स्ट्रिंग निर्दिष्ट करती है):

public static class ResourceStrings
{
    public const string ForegroundColorDisplayName="ForegroundColorDisplayName";
    public const string FontSizeDisplayName="FontSizeDisplayName";
}
Question

मैं PropertyGrid में प्रदर्शित गुणों को नामित करने का एक तरीका ढूंढ रहा हूं। DisplayNameAttribute विशेषता का उपयोग कर संपत्ति का नाम "ओवर्रिडेन" हो सकता है। दुर्भाग्यवश विशेषताओं में निरंतर अभिव्यक्ति नहीं हो सकती है। तो मैं दृढ़ता से टाइप किए गए संसाधनों का उपयोग नहीं कर सकता जैसे कि:

class Foo
{
   [DisplayAttribute(Resources.MyPropertyNameLocalized)]  // do not compile
   string MyProperty {get; set;}
}

मैंने संसाधनों का उपयोग करने में सक्षम होने के लिए DisplayNameAttribute से प्राप्त करने के लिए कुछ सुझाव देखा और कुछ सुझाव पाया। मैं कोड के साथ खत्म हो जाएगा जैसे:

class Foo
{
   [MyLocalizedDisplayAttribute("MyPropertyNameLocalized")] // not strongly typed
   string MyProperty {get; set;}
}

हालांकि मैं दृढ़ता से टाइप किए गए संसाधन लाभ खो देता हूं जो निश्चित रूप से अच्छी बात नहीं है। तब मैं DisplayNameResourceAttribute आया जो कि मैं जो खोज रहा हूं वह हो सकता है। लेकिन यह माइक्रोसॉफ्ट में होना चाहिए। VisualStudio.Modeling.Design नामस्थान और मुझे नहीं पता कि मुझे इस नामस्थान के लिए कौन सा संदर्भ जोड़ना है।

किसी को भी पता है कि क्या प्रदर्शन नाम स्थानीयकरण को एक अच्छे तरीके से हासिल करने का कोई आसान तरीका है? या यदि विज़ुअल स्टूडियो के लिए माइक्रोसॉफ्ट का उपयोग करने के लिए माइक्रोसॉफ्ट का उपयोग करने का तरीका है?




मैं इस मामले का उपयोग अपने मामले में हल करता हूं

[LocalizedDisplayName("Age", NameResourceType = typeof(RegistrationResources))]
 public bool Age { get; set; }

कोड के साथ

public sealed class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
    private PropertyInfo _nameProperty;
    private Type _resourceType;


    public LocalizedDisplayNameAttribute(string displayNameKey)
        : base(displayNameKey)
    {

    }

    public Type NameResourceType
    {
        get
        {
            return _resourceType;
        }
        set
        {
            _resourceType = value;
            _nameProperty = _resourceType.GetProperty(base.DisplayName, BindingFlags.Static | BindingFlags.Public);
        }
    }

    public override string DisplayName
    {
        get
        {
            if (_nameProperty == null)
            {
                return base.DisplayName;
            }

            return (string)_nameProperty.GetValue(_nameProperty.DeclaringType, null);
        }
    }

}



मैं वीबीएनईटी कोड के लिए क्षमा चाहता हूं, मेरा सी # थोड़ा जंगली है ... लेकिन आपको विचार मिल जाएगा, है ना?

सबसे पहले, एक नई कक्षा बनाएं: LocalizedPropertyDescriptor , जो PropertyDescriptor विरासत में लेता है। इस तरह DisplayName संपत्ति को ओवरराइड करें:

Public Overrides ReadOnly Property DisplayName() As String
         Get
            Dim BaseValue As String = MyBase.DisplayName
            Dim Translated As String = Some.ResourceManager.GetString(BaseValue)
            If String.IsNullOrEmpty(Translated) Then
               Return MyBase.DisplayName
            Else
               Return Translated
           End If
    End Get
End Property

Some.ResourceManager संसाधन फ़ाइल का संसाधन Some.ResourceManager है जिसमें आपके अनुवाद शामिल हैं।

इसके बाद, स्थानीय संपत्तियों के साथ कक्षा में ICustomTypeDescriptor लागू करें, और ICustomTypeDescriptor विधि को ओवरराइड करें:

Public Function GetProperties() As PropertyDescriptorCollection Implements System.ComponentModel.ICustomTypeDescriptor.GetProperties
    Dim baseProps As PropertyDescriptorCollection = TypeDescriptor.GetProperties(Me, True)
    Dim LocalizedProps As PropertyDescriptorCollection = New PropertyDescriptorCollection(Nothing)

    Dim oProp As PropertyDescriptor
    For Each oProp In baseProps
        LocalizedProps.Add(New LocalizedPropertyDescriptor(oProp))
    Next
    Return LocalizedProps
End Function

संसाधन संसाधन में किसी मान के संदर्भ को संग्रहीत करने के लिए अब आप 'DisplayName` विशेषता का उपयोग कर सकते हैं ...

<DisplayName("prop_description")> _
Public Property Description() As String

prop_description संसाधन फ़ाइल में कुंजी है।




यह एक पुराना सवाल है, लेकिन मुझे लगता है कि यह एक बहुत ही आम समस्या है, और यहां मेरा समाधान एमवीसी 3 में है।

सबसे पहले, गंदे तारों से बचने के लिए स्थिरांक उत्पन्न करने के लिए एक टी 4 टेम्पलेट की आवश्यकता होती है। हमारे पास एक संसाधन फ़ाइल 'Labels.resx' है जिसमें सभी लेबल स्ट्रिंग हैं। इसलिए टी 4 टेम्पलेट सीधे संसाधन फ़ाइल का उपयोग करता है,

<#@ 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#>";                    
<#
           }    
#>
    }
}

फिर, 'प्रदर्शन नाम' को स्थानांतरित करने के लिए एक एक्सटेंशन विधि बनाई गई है,

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' विशेषता को 'Labels.resx' से स्वचालित रूप से पढ़ने के लिए 'DisplayLabel' विशेषता द्वारा प्रतिस्थापित किया गया है,

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; }
    }
}

डिफ़ॉल्ट रूप से, 'name.resx' को देखने के लिए प्रॉपर्टी नाम का उपयोग किया जाता है, लेकिन यदि आप इसे 'DisplayLabel' के माध्यम से सेट करते हैं, तो इसका उपयोग इसके बजाय होगा।




आप स्थिरांक उत्पन्न करने के लिए टी 4 का उपयोग कर सकते हैं। मैंने एक लिखा है:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Xml.XPath" #>
using System;
using System.ComponentModel;


namespace Bear.Client
{
 /// <summary>
 /// Localized display name attribute
 /// </summary>
 public class LocalizedDisplayNameAttribute : DisplayNameAttribute
 {
  readonly string _resourceName;

  /// <summary>
  /// Initializes a new instance of the <see cref="LocalizedDisplayNameAttribute"/> class.
  /// </summary>
  /// <param name="resourceName">Name of the resource.</param>
  public LocalizedDisplayNameAttribute(string resourceName)
   : base()
  {
   _resourceName = resourceName;
  }

  /// <summary>
  /// Gets the display name for a property, event, or public void method that takes no arguments stored in this attribute.
  /// </summary>
  /// <value></value>
  /// <returns>
  /// The display name.
  /// </returns>
  public override String DisplayName
  {
   get
   {
    return Resources.ResourceManager.GetString(this._resourceName);
   }
  }
 }

 partial class Constants
 {
  public partial class Resources
  {
  <# 
   var reader = XmlReader.Create(Host.ResolvePath("resources.resx"));
   var document = new XPathDocument(reader);
   var navigator = document.CreateNavigator();
   var dataNav = navigator.Select("/root/data");
   foreach (XPathNavigator item in dataNav)
   {
    var name = item.GetAttribute("name", String.Empty);
  #>
   public const String <#= name#> = "<#= name#>";
  <# } #>
  }
 }
}



Links