자원의 DisplayName 속성?


160

지역화 된 응용 프로그램 DisplayName이 있으며 특정 모델 속성을 Resource에서 설정할 수 있는지 궁금합니다 .

나는 이런 식으로하고 싶다 :

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

그러나 컴파일러가 "속성 인수는 속성 매개 변수 유형의 상수 표현식, 유형 유형 또는 배열 작성 표현식이어야합니다."

해결 방법이 있습니까? 레이블을 수동으로 출력하고 있지만 유효성 검사기 출력에 레이블이 필요합니다!

답변:


112

맞춤 속성을 작성하는 방법은 다음과 같습니다.

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

이것은 다음과 같이 사용될 수 있습니다 :

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

예, 오늘 아침에 비슷한 솔루션으로 작업했으며 가능했습니다. 그런 다음 같은 접근 방식을 가진이 게시물을 발견했습니다 : adamyan.blogspot.com/2010/02/…
Palantir

23
@이 게시물 아래에서 (투표가 가장 많은) @ 훨씬 좋은 솔루션입니다. 수락 된 게시물 만 읽는 사람 만 해당
321X

1
이것은 다른 번역에 액세스하는 데 실제로 작동하지 않습니다. 모든 사용자에 대해 동일한 값을 반환하지 않기 때문입니다. resourceid를 로컬 변수에 저장하고 대신 DisplayName을 재정의하십시오.
Fischer

5
TODO 제안 : return Resources.Language.ResourceManager.GetString (resourceId);
Leonel Sanches 다 실바

4
아래에 설명 된대로 [Display (Name = "labelForName", ResourceType = typeof (Resources.Resources))]를 사용해야합니다.
Frank Boucher

375

MVC 3 및 ​​.NET 4를 사용하는 Display경우 System.ComponentModel.DataAnnotations네임 스페이스 에서 새 속성을 사용할 수 있습니다 . 이 속성은 속성을 대체하고 DisplayName현지화 지원을 포함하여 훨씬 더 많은 기능을 제공합니다.

귀하의 경우 다음과 같이 사용하십시오.

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

참고로이 속성은 App_GlobalResources또는 내부의 리소스에서는 작동하지 않습니다 App_LocalResources. 이는 GlobalResourceProxyGenerator이러한 리소스가 사용 하는 사용자 지정 도구 ( )와 관련이 있습니다. 대신 리소스 파일이 '내장 리소스'로 설정되어 있는지 확인하고 'ResXFileCodeGenerator'사용자 지정 도구를 사용하십시오.

(추가 참고로, MVC를 사용 App_GlobalResources하거나 사용해서는 안됩니다 App_LocalResources. 이것이 왜 그런지에 대한 자세한 내용은 여기를 참조 하십시오 )


이것은 여기에 사용 된 특정 예제에는 좋지만 문자열을 원하는 대부분의 동적 속성 설정기에는 작동하지 않습니다.
kingdango

1
프로덕션에 배포하기 전에 모든 로캘을 가지고있을 때 좋습니다. 그러나 db 문자열에 대해 db를 호출하려면 이러한 종류의 접근 방식이 적합하지 않습니다. 또한 리소스 파일의 단점은 변경 사항을 적용하기 위해 다시 컴파일해야한다는 것입니다. 즉, 클라이언트에 다른 버전을 릴리스해야합니다. 나는 이것을 나쁜 접근법으로 말하고 있지 않다. 그렇게 느끼지 말아라
kbvishnu

단지 문제 : 모델의 리소스 유형을 알아야합니다. 두 가지 별개의 프로젝트에 모델 DLL과 웹 사이트가 있습니다. 모델에서 표시 이름을 설정하고 웹 사이트에서 자원 유형을 설정하고 싶습니다 ...
Kek

1
Resharper를 가져 와서 프로젝트에서 리소스 파일을 만들면 자동으로 알림을 표시 한 다음 이름을 리소스 파일로 이동하는 데 도움이됩니다.
IBMer

