Asp рдХреЛрд░ + VueJS рдХреЗ рдЙрджрд╛рд╣рд░рдг рджреНрд╡рд╛рд░рд╛ рд╕рддреНрдпрд╛рдкрди рдирд┐рдпрдореЛрдВ рдХрд╛ рдПрдХреАрдХрд░рдг


рдпрд╣ рдЖрд▓реЗрдЦ рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд░реНрд╡рд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдирдкреБрдЯ рд╕рддреНрдпрд╛рдкрди рдирд┐рдпрдореЛрдВ рдХреЛ рдПрдХрдЬреБрдЯ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рд╕рд░рд▓ рддрд░реАрдХрд╛ рдмрддрд╛рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕рд░рд▓ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдореИрдВ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдпрд╣ рдПрд╕реНрдк рдиреЗрдЯ рдХреЛрд░ рдФрд░ рд╡реАрдпреВ рдЬреЗрдПрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд┐рдХрд╕рд┐рдд рдХрд░рддреЗ рд╕рдордп, рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдирдкреБрдЯ рдХреЗ рджреЛрд╣рд░реЗ рд╕рддреНрдпрд╛рдкрди рдХреЗ рдХрд╛рд░реНрдп рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рддреЗ рд╣реИрдВред рдПрдХ рдУрд░, рд╕рд░реНрд╡рд░ рдкрд░ рдирд┐рд░рд░реНрдердХ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдХрдо рдХрд░рдиреЗ рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рд╕рддреНрдпрд╛рдкрди рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдирдкреБрдЯ рдХреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдкрд░ рдорд╛рдиреНрдп рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рджреВрд╕рд░реА рдУрд░, рд╕рддреНрдпрд╛рдкрди рдХреА рдмрд╛рдд рдХрд░рддреЗ рд╣реБрдП, рд╕рд░реНрд╡рд░ "рд╡рд┐рд╢реНрд╡рд╛рд╕ рдкрд░" рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЧреНрд░рд╛рд╣рдХ рд╕рддреНрдпрд╛рдкрди рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЕрдиреБрд░реЛрдз рднреЗрдЬрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рддреНрдпрд╛рдкрди рдХреЛрдб рдХреЛ рдЕрдХреНрд╖рдо рдпрд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдпрд╛ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдкреАрдЖрдИ рд╕реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдЕрдиреБрд░реЛрдз рдХрд░реЗрдВред


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдХреНрд▓рд╛рд╕рд┐рдХ рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд░реНрд╡рд░ рдЗрдВрдЯрд░реИрдХреНрд╢рди рдореЗрдВ 2 рдиреЛрдб рд╣реЛрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рдЕрдХреНрд╕рд░ рд╕рдорд╛рди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдирдкреБрдЯ рд╕рддреНрдпрд╛рдкрди рдирд┐рдпрдо рд╣реЛрддреЗ рд╣реИрдВред рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд╕рдВрдкреВрд░реНрдг рд░реВрдк рд╕реЗ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рд▓реЗрдЦреЛрдВ рдореЗрдВ рдЪрд░реНрдЪрд╛ рдХреА рдЧрдИ рд╣реИ; рдПрдХ рд╣рд▓реНрдХреЗ рд╕рдорд╛рдзрд╛рди рдХрд╛ рд╡рд░реНрдгрди рдпрд╣рд╛рдВ ASP.Net рдХреЛрд░ API рд╕рд░реНрд╡рд░ рдФрд░ Vue js рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред


рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВрдЧреЗ рдХрд┐ рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ (рдЯреАрдо) рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдорд╛рдиреНрдп рдХрд░реЗрдВрдЧреЗ, рди рдХрд┐ рдЗрдХрд╛рдИ рдХреЛ, рдФрд░, рд╢рд╛рд╕реНрддреНрд░реАрдп 3-рд▓реЗрдпрд░ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕реЗ, рд╣рдорд╛рд░реА рдорд╛рдиреНрдпрддрд╛ рдкреНрд░реЗрдЬреЗрдВрдЯреЗрд╢рди рд▓реЗрдпрд░ рдореЗрдВ рд╣реИред


рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб


рдЬрдмрдХрд┐ Visual Studio 2019 рдореЗрдВ рдореИрдВ рдПрдХ API рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рд╛рде ASP.NET рдХреЛрд░ рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рд╕рд░реНрд╡рд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдмрдирд╛рдКрдВрдЧрд╛ред рдмреЙрдХреНрд╕ рд╕реЗ рдмрд╛рд╣рд░ рдПрдПрд╕рдкреА рдореЗрдВ рдХрд╛рдлреА рдордЬрдмреВрдд рдФрд░ рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд▓ рд╡реЗрд▓рд┐рдбреЗрд╢рди рдореИрдХреЗрдирд┐рдЬреНрдо рд╣реИ - рдореЙрдбрд▓ рд╡реЗрд▓рд┐рдбреЗрд╢рди, рдЬрд┐рд╕рдХреЗ рдЕрдиреБрд╕рд╛рд░, рдореЙрдбрд▓ рд░рд┐рдХреНрд╡реЗрд╕реНрдЯ рдкреНрд░реЙрдкрд░реНрдЯреАрдЬ рдХреЛ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╡реЗрд▓рд┐рдбреЗрд╢рди рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рд╕рд╛рде рдЗрд╕ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:


