2009-10-13 2 views
4

이전에 단 하나의 답변이있는 question을 요청했습니다. 나는 지금 이것으로 놀고 계획을 가지고 있지만 좋은 생각인지에 대한 피드백을 원할 때가있다.이것은 플러그 가능한 구성 요소의 현지화를위한 좋은 솔루션입니까?

문제 :

내가 함께 구성 요소의 모델을 오염하지 않고, 그 이름을 소모하는 응용 프로그램에 지역화 가지고 (구성 요소를 식별하는 데 사용 불변) 이름이 구성 요소를 원하는 DisplayName 특성입니다. 구성 요소는 별도의 dll에 존재할 수 있으며 런타임에 동적으로로드됩니다.

내 생각에 구성 요소 dll은 지역화 된 이름을 제공해야합니다 (이것은 좋은 캡슐화처럼 보입니다). 그러나 구성 요소를 사용하는 응용 프로그램은 지역화 된 이름을 가져 오거나 사용하는 책임을 져야합니다. 표시 목적에 대한 다른 이름은 구성 요소의 문제가 아니라이 솔루션은

해당 구성 요소를 사용하여 '보기')의 :

파일과 동일한 이름을 가진 구성 요소 DLL에 리소스를 추가 구성 요소 클래스가 있습니다. 구성 요소의 이름 인 키를 사용하여 문자열을 리소스에 추가합니다. 응용 프로그램에서

는 지역화 된 이름과 같이 얻을 :

ExternalObject obj = GetExternalObject();    
ResourceManager manager = new ResourceManager (obj.GetType()); 
string localisedName= manager.GetString (obj.Name); 

이 코드는 아마 로칼 라이져 클래스에 캡슐화하지만, 요점을 전달한다. 이것은 작동하는 것처럼 보이지만, 좋은 생각입니까, 아니면 표준/표준 방법이 더 좋습니까?

편집 : 나는이 솔루션에 대해 잘 모르는 한 가지는 리소스가 클래스에있는 파일과 동일한 이름을 가진 .resx 파일에 있어야한다는 것입니다. 리소스 파일을 형식 이름에서 식별 할 수 있으므로 제대로 작동합니다. 이것은 양식의 현지화가 작동하는 것처럼 보이며 Visual Studio가 .csx 파일의 '하위 구성 요소'로 표시되도록합니다. 모두 멋지게 보입니다. 그러나 Visual Studio에서는이 파일을 편집하려고하면 (다른 프로젝트 항목에 포함 된 리소스를 편집하는 것과 관련하여) 경고를 던지므로이 작업을 수행하는 다른 방법이 있다고 생각하게 만듭니다.

+0

rex를 편집하려면 기본 제공 Resource Editor를 사용하십시오. 그러나 그 경고는 무시할 수 있어야합니다, AFAICT. – psychotik

+0

이것은 내장 편집기를 사용하고 있었으며 무시할 수 있으며 모든 것이 정상적으로 작동하는 것 같습니다. 유모를 좋아할 때 내가하지 말아야 할 일을하고있는 것처럼 느껴집니다. –

답변

1

나는 생각합니다. 당신은 올바른 아이디어가 있다고 생각합니다. 그러나 이것을 달성하는 더 좋은 방법이 있습니다.

아마도 플러그 가능한 구성 요소가 구현하는 인터페이스가 있습니다. , IPluggable을 말 : 주 바이너리에서

interface IPluggable { 
    ... 
    string LocalizedName {get;} 
    ... 
} 

를 플러그 어셈블리를로드 및 반사를 사용하여 IPluggable 인스턴스를 만든 다음 LocalizedName 속성을 사용하여 지역화 된 이름을 액세스 (나는 당신이 가지고있는 GetExternalObject() 방법은 무엇이다 가정). 내부에 IPluggable 구현을 만들고 ResourceManager을 만들고 해당 플러그 가능 어셈블리의 resx에서 LocalizedName에 액세스하십시오.

플러그 식 어셈블리에서 동작을 캡슐화하는 것이 좋습니다. 로컬 컴퓨터에 액세스하기 위해 ResourceManager을 만들 수 있다고 가정하면 사용자 프로그램을 사용하지 않고도 지역화 된 이름을 제공 할 책임이 있습니다. 현지화 된 이름.

