2011-09-13 13 views
14

私は、他の国の人たちが使うクラスに取り組んでいます。すべてのメッセージをローカライズする必要があります。彼らは私たちが何を意味するのかを理解することができます。多くの場合、私は自分の目標を達成しました。しかし、説明のようなこれらのプロパティ属性は、お尻のような痛みです。私が今持っているものC#でプロパティの説明をローカライズする方法は?

Here`s:

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

私がやろうとしているものです。しかし、このようにローカリゼーションを使用することはできません。私はそれの代わりに使うことができる何かについての示唆?

答えて

18

サブクラス:

[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

私は本当に理解できなかったことを告白する必要があります。つまり、「desc」はローカライズされた属性のキーですか?指定したプロパティの属性にアクセスするにはどうすればよいですか?あなたの例を私のものに適応してください。 – 3yanlis1bos

+0

@ 3yanlis1bosこの例では文字列をキーとして使用しています - 手動でRESXをフェッチする必要があります(RESXの後ろに生成されたファイルを参照してください)。または反射を使用してください。 –

+0

わかりました。 description属性を拡張し、ローカライズされた文字列を入力として扱うように、私のニーズに合わせて修正しました。そうですか?私がしなければならないのは古いものの代わりに新しい属性を使うことだけです。 – 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; } 

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

+2

OPは 'CategoryAttribute' /' DescriptionAttribute'を使用しているので、おそらく話しているでしょう* regular * 'System.ComponentModel MVCではなく、この場合は単に適用されません。 –

+0

ああ、それを知らなかった。私は主にMVCを開発し、その属性が汎用的であると考えました(ただし、素晴らしい機能になります)。 – Patrick

+0

@パトリック私はどちらも理解できませんでした。 C#でちょっとした初心者。とにかく試してくれてありがとう。ローカライズされたリソース文字列にアクセスする "Resources.Global"がありましたか?はいの場合、そのようなものを記述属性にどのように記述すればよいですか? – 3yanlis1bos

1

CategoryAttributeが内部リソースに基づいて、ローカライズされた文字列を探すために、コードを持っているようだが、DescriptionAttributeは何の局在性を持っていません。

リフレクターから:

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

私はあなたの属性を拡張し、ResourceTypeがに渡し、独自の実装を作成すると思います。このようなものは、DataAnnotationロジックに曖昧に基づいています。明らかにもう少しクリーンアップが必要です。

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

実際、このカテゴリ属性は、エンド・エフェクトの説明とあまり変わりません。私はファイル内にローカライズされた文字列を持っていますが、例外にそれらを適用するような属性にそれらを適用するためのパーミッションを得ることはできません。私が理解しようとしている唯一のことは、あなたが言ったように内部ソースを持つDescriptionAttributeをどのように満たすかということです。 – 3yanlis1bos

3

のは、このサンプル・クラスを見てみましょう:カスタム属性クラスを実装することができ

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

は今:

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

私はすでにリソースファイルを持っています。私は警告とメッセージのためにそれらを使用します。しかし、問題は、記述属性にローカライズされたリソースを渡すことができないことです(不可能です)。それは私が言っていることです。 – 3yanlis1bos

+0

私はマークと同じように見えます。しかし、それは私にとって理解しやすいです。私はこれを試してみたいと思う。 – 3yanlis1bos

2

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

今、あなたは、ローカライズされた記述を持っていますJani's aへのわずかな拡張(私のためによく働いた)nswer:

string description = Strings.GetString(Key); 

はより明確に

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

として行うことができますそれは漠然と暗示が、元のコードから失われたものは明らかではなかったです。リソースクラスの.ResourceManagerプロパティは自動生成されます。

これにアクセスするには、フィールド/クラス名をハードコードする代わりに、Glennularの説明にあるStackOverflowという拡張メソッドを使用します(DescriptionAttributeの代わりにLocDescriptionAttributeを使用してください)。

私が作成した唯一の調整は、this IComparable enumに基づいて静的にして、特定の型にロックされずに任意の列挙型で使用できるようにすることでした。説明を追加した列挙型に限定するためのインタフェースを適用できないということを考えれば、私ができることは最高です。

2
私は Marc Gravell組み合わせました

dsmithさんの答え:

まず:LocalizedDescriptionAttributeという名前の属性クラスを作成

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

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

(単語は "属性" は必要ありません)

LocalizedDescriptionとして使用してください
public class Foo 
{ 
    // myString is a key that exists in your Resources file 
    [LocalizedDescription("myString")] 
    public string Bar { get; set; } 
} 
関連する問題