[Route("[controller]")] [ApiController] public class AccountController : ControllerBase { [HttpPost(nameof(Registration))] public ActionResult Registration([FromBody]RegistrationRequest request) { return Ok($"{request.Name},  !"); } } 

рдирдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдиреЗ рдХрд╛ рдЕрдиреБрд░реЛрдз рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реЛрдЧрд╛:


RegistrationRequest
  public class RegistrationRequest { [StringLength(maximumLength: 50, MinimumLength = 2, ErrorMessage = "     2  50 ")] [Required(ErrorMessage = " ")] public string Name { get; set; } [Required(ErrorMessage = "  . ")] [EmailAddress(ErrorMessage = "  . ")] public string Email { get; set; } [Required(ErrorMessage = " ")] [MaxLength(100, ErrorMessage = "{0}    {1} ")] [MinLength(6, ErrorMessage ="{0}    {1} ")] [DisplayName("")] public string Password { get; set; } [Required(ErrorMessage = " ")] [Range(18,150, ErrorMessage = "      18  150")] public string Age { get; set; } [DisplayName("")] public string Culture { get; set; } } 

рдпрд╣ System.ComponentModel.DataAnnotations рдирд╛рдорд╕реНрдерд╛рди рд╕реЗ рдкреВрд░реНрд╡рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╕рддреНрдпрд╛рдкрди рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдЖрд╡рд╢реНрдпрдХ рдЧреБрдг рдЖрд╡рд╢реНрдпрдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд╕рд╛рде рдЪрд┐рд╣реНрдирд┐рдд рд╣реИрдВред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЦрд╛рд▓реА JSON ("{}") рднреЗрдЬрддреЗ рд╕рдордп, рд╣рдорд╛рд░рд╛ рдПрдкреАрдЖрдИ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧрд╛:


 { ... "errors": { "Age": [ " " ], "Name": [ " " ], "Email": [ "  . " ], "Password": [ " " ] } } 

рдЗрд╕ рд╕реНрддрд░ рдкрд░ рдкрд╣рд▓реА рд╕рдорд╕реНрдпрд╛ рдЬреЛ рд╕рд╛рдордиреЗ рдЖ рд╕рдХрддреА рд╣реИ, рд╡рд╣ рд╣реИ рддреНрд░реБрдЯрд┐ рд╡рд┐рд╡рд░рдг рдХрд╛ рд╕реНрдерд╛рдиреАрдпрдХрд░рдгред рд╡реИрд╕реЗ, рдПрдПрд╕рдкреА рдореЗрдВ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдЙрдкрдХрд░рдг рд╣реИрдВ, рд╣рдо рдмрд╛рдж рдореЗрдВ рдЗрд╕ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред


рд╕реНрдЯреНрд░рд┐рдВрдЧ рдбреЗрдЯрд╛ рдХреА рд▓рдВрдмрд╛рдИ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдмреЛрд▓ рд░рд╣реЗ рдирд╛рдореЛрдВ рдХреЗ рд╕рд╛рде рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ: рд╕реНрдЯреНрд░рд┐рдВрдЧрд▓реЗрдВрдЧреНрдирд┐, рдореИрдХреНрд╕ рд▓реИрдВрде рдФрд░ рдорд┐рдирд▓реЙрдиреНрдЧред рдЙрд╕реА рд╕рдордп, рд╕реНрдЯреНрд░рд┐рдВрдЧреНрд╕ (рдШреБрдВрдШрд░рд╛рд▓реЗ рдмреНрд░реЗрд╕) рдХреЛ рдкреНрд░рд╛рд░реВрдкрд┐рдд рдХрд░рдХреЗ, рд╡рд┐рд╢реЗрд╖рддрд╛ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдПрдХ рд╕рдВрджреЗрд╢ рдореЗрдВ рдПрдХреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕рдВрджреЗрд╢ рдореЗрдВ рдиреНрдпреВрдирддрдо рдФрд░ рдЕрдзрд┐рдХрддрдо рд▓рдВрдмрд╛рдИ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдЙрд╕реА рдирд╛рдо рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛ рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдкрд╛рд╕рд╡рд░реНрдб "рдкреНрд░рджрд░реНрд╢рди рдирд╛рдо" рдХреЗ рд▓рд┐рдПред рд╕реАрдорд╛ рд╡рд┐рд╢реЗрд╖рддрд╛ рдЙрд╕ рдорд╛рди рдХреА рдЬрд╛рдБрдЪ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ рдЬреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реАрдорд╛ рдореЗрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЖрдЗрдП рдПрдХ рдЕрд╕реНрд╡реАрдХрд╛рд░реНрдп рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рдХреЗ рд╕рд╛рде рдПрдХ рдЕрдиреБрд░реЛрдз рднреЗрдЬреЗрдВ:


  { "Name": "a", "Password" : "123" } 

рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ, рдЖрдк рдирдП рд╕рддреНрдпрд╛рдкрди рддреНрд░реБрдЯрд┐ рд╕рдВрджреЗрд╢ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ:


  "Name": [ "     2  50 " ], "Password": [ "    6 " ] 

рд╕рдорд╕реНрдпрд╛, рдЬреЛ рдХреБрдЫ рд╕рдордп рдХреЗ рд▓рд┐рдП рд╣реЛ рд╕рдХрддреА рд╣реИ, рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ, рдпрд╣ рд╣реИ рдХрд┐ рдирд╛рдо рдФрд░ рдкрд╛рд╕рд╡рд░реНрдб рдХреА рд▓рдВрдмрд╛рдИ рдХреЗ рд▓рд┐рдП рд╕реАрдорд╛ рдорд╛рди рдХреНрд▓рд╛рдЗрдВрдЯ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдореЗрдВ рднреА рдореМрдЬреВрдж рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдРрд╕реА рд╕реНрдерд┐рддрд┐ рдЬрд┐рд╕рдореЗрдВ рджреЛ рдпрд╛ рд╢рд╛рд░реАрд░рд┐рдХ рд╕реНрдерд╛рдиреЛрдВ рдкрд░ рдПрдХ рд╣реА рдбреЗрдЯрд╛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдмрдЧ рдХреЗ рд▓рд┐рдП рд╕рдВрднрд╛рд╡рд┐рдд рдкреНрд░рдЬрдирди рдЬрдореАрди рд╣реИ, рдЬреЛ рдЦрд░рд╛рдм рдбрд┐рдЬрд╛рдЗрди рдХреЗ рд╕рдВрдХреЗрддреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИред рдЪрд▓реЛ рдЗрд╕реЗ рдареАрдХ рдХрд░рддреЗ рд╣реИрдВред


рд╣рдо рд╕рдм рдХреБрдЫ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗ рдЬреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рд╕рдВрд╕рд╛рдзрди рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рдПрдХ рд╕рд╛рдЭрд╛ рд╕рдВрд╕рд╛рдзрди рдореЗрдВ Controllers.AccountController.ru.resx рдФрд░ рд╕рд╛рдВрд╕реНрдХреГрддрд┐рдХ рд░реВрдк рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░ рдбреЗрдЯрд╛ рдХреЗ рд╕рдВрджреЗрд╢: Controllers.AccountController.resxред рдореИрдВ рдЗрд╕ рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдкрд╛рд▓рди рдХрд░рддрд╛ рд╣реВрдВ:


 {PropertyName}DisplayName {PropertyName}{RuleName} {PropertyName}{RuleName}Message 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪрд┐рддреНрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ


рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдИрдореЗрд▓ рдкрддреЗ рдХреЛ рдорд╛рдиреНрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд┐рдпрдорд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╣реИред рдФрд░ рд╕рдВрд╕реНрдХреГрддрд┐ рд╕рддреНрдпрд╛рдкрди рдХреЗ рд▓рд┐рдП, рдПрдХ рдХрд╕реНрдЯрдо рдирд┐рдпрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ - "рдорд╛рди" (рдореВрд▓реНрдпреЛрдВ рдХреА рд╕реВрдЪреА)ред рдЖрдкрдХреЛ рдкрд╛рд╕рд╡рд░реНрдб рдкреБрд╖реНрдЯрд┐рдХрд░рдг рдХреНрд╖реЗрддреНрд░ рдХреА рднреА рдЬрд╛рдВрдЪ рдХрд░рдиреА рд╣реЛрдЧреА, рдЬрд┐рд╕реЗ рд╣рдо рдмрд╛рдж рдореЗрдВ рдпреВрдЖрдИ рдкрд░ рджреЗрдЦреЗрдВрдЧреЗред


рдХрд┐рд╕реА рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдВрд╕реНрдХреГрддрд┐ рдХреЗ рд▓рд┐рдП рд╕рдВрд╕рд╛рдзрди рдлрд╝рд╛рдЗрд▓реЛрдВ рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо Startup.ConfigureServices рд╡рд┐рдзрд┐ рдореЗрдВ рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдЬреЛ рд╕рдВрд╕рд╛рдзрди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдкрде рдХреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ:


 services.AddLocalization(options => options.ResourcesPath = "Resources"); 

рдФрд░ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рдореЗрдВ рднреАред рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рд╡рд┐рдзрд┐, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЕрдиреБрд░реЛрдз рдХреЗ рд╣реЗрдбрд░ рджреНрд╡рд╛рд░рд╛ рд╕рдВрд╕реНрдХреГрддрд┐ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг:


  app.UseRequestLocalization(new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture("ru-RU"), SupportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("ru-RU") }, RequestCultureProviders = new List<IRequestCultureProvider> { new AcceptLanguageHeaderRequestCultureProvider() } }); 

