ローカライズされたアプリケーションがあり、特定のモデルプロパティのDisplayName
をリソースから設定できるかどうか疑問に思っています。
私はこのようなことをしたいです:
public class MyModel {
[Required]
[DisplayName(Resources.Resources.labelForName)]
public string name{ get; set; }
}
しかし、コンパイラーが「属性引数は定数式、typeof式、または属性パラメーター型の配列作成式でなければならない」と言っているように、私はそれができません。
回避策はありますか?ラベルを手動で出力していますが、これらはバリデータの出力に必要です!
カスタム属性の記述はどうですか:
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; }
}
MVC 3および.NET 4を使用している場合、System.ComponentModel.DataAnnotations
名前空間で新しい Display
属性を使用できます。この属性は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
を使用するべきではありません。これがなぜなのかについて詳しく読むことができます here )
リソースファイルを開いてアクセス修飾子をpublicまたはinternalに変更すると、リソースファイルからクラスが生成され、厳密に型指定されたリソース参照を作成できます。
つまり、代わりにこのようなことを行うことができます(C#6.0を使用)。次に、firstnameが小文字であるかラクダケースであるかを覚えておく必要はありません。また、他のプロパティが同じリソース値を使用しているかどうかを確認し、すべての参照を検索します。
[Display(Name = nameof(PropertyNames.FirstName), ResourceType = typeof(PropertyNames))]
public string FirstName { get; set; }
遅すぎることはわかっていますが、このアップデートを追加したいと思います。
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; }
完全なローカライズチュートリアルについては、 このページ を参照してください。
リソースプロパティを選択し、「カスタムツール」を「PublicResXFileCodeGenerator」に切り替えて、アクションを「Embedded Resource」にビルドすることで、App_GlobalResourcesでGundersの回答を得ました。以下のガンダーズのコメントをご覧ください。
魅力のように動作します:)
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))]
}
リソースのキーに使用される属性のNameを定義します。C#6.0以降では、キーをハードコーディングする代わりにnameof
を使用して強力な型付きサポートを行うことができます。
現在のスレッドのカルチャをコントローラーに設定します。
Resource.Culture = CultureInfo.GetCultureInfo("zh-CN");
リソースのアクセシビリティをパブリックに設定します
ラベルをcshtmlのように表示します
@Html.DisplayNameFor(model => model.Age)