+0

이것은 현재 내가 가지고있는 상황이지만, 내가 벗어나려고 노력하고있는 것입니다. 지역화 된 이름이 모델의 관심사가 아니기 때문에 내 모델에 LocalizedName 속성이 포함되는 것을 원하지 않습니다. 당신이 가지고있는 것은 좋은 캡슐화일지도 모르지만 우려의 분리는 아닙니다. 내가 트리를 대표한다고 상상해보십시오. 이름은 트리의 라틴어 이름입니다. 영어 사용자에게 표시 될 때 라틴어 이름과 다른 이름을보고 싶다는 사실을 염두에 두지 않아야합니다. –

+0

캡슐화 (구성 요소의 dll에 리소스를 저장)를 유지하고 불변 이름을 키로 사용하여 구성 요소 리소스를 쿼리하여 뷰에 LocalisedName에 액세스하도록하여 SOC를 유지하려고합니다. –

-1

제안한 방식의 문제점은 번역을 업데이트하기가 어려워 프로그래머가 필요할 수도 있다는 것입니다. 또한 전체 응용 프로그램을 업데이트하지 않고 번역을 어떻게 업데이 트합니까?

나는 번역 응용 프로그램을 많이 수행하고, 내가 무슨 짓을하는 것은 이런 식 형식의 translatations와 별도의 텍스트 파일이 있습니다 않은 :

[영어]
완료 =이

을 완료

[노르웨이어를 ] 그쪽 난 형태 이벤트 표시 내부 부르는)는
= Ferdig

짓 그리고 난 TranslateForm (라는 기능을 가지고 모든 UI 요소가 번역됩니다. TranslateForm() 함수는

buttonDone.Text = Translate.GetTranslation("Done"); 

TranslateForm와 마지막 부분은 최적의 해결책이 아니다처럼 일을해야합니다, 나는 시간이 지남에 내가 컨트롤 자체가 호출하는 곳이 클래스를 번역하는 솔루션으로 마이그레이션 할 것이라 생각합니다. 이 시스템을 사용할 때의 이점은 프로그래머가 간단하다는 것입니다. 나중에 수동 작업을하지 않아도 다른 ppl 추가 번역이 가능합니다 (커뮤니티 주도 번역이 있으므로이 번역은 나에게 유용합니다). 나는 그것에 시간을 보내고 싶지 않다. 응용 프로그램을 다시 시작하거나 업데이트 할 필요없이 응용 프로그램이 실행되는 동안 번역을 업데이트 할 수도 있습니다.

+1

귀하의 우려를 이해하고 있는지 잘 모르겠습니다. 번역은 위성 어셈블리를 통해 이루어지며 특별히 새로운 번역을 제공하기 위해 응용 프로그램을 업데이트 할 필요가 없으며 새로운 위성 어셈블리를 제공합니다. 이것은 표준 .net 번역 방법입니다. 귀하의 접근 방식에 대한 문제는 (비록 이것이 내 시나리오에는 해당되지 않지만) 손으로 모든 번역을해야한다는 것과 b. '완료'텍스트가 귀하가 만든 버튼에 맞지 않는 경우 어떤 언어? 표준 접근 방식을 사용하면 새로운 텍스트뿐만 아니라 새로운 버튼 크기를 제공 할 수 있습니다. –

+1

EKS, 당신이 제안하는 것은 원시적입니다. .NET에는 resx 파일과 위성 어셈블리를 사용하기 위해 여러 가지 지원 기능이 내장되어있어 새로운 코드를 선적해야합니다.업데이트/새 번역의 경우 코드가 아닌 리소스 바이너리를 제공하기 만하면됩니다. – psychotik

+0

원시적이지만 작동합니다. 내 게시물에서 정리하려고했듯이 번역본의 업데이트 빈도에 따라 다릅니다. 그리고 WHO는 당신이 그것을하기 위해 누군가를 고용한다면, 나의 방법은 사용할 사람이 아닐 수도 있습니다. 하지만 "모든 사람"이 번역을 업데이트 할 수 있기 때문에 지역 사회에서 번역을 운영하는 경우 유용합니다. – EKS

0

전 몇 시간 전에 enum 값을 지역화하는 데 문제가있었습니다. 질문에 답을했는지 확신 할 수 없지만 적어도 다른 방법을 생각해보십시오. 나는 내가 LocalizationAttribute 설명 키를 가져오고 리소스 파일에 액세스하는 형식 변환기를 만든 다음에 열거 자체

[TypeConverter(typeof(EnumToLocalizedString))] 
public enum ReviewReason 
{ 
    [LocalizationAttribute("ReviewReasonNewDocument")] 
    NewDocument = 1, 


    [LocalizationAttribute("ReviewReasonInternalAudit")] 
    InternalAudit = 2, 


    [LocalizationAttribute("ReviewReasonExternalAudit")] 
    ExternalAudit = 3, 


    [LocalizationAttribute("ReviewReasonChangedWorkBehaviour")] 
    ChangedWorkBehaviour = 4, 


    [LocalizationAttribute("ReviewReasonChangedWorkBehaviourBecauseOfComplaints")] 
    ChangedWorkBehaviourBecauseOfComplaints = 5, 


    [LocalizationAttribute("ReviewReasonMovedFromOlderSystem")] 
    MovedFromOlderSystem = 6, 


    [LocalizationAttribute("ReviewReasonPeriodicUpdate")] 
    PeriodicUpdate = 7, 


    [LocalizationAttribute("ReviewReasonDocumentChanged")] 
    DocumentChanged = 8 
} 

을 만들 거기에서 내 자신의 지역화 속성

/// <SUMMARY> 
/// Attribute used for localization. Description field should contain a reference to the Resource file for correct localization 
/// </SUMMARY> 
public class LocalizationAttribute : Attribute 
{ 
    public LocalizationAttribute(string description) 
    { 
     this._description = description; 
    } 

    private string _description; 
    /// <SUMMARY> 
    /// Used to reference a resource key 
    /// </SUMMARY> 
    public string Description 
    { 
     get 
     { 
      return this._description; 
     } 
    } 
} 

를 작성하여 시작

현지화를 얻으려면 (속성 설명이 자원 키와 일치해야합니다 :))