рдЕрдм, рддрд╛рдХрд┐ рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рдЕрдВрджрд░, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рддрдХ рдкрд╣реБрдВрдЪ рд╣реЛ, рд╣рдо рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ IStringLocalizer рдкреНрд░рдХрд╛рд░ рдХреА рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдкрдВрдЬреАрдХрд░рдг рдХрд╛рд░реНрд░рд╡рд╛рдИ рдХреА рд╡рд╛рдкрд╕реА рдХреА рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░реЗрдВрдЧреЗ:

  return Ok(string.Format(_localizer["RegisteredMessage"], request.Name)); 

ResxValidatior рд╡рд░реНрдЧ рдирд┐рдпрдореЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧрд╛, рдЬреЛ рдмрдирд╛рдП рдЧрдП рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред рдЗрд╕рдореЗрдВ рдХреАрд╡рд░реНрдб рдХреА рдЖрд░рдХреНрд╖рд┐рдд рд╕реВрдЪреА, рдкреНрд░реАрд╕реЗрдЯ рд░реЛрд▓ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдЬрд╛рдВрдЪрдиреЗ рдХреА рдПрдХ рд╡рд┐рдзрд┐ рд╣реИред


ResxValidatior
 public class ResxValidator { public const char ValuesSeparator = ','; public const char RangeSeparator = '-'; public enum Keywords { DisplayName, Message, Required, Pattern, Length, MinLength, MaxLength, Range, MinValue, MaxValue, Values, Compare } private readonly Dictionary<Keywords, Func<string, string, bool>> _rules = new Dictionary<Keywords, Func<string, string, bool>>() { [Keywords.Required] = (v, arg) => !string.IsNullOrEmpty(v), [Keywords.Pattern] = (v, arg) => !string.IsNullOrWhiteSpace(v) && Regex.IsMatch(v, arg), [Keywords.Range] = (v, arg) => !string.IsNullOrWhiteSpace(v) && long.TryParse(v, out var vLong) && long.TryParse(arg.Split(RangeSeparator)[0].Trim(), out var vMin) && long.TryParse(arg.Split(RangeSeparator)[1].Trim(), out var vMax) && vLong >= vMin && vLong <= vMax, [Keywords.Length] = (v, arg) => !string.IsNullOrWhiteSpace(v) && long.TryParse(arg.Split(RangeSeparator)[0].Trim(), out var vMin) && long.TryParse(arg.Split(RangeSeparator)[1].Trim(), out var vMax) && v.Length >= vMin && v.Length <= vMax, [Keywords.MinLength] = (v, arg) => !string.IsNullOrWhiteSpace(v) && v.Length >= int.Parse(arg), [Keywords.MaxLength] = (v, arg) => !string.IsNullOrWhiteSpace(v) && v.Length <= int.Parse(arg), [Keywords.Values] = (v, arg) => !string.IsNullOrWhiteSpace(v) && arg.Split(ValuesSeparator).Select(x => x.Trim()).Contains(v), [Keywords.MinValue] = (v, arg) => !string.IsNullOrEmpty(v) && long.TryParse(v, out var vLong) && long.TryParse(arg, out var argLong) && vLong >= argLong, [Keywords.MaxValue] = (v, arg) => !string.IsNullOrEmpty(v) && long.TryParse(v, out var vLong) && long.TryParse(arg, out var argLong) && vLong <= argLong }; private readonly IStringLocalizer _localizer; public ResxValidator(IStringLocalizer localizer) { _localizer = localizer; } public bool IsValid(string memberName, string value, out string message) { var rules = _rules.Select(x => new { Name = x.Key, Check = x.Value, String = _localizer.GetString(memberName + x.Key) }).Where(x => x.String != null && !x.String.ResourceNotFound); foreach (var rule in rules) { if (!rule.Check(value, rule.String?.Value)) { var messageResourceKey = $"{memberName}{rule.Name}{Keywords.Message}"; var messageResource = _localizer[messageResourceKey]; var displayNameResourceKey = $"{memberName}{Keywords.DisplayName}"; var displayNameResource = _localizer[displayNameResourceKey] ?? displayNameResourceKey; message = messageResource != null && !messageResource.ResourceNotFound ? string.Format(messageResource.Value, displayNameResource, rule.String?.Value) : messageResourceKey; return false; } } message = null; return true; } } 

рдПрдХ рдХрд╕реНрдЯрдо рд╕рддреНрдпрд╛рдкрди рд╡рд┐рд╢реЗрд╖рддрд╛ рдмрдирд╛рдПрдВ рдЬрд┐рд╕реЗ рд╣рдорд╛рд░рд╛ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХреЙрд▓ рдХрд░реЗрдЧрд╛ред рдпрд╣рд╛рдВ, рдорд╛рдирдХ рддрд░реНрдХ рдореЙрдбрд▓ рдХреЗ рд╕рддреНрдпрд╛рдкрд┐рдд рд╕рдВрдкрддреНрддрд┐ рдХреЗ рдореВрд▓реНрдп, рдЙрд╕рдХреЗ рдирд╛рдо рдФрд░ рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реИред


