BindProperty & Required Attribute & jquery validation unobstrusive 사용중 Error Message가 기본 영문인지라 한글로 변경을 할려고 했더니 일일이 에러메시지를 써야하는 상황인지라…
[Required(ErrorMessage=‘에러메시지’)]
Globalization & Localization을 해야한다는건데 배보다 배꼽이 큰 상황이라 간략히 사용가능한 글을 보게되어 남깁니다.
opened 05:10PM - 22 Aug 17 UTC
enhancement
area-mvc
feature-model-binding
severity-minor
affected-medium
Currently, [ValidationAttributeAdapterOfTAttribute.GetErrorMessage](https://gith… ub.com/aspnet/Mvc/blob/900a5c7c4c789e71bf18e8e90bf9b28b4e51013f/src/Microsoft.AspNetCore.Mvc.DataAnnotations/ValidationAttributeAdapterOfTAttribute.cs#L67) uses IStringLocalizer only when ErrorMessage is set:
```csharp
protected virtual string GetErrorMessage(ModelMetadata modelMetadata, params object[] arguments)
{
if (modelMetadata == null)
{
throw new ArgumentNullException(nameof(modelMetadata));
}
if (_stringLocalizer != null &&
!string.IsNullOrEmpty(Attribute.ErrorMessage) &&
string.IsNullOrEmpty(Attribute.ErrorMessageResourceName) &&
Attribute.ErrorMessageResourceType == null)
{
return _stringLocalizer[Attribute.ErrorMessage, arguments];
}
return Attribute.FormatErrorMessage(modelMetadata.GetDisplayName());
}
```
The consequence is that you have to set the ErrorMessage property each time you want to translate an error message.
Suppose you just want to translate the default RequiredAttribute ErrorMessageString, which is `The {0} field is required.` for all your Model classes.
1) You must override the default DataAnnotationLocalizerProvider to return a shared resource.
2) You add a generic entry named, for example, "DataAnnotations_Required" with the translated value format: `Le champ {0} doit être renseigné.`
3) You must replace all the `[Required]` attributes with `[Required(ErrorMessage = "DataAnnotations_Required")]`
More generally, there is no way to just adapt the generic DataAnnotation validation messages to your language. (the ones in [System.ComponentModel.Annotations.SR.resources](https://github.com/dotnet/corefx/blob/master/src/System.ComponentModel.Annotations/src/Resources/Strings.resx)) without having to replace all your data annotations.
The [documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization#dataannotations-localization) only provide a sample where the messages are customized for each property (despite the fact that only the property name change).
There is no easy workaround either:
- You can't inherit from RequiredAttribute to fix the ErrorMessage property, since the framework uses strict type comparison
- Replacing the default ValidationAttributeAdapterProvider is not trivial, because you have to replace all adapters with custom ones to override the GetErrorMessage method.
Is there a better way to achieve localization for all default data annotation error messages ?
Or room for improvement in asp.net core mvc to reduce the burden of writing all this custom code ?
<form method="post">
<div class="flex flex-col">
<label>Email</label>
<input asp-for="Email" class="border" />
<span asp-validation-for="Email" class="text-red-500"></span>
</div>
<div class="flex justify-center mt-10 mb-10">
<input type="submit" value="전송"/>
</div>
</form>
[BindProperty]
[Required]
[MinLength(6)]
public string? Email { get; set; }
[추가글 : in razor pages]
// Add services to the container.
builder.Services.AddRazorPages(options =>
{
options.Conventions.AuthorizeFolder("/", "RequireAdmin");
options.Conventions.AllowAnonymousToFolder("/Login");
}).AddMvcOptions(options =>
{
options.ModelBindingMessageProvider.SetAttemptedValueIsInvalidAccessor((value, fieldname) =>
/* provide your own translation */
string.Format("Value {0} for field {1} is incorrect", value, fieldname));
// and do the same for all the Set*Accessor...
options.ModelMetadataDetailsProviders.Add(new MetadataTranslationProvider(typeof(Resources.DataAnotation)));
//
});
4개의 좋아요
최근에 작업에 이용하다보니 위 적용법을 조금 더 정리해 보았습니다.
저 같은 경우엔 Razor Pages에서 BindProperty, Data Annotation, jquery validation unobstrusive ajax를 사용하다보니 유용했습니다.
[program.cs]
builder.Services.AddRazorPages().AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(new MetadataTranslationProvider(typeof(Resources.DataAnnotation)));
});
builder.Services.AddControllersWithViews(options =>
{
options.ModelMetadataDetailsProviders.Add(new MetadataTranslationProvider(typeof(Resources.DataAnnotation)));
});
루트폴더에 Resources\DataAnnotation.resx 파일생성 및 Attribute 메세지 작성
[index.cshtml]
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script src="~/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.js"></script>
<script>
//validator를 alert으로 처리
jQuery.validator.setDefaults({
onkeyup: false,
onclick: false,
onfocusout: false,
showErrors: function (errorMap, errorList) {
if (this.numberOfInvalids()) {
alert(errorList[0].message);
$(errorList[0].element).focus();
}
}
})
confirm = function() {
return true;
};
success = function (xhr) {
alert(xhr.message);
};
error = function (xhr) {
alert('에러가 발생하였습니다.');
};
</script>
<form method="post" data-ajax="true" data-ajax-method="post" data-ajax-confirm="confirm" data-ajax-success="success" data-ajax-failure="error">
<input type="text" asp-for="@Model._test!.Name" value="@Model._test?.Name" />
</form>
[index.cshtml.cs]
public class test
{
[DisplayName("이름")]
[Required]
[StringLength(30)]
public string? Name { get; set; }
}
public class IndexModel : PageModel
{
[BindProperty]
public test? _test { get; set; }
}
이렇게 작성후 해당페이지를 브라우저로 로딩하면 요렇게 html태그가 생성됩니다.
<input type="text" value="테스트" data-val="true" data-val-length="[이름] : 30자리 이하입니다." data-val-length-max="30" data-val-required="[이름] : 입력하시기 바랍니다." id="ztest_Name" maxlength="30" name="_test.Name">
폼작성시 client validation과 server validation을 한번에 처리할수 있습니다.
2개의 좋아요
파란매
3월 24, 2023, 9:58오전
4
세상 에 이걺몰라 그동 안 노가다 했네요 감사합니다
2개의 좋아요