public ExtendedValidationAttributeAdapter(TAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { _textLocalizer = stringLocalizer != null ? stringLocalizer as StringLocalizerAdapter ?? new StringLocalizerAdapter(stringLocalizer) : (ITextLocalizer)NullTextLocalizer.Instance; }
public IAttributeAdapter?GetAttributeAdapter( ValidationAttribute attribute, IStringLocalizer?stringLocalizer) { if (attribute is ClassicMovieAttribute classicMovieAttribute) { return(new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer)); } return(baseProvider.GetAttributeAdapter(attribute, stringLocalizer)); }
public DataTypeAttributeAdapter(DataTypeAttribute attribute, string ruleName, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { if (string.IsNullOrEmpty(ruleName)) { throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(ruleName)); } RuleName = ruleName; }
public static string Localize(this string value, IStringLocalizer?localizer) { if (localizer is null) { return(value); } string?localized = localizer[value]; return(localized ?? value); }
public static string Localize(this string value, IStringLocalizer?localizer, params object[] args) { if (localizer is null) { return(value); } string?localized = localizer[value, args]; return(localized ?? value); }
public void CreateValidators(ModelValidatorProviderContext context) { IStringLocalizer?stringLocalizer = null; if (_stringLocalizerFactory != null && _options.Value.DataAnnotationLocalizerProvider != null) { stringLocalizer = _options.Value.DataAnnotationLocalizerProvider( context.ModelMetadata.ContainerType ?? context.ModelMetadata.ModelType, _stringLocalizerFactory); } var results = context.Results; // Read interface .Count once rather than per iteration var resultsCount = results.Count; for (var i = 0; i < resultsCount; i++) { var validatorItem = results[i]; if (validatorItem.Validator != null) { continue; } if (!(validatorItem.ValidatorMetadata is ValidationAttribute attribute)) { continue; } var validator = new DataAnnotationsModelValidator( _validationAttributeAdapterProvider, attribute, stringLocalizer); validatorItem.Validator = validator; validatorItem.IsReusable = true; // Inserts validators based on whether or not they are 'required'. We want to run // 'required' validators first so that we get the best possible error message. if (attribute is RequiredAttribute) { context.Results.Remove(validatorItem); context.Results.Insert(0, validatorItem); } } // Produce a validator if the type supports IValidatableObject if (typeof(IValidatableObject).IsAssignableFrom(context.ModelMetadata.ModelType)) { context.Results.Add(new ValidatorItem { Validator = new ValidatableObjectAdapter(), IsReusable = true }); } }
/// <summary> /// 获取指定 Type 的资源文件 /// </summary> /// <param name="localizer"></param> /// <param name="key"></param> /// <param name="text"></param> /// <returns></returns> public static bool TryGetLocalizerString(IStringLocalizer?localizer, string key, [MaybeNullWhen(false)] out string?text) { text = null; var l = localizer?[key]; var ret = !(l?.ResourceNotFound ?? false); if (ret) { text = l?.Value; } return(ret); }
public RangeAttributeAdapter(RangeAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { // This will trigger the conversion of Attribute.Minimum and Attribute.Maximum. // This is needed, because the attribute is stateful and will convert from a string like // "100m" to the decimal value 100. // // Validate a randomly selected number. attribute.IsValid(3); _max = Convert.ToString(Attribute.Maximum, CultureInfo.InvariantCulture) !; _min = Convert.ToString(Attribute.Minimum, CultureInfo.InvariantCulture) !; }
public FileExtensionsAttributeAdapter(FileExtensionsAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { // Build the extension list based on how the JQuery Validation's 'extension' method expects it // https://jqueryvalidation.org/extension-method/ // These lines follow the same approach as the FileExtensionsAttribute. var normalizedExtensions = Attribute.Extensions.Replace(" ", string.Empty).Replace(".", string.Empty).ToLowerInvariant(); var parsedExtensions = normalizedExtensions.Split(',').Select(e => "." + e); _formattedExtensions = string.Join(", ", parsedExtensions); _extensions = string.Join(",", parsedExtensions); }
private static string GetDisplayName(FieldInfo field, IStringLocalizer? stringLocalizer) { var display = field.GetCustomAttribute<DisplayAttribute>(inherit: false); if (display != null) { // Note [Display(Name = "")] is allowed but we will not attempt to localize the empty name. var name = display.GetName(); if (stringLocalizer != null && !string.IsNullOrEmpty(name) && display.ResourceType == null) { name = stringLocalizer[name]; } return name ?? field.Name; } return field.Name; }
/// <summary> /// Create a new instance of <see cref="DataAnnotationsModelValidator"/>. /// </summary> /// <param name="attribute">The <see cref="ValidationAttribute"/> that defines what we're validating.</param> /// <param name="stringLocalizer">The <see cref="IStringLocalizer"/> used to create messages.</param> /// <param name="validationAttributeAdapterProvider">The <see cref="IValidationAttributeAdapterProvider"/> /// which <see cref="ValidationAttributeAdapter{TAttribute}"/>'s will be created from.</param> public DataAnnotationsModelValidator( IValidationAttributeAdapterProvider validationAttributeAdapterProvider, ValidationAttribute attribute, IStringLocalizer?stringLocalizer) { if (validationAttributeAdapterProvider == null) { throw new ArgumentNullException(nameof(validationAttributeAdapterProvider)); } if (attribute == null) { throw new ArgumentNullException(nameof(attribute)); } _validationAttributeAdapterProvider = validationAttributeAdapterProvider; Attribute = attribute; _stringLocalizer = stringLocalizer; }
public static string GetAppropriateSingularOrPluralTerm <TEnum>(this TEnum instance, long quantity, IStringLocalizer?localizer = null) where TEnum : Enum { switch (quantity) { case 1: return(instance.GetSingularTerm(localizer)); case -1: return(instance.GetSingularTerm(localizer)); case 2: return(instance.GetDualTerm(localizer)); default: return(instance.GetPluralTerm(localizer)); } }
public IAttributeAdapter?GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer?stringLocalizer) { return(attribute switch { StringLengthAttribute stringLength => new StringLengthAdapter(stringLength), GreaterThanAttribute greaterThan => new GreaterThanAdapter(greaterThan), AcceptFilesAttribute acceptFiles => new AcceptFilesAdapter(acceptFiles), MinLengthAttribute minLength => new MinLengthAdapter(minLength), EmailAddressAttribute email => new EmailAddressAdapter(email), RequiredAttribute required => new RequiredAdapter(required), MaxValueAttribute maxValue => new MaxValueAdapter(maxValue), MinValueAttribute minValue => new MinValueAdapter(minValue), LessThanAttribute lessThan => new LessThanAdapter(lessThan), FileSizeAttribute fileSize => new FileSizeAdapter(fileSize), EqualToAttribute equalTo => new EqualToAdapter(equalTo), IntegerAttribute integer => new IntegerAdapter(integer), DigitsAttribute digits => new DigitsAdapter(digits), NumberAttribute number => new NumberAdapter(number), RangeAttribute range => new RangeAdapter(range), _ => null });
public static string GetAppropriateSingularOrPluralTerm( this int number, string singularTerm, string pluralTerm, string?dualTerm = null, IStringLocalizer?localizer = null) { dualTerm ??= pluralTerm; switch (Math.Abs(number)) { case 1: return(singularTerm.Localize(localizer)); case 2: return(dualTerm.Localize(localizer)); default: return(pluralTerm.Localize(localizer)); } }
public StringLengthAttributeAdapter(StringLengthAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { _max = Attribute.MaximumLength.ToString(CultureInfo.InvariantCulture); _min = Attribute.MinimumLength.ToString(CultureInfo.InvariantCulture); }
public static string GetSingularTerm(this Type type, IStringLocalizer?localizer = null) { return(type.GetAttribute <PluralizerAttribute>(false)?.Singular.Localize(localizer) ?? type.Name); }
public static string GetAppropriateSingularOrPluralTerm(this Type type, long quantity, IStringLocalizer?localizer = null) { return(Math.Abs(quantity) switch { 1 => type.GetSingularTerm(localizer), 2 => type.GetDualTerm(localizer), _ => type.GetPluralTerm(localizer), });
public static string GetDualTerm(this Type type, IStringLocalizer?localizer = null) { return(type.GetAttribute <PluralizerAttribute>(false)?.Dual.Localize(localizer) ?? type.Name.NaivePluralize()); }
public IAttributeAdapter?GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer?localizer) { Type type = attribute.GetType(); if (type == typeof(RequiredAttribute)) { return(new RequiredAdapter((RequiredAttribute)attribute)); } if (type == typeof(StringLengthAttribute)) { return(new StringLengthAdapter((StringLengthAttribute)attribute)); } if (type == typeof(EmailAddressAttribute)) { return(new EmailAddressAdapter((EmailAddressAttribute)attribute)); } if (type == typeof(GreaterThanAttribute)) { return(new GreaterThanAdapter((GreaterThanAttribute)attribute)); } if (type == typeof(AcceptFilesAttribute)) { return(new AcceptFilesAdapter((AcceptFilesAttribute)attribute)); } if (type == typeof(MinLengthAttribute)) { return(new MinLengthAdapter((MinLengthAttribute)attribute)); } if (type == typeof(MaxValueAttribute)) { return(new MaxValueAdapter((MaxValueAttribute)attribute)); } if (type == typeof(MinValueAttribute)) { return(new MinValueAdapter((MinValueAttribute)attribute)); } if (type == typeof(FileSizeAttribute)) { return(new FileSizeAdapter((FileSizeAttribute)attribute)); } if (type == typeof(EqualToAttribute)) { return(new EqualToAdapter((EqualToAttribute)attribute)); } if (type == typeof(IntegerAttribute)) { return(new IntegerAdapter((IntegerAttribute)attribute)); } if (type == typeof(DigitsAttribute)) { return(new DigitsAdapter((DigitsAttribute)attribute)); } if (type == typeof(NumberAttribute)) { return(new NumberAdapter((NumberAttribute)attribute)); } if (type == typeof(RangeAttribute)) { return(new RangeAdapter((RangeAttribute)attribute)); } return(null); }
/// <summary> /// Instantiates a new <see cref="AttributeAdapterBase{TAttribute}"/>. /// </summary> /// <param name="attribute">The <see cref="ValidationAttribute"/> being wrapped.</param> /// <param name="stringLocalizer">The <see cref="IStringLocalizer"/> to be used in error generation.</param> public AttributeAdapterBase(TAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { }
/// <summary> /// Create a new instance of <see cref="ValidationAttributeAdapter{TAttribute}"/>. /// </summary> /// <param name="attribute">The <typeparamref name="TAttribute"/> instance to validate.</param> /// <param name="stringLocalizer">The <see cref="IStringLocalizer"/>.</param> public ValidationAttributeAdapter(TAttribute attribute, IStringLocalizer?stringLocalizer) { Attribute = attribute; _stringLocalizer = stringLocalizer; }
public MinLengthAttributeAdapter(MinLengthAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { _min = Attribute.Length.ToString(CultureInfo.InvariantCulture); }
/// <inheritdoc /> public void CreateValidators(ClientValidatorProviderContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } IStringLocalizer?stringLocalizer = null; if (_options.Value.DataAnnotationLocalizerProvider != null && _stringLocalizerFactory != null) { // This will pass first non-null type (either containerType or modelType) to delegate. // Pass the root model type(container type) if it is non null, else pass the model type. stringLocalizer = _options.Value.DataAnnotationLocalizerProvider( context.ModelMetadata.ContainerType ?? context.ModelMetadata.ModelType, _stringLocalizerFactory); } var hasRequiredAttribute = false; var results = context.Results; // Read interface .Count once rather than per iteration var resultsCount = results.Count; for (var i = 0; i < resultsCount; i++) { var validatorItem = results[i]; if (validatorItem.Validator != null) { // Check if a required attribute is already cached. hasRequiredAttribute |= validatorItem.Validator is RequiredAttributeAdapter; continue; } var attribute = validatorItem.ValidatorMetadata as ValidationAttribute; if (attribute == null) { continue; } hasRequiredAttribute |= attribute is RequiredAttribute; var adapter = _validationAttributeAdapterProvider.GetAttributeAdapter(attribute, stringLocalizer); if (adapter != null) { validatorItem.Validator = adapter; validatorItem.IsReusable = true; } } if (!hasRequiredAttribute && context.ModelMetadata.IsRequired) { // Add a default '[Required]' validator for generating HTML if necessary. context.Results.Add(new ClientValidatorItem { Validator = _validationAttributeAdapterProvider.GetAttributeAdapter( new RequiredAttribute(), stringLocalizer), IsReusable = true }); } }
/// <summary> /// Creates an <see cref="IAttributeAdapter"/> for the given attribute. /// </summary> /// <param name="attribute">The attribute to create an adapter for.</param> /// <param name="stringLocalizer">The localizer to provide to the adapter.</param> /// <returns>An <see cref="IAttributeAdapter"/> for the given attribute.</returns> public IAttributeAdapter?GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer?stringLocalizer) { if (attribute == null) { throw new ArgumentNullException(nameof(attribute)); } var type = attribute.GetType(); if (typeof(RegularExpressionAttribute).IsAssignableFrom(type)) { return(new RegularExpressionAttributeAdapter((RegularExpressionAttribute)attribute, stringLocalizer)); } else if (typeof(MaxLengthAttribute).IsAssignableFrom(type)) { return(new MaxLengthAttributeAdapter((MaxLengthAttribute)attribute, stringLocalizer)); } else if (typeof(RequiredAttribute).IsAssignableFrom(type)) { return(new RequiredAttributeAdapter((RequiredAttribute)attribute, stringLocalizer)); } else if (typeof(CompareAttribute).IsAssignableFrom(type)) { return(new CompareAttributeAdapter((CompareAttribute)attribute, stringLocalizer)); } else if (typeof(MinLengthAttribute).IsAssignableFrom(type)) { return(new MinLengthAttributeAdapter((MinLengthAttribute)attribute, stringLocalizer)); } else if (typeof(CreditCardAttribute).IsAssignableFrom(type)) { return(new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-creditcard", stringLocalizer)); } else if (typeof(StringLengthAttribute).IsAssignableFrom(type)) { return(new StringLengthAttributeAdapter((StringLengthAttribute)attribute, stringLocalizer)); } else if (typeof(RangeAttribute).IsAssignableFrom(type)) { return(new RangeAttributeAdapter((RangeAttribute)attribute, stringLocalizer)); } else if (typeof(EmailAddressAttribute).IsAssignableFrom(type)) { return(new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-email", stringLocalizer)); } else if (typeof(PhoneAttribute).IsAssignableFrom(type)) { return(new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-phone", stringLocalizer)); } else if (typeof(UrlAttribute).IsAssignableFrom(type)) { return(new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-url", stringLocalizer)); } else if (typeof(FileExtensionsAttribute).IsAssignableFrom(type)) { return(new FileExtensionsAttributeAdapter((FileExtensionsAttribute)attribute, stringLocalizer)); } else { return(null); } }
/// <inheritdoc /> public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var attributes = context.Attributes; var dataTypeAttribute = attributes.OfType <DataTypeAttribute>().FirstOrDefault(); var displayAttribute = attributes.OfType <DisplayAttribute>().FirstOrDefault(); var displayColumnAttribute = attributes.OfType <DisplayColumnAttribute>().FirstOrDefault(); var displayFormatAttribute = attributes.OfType <DisplayFormatAttribute>().FirstOrDefault(); var displayNameAttribute = attributes.OfType <DisplayNameAttribute>().FirstOrDefault(); var hiddenInputAttribute = attributes.OfType <HiddenInputAttribute>().FirstOrDefault(); var scaffoldColumnAttribute = attributes.OfType <ScaffoldColumnAttribute>().FirstOrDefault(); var uiHintAttribute = attributes.OfType <UIHintAttribute>().FirstOrDefault(); // Special case the [DisplayFormat] attribute hanging off an applied [DataType] attribute. This property is // non-null for DataType.Currency, DataType.Date, DataType.Time, and potentially custom [DataType] // subclasses. The DataType.Currency, DataType.Date, and DataType.Time [DisplayFormat] attributes have a // non-null DataFormatString and the DataType.Date and DataType.Time [DisplayFormat] attributes have // ApplyFormatInEditMode==true. if (displayFormatAttribute == null && dataTypeAttribute != null) { displayFormatAttribute = dataTypeAttribute.DisplayFormat; } var displayMetadata = context.DisplayMetadata; // ConvertEmptyStringToNull if (displayFormatAttribute != null) { displayMetadata.ConvertEmptyStringToNull = displayFormatAttribute.ConvertEmptyStringToNull; } // DataTypeName if (dataTypeAttribute != null) { displayMetadata.DataTypeName = dataTypeAttribute.GetDataTypeName(); } else if (displayFormatAttribute != null && !displayFormatAttribute.HtmlEncode) { displayMetadata.DataTypeName = nameof(DataType.Html); } var containerType = context.Key.ContainerType ?? context.Key.ModelType; IStringLocalizer?localizer = null; if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null) { localizer = _localizationOptions.DataAnnotationLocalizerProvider(containerType, _stringLocalizerFactory); } // Description if (displayAttribute != null) { if (localizer != null && !string.IsNullOrEmpty(displayAttribute.Description) && displayAttribute.ResourceType == null) { displayMetadata.Description = () => localizer[displayAttribute.Description]; } else { displayMetadata.Description = () => displayAttribute.GetDescription(); } } // DisplayFormatString if (displayFormatAttribute != null) { displayMetadata.DisplayFormatString = displayFormatAttribute.DataFormatString; } // DisplayName // DisplayAttribute has precedence over DisplayNameAttribute. if (displayAttribute?.GetName() != null) { if (localizer != null && !string.IsNullOrEmpty(displayAttribute.Name) && displayAttribute.ResourceType == null) { displayMetadata.DisplayName = () => localizer[displayAttribute.Name]; } else { displayMetadata.DisplayName = () => displayAttribute.GetName(); } } else if (displayNameAttribute != null) { if (localizer != null && !string.IsNullOrEmpty(displayNameAttribute.DisplayName)) { displayMetadata.DisplayName = () => localizer[displayNameAttribute.DisplayName]; } else { displayMetadata.DisplayName = () => displayNameAttribute.DisplayName; } } // EditFormatString if (displayFormatAttribute != null && displayFormatAttribute.ApplyFormatInEditMode) { displayMetadata.EditFormatString = displayFormatAttribute.DataFormatString; } // IsEnum et cetera var underlyingType = Nullable.GetUnderlyingType(context.Key.ModelType) ?? context.Key.ModelType; if (underlyingType.IsEnum) { // IsEnum displayMetadata.IsEnum = true; // IsFlagsEnum displayMetadata.IsFlagsEnum = underlyingType.IsDefined(typeof(FlagsAttribute), inherit: false); // EnumDisplayNamesAndValues and EnumNamesAndValues // // Order EnumDisplayNamesAndValues by DisplayAttribute.Order, then by the order of Enum.GetNames(). // That method orders by absolute value, then its behavior is undefined (but hopefully stable). // Add to EnumNamesAndValues in same order but Dictionary does not guarantee order will be preserved. var groupedDisplayNamesAndValues = new List <KeyValuePair <EnumGroupAndName, string> >(); var namesAndValues = new Dictionary <string, string>(); IStringLocalizer?enumLocalizer = null; if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null) { enumLocalizer = _localizationOptions.DataAnnotationLocalizerProvider(underlyingType, _stringLocalizerFactory); } var enumFields = Enum.GetNames(underlyingType) .Select(name => underlyingType.GetField(name) !) .OrderBy(field => field.GetCustomAttribute <DisplayAttribute>(inherit: false)?.GetOrder() ?? 1000); foreach (var field in enumFields) { var groupName = GetDisplayGroup(field); var value = ((Enum)field.GetValue(obj: null) !).ToString("d"); groupedDisplayNamesAndValues.Add(new KeyValuePair <EnumGroupAndName, string>( new EnumGroupAndName( groupName, () => GetDisplayName(field, enumLocalizer)), value)); namesAndValues.Add(field.Name, value); } displayMetadata.EnumGroupedDisplayNamesAndValues = groupedDisplayNamesAndValues; displayMetadata.EnumNamesAndValues = namesAndValues; } // HasNonDefaultEditFormat if (!string.IsNullOrEmpty(displayFormatAttribute?.DataFormatString) && displayFormatAttribute?.ApplyFormatInEditMode == true) { // Have a non-empty EditFormatString based on [DisplayFormat] from our cache. if (dataTypeAttribute == null) { // Attributes include no [DataType]; [DisplayFormat] was applied directly. displayMetadata.HasNonDefaultEditFormat = true; } else if (dataTypeAttribute.DisplayFormat != displayFormatAttribute) { // Attributes include separate [DataType] and [DisplayFormat]; [DisplayFormat] provided override. displayMetadata.HasNonDefaultEditFormat = true; } else if (dataTypeAttribute.GetType() != typeof(DataTypeAttribute)) { // Attributes include [DisplayFormat] copied from [DataType] and [DataType] was of a subclass. // Assume the [DataType] constructor used the protected DisplayFormat setter to override its // default. That is derived [DataType] provided override. displayMetadata.HasNonDefaultEditFormat = true; } } // HideSurroundingHtml if (hiddenInputAttribute != null) { displayMetadata.HideSurroundingHtml = !hiddenInputAttribute.DisplayValue; } // HtmlEncode if (displayFormatAttribute != null) { displayMetadata.HtmlEncode = displayFormatAttribute.HtmlEncode; } // NullDisplayText if (displayFormatAttribute != null) { displayMetadata.NullDisplayText = displayFormatAttribute.NullDisplayText; } // Order if (displayAttribute?.GetOrder() is int order) { displayMetadata.Order = order; } // Placeholder if (displayAttribute != null) { if (localizer != null && !string.IsNullOrEmpty(displayAttribute.Prompt) && displayAttribute.ResourceType == null) { displayMetadata.Placeholder = () => localizer[displayAttribute.Prompt]; } else { displayMetadata.Placeholder = () => displayAttribute.GetPrompt(); } } // ShowForDisplay if (scaffoldColumnAttribute != null) { displayMetadata.ShowForDisplay = scaffoldColumnAttribute.Scaffold; } // ShowForEdit if (scaffoldColumnAttribute != null) { displayMetadata.ShowForEdit = scaffoldColumnAttribute.Scaffold; } // SimpleDisplayProperty if (displayColumnAttribute != null) { displayMetadata.SimpleDisplayProperty = displayColumnAttribute.DisplayColumn; } // TemplateHint if (uiHintAttribute != null) { displayMetadata.TemplateHint = uiHintAttribute.UIHint; } else if (hiddenInputAttribute != null) { displayMetadata.TemplateHint = "HiddenInput"; } }
/// <summary> /// Initializes a new instance of <see cref="RequiredAttributeAdapter"/>. /// </summary> /// <param name="attribute">The <see cref="RequiredAttribute"/>.</param> /// <param name="stringLocalizer">The <see cref="IStringLocalizer"/>.</param> public RequiredAttributeAdapter(RequiredAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { }
public RegularExpressionAttributeAdapter(RegularExpressionAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { }
public CompareAttributeAdapter(CompareAttribute attribute, IStringLocalizer?stringLocalizer) : base(new CompareAttributeWrapper(attribute), stringLocalizer) { _otherProperty = "*." + attribute.OtherProperty; }
public ClassicMovieAttributeAdapter( ClassicMovieAttribute attribute, IStringLocalizer?stringLocalizer) : base(attribute, stringLocalizer) { }
public static string GetDualTerm <TEnum>(this TEnum instance, IStringLocalizer?localizer = null) where TEnum : Enum { return(instance.GetQuantifierAttribute().Dual); }