ResxAttribute
 public sealed class ResxAttribute : ValidationAttribute { private readonly string _baseName; private string _resourceName; public ResxAttribute(string sectionName, string resourceName = null) { _baseName = sectionName; _resourceName = resourceName; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (_resourceName == null) _resourceName = validationContext.MemberName; var factory = validationContext .GetService(typeof(IStringLocalizerFactory)) as IStringLocalizerFactory; var localizer = factory?.Create(_baseName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); ErrorMessage = ErrorMessageString; var currentValue = value as string; var validator = new ResxValidator(localizer); return validator.IsValid(_resourceName, currentValue, out var message) ? ValidationResult.Success : new ValidationResult(message); } } 

рдЕрдВрдд рдореЗрдВ, рдЖрдк рд╕рдВрд╕рд╛рдзрди рдХреЗ рдирд╛рдо рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реБрдП, рд╣рдорд╛рд░реЗ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рдХреЗ рд╕рд╛рде рдЕрдиреБрд░реЛрдз рдореЗрдВ рд╕рднреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ:


  [Resx(sectionName: "Controllers.AccountController")] 

рд╣рдо рд╕рдорд╛рди рдЕрдиреБрд░реЛрдз рднреЗрдЬрдХрд░ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВрдЧреЗ:


  { "Name": "a", "Password" : "123" } 

рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдХреЗ рд▓рд┐рдП, рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЛ рдЬреЛрдбрд╝реЗрдВред рдЕрдВрдЧреНрд░реЗрдЬреА рдореЗрдВ рд╕рдВрджреЗрд╢реЛрдВ рдХреЗ рд╕рд╛рде рдХрдВрдЯреНрд░реЛрд▓рд░ред рдХрдВрдЯреЛрд▓рд░ред рдПрдирдЖрд░рдПрдХреНрд╕, рд╕рд╛рде рд╣реА рд╣реЗрдбрд░, рд╕рдВрд╕реНрдХреГрддрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде: рд╕реНрд╡реАрдХрд╛рд░-рднрд╛рд╖рд╛: рдПрди-рдпреВрдПрд╕ред


рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЕрдм рд╣рдо рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдВрд╕реНрдХреГрддрд┐ рдХреЗ рд▓рд┐рдП рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред * .En.resx рдлрд╝рд╛рдЗрд▓ рдореЗрдВ, рдореИрдВрдиреЗ рдиреНрдпреВрдирддрдо рдкрд╛рд╕рд╡рд░реНрдб рд▓рдВрдмрд╛рдИ 8 рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреА рд╣реИ, рдФрд░ рдореБрдЭреЗ рдПрдХ рдЙрдкрдпреБрдХреНрдд рд╕рдВрджреЗрд╢ рдорд┐рд▓рд╛ рд╣реИ:


  "Password": [ "Password must be at least 8 characters" ] 

рдХреНрд▓рд╛рдЗрдВрдЯ рд╕рддреНрдпрд╛рдкрди рдХреЗ рджреМрд░рд╛рди рд╕рдорд╛рди рд╕рдВрджреЗрд╢ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдХрд┐рд╕реА рддрд░рд╣ рдХреНрд▓рд╛рдЗрдВрдЯ рд╣рд┐рд╕реНрд╕реЗ рдХреЗ рд▓рд┐рдП рд╕рдВрджреЗрд╢реЛрдВ рдХреА рдкреВрд░реА рд╕реВрдЪреА рдХреЛ рдирд┐рд░реНрдпрд╛рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдЕрд▓рдЧ рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рдЖрдкрдХреЛ i18n рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рдм рдХреБрдЫ рджреЗрдЧрд╛ред


LocaleController
  [Route("[controller]")] [ApiController] public class LocaleController : ControllerBase { private readonly IStringLocalizerFactory _factory; private readonly string _assumbly; private readonly string _location; public LocaleController(IStringLocalizerFactory factory) { _factory = factory; _assumbly = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; _location = Path.Combine(Directory.GetCurrentDirectory(), "Resources"); } [HttpGet("Config")] public IActionResult GetConfig(string culture) { if (!string.IsNullOrEmpty(culture)) { CultureInfo.CurrentCulture = new CultureInfo(culture); CultureInfo.CurrentUICulture = new CultureInfo(culture); } var resources = Directory.GetFiles(_location, "*.resx", SearchOption.AllDirectories) .Select(x => x.Replace(_location + Path.DirectorySeparatorChar, string.Empty)) .Select(x => x.Substring(0, x.IndexOf('.'))) .Distinct(); var config = new Dictionary<string, Dictionary<string, string>>(); foreach (var resource in resources.Select(x => x.Replace('\\', '.'))) { var section = _factory.Create(resource, _assumbly) .GetAllStrings() .OrderBy(x => x.Name) .ToDictionary(x => x.Name, x => x.Value); config.Add(resource.Replace('.', '-'), section); } var result = JsonConvert.SerializeObject(config, Formatting.Indented); return Ok(result); } } 

рд╕реНрд╡реАрдХрд╛рд░-рднрд╛рд╖рд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдпрд╣ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧрд╛:


