2009-10-13 56 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將.resx作爲.cs文件的「子組件」,這看起來都很不錯。但是,如果我嘗試編輯這個文件,visual studio會拋出一個警告(關於編輯另一個項目的一部分的資源),這讓我覺得也許還有其他一些方法,我應該這樣做。

+0

要編輯rex,請使用內置的資源編輯器。但是這個警告應該是可以忽略的,AFAICT。 – psychotik 2009-10-13 20:22:23

+0

這是使用內置的編輯器,是的,它是可以忽略的,一切似乎工作正常。它只是覺得我正在做一些我不應該做的事情,當它試圖保姆我這樣。 – 2009-10-14 08:09:48

回答

1

我認爲你有正確的想法,但有更好的方法來實現這一點。

推測,您有一個可插拔組件實現的接口。再說了,IPluggable:

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

從你的主要二進制文件,加載可插入組裝,並使用反射IPluggable實例(我假設是什麼GetExternalObject()方法你必須做),然後使用LocalizedName屬性訪問的本地化名稱。 Inside IPluggable實現中,創建一個ResourceManager並從該可插拔部件的resx訪問LocalizedName

你在做什麼是可插拔組件中行爲的良好封裝 - 它負責爲你提供本地化名稱,但它選擇這樣做,沒有你的man程序假定可以創建ResourceManager來訪問本地化名稱。

+0

這是目前我遇到的情況,但正是我想擺脫的。我不希望我的模型包含LocalizedName屬性,因爲存在本地化名稱的事實不是模型的關注點。你有什麼可能是好的封裝,但不是分離的擔憂。想象一下,我有ITree代表一棵樹。它有一個名字,這是樹的拉丁名字。當向英文用戶顯示時,他們不應該關心他們希望看到與拉丁名稱不同的名稱。 – 2009-10-14 08:04:33

+0

我想保留封裝(通過讓資源存在於組件的dll中),並通過使用不變名稱作爲關鍵字來查看組件資源,使視圖訪問LocalisedName來擁有SOC。 – 2009-10-14 08:12:26

-1

您提出的方式存在的問題是,它很難更新翻譯,甚至可能需要程序員。另外你如何在不更新整個應用程序的情況下更新翻譯?

我已經做了很多翻譯應用程序,而我所做的就是與格式化像這樣translatations一個單獨的文本文件:

[英]
DONE =完成

[挪威]
完成= Ferdig

,我有一個叫做TranslateForm(功能),我稱之爲形式顯示事件中,塔t將翻譯所有UI元素。該TranslateForm()函數將有事情像

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

與TranslateForm最後一部分是不是一個最佳的解決方案,我想隨着時間的推移,我會遷移到一個解決方案,在控制自身調用翻譯類。 使用這個系統的好處是,它對於程序員來說很簡單,你可以有其他的PPL添加翻譯,而不必在事後做手工工作(這對我來說是重要的,因爲我有社區驅動的翻譯),所以它們經常更新,我不想花時間在那。 我也可以在應用程序運行時更新翻譯,而不必重新啓動或更新應用程序。

+1

我不確定我瞭解你的顧慮。翻譯是通過衛星組件完成的,並且不需要更新應用程序來提供新的翻譯,只需提供一個新的衛星組件。這是標準的.net翻譯方法。你的方法存在問題(雖然我承認這不適用於我的情況),你必須手工做所有翻譯,並且b如果'完成'的文本不適合你創建的按鈕怎麼辦?有些語言?使用標準方法,您可以提供新的按鈕大小以及新的文本。 – 2009-10-13 12:37:57

+1

EKS,你的建議是原始的。 .NET有一些內置的支持來使用resx文件和衛星程序集,這些程序不需要運行新代碼。對於更新/新的翻譯,您只需發送資源二進制文件,它不是代碼。 – psychotik 2009-10-13 20:21:13

+0

原始但工作。 就像我試圖在我的文章中清理一樣,這取決於你更新翻譯的頻率。世衛組織也會這樣做,如果你僱人來做,我的方法可能不是那個人使用的方法。但如果你有一個社區驅動的翻譯它的好,因爲「任何人」都可以更新翻譯。 – EKS 2009-10-14 08:18:52

0

前段時間我有一個本地化枚舉值的問題,我不確定它是否回答你的問題,但至少給你另一種方法來記住。

通過創建我自己的本地化屬性

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

從那裏開始,我創建了枚舉本身

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

然後我創建了一個類型轉換器,這將提取LocalizationAttribute描述鍵和訪問資源文件以獲得本地化(屬性描述必須匹配資源鍵:))

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

最後我創建它使用的TypeConverter,在這種情況下是一家集

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客戶端。希望它可以幫助你:)

相關問題