public class EnumToLocalizedString : TypeConverter 
    { 
     public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
     { 
      return (sourceType.Equals(typeof(Enum))); 
     } 

     public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
     { 
      return (destinationType.Equals(typeof(String))); 
     } 

     public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
     { 
      return base.ConvertFrom(context, culture, value); 
     } 

     public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
     { 
      if (!destinationType.Equals(typeof(String))) 
      { 
       throw new ArgumentException("Can only convert to string.", "destinationType"); 
      } 
      if (!value.GetType().BaseType.Equals(typeof(Enum))) 
      { 
       throw new ArgumentException("Can only convert an instance of enum.", "value"); 
      } 

      string name = value.ToString(); 
      object[] attrs = value.GetType().GetField(name).GetCustomAttributes(typeof(LocalizationAttribute), false); 
      if (attrs.Length != 1 !(attrs[0] is LocalizationAttribute)) 
      { 
       throw new ArgumentException("Invalid enum argument"); 
      } 
      return Handbok.Code.Resources.handbok.ResourceManager.GetString(((LocalizationAttribute)attrs[0]).Description); 
     } 
    } 
,

마지막으로 나는이 경우 집합

public class ReviewReasonCollection 
{ 
    private static Collection<KEYVALUEPAIR<REVIEWREASON,>> _reviewReasons; 

    public static Collection<KEYVALUEPAIR<REVIEWREASON,>> AllReviewReasons 
    { 
     get 
     { 
      if (_reviewReasons == null) 
      { 
       _reviewReasons = new Collection<KEYVALUEPAIR<REVIEWREASON,>>(); 
       TypeConverter t = TypeDescriptor.GetConverter(typeof(ReviewReason)); 

       foreach (ReviewReason reviewReason in Enum.GetValues(typeof(ReviewReason))) 
       { 
        _reviewReasons.Add(new KeyValuePair<REVIEWREASON,>(reviewReason, t.ConvertToString(reviewReason))); 
       } 
      } 
      return _reviewReasons; 
     } 
    } 
} 

나는 원래 posted this solution on my blog입니다 TypeConverter가를 사용하는 클라이언트를 만들었습니다. 그것이 당신을 도와 줄 수 있기를 바랍니다 :)

관련 문제