рд╕реНрд╡реАрдХрд╛рд░-рднрд╛рд╖рд╛: en-US
 { "Controllers-AccountController": { "AgeDisplayName": "Age", "AgeRange": "18 - 150", "AgeRangeMessage": "{0} must be {1}", "EmailDisplayName": "Email", "EmailPattern": "^[-\\w.]+@([A-z0-9][-A-z0-9]+\\.)+[Az]{2,4}$", "EmailPatternMessage": "Incorrect email", "EmailRequired": "", "EmailRequiredMessage": "Email required", "LanguageDisplayName": "Language", "LanguageValues": "ru-RU, en-US", "LanguageValuesMessage": "Incorrect language. Possible: {1}", "NameDisplayName": "Name", "NameLength": "2 - 50", "NameLengthMessage": "Name length must be {1} characters", "PasswordConfirmCompare": "Password", "PasswordConfirmCompareMessage": "Passwords must be the same", "PasswordConfirmDisplayName": "Password confirmation", "PasswordDisplayName": "Password", "PasswordMaxLength": "100", "PasswordMaxLengthMessage": "{0} can't be greater than {1} characters", "PasswordMinLength": "8", "PasswordMinLengthMessage": "{0} must be at least {1} characters", "PasswordRequired": "", "PasswordRequiredMessage": "Password required", "RegisteredMessage": "{0}, you've been registered!" } } 

рд╕реНрд╡реАрдХрд╛рд░-рднрд╛рд╖рд╛: en-RU
 { "Controllers-AccountController": { "AgeDisplayName": "", "AgeRange": "18 - 150", "AgeRangeMessage": "{0}     {1}", "EmailDisplayName": " . ", "EmailPattern": "^[-\\w.]+@([A-z0-9][-A-z0-9]+\\.)+[Az]{2,4}$", "EmailPatternMessage": "  . ", "EmailRequired": "", "EmailRequiredMessage": "  . ", "LanguageDisplayName": "", "LanguageValues": "ru-RU, en-US", "LanguageValuesMessage": " .  : {1}", "NameDisplayName": "", "NameLength": "2 - 50", "NameLengthMessage": "    {1} ", "PasswordConfirmCompare": "Password", "PasswordConfirmCompareMessage": "  ", "PasswordConfirmDisplayName": " ", "PasswordDisplayName": "", "PasswordMaxLength": "100", "PasswordMaxLengthMessage": "{0}    {1} ", "PasswordMinLength": "6", "PasswordMinLengthMessage": "{0}    {1} ", "PasswordRequired": "", "PasswordRequiredMessage": " ", "RegisteredMessage": "{0},  !" } } 

рдЧреНрд░рд╛рд╣рдХ рдХреЗ рд▓рд┐рдП рдХреНрд░реЙрд╕-рдСрд░рд┐рдЬрдирд▓ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЦрд┐рд░реА рдХрд╛рдо рдХрд░рдирд╛ рдмрд╛рдХреА рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, Startup.ConfigureServices рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:


  services.AddCors(); 

рдФрд░ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ:


  app.UseCors(x => x .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader()); 

рдЧреНрд░рд╛рд╣рдХ рднрд╛рдЧ


рдореИрдВ рдПрдХ IDE рдореЗрдВ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рднреА рднрд╛рдЧреЛрдВ рдХреЛ рджреЗрдЦрдирд╛ рдкрд╕рдВрдж рдХрд░рддрд╛ рд╣реВрдВ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рд╡рд┐рдЬрд╝реБрдЕрд▓ рд╕реНрдЯреВрдбрд┐рдпреЛ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдКрдВрдЧрд╛: рдмреЗрд╕рд┐рдХ Vue.js рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рдиред рдпрджрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдпрд╣ рдирд╣реАрдВ рд╣реИ / рдЖрдк рд╡реАрдПрд╕ рдХреЛ рдРрд╕реЗ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХреЗ рд╕рд╛рде рд░реЛрдХрдирд╛ рдирд╣реАрдВ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рд╡реАрдпреВрдЖрдИ рдХреНрд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ, рдЗрд╕рдХреЗ рд╕рд╛рде рдореИрдВ рдкрд╣рд▓реЗ рдХрдИ рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реВрдВрдЧрд╛: vuetify, axios, vue-i18nред


рд╣рдо LocaleController рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╕рдВрд╕рд╛рдзрди рдлрд╝рд╛рдЗрд▓реЛрдВ рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реИрдВ, рд╕реНрд╡реАрдХрд╛рд░-рднрд╛рд╖рд╛ рд╣реЗрдбрд░ рдореЗрдВ рд╕рдВрд╕реНрдХреГрддрд┐ рдХрд╛ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ, рдФрд░ рд╕реНрдерд╛рди рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ en.json рдФрд░ ru.json рдлрд╝рд╛рдЗрд▓реЛрдВ рдореЗрдВ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреЗрддреЗ рд╣реИрдВред


рдЕрдЧрд▓рд╛, рд╣рдореЗрдВ рд╕рд░реНрд╡рд░ рд╕реЗ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реЗрд╡рд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


