2011-09-13 29 views
14

Tôi đang làm việc trên một lớp học sẽ được sử dụng bởi một số người từ một quốc gia khác. Tôi phải bản địa hóa mọi thư, cảnh báo e.c. để họ có thể hiểu ý của chúng ta. Trong nhiều trường hợp, tôi đã đạt được mục tiêu của mình. Nhưng những thuộc tính tài sản như mô tả như vậy là một nỗi đau trong ass.cách bản địa hóa mô tả thuộc tính trong C#?

Here`s những gì tôi có ngay bây giờ:

[Category("Editable Values"), Description("Sets the minimum select...")] 
    public Ampere Simin 
    { 
     get 
     {...} 
     set 
     {...} 
    } 

[Category("Editable Values"), Description(Localisation.Simin)] // "Localisation" here is the internal resource file that i wrote for messages, warnings, exceptions and -unfortunately- descriptions 
     public Ampere Simin 
     { 
      get 
      {...} 
      set 
      {...} 
     } 

Đó là những gì tôi đang cố gắng làm. Nhưng không thể sử dụng Localisations theo cách này. Bất kỳ Gợi ý nào về thứ mà tôi có thể sử dụng thay vì nó?

Trả lời

18

lớp con:

[STAThread] 
static void Main() 
{ // just some example code to show it working in winforms, but 
    // anything using System.ComponentModel should see the change 
    Application.EnableVisualStyles();   
    Application.Run(new Form {Controls = {new PropertyGrid {Dock = DockStyle.Fill, SelectedObject = new Foo()}}}); 
} 

class Foo 
{ // assume the following literals are keys, for example to a RESX 
    [LocalizedCategory("cat")] 
    [LocalizedDescription("desc")] 
    [LocalizedDisplayName("disp name")] 
    public string Bar { get; set; } 
} 
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter)] 
class LocalizedDescriptionAttribute : DescriptionAttribute 
{ 
    static string Localize(string key) 
    { 
     // TODO: lookup from resx, perhaps with cache etc 
     return "Something for " + key; 
    } 
    public LocalizedDescriptionAttribute(string key) 
     : base(Localize(key)) 
    { 
    } 
} 
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event)] 
class LocalizedDisplayNameAttribute : DisplayNameAttribute 
{ 
    static string Localize(string key) 
    { 
     // TODO: lookup from resx, perhaps with cache etc 
     return "Something for " + key; 
    } 
    public LocalizedDisplayNameAttribute(string key) 
     : base(Localize(key)) 
    { 
    } 
} 
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.Delegate | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter)] 
class LocalizedCategoryAttribute : CategoryAttribute 
{ 
    public LocalizedCategoryAttribute(string key) : base(key) { } 
    protected override string GetLocalizedString(string value) 
    { 
      // TODO: lookup from resx, perhaps with cache etc 
     return "Something for " + value; 
    } 
} 
+0

Tôi phải thú nhận rằng tôi thực sự không thể hiểu được. Nghĩa là "desc" có phải là khóa cho thuộc tính được bản địa hóa không? Làm cách nào để truy cập thuộc tính của thuộc tính được chỉ định? Bạn có thể thích ứng với ví dụ của bạn để tôi? – 3yanlis1bos

+0

@ 3yanlis1bos trong ví dụ tôi đang sử dụng chuỗi như là chìa khóa duy nhất - bạn sẽ phải lấy ra khỏi RESX theo cách thủ công (xem tệp được tạo phía sau RESX) hoặc sử dụng phản chiếu –

+0

Ok, tôi nghĩ rằng tôi đã hiểu. Bạn đã mở rộng mô tả và sửa đổi cho phù hợp với nhu cầu của tôi như lấy chuỗi được bản địa hóa làm đầu vào. Có đúng không? thì điều duy nhất mà tôi phải làm là sử dụng thuộc tính mới thay vì thuộc tính cũ? – 3yanlis1bos

4
[Required(ErrorMessageResourceName = "LogOnModel_UserName_Required",  
     ErrorMessageResourceType = typeof(Resources.Global))]  
[Display(Name = "LogOnModel_UserName_Required",resourceType = typeof(Resources.Global))] 
public string UserName { get; set; } 

see: http://geekswithblogs.net/shaunxu/archive/2010/05/06/localization-in-asp.net-mvc-ndash-3-days-investigation-1-day.aspx

+2

Vì OP đang sử dụng 'CategoryAttribute' /' DescriptionAttribute', có lẽ họ đang nói * thường xuyên * 'System.ComponentModel ', không phải MVC - trong trường hợp này chỉ đơn giản là không áp dụng. –

+0

ah, không biết điều đó. Tôi chủ yếu là dev MVC và nghĩ rằng các thuộc tính sẽ là chung chung (sẽ là một tính năng tuyệt vời mặc dù). – Patrick

+0

@Patrick Tôi không hiểu điều đó :). kinda newbie trong C#. nhưng cảm ơn bạn đã cố gắng. đó có phải là "Resources.Global" mà bạn truy cập vào chuỗi tài nguyên được bản địa hóa không? Nếu có, làm thế nào để tôi viết một cái gì đó như thế trong một thuộc tính mô tả? – 3yanlis1bos

1

Có vẻ như CategoryAttribute có mã để tìm kiếm một chuỗi cục bộ dựa trên nội lực, nhưng DescriptionAttribute không có nội địa hóa.

Từ Reflector:

public string Category 
{ 
    get 
    { 
     if (!this.localized) 
     { 
      this.localized = true; 
      string localizedString = this.GetLocalizedString(this.categoryValue); 
      if (localizedString != null) 
      { 
       this.categoryValue = localizedString; 
      } 
     } 
     return this.categoryValue; 
    } 
} 

Tôi nghĩ rằng bạn sẽ mở rộng các thuộc tính và tạo thực hiện của riêng bạn, đi qua trong ResourceType. Một cái gì đó như thế này, dựa trên mơ hồ trên DataAnnotation logic. Rõ ràng là cần dọn dẹp hơn một chút.

public class LocaleDescriptionAttribute : DescriptionAttribute 
{ 
    ... 

    public LocaleDescriptionAttribute(string resourceKey, Type resourceType) 
     : base(resourceKey) 
    { 
     this.resourceType = resourceType; 
    } 

    public override string Description 
    { 
     get 
     { 
      var description = base.Description; 
      PropertyInfo property = resourceType.GetProperty(
         description, BindingFlags.Public | BindingFlags.Static); 
      if (property == null) 
      { 
       return description; 
      } 
      return property.GetValue(null, null) as string; 
     } 
    }  
} 
+0

Trên thực tế thuộc tính Danh mục này không khác với Mô tả trong hiệu ứng cuối cùng. Tôi có các chuỗi được bản địa hóa trong tệp của mình, nhưng tôi không thể nhận được bất kỳ quyền nào để áp dụng chúng cho Thuộc tính như áp dụng chúng trong Ngoại lệ. Điều duy nhất mà tôi cố gắng hiểu là làm thế nào để điền vào tức là DescriptionAttribute với một nguồn nội bộ như bạn đã nói. – 3yanlis1bos

3

Chúng ta hãy lớp mẫu này:

// ------------------------------------------------------------------------ 
public class Customer 
{ 
    // ---------------------------------------------------------------------- 
    [Category("Editable Values"), LocDescription("FirstName", "Sets the first name...")] 
    public string FirstName { get; set; } 

    // ---------------------------------------------------------------------- 
    [Category("Editable Values"), LocDescription( Key = "LastName", DefaultDescription = "Sets the last name...")] 
    public string LastName { get; set; } 
} // class Customer 

Bây giờ bạn có thể thực hiện một tùy chỉnh thuộc tính lớp:

// ------------------------------------------------------------------------ 
public class LocDescriptionAttribute : DescriptionAttribute 
{ 
    // ---------------------------------------------------------------------- 
    public LocDescriptionAttribute() 
    { 
    } // LocDescriptionAttribute 

    // ---------------------------------------------------------------------- 
    public LocDescriptionAttribute(string key, string defaultDescription) : 
     base(defaultDescription) 
    { 
     Key = key; 
     DefaultDescription = defaultDescription; 
    } // LocDescriptionAttribute 

    // ---------------------------------------------------------------------- 
    public string Key { get; set; } 

    // ---------------------------------------------------------------------- 
    public string DefaultDescription { get; set; } 

    // ---------------------------------------------------------------------- 
    public override string Description 
    { 
     get 
     { 
      // load from resx 
      string description = Strings.GetString(Key); 
      if (string.IsNullOrEmpty(description)) 
      { 
       description = DefaultDescription; 
      } 
      return description; 
     } 
    } // Description 
} // class LocDescriptionAttribute 

Bây giờ bạn có mô tả cục bộ:

AttributeCollection attributes = TypeDescriptor.GetProperties(customer)[ "FirstName" ].Attributes; 
DescriptionAttribute myAttribute = (DescriptionAttribute)attributes[ typeof(DescriptionAttribute) ]; 
ConsoleWiterLine(myAttribute.Description); 
+0

Tôi đã có một tệp Tài nguyên. Tôi sử dụng chúng cho các cảnh báo và tin nhắn của tôi. Nhưng vấn đề là, bạn chỉ có thể không chuyển tài nguyên cục bộ vào thuộc tính mô tả (không thể). đó là ý tôi. – 3yanlis1bos

+0

Tôi trông giống như những gì Marc đã làm. Nhưng nó dễ hiểu hơn cho tôi. Tôi nghĩ tôi sẽ thử cái này. – 3yanlis1bos

2

Mở rộng nhẹ cho Jani's a nswer (mà đã làm việc tốt cho tôi):

string description = Strings.GetString(Key); 

thể được thực hiện rõ ràng hơn như

ResourceManager rm = YourResourceClassName.ResourceManager; 
string description = rm.GetString(Key); 

Nó được mơ hồ ngụ ý, nhưng đã không được rõ ràng những gì đã mất tích từ mã gốc. Thuộc tính .ResourceManager của lớp tài nguyên được tạo tự động. Sau đó, để truy cập nó, sử dụng phương pháp mở rộng được Glennular mô tả ở đây: StackOverflow thay vì mã hóa cứng trong tên trường/lớp (chỉ cần sử dụng LocDescriptionAttribute thay vì DescriptionAttribute).

Điều chỉnh duy nhất khác mà tôi đã thực hiện là làm cho nó tĩnh dựa trên this IComparable enum, để cho phép nó được sử dụng bởi bất kỳ enum nào thay vì bị khóa cho một loại cụ thể; đó là điều tốt nhất tôi có thể làm cho rằng tôi không thể áp dụng một giao diện để giới hạn nó chỉ là enums tôi đã thêm mô tả.

2

tôi đã kết hợp Marc Gravell và câu trả lời dsmith 's:

Đầu tiên: tạo một lớp Thuộc tính tên là LocalizedDescriptionAttribute

public class LocalizedDescriptionAttribute : DescriptionAttribute 
{ 
    static string Localize(string key) 
    { 
     return YourResourceClassName.ResourceManager.GetString(key); 
    } 

    public LocalizedDescriptionAttribute(string key) 
     : base(Localize(key)) 
    { 
    } 
} 

Sử dụng nó như LocalizedDescription (từ "Thuộc tính" là không cần thiết)

public class Foo 
{ 
    // myString is a key that exists in your Resources file 
    [LocalizedDescription("myString")] 
    public string Bar { get; set; } 
} 
Các vấn đề liên quan