mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
#17754: Localizing validation attributes
Work Items: 17754 --HG-- branch : 1.x
This commit is contained in:
@@ -1,39 +0,0 @@
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Comments.Annotations {
|
||||
public class RequiredAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute {
|
||||
public RequiredAttribute() {
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override string FormatErrorMessage(string name) {
|
||||
return T("You must provide a {0} in order to comment.", name).Text;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommentRequiredAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute {
|
||||
public CommentRequiredAttribute() {
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override string FormatErrorMessage(string name) {
|
||||
return T("You must provide a Comment.", name).Text;
|
||||
}
|
||||
}
|
||||
|
||||
public class RegularExpressionAttribute : System.ComponentModel.DataAnnotations.RegularExpressionAttribute {
|
||||
public RegularExpressionAttribute(string pattern) : base(pattern) {
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override string FormatErrorMessage(string name) {
|
||||
return T("The {0} is not valid.", name).Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,6 @@
|
||||
<Compile Include="Drivers\CommentsContainerPartDriver.cs" />
|
||||
<Compile Include="Drivers\CommentSettingsPartDriver.cs" />
|
||||
<Compile Include="Drivers\CommentsPartDriver.cs" />
|
||||
<Compile Include="Annotations\CommentValidationAttributes.cs" />
|
||||
<Compile Include="ResourceManifest.cs" />
|
||||
<Compile Include="Rules\CommentsActions.cs" />
|
||||
<Compile Include="Rules\CommentsForms.cs" />
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.Comments.Annotations;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Orchard.Comments.ViewModels {
|
||||
public class CommentsCreateViewModel {
|
||||
[Annotations.Required]
|
||||
[Required]
|
||||
[StringLength(255)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Annotations.RegularExpression(@"^[^@\s]+@[^@\s]+$")]
|
||||
[RegularExpression(@"^[^@\s]+@[^@\s]+$")]
|
||||
[StringLength(255)]
|
||||
public string Email { get; set; }
|
||||
|
||||
[StringLength(245)]
|
||||
[Annotations.RegularExpression(@"^(http(s)?://)?([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}[\S]+$")]
|
||||
[DisplayName("Site")]
|
||||
[RegularExpression(@"^(http(s)?://)?([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}[\S]+$")]
|
||||
public string SiteName { get; set; }
|
||||
|
||||
[CommentRequired]
|
||||
[Required, DisplayName("Comment")]
|
||||
public string CommentText { get; set; }
|
||||
|
||||
public int CommentedOn { get; set; }
|
||||
|
||||
@@ -23,6 +23,7 @@ using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.FileSystems.WebSite;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Mvc.DataAnnotations;
|
||||
using Orchard.Mvc.ViewEngines.Razor;
|
||||
using Orchard.Mvc.ViewEngines.ThemeAwareness;
|
||||
using Orchard.Services;
|
||||
@@ -143,6 +144,10 @@ namespace Orchard.Environment {
|
||||
//MvcServiceLocator.SetCurrent(hostContainer);
|
||||
OrchardHostContainerRegistry.RegisterHostContainer(hostContainer);
|
||||
|
||||
// Register localized data annotations
|
||||
ModelValidatorProviders.Providers.Clear();
|
||||
ModelValidatorProviders.Providers.Add(new LocalizedModelValidatorProvider());
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Mvc.DataAnnotations {
|
||||
public class LocalizedModelValidatorProvider : DataAnnotationsModelValidatorProvider {
|
||||
private static readonly Dictionary<Type, Func<ValidationAttribute, Localizer, ValidationAttribute>> _validationAttributes;
|
||||
|
||||
static LocalizedModelValidatorProvider() {
|
||||
_validationAttributes = new Dictionary<Type, Func<ValidationAttribute, Localizer, ValidationAttribute>> {
|
||||
{ typeof(RequiredAttribute), (attribute, t) => new LocalizedRequiredAttribute((RequiredAttribute)attribute, t)},
|
||||
{ typeof(RangeAttribute), (attribute, t) => new LocalizedRangeAttribute((RangeAttribute)attribute, t)},
|
||||
{ typeof(StringLengthAttribute), (attribute, t) => new LocalizedStringLengthAttribute((StringLengthAttribute)attribute, t)},
|
||||
{ typeof(RegularExpressionAttribute), (attribute, t) => new LocalizedRegularExpressionAttribute((RegularExpressionAttribute)attribute, t)}
|
||||
};
|
||||
}
|
||||
|
||||
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes) {
|
||||
var localizedAttributes = new List<Attribute>();
|
||||
|
||||
foreach ( var attribute in attributes ) {
|
||||
Func<ValidationAttribute, Localizer, ValidationAttribute> localizedAttribute;
|
||||
|
||||
// overriden messages have their localization in the scope of the class they are applied to
|
||||
var tContainer = LocalizationUtilities.Resolve(context, metadata.ContainerType.FullName);
|
||||
|
||||
// default translations use the attribute's scope, e.g., System.ComponentModel.DataAnnotations.RequiredAttribute
|
||||
var tProvider = LocalizationUtilities.Resolve(context, attribute.GetType().FullName);
|
||||
|
||||
var validationAttribute = attribute as ValidationAttribute;
|
||||
|
||||
// substitute the attribute to its localized version if available
|
||||
if ( _validationAttributes.TryGetValue(attribute.GetType(), out localizedAttribute) ) {
|
||||
localizedAttributes.Add(localizedAttribute((ValidationAttribute)attribute, tProvider));
|
||||
}
|
||||
else {
|
||||
|
||||
// try to inject the localizer if it's an unkown validation attribute
|
||||
if ( validationAttribute != null ) {
|
||||
|
||||
var propertyInfo = validationAttribute.GetType().GetProperty("T", typeof(Localizer));
|
||||
if ( propertyInfo != null ) {
|
||||
propertyInfo.SetValue(attribute, tProvider, null);
|
||||
}
|
||||
}
|
||||
|
||||
if ( attribute is DisplayNameAttribute ) {
|
||||
metadata.DisplayName = tContainer(metadata.DisplayName).Text;
|
||||
}
|
||||
|
||||
localizedAttributes.Add(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
var result = base.GetValidators(metadata, context, localizedAttributes);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/Orchard/Mvc/DataAnnotations/LocalizedRangeAttribute.cs
Normal file
24
src/Orchard/Mvc/DataAnnotations/LocalizedRangeAttribute.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.Serialization;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Mvc.DataAnnotations {
|
||||
public class LocalizedRangeAttribute : RangeAttribute {
|
||||
public LocalizedRangeAttribute(RangeAttribute attribute, Localizer t)
|
||||
: base(attribute.OperandType, new FormatterConverter().ToString(attribute.Minimum), new FormatterConverter().ToString(attribute.Maximum)) {
|
||||
if ( !String.IsNullOrEmpty(attribute.ErrorMessage) )
|
||||
ErrorMessage = attribute.ErrorMessage;
|
||||
|
||||
T = t;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override string FormatErrorMessage(string name) {
|
||||
return String.IsNullOrEmpty(ErrorMessage)
|
||||
? T("The field {0} must be between {1} and {2}.", name, Minimum, Maximum).Text
|
||||
: T(ErrorMessage, name, Minimum, Maximum).Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Mvc.DataAnnotations {
|
||||
public class LocalizedRequiredAttribute : RequiredAttribute {
|
||||
public LocalizedRequiredAttribute(RequiredAttribute attribute, Localizer t) {
|
||||
AllowEmptyStrings = attribute.AllowEmptyStrings;
|
||||
|
||||
if ( !String.IsNullOrEmpty(attribute.ErrorMessage) )
|
||||
ErrorMessage = attribute.ErrorMessage;
|
||||
|
||||
T = t;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override string FormatErrorMessage(string name) {
|
||||
return String.IsNullOrEmpty(ErrorMessage)
|
||||
? T("The field {0} is required.", name).Text
|
||||
: T(ErrorMessage, name).Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Mvc.DataAnnotations {
|
||||
public class LocalizedRegularExpressionAttribute : RegularExpressionAttribute {
|
||||
public LocalizedRegularExpressionAttribute(RegularExpressionAttribute attribute, Localizer t)
|
||||
: base(attribute.Pattern) {
|
||||
if ( !String.IsNullOrEmpty(attribute.ErrorMessage) )
|
||||
ErrorMessage = attribute.ErrorMessage;
|
||||
|
||||
T = t;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override string FormatErrorMessage(string name) {
|
||||
return String.IsNullOrEmpty(ErrorMessage)
|
||||
? T("The field {0} must match the regular expression '{1}'.", name, Pattern).Text
|
||||
: T(ErrorMessage, name, Pattern).Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Mvc.DataAnnotations {
|
||||
public class LocalizedStringLengthAttribute : StringLengthAttribute {
|
||||
public LocalizedStringLengthAttribute(StringLengthAttribute attribute, Localizer t)
|
||||
: base(attribute.MaximumLength) {
|
||||
if ( !String.IsNullOrEmpty(attribute.ErrorMessage) )
|
||||
ErrorMessage = attribute.ErrorMessage;
|
||||
|
||||
MinimumLength = attribute.MinimumLength;
|
||||
|
||||
T = t;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public override string FormatErrorMessage(string name) {
|
||||
if ( !String.IsNullOrEmpty(ErrorMessage) )
|
||||
return T(ErrorMessage, name, MaximumLength, MinimumLength).Text;
|
||||
|
||||
return MinimumLength > 0
|
||||
? T("The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.", name, MaximumLength, MinimumLength).Text
|
||||
: T("The field {0} must be a string with a maximum length of {1}.", name, MaximumLength, MinimumLength).Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,6 +230,11 @@
|
||||
<Compile Include="Logging\OrchardLog4netFactory.cs" />
|
||||
<Compile Include="Logging\OrchardLog4netLogger.cs" />
|
||||
<Compile Include="Messaging\Services\DefaultMessageManager.cs" />
|
||||
<Compile Include="Mvc\DataAnnotations\LocalizedReularExpressionAttribute.cs" />
|
||||
<Compile Include="Mvc\DataAnnotations\LocalizedStringMaxLengthAttribute.cs" />
|
||||
<Compile Include="Mvc\DataAnnotations\LocalizedRangeAttribute.cs" />
|
||||
<Compile Include="Mvc\DataAnnotations\LocalizedModelValidatorProvider.cs" />
|
||||
<Compile Include="Mvc\DataAnnotations\LocalizedRequiredAttribute.cs" />
|
||||
<Compile Include="Mvc\Extensions\RouteExtension.cs" />
|
||||
<Compile Include="Mvc\HttpContextWorkContext.cs" />
|
||||
<Compile Include="Mvc\Extensions\ControllerExtensions.cs" />
|
||||
|
||||
Reference in New Issue
Block a user