Thuộc tính DisplayName từ Tài nguyên?


160

Tôi có một ứng dụng được bản địa hóa và tôi tự hỏi liệu có thể có DisplayNamemột thuộc tính mô hình nhất định được đặt từ Tài nguyên không.

Tôi muốn làm một cái gì đó như thế này:

public class MyModel {
  [Required]
  [DisplayName(Resources.Resources.labelForName)]
  public string name{ get; set; }
}

Nhưng tôi không thể làm như vậy, vì trình biên dịch nói: "Đối số thuộc tính phải là biểu thức không đổi, biểu thức typeof hoặc biểu thức tạo mảng của loại tham số thuộc tính" :(

Có cách giải quyết nào không? Tôi xuất nhãn theo cách thủ công, nhưng tôi cần những nhãn này cho đầu ra trình xác nhận!

Câu trả lời:


112

Làm thế nào về việc viết một thuộc tính tùy chỉnh:

public class LocalizedDisplayNameAttribute: DisplayNameAttribute
{
    public LocalizedDisplayNameAttribute(string resourceId) 
        : base(GetMessageFromResource(resourceId))
    { }

    private static string GetMessageFromResource(string resourceId)
    {
        // TODO: Return the string from the resource file
    }
}

có thể được sử dụng như thế này:

public class MyModel 
{
    [Required]
    [LocalizedDisplayName("labelForName")]
    public string Name { get; set; }
}

Vâng, tôi đã làm việc trên một giải pháp tương tự sáng nay và nó khả thi. Sau đó, tôi tìm thấy bài đăng này có cùng một cách tiếp cận: adamyan.blogspot.com/2010/02/ Kẻ
Palantir

23
@Gunder bài đăng của anh ấy, dưới bài này (có nhiều phiếu nhất), là một giải pháp đẹp hơn nhiều. Chỉ dành cho những người chỉ đọc các bài đăng được chấp nhận
321X

1
Điều này thực sự KHÔNG hoạt động để truy cập các bản dịch khác nhau vì nó sẽ trả về cùng một giá trị cho tất cả người dùng không có vấn đề gì. Lưu trữ resourceid trong một biến cục bộ và ghi đè DisplayName thay vào đó
Fischer

5
Đề xuất cho TODO: trả về Tài nguyên. Ngôn ngữ.ResourceManager.GetString (resourceId);
Leonel Sanches da Silva

4
Bạn nên sử dụng: [Display (Name = "nhãnForName", ResourceType = typeof (Resources.Resource))] như mô tả bên dưới ...
Frank Boucher

375

Nếu bạn sử dụng MVC 3 và .NET 4, bạn có thể sử dụng Displaythuộc tính mới trong System.ComponentModel.DataAnnotationskhông gian tên. Thuộc tính này thay thế DisplayNamethuộc tính và cung cấp nhiều chức năng hơn, bao gồm hỗ trợ bản địa hóa.

Trong trường hợp của bạn, bạn sẽ sử dụng nó như thế này:

public class MyModel
{
    [Required]
    [Display(Name = "labelForName", ResourceType = typeof(Resources.Resources))]
    public string name{ get; set; }
}

Là một lưu ý phụ, thuộc tính này sẽ không hoạt động với các tài nguyên bên trong App_GlobalResourceshoặc App_LocalResources. Điều này phải làm với công cụ tùy chỉnh ( GlobalResourceProxyGenerator) những tài nguyên này sử dụng. Thay vào đó, hãy đảm bảo tệp tài nguyên của bạn được đặt thành 'Tài nguyên được nhúng' và sử dụng công cụ tùy chỉnh 'ResXFileCodeGenerator'.

(Như một lưu ý phụ, bạn không nên sử dụng App_GlobalResourceshoặc App_LocalResourcesvới MVC. Bạn có thể đọc thêm về lý do tại sao đây là trường hợp ở đây )


Điều này tốt cho ví dụ cụ thể được sử dụng ở đây nhưng nó sẽ không hoạt động đối với phần lớn các setters thuộc tính động muốn có chuỗi.
kingdango

1
Điều này là tốt khi chúng tôi có tất cả ngôn ngữ của chúng tôi với chúng tôi trước khi triển khai vào sản xuất. Nhưng nếu tôi muốn gọi db cho chuỗi db thì cách tiếp cận này không phù hợp. Ngoài ra nhược điểm của tệp tài nguyên là nó yêu cầu biên dịch lại để thực hiện các thay đổi, điều đó có nghĩa là bạn cần phát hành phiên bản khác cho máy khách. Tôi không nói đây là một cách tiếp cận tồi, xin đừng cảm thấy như vậy
kbvishnu

Chỉ là một vấn đề: chúng ta phải biết loại tài nguyên trong mô hình. Tôi có một mô hình DLL và một trang web trong hai dự án riêng biệt. Tôi muốn có thể đặt tên hiển thị trong mô hình và đặt loại tài nguyên trong trang web ...
Kek

1
Nhận Resharper và tạo tệp tài nguyên trong dự án của bạn và nó sẽ tự động nhắc nhở và sau đó giúp bạn di chuyển Tên vào tệp tài nguyên.
anIBMer

14
Với C # 6, thay vì Name = "labelForName"bạn cũng có thể sử dụng Name = nameof(Resources.Resources.labelForName).
Uwe Keim

35

Nếu bạn mở tệp tài nguyên của mình và thay đổi công cụ sửa đổi truy cập thành công khai hoặc nội bộ, nó sẽ tạo một lớp từ tệp tài nguyên của bạn, cho phép bạn tạo các tham chiếu tài nguyên được gõ mạnh.

Tùy chọn để tạo mã tệp tài nguyên

Điều đó có nghĩa là bạn có thể làm một cái gì đó như thế này thay vào đó (sử dụng C # 6.0). Sau đó, bạn không cần phải nhớ nếu tên đầu tiên được hạ thấp hoặc lạc đà. Và bạn có thể thấy nếu các thuộc tính khác sử dụng cùng một giá trị tài nguyên với tìm tất cả các tham chiếu.

[Display(Name = nameof(PropertyNames.FirstName), ResourceType = typeof(PropertyNames))]
public string FirstName { get; set; }

điều này sẽ làm việc với Winforms? Tôi có một lớp mà tôi đã thêm chú thích Hiển thị từ các tài nguyên và tôi đã sử dụng phương thức GetAttributionFrom từ liên kết để lấy tên của thuộc tính nhưng nó không hiển thị địa phương!
Dark_Knight 24/07/2016

2
Bạn đang sử dụng thuộc tính.Name hoặc property.GetName () để lấy văn bản được bản địa hóa? Tài liệu cho .Name cho biết "Không sử dụng thuộc tính này để nhận giá trị của thuộc tính Tên. Thay vào đó, hãy sử dụng phương thức GetName." msdn.microsoft.com/en-us/l
Library / từ

Vâng, tôi đã hiểu rằng tôi phải sử dụng GetName (). Cảm ơn
Dark_Knight

20

Cập nhật:

Tôi biết đã quá muộn nhưng tôi muốn thêm bản cập nhật này:

Tôi đang sử dụng Nhà cung cấp siêu dữ liệu mô hình thông thường do Phil Haacked trình bày, nó mạnh mẽ và dễ áp ​​dụng hơn, hãy nhìn vào nó: thông thườngModelMetadataProvider


Câu trả lời cũ

Ở đây nếu bạn muốn hỗ trợ nhiều loại tài nguyên:

public class LocalizedDisplayNameAttribute : DisplayNameAttribute
{
    private readonly PropertyInfo nameProperty;

    public LocalizedDisplayNameAttribute(string displayNameKey, Type resourceType = null)
        : base(displayNameKey)
    {
        if (resourceType != null)
        {
            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);
        }
    }
}

Sau đó sử dụng nó như thế này:

    [LocalizedDisplayName("Password", typeof(Res.Model.Shared.ModelProperties))]
    public string Password { get; set; }

Đối với hướng dẫn nội địa hóa đầy đủ xem trang này .


1
+1. Giải pháp của Haack chắc chắn là giải pháp thanh lịch nhất so với những giải pháp khác ở đây. Nó rất phù hợp với phong cách lập trình dựa trên quy ước trong ASP.NET MVC và được thực hiện dễ dàng thông qua một lệnh nuget và một dòng mã duy nhất trong Global.asax.cs.
Nilzor

11

Tôi đã nhận được câu trả lời của Người chơi làm việc với App_GlobalResource của tôi bằng cách chọn các thuộc tính tài nguyên và chuyển "Công cụ tùy chỉnh" thành "PublicResXFileCodeGenerator" và xây dựng hành động thành "Tài nguyên nhúng". Hãy quan sát bình luận của người chơi dưới đây.

nhập mô tả hình ảnh ở đây

Hoạt động như một bùa mê :)


