Как локализовать стандартные сообщения об ошибках атрибутов проверки в ASP.NET Core

Как локализовать стандартные сообщения об ошибках атрибутов проверки в ASP.NET Core (v2.2)? Например, атрибут [Required] имеет следующее сообщение об ошибке "Поле xxx обязательно."; [EmailAddress] имеет "Поле xxx не является действительным адресом электронной почты."; [Сравнить] содержит "'xxx' и 'yyy' не совпадают" и т. д. В нашем проекте мы используем не английский язык, и я хочу найти способ, как переводить стандартные сообщения об ошибках, не записывая их напрямую в каждый атрибут каждого класса модели данных.


person Vitaliy    schedule 11.12.2019    source источник
comment
Вы нашли какое-нибудь решение?   -  person user3172616    schedule 24.12.2020


Ответы (2)


Это указано в документы. Вы можете сделать либо:

  1. Используйте опцию ResourcePath для атрибута.

    [Required(ResourcePath = "Resources")]
    

    Затем вы добавите локализованное сообщение в Resources/Namespace.To.MyClass.[lang].resx.

  2. Используйте один файл ресурсов для всех классов:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc()
            .AddDataAnnotationsLocalization(options => {
                options.DataAnnotationLocalizerProvider = (type, factory) =>
                    factory.Create(typeof(SharedResource));
            });
    }
    
person Chris Pratt    schedule 11.12.2019
comment
похоже, что этот подход предполагает перевод параметра ErrorMessage для всех атрибутов во всех моделях. Я хочу избежать этого - person Vitaliy; 12.12.2019

Если вы просто хотите локализовать сообщения об ошибках, а не создавать многоязычный сайт, вы можете попробовать следующее: (строки сообщений могут быть на вашем языке.)

  1. Добавьте пользовательский IValidationMetadataProvider :
    public class MyModelMetadataProvider : IValidationMetadataProvider
    {
        public void CreateValidationMetadata(ValidationMetadataProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException();
            }
            var validators = context.ValidationMetadata.ValidatorMetadata;

            // add [Required] for value-types (int/DateTime etc)
            // to set ErrorMessage before asp.net does it
            var theType = context.Key.ModelType;
            var underlyingType = Nullable.GetUnderlyingType(theType);

            if (theType.IsValueType &&
                underlyingType == null && // not nullable type
                validators.Where(m => m.GetType() == typeof(RequiredAttribute)).Count() == 0)
            {
                validators.Add(new RequiredAttribute());
            }
            foreach (var obj in validators)
            {
                if (!(obj is ValidationAttribute attribute))
                {
                    continue;
                }
                fillErrorMessage<RequiredAttribute>(attribute, 
                    "You must fill in '{0}'.");
                fillErrorMessage<MinLengthAttribute>(attribute, 
                    "Min length of '{0}' is {1}.");
                fillErrorMessage<MaxLengthAttribute>(attribute, 
                    "Max length of '{0}' is {1}.");
                fillErrorMessage<EmailAddressAttribute>(attribute, 
                    "Invalid email address.", true);
                // other attributes like RangeAttribute, CompareAttribute, etc
            }
        }
        private void fillErrorMessage<T>(object attribute, string errorMessage, 
            bool forceOverriding = false) 
            where T : ValidationAttribute
        {
            if (attribute is T validationAttribute)
            {
                if (forceOverriding ||
                    (validationAttribute.ErrorMessage == null 
                    && validationAttribute.ErrorMessageResourceName == null))
                {
                    validationAttribute.ErrorMessage = errorMessage;
                }
            }
        }
    }
  1. добавьте несколько строк в Startup.cs :
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews()
                .AddMvcOptions(m => {
                    m.ModelMetadataDetailsProviders.Add(new MyModelMetadataProvider());

                    m.ModelBindingMessageProvider.SetValueMustBeANumberAccessor(
                        fieldName => string.Format("'{0}' must be a valid number.", fieldName));
                    // you may check the document of `DefaultModelBindingMessageProvider`
                    // and add more if needed

                })
                ;
        }

см. документ DefaultModelBindingMessageProvider

Если вы умеете читать на японском, см. эту статью для более подробной информации.

person percyboy    schedule 18.02.2021