errorHandler.service.js
 const ErrorHandlerService = { parseResponseError (error) { if (error.toString().includes('Network Error')) { return 'ServerUnavailable' } if (error.response) { let statusText = error.response.statusText; if (error.response.data && error.response.data.errors) { let message = ''; for (let property in error.response.data.errors) { error.response.data.errors[property].forEach(function (entry) { if (entry) { message += entry + '\n' } }) } return message } else if (error.response.data && error.response.data.message) { return error.response.data.message } else if (statusText) { return statusText } } } }; export { ErrorHandlerService } 

Vutify.js рдореЗрдВ рдирд┐рд░реНрдорд┐рдд vee-validate рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХреЛ рдирд┐рдпрдо рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЗ рд╕рд╛рде рд╕рддреНрдпрд╛рдкрди рдХрд╛рд░реНрдпреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд╣рдо рдЙрдиреНрд╣реЗрдВ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реЗрд╡рд╛ рд╕реЗ рдЕрдиреБрд░реЛрдз рдХрд░реЗрдВрдЧреЗред


locale.service.js
 import i18n from '../i18n'; const LocaleService = { getRules(resource, options) { let rules = []; options = this.prepareOptions(options); this.addRequireRule(rules, resource, options); this.addPatternRule(rules, resource, options); this.addRangeRule(rules, resource, options); this.addLengthRule(rules, resource, options); this.addMaxLengthRule(rules, resource, options); this.addMinLengthRule(rules, resource, options); this.addValuesRule(rules, resource, options); this.addCompareRule(rules, resource, options); return rules; }, prepareOptions(options){ let getter = v => v; let compared = () => null; if (!options){ options = { getter: getter, compared: compared }; } if (!options.getter) options.getter = getter; if (!options.compared) options.compared = compared; return options; }, addRequireRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'Required'); if(settings){ rules.push(v => !!options.getter(v) || settings.message); } }, addPatternRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'Pattern'); if(settings){ rules.push(v => !!options.getter(v) || settings.message); rules.push(v => new RegExp(settings.value).test(options.getter(v)) || settings.message); } }, addRangeRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'Range'); if(settings){ let values = settings.value.split('-'); rules.push(v => !!options.getter(v) || settings.message); rules.push(v => parseInt(options.getter(v)) >= values[0] && parseInt(options.getter(v)) <= values[1] || settings.message); } }, addLengthRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'Length'); if(settings){ let values = settings.value.split('-'); rules.push(v => !!options.getter(v) || settings.message); rules.push(v => options.getter(v).length >= values[0] && options.getter(v).length <= values[1] || settings.message); } }, addMaxLengthRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'MaxLength'); if(settings){ rules.push(v => !!options.getter(v) || settings.message); rules.push(v => options.getter(v).length <= settings.value || settings.message); } }, addMinLengthRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'MinLength'); if(settings){ rules.push(v => !!options.getter(v) || settings.message); rules.push(v => options.getter(v).length >= settings.value || settings.message); } }, addValuesRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'Values'); if(settings) { let values = settings.value.split(','); rules.push(v => !!options.getter(v) || settings.message); rules.push(v => !!values.find(x => x.trim() === options.getter(v)) || settings.message); } }, addCompareRule(rules, resource, options){ let settings = this.getRuleSettings(resource, 'Compare'); if(settings) { rules.push(() => { return settings.value === '' || !!settings.value || settings.message }); rules.push(v => { return options.getter(v) === options.compared() || settings.message; }); } }, getRuleSettings(resource, rule){ let value = this.getRuleValue(resource, rule); let message = this.getRuleMessage(resource, rule, value); return value === '' || value ? { value: value, message: message } : null; }, getRuleValue(resource, rule){ let key =`${resource}${rule}`; return this.getI18nValue(key); }, getDisplayName(resource){ let key =`${resource}DisplayName`; return this.getI18nValue(key); }, getRuleMessage(resource, rule, value){ let key =`${resource}${rule}Message`; return i18n.t(key, [this.getDisplayName(resource), value]); }, getI18nValue(key){ let value = i18n.t(key); return value !== key ? value : null; } }; export { LocaleService } 

рдЗрд╕ рд╕реЗрд╡рд╛ рдХрд╛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣ ResxValidator рд╡рд░реНрдЧ рдХреЛ рдЖрдВрд╢рд┐рдХ рд░реВрдк рд╕реЗ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдХрд░рддрд╛ рд╣реИред рдореИрдВ рдзреНрдпрд╛рди рджреЗрддрд╛ рд╣реВрдВ рдХрд┐ рддреБрд▓рдирд╛ рдирд┐рдпрдо рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЬрд╣рд╛рдВ рд╡рд░реНрддрдорд╛рди рд╕рдВрдкрддреНрддрд┐ рдХреЗ рдореВрд▓реНрдп рдХреА рджреВрд╕рд░реЗ рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рд╡рд┐рдХрд▓реНрдк рд╡рд╕реНрддреБ рдкрд╛рд░рд┐рдд рдХреА рдЬрд╛рддреА рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рдХреА рддреБрд▓рдирд╛ рдХреА рдЬрд╛рддреА рд╣реИ, рдЬреЛ рддреБрд▓рдирд╛ рдХреЗ рд▓рд┐рдП рдореВрд▓реНрдп рд▓реМрдЯрд╛рддрд╛ рд╣реИред


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдлреЙрд░реНрдо рдлрд╝реАрд▓реНрдб рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:


 <v-text-field :label="displayFor('Name')" :rules="rulesFor('Name')" v-model="model.Name" type="text" prepend-icon="mdi-account"></v-text-field> 