Điều này dẫn đến một tệp tài nguyên sẽ được biên dịch giống như bạn đã thêm một tệp tài nguyên bên ngoài App_GlobalResource. Vì vậy, tệp tài nguyên của bạn sẽ không còn hoạt động như một tệp tài nguyên "App_GlobalResource", điều này hoàn toàn tốt. Nhưng bạn chỉ nên nhận thức về nó. Vì vậy, bạn không còn có "lợi ích" khi đặt tệp tài nguyên vào App_GlobalResource. Bạn cũng có thể đặt nó ở một nơi khác.
René

5
public class Person
{
    // Before C# 6.0
    [Display(Name = "Age", ResourceType = typeof(Testi18n.Resource))]
    public string Age { get; set; }

    // After C# 6.0
    // [Display(Name = nameof(Resource.Age), ResourceType = typeof(Resource))]
}
  1. Xác định ResourceType của thuộc tính để nó tìm tài nguyên
  2. Xác định Tên của thuộc tính được sử dụng cho khóa tài nguyên, sau C # 6.0, bạn có thể sử dụng nameofđể hỗ trợ gõ mạnh thay vì mã hóa khóa cứng.

  3. Đặt văn hóa của luồng hiện tại trong bộ điều khiển.

Resource.Culture = CultureInfo.GetCultureInfo("zh-CN");

  1. Đặt khả năng truy cập của tài nguyên thành công khai

  2. Hiển thị nhãn trong cshtml như thế này

@Html.DisplayNameFor(model => model.Age)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.