14
C # 6에서는 대신 Name = "labelForName"을 사용할 수도 있습니다 Name = nameof(Resources.Resources.labelForName).
Uwe Keim

35

리소스 파일을 열고 액세스 수정자를 public 또는 internal로 변경하면 리소스 파일에서 클래스를 생성하여 강력한 형식의 리소스 참조를 만들 수 있습니다.

리소스 파일 코드 생성을위한 옵션

즉 C # 6.0을 사용하여 대신 이와 같은 작업을 수행 할 수 있습니다. 그런 다음 이름이 소문자인지 낙타인지 기억하지 않아도됩니다. 그리고 다른 속성이 모든 리소스 찾기에서 동일한 리소스 값을 사용하는지 확인할 수 있습니다.

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

이것이 Winforms에서 작동합니까? 리소스에서 Display 주석을 추가하고 링크 에서 GetAttributeFrom 메서드를 사용 하여 속성 이름을 가져 오는 클래스가 있지만 현지화 된 것을 표시하지 않습니다!
Dark_Knight

2
현지화 된 텍스트를 얻기 위해 attribute.Name 또는 attribute.GetName ()을 사용하고 있습니까? .Name 설명서에 "Name 속성 값을 가져 오는 데이 속성을 사용하지 마십시오. 대신 GetName 메서드를 사용하십시오."라고 표시되어 있습니다. msdn.microsoft.com/ko-kr/library/…
Tikall

예, GetName ()을 사용해야한다는 것을 알았습니다. 감사합니다
Dark_Knight

20

최신 정보:

너무 늦었지만이 업데이트를 추가하고 싶습니다.

Phil Haacked 가 제시 한 Conventional Model Metadata Provider 를 사용하고 있습니다.이 모델 은 더 강력하고 적용하기 쉽습니다. ConventionalModelMetadataProvider


기존 답변

여러 유형의 리소스를 지원하려면 다음을 수행하십시오.

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

그런 다음 다음과 같이 사용하십시오.

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

전체 현지화 자습서를 보려면 이 페이지를 참조 하십시오 .


1
+1. Haack의 솔루션은 다른 솔루션에 비해 확실히 가장 우아한 솔루션입니다. ASP.NET MVC의 컨벤션 기반 프로그래밍 스타일에 매우 적합하며 Global.asax.cs의 단일 nuget 명령과 단일 코드 줄을 통해 쉽게 구현됩니다.
Nilzor

11

리소스 속성을 선택하고 "사용자 지정 도구"를 "PublicResXFileCodeGenerator"로 전환하고 작업을 "내장 리소스"로 빌드하여 Gunders가 내 App_GlobalResources 작업에 대한 답변을 얻었습니다. 아래의 Gunders 의견을 준수하십시오.

여기에 이미지 설명을 입력하십시오

매력처럼 작동합니다 :)


이렇게하면 App_GlobalResources 외부에 리소스 파일을 추가 한 것처럼 컴파일되는 리소스 파일이 생성됩니다. 따라서 리소스 파일은 더 이상 "App_GlobalResources"리소스 파일처럼 작동하지 않습니다. 그러나 당신은 그것을 알고 있어야합니다. 따라서 더 이상 리소스 파일을 App_GlobalResources에 넣는 "혜택"이 없습니다. 다른 곳에도 넣을 수 있습니다.
르네

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. 자원 을 찾도록 속성의 ResourceType 을 정의하십시오.
  2. 리소스 키에 사용되는 특성의 이름 을 정의합니다. C # 6.0 이후 nameof에는 키를 하드 코딩하는 대신 강력한 형식의 지원에 사용할 수 있습니다 .

  3. 컨트롤러에서 현재 스레드의 문화권을 설정하십시오.

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

  1. 자원의 접근성을 공개로 설정

  2. 다음 과 같이 cshtml에 레이블을 표시하십시오.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.