рд▓реЗрдмрд▓ рдХреЗ рд▓рд┐рдП, рдЖрд╡рд░рдг рдлрд╝рдВрдХреНрд╢рди рдХреЛ locale.service рдкрд░ рдХреЙрд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рд╕рдВрд╕рд╛рдзрди рдХрд╛ рдкреВрд░рд╛ рдирд╛рдо, рд╕рд╛рде рд╣реА рд╕рд╛рде рдЙрд╕ рд╕рдВрдкрддреНрддрд┐ рдХрд╛ рдирд╛рдо рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдЖрдк рдкреНрд░рджрд░реНрд╢рди рдирд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдЗрд╕реА рддрд░рд╣ рдирд┐рдпрдореЛрдВ рдХреЗ рд▓рд┐рдПред рд╡реА-рдореЙрдбрд▓ рджрд░реНрдЬ рдХрд┐рдП рдЧрдП рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдореЙрдбрд▓ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддрд╛ рд╣реИред
рдкрд╛рд╕рд╡рд░реНрдб рдкреБрд╖реНрдЯрд┐рдХрд░рдг рд╕рдВрдкрддреНрддрд┐ рдХреЗ рд▓рд┐рдП, рд╡рд┐рдХрд▓реНрдк рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдкрд╛рд╕рд╡рд░реНрдб рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдкрд╛рд╕ рдХрд░реЗрдВ:


 :rules="rulesFor('PasswordConfirm', { compared:() => model.Password })" 

рднрд╛рд╖рд╛ рдЪрдпрди рдХреЗ рд▓рд┐рдП v- рдЪрдпрди рдореЗрдВ рддрддреНрд╡реЛрдВ рдХреА рдкреВрд░реНрд╡рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд╕реВрдЪреА рд╣реЛрддреА рд╣реИ (рдпрд╣ рдЙрджрд╛рд╣рд░рдг рдХреА рд╕рд░рд▓рддрд╛ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ) рдФрд░ onChange рдПрдХ рд╣реИрдВрдбрд▓рд░ рд╣реИред рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдПрд╕рдкреАрдП рдХрд░рддреЗ рд╣реИрдВ, рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рджреНрд╡рд╛рд░рд╛ рдХрд┐рд╕реА рднрд╛рд╖рд╛ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдкрд░ рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдХреЛ рдмрджрд▓рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП, рдСрди-рдЪреЗрдВрдЬ рдЪрдпрди рдореЗрдВ, рдЪрдпрдирд┐рдд рднрд╛рд╖рд╛ рдХреА рдЬрд╛рдВрдЪ рдХреА рдЬрд╛рддреА рд╣реИ, рдФрд░ рдпрджрд┐ рдпрд╣ рдмрджрд▓рддрд╛ рд╣реИ, рддреЛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓реЛрдХреЗрд▓ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИ:


  onCultureChange (value) { let culture = this.cultures.find(x => x.value === value); this.model.Culture = culture.value; if (culture.locale !== this.$i18n.locale) { this.$i18n.locale = culture.locale; this.$refs.form.resetValidation(); } } 

рдпрд╣ рд╕рдм, рдПрдХ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рдЖрд╡реЗрджрди рдХреЗ рд╕рд╛рде рднрдВрдбрд╛рд░ рдпрд╣рд╛рдБ рд╣реИ ред


рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдореИрдВ рдпрд╣ рдиреЛрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ рдХрд┐ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреЛ рдЦреБрдж рдХреЛ рдПрдХ рд╕рд┐рдВрдЧрд▓ JSON рдлреЙрд░реНрдореЗрдЯ рдореЗрдВ рд╕реНрдЯреЛрд░ рдХрд░рдирд╛ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛, рдЬрд┐рд╕реЗ рд╣рдо рд▓реЛрдХреЗрд▓рдХреЙрдиреНрдЯреНрд░реЛрд▓рд░ рд╕реЗ рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реИрдВ, рддрд╛рдХрд┐ рдПрдПрд╕рдкреА рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреА рдмрд╛рд░реАрдХрд┐рдпреЛрдВ рд╕реЗ рдЗрд╕реЗ рдЕрд▓рдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред ResxValidatior рдореЗрдВ, рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд┐рд▓рд┐рдЯреА рдФрд░ рдХрд╕реНрдЯрдо рдирд┐рдпрдореЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЬреЛрдбрд╝ рд╕рдХрддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА рд▓реЛрдХреЗрд▓ рдХреЗ рд╕рдорд╛рди рдХреЛрдб рдХреЛ рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рд╕рдорд░реНрдерди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ JS рд╕реНрдЯрд╛рдЗрд▓ рдореЗрдВ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦ рд╕рдХрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдореИрдВ рд╕рд╛рджрдЧреА рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реВрдВред

Source: https://habr.com/ru/post/hi473776/


All Articles