티스토리 뷰
반응형
.NET Core 인증을 구현했을 때 에러메시지가 다음과 같이 영어로 나타날 때 한글화 하는 방법을 소개합니다.
- Passwords must have at least one non alphanumeric character.
- Passwords must have at least one lowercase ('a'-'z').
- Passwords must have at least one uppercase ('A'-'Z').
방법1: IdentityErrorDescriber 재정의하기
직접 원하는 오류 메시지를 작성하고 싶다면 IdentityErrorDescriber Class를 Override해야 합니다.
- IdentityErrorDescriber를 상속하여 원하는 에러메시지로 Override합니다. 아래는 영문으로 작성된 코드이므로 적절히 한글화 하여 프로젝트 추가해주세요.
영문 IdentityErrorDescriber
한글화 후 IdentityErrorDescriber 예시12345678910111213141516171819202122232425public
class
CustomIdentityErrorDescriber : IdentityErrorDescriber
{
public
override
IdentityError DefaultError() {
return
new
IdentityError { Code =
nameof
(DefaultError), Description = $
"An unknown failure has occurred."
}; }
public
override
IdentityError ConcurrencyFailure() {
return
new
IdentityError { Code =
nameof
(ConcurrencyFailure), Description =
"Optimistic concurrency failure, object has been modified."
}; }
public
override
IdentityError PasswordMismatch() {
return
new
IdentityError { Code =
nameof
(PasswordMismatch), Description =
"Incorrect password."
}; }
public
override
IdentityError InvalidToken() {
return
new
IdentityError { Code =
nameof
(InvalidToken), Description =
"Invalid token."
}; }
public
override
IdentityError LoginAlreadyAssociated() {
return
new
IdentityError { Code =
nameof
(LoginAlreadyAssociated), Description =
"A user with this login already exists."
}; }
public
override
IdentityError InvalidUserName(
string
userName) {
return
new
IdentityError { Code =
nameof
(InvalidUserName), Description = $
"User name '{userName}' is invalid, can only contain letters or digits."
}; }
public
override
IdentityError InvalidEmail(
string
email) {
return
new
IdentityError { Code =
nameof
(InvalidEmail), Description = $
"Email '{email}' is invalid."
}; }
public
override
IdentityError DuplicateUserName(
string
userName) {
return
new
IdentityError { Code =
nameof
(DuplicateUserName), Description = $
"User Name '{userName}' is already taken."
}; }
public
override
IdentityError DuplicateEmail(
string
email) {
return
new
IdentityError { Code =
nameof
(DuplicateEmail), Description = $
"Email '{email}' is already taken."
}; }
public
override
IdentityError InvalidRoleName(
string
role) {
return
new
IdentityError { Code =
nameof
(InvalidRoleName), Description = $
"Role name '{role}' is invalid."
}; }
public
override
IdentityError DuplicateRoleName(
string
role) {
return
new
IdentityError { Code =
nameof
(DuplicateRoleName), Description = $
"Role name '{role}' is already taken."
}; }
public
override
IdentityError UserAlreadyHasPassword() {
return
new
IdentityError { Code =
nameof
(UserAlreadyHasPassword), Description =
"User already has a password set."
}; }
public
override
IdentityError UserLockoutNotEnabled() {
return
new
IdentityError { Code =
nameof
(UserLockoutNotEnabled), Description =
"Lockout is not enabled for this user."
}; }
public
override
IdentityError UserAlreadyInRole(
string
role) {
return
new
IdentityError { Code =
nameof
(UserAlreadyInRole), Description = $
"User already in role '{role}'."
}; }
public
override
IdentityError UserNotInRole(
string
role) {
return
new
IdentityError { Code =
nameof
(UserNotInRole), Description = $
"User is not in role '{role}'."
}; }
public
override
IdentityError PasswordTooShort(
int
length) {
return
new
IdentityError { Code =
nameof
(PasswordTooShort), Description = $
"Passwords must be at least {length} characters."
}; }
public
override
IdentityError PasswordRequiresNonAlphanumeric() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresNonAlphanumeric), Description =
"Passwords must have at least one non alphanumeric character."
}; }
public
override
IdentityError PasswordRequiresDigit() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresDigit), Description =
"Passwords must have at least one digit ('0'-'9')."
}; }
public
override
IdentityError PasswordRequiresLower() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresLower), Description =
"Passwords must have at least one lowercase ('a'-'z')."
}; }
public
override
IdentityError PasswordRequiresUpper() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresUpper), Description =
"Passwords must have at least one uppercase ('A'-'Z')."
}; }
public
override
IdentityError RecoveryCodeRedemptionFailed() {
return
new
IdentityError { Code =
nameof
(RecoveryCodeRedemptionFailed), Description =
"Recovery code was not redeemed."
}; }
public
override
IdentityError PasswordRequiresUniqueChars(
int
uniqueChars) {
return
new
IdentityError { Code =
nameof
(PasswordRequiresUniqueChars), Description =
"Passwords must use at least {0} different characters."
}; }
}
12345678910111213141516171819202122232425public
class
IdentityErrorDescriberKr : IdentityErrorDescriber
{
public
override
IdentityError DefaultError() {
return
new
IdentityError { Code =
nameof
(DefaultError), Description = $
"알 수 없는 오류가 발생했습니다."
}; }
public
override
IdentityError ConcurrencyFailure() {
return
new
IdentityError { Code =
nameof
(ConcurrencyFailure), Description =
"동시성 문제가 발생했습니다. 데이터가 다른 곳에서 수정된 것 같습니다."
}; }
public
override
IdentityError PasswordMismatch() {
return
new
IdentityError { Code =
nameof
(PasswordMismatch), Description =
"잘못된 비밀번호입니다."
}; }
public
override
IdentityError InvalidToken() {
return
new
IdentityError { Code =
nameof
(InvalidToken), Description =
"유효하지 않은 토큰입니다."
}; }
public
override
IdentityError LoginAlreadyAssociated() {
return
new
IdentityError { Code =
nameof
(LoginAlreadyAssociated), Description =
"로그인하려는 이 사용자는 이미 다른 계정과 연결되어있습니다."
}; }
public
override
IdentityError InvalidUserName(
string
userName) {
return
new
IdentityError { Code =
nameof
(InvalidUserName), Description = $
"사용자명 '{userName}'는 유효하지 않습니다. 허용되지 않은 문자가 포함되어 있습니다."
}; }
public
override
IdentityError InvalidEmail(
string
email) {
return
new
IdentityError { Code =
nameof
(InvalidEmail), Description = $
"이메일 '{email}'는 유효하지 않습니다."
}; }
public
override
IdentityError DuplicateUserName(
string
userName) {
return
new
IdentityError { Code =
nameof
(DuplicateUserName), Description = $
"사용자명 '{userName}'는 이미 사용 중입니다."
}; }
public
override
IdentityError DuplicateEmail(
string
email) {
return
new
IdentityError { Code =
nameof
(DuplicateEmail), Description = $
"이메일 '{email}'는 이미 사용 중 입니다."
}; }
public
override
IdentityError InvalidRoleName(
string
role) {
return
new
IdentityError { Code =
nameof
(InvalidRoleName), Description = $
"역할 '{role}'는 유효하지 않습니다."
}; }
public
override
IdentityError DuplicateRoleName(
string
role) {
return
new
IdentityError { Code =
nameof
(DuplicateRoleName), Description = $
"역할 '{role}'는 이미 사용 중 입니다."
}; }
public
override
IdentityError UserAlreadyHasPassword() {
return
new
IdentityError { Code =
nameof
(UserAlreadyHasPassword), Description =
"사용자가 이미 비밀번호를 설정했습니다."
}; }
public
override
IdentityError UserLockoutNotEnabled() {
return
new
IdentityError { Code =
nameof
(UserLockoutNotEnabled), Description =
"이 사용자는 Lockout이 설정되지 않았습니다."
}; }
public
override
IdentityError UserAlreadyInRole(
string
role) {
return
new
IdentityError { Code =
nameof
(UserAlreadyInRole), Description = $
"역할 '{role}'에 존재하는 사용자입니다."
}; }
public
override
IdentityError UserNotInRole(
string
role) {
return
new
IdentityError { Code =
nameof
(UserNotInRole), Description = $
"역할 '{role}'에 포함되지 않은 사용자입니다."
}; }
public
override
IdentityError PasswordTooShort(
int
length) {
return
new
IdentityError { Code =
nameof
(PasswordTooShort), Description = $
"비밀번호는 최소 {length}자 이상이어야 합니다."
}; }
public
override
IdentityError PasswordRequiresNonAlphanumeric() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresNonAlphanumeric), Description =
"비밀번호에는 영문자, 숫자가 아닌 문자가 하나 이상 있어야 합니다."
}; }
public
override
IdentityError PasswordRequiresDigit() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresDigit), Description =
"비밀번호에는 적어도 하나의 숫자가 있어야합니다."
}; }
public
override
IdentityError PasswordRequiresLower() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresLower), Description =
"비밀번호에는 영어 소문자가 하나 이상 있어야합니다."
}; }
public
override
IdentityError PasswordRequiresUpper() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresUpper), Description =
"비밀번호에는 영어 대문자가 하나 이상 있어야합니다."
}; }
public
override
IdentityError RecoveryCodeRedemptionFailed() {
return
new
IdentityError { Code =
nameof
(RecoveryCodeRedemptionFailed), Description =
"복구 코드 사용에 실패했습니다."
}; }
public
override
IdentityError PasswordRequiresUniqueChars(
int
uniqueChars) {
return
new
IdentityError { Code =
nameof
(PasswordRequiresUniqueChars), Description =
"비밀번호는 최소한 {0}개의 다른 문자를 사용해야합니다."
}; }
}
- Startup.cs의 ConfigureServices를 열고 AddIdentity 메서드 다음에 아래와 같이 AddErrorDescriber 메서드를 추가해주시면 됩니다.
12services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<IdentityErrorDescriberKr>();
방법2: Resources(.resx) 파일 사용하기
여러 국가의 언어로 서비스할 예정이라면 Resources(.resx)파일을 이용하는 방법이 권장됩니다. Microsoft에서도 이와 같이 구현하고 있으며 Resources.rexs(Github)와 IdentityErrorDescriber.cs(Github)에서 확인할 수 있습니다.
- 먼저 프로젝트에 Resources 폴더를 추가하고 .resx 파일을 추가합니다.
파일 명 뒤에 .ko-KR, .ja-JP는 .NET의 언어-국가 코드입니다. C#언어-국가 코드와 ISO 언어코드, MSDN(CultureInfo)를 참고하셔서 필요한 언어별로 파일을 추가하시면 됩니다. - IdentityErrorMessages.resx의 파일을 텍스트 에디터로 열고 아래 코드를 추가해주세요.
저장 후 IdentityErrorMessages.resx 파일을 VisualStudio에서 파일을 열면 아래와 같이 나타납니다.12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788<
data
name
=
"ConcurrencyFailure"
xml:space
=
"preserve"
>
<
value
>Optimistic concurrency failure, object has been modified.</
value
>
<
comment
>Error when optimistic concurrency fails</
comment
>
</
data
>
<
data
name
=
"DefaultError"
xml:space
=
"preserve"
>
<
value
>An unknown failure has occurred.</
value
>
<
comment
>Default identity result error message</
comment
>
</
data
>
<
data
name
=
"DuplicateEmail"
xml:space
=
"preserve"
>
<
value
>Email '{0}' is already taken.</
value
>
<
comment
>Error for duplicate emails</
comment
>
</
data
>
<
data
name
=
"DuplicateRoleName"
xml:space
=
"preserve"
>
<
value
>Role name '{0}' is already taken.</
value
>
<
comment
>Error for duplicate roles</
comment
>
</
data
>
<
data
name
=
"DuplicateUserName"
xml:space
=
"preserve"
>
<
value
>User name '{0}' is already taken.</
value
>
<
comment
>Error for duplicate user names</
comment
>
</
data
>
<
data
name
=
"InvalidEmail"
xml:space
=
"preserve"
>
<
value
>Email '{0}' is invalid.</
value
>
<
comment
>Invalid email</
comment
>
</
data
>
<
data
name
=
"InvalidRoleName"
xml:space
=
"preserve"
>
<
value
>Role name '{0}' is invalid.</
value
>
<
comment
>Error for invalid role names</
comment
>
</
data
>
<
data
name
=
"InvalidToken"
xml:space
=
"preserve"
>
<
value
>Invalid token.</
value
>
<
comment
>Error when a token is not recognized</
comment
>
</
data
>
<
data
name
=
"InvalidUserName"
xml:space
=
"preserve"
>
<
value
>User name '{0}' is invalid, can only contain letters or digits.</
value
>
<
comment
>User names can only contain letters or digits</
comment
>
</
data
>
<
data
name
=
"LoginAlreadyAssociated"
xml:space
=
"preserve"
>
<
value
>A user with this login already exists.</
value
>
<
comment
>Error when a login already linked</
comment
>
</
data
>
<
data
name
=
"PasswordMismatch"
xml:space
=
"preserve"
>
<
value
>Incorrect password.</
value
>
<
comment
>Error when a password doesn't match</
comment
>
</
data
>
<
data
name
=
"PasswordRequiresDigit"
xml:space
=
"preserve"
>
<
value
>Passwords must have at least one digit ('0'-'9').</
value
>
<
comment
>Error when passwords do not have a digit</
comment
>
</
data
>
<
data
name
=
"PasswordRequiresLower"
xml:space
=
"preserve"
>
<
value
>Passwords must have at least one lowercase ('a'-'z').</
value
>
<
comment
>Error when passwords do not have a lowercase letter</
comment
>
</
data
>
<
data
name
=
"PasswordRequiresNonAlphanumeric"
xml:space
=
"preserve"
>
<
value
>Passwords must have at least one non alphanumeric character.</
value
>
<
comment
>Error when password does not have enough non alphanumeric characters</
comment
>
</
data
>
<
data
name
=
"PasswordRequiresUpper"
xml:space
=
"preserve"
>
<
value
>Passwords must have at least one uppercase ('A'-'Z').</
value
>
<
comment
>Error when passwords do not have an uppercase letter</
comment
>
</
data
>
<
data
name
=
"PasswordTooShort"
xml:space
=
"preserve"
>
<
value
>Passwords must be at least {0} characters.</
value
>
<
comment
>Error message for passwords that are too short</
comment
>
</
data
>
<
data
name
=
"RecoveryCodeRedemptionFailed"
xml:space
=
"preserve"
>
<
value
>Recovery code redemption failed.</
value
>
<
comment
>Error when a recovery code is not redeemed.</
comment
>
</
data
>
<
data
name
=
"UserAlreadyHasPassword"
xml:space
=
"preserve"
>
<
value
>User already has a password set.</
value
>
<
comment
>Error when AddPasswordAsync called when a user already has a password</
comment
>
</
data
>
<
data
name
=
"UserAlreadyInRole"
xml:space
=
"preserve"
>
<
value
>User already in role '{0}'.</
value
>
<
comment
>Error when a user is already in a role</
comment
>
</
data
>
<
data
name
=
"UserLockoutNotEnabled"
xml:space
=
"preserve"
>
<
value
>Lockout is not enabled for this user.</
value
>
<
comment
>Error when lockout is not enabled</
comment
>
</
data
>
<
data
name
=
"UserNotInRole"
xml:space
=
"preserve"
>
<
value
>User is not in role '{0}'.</
value
>
<
comment
>Error when a user is not in the role</
comment
>
</
data
>
<
data
name
=
"PasswordRequiresUniqueChars"
xml:space
=
"preserve"
>
<
value
>Passwords must use at least {0} different characters.</
value
>
<
comment
>Error message for passwords that are based on similar characters</
comment
>
</
data
>
- IdentityErrorMessages.ko-KR.rexs과 IdentityErrorMessages.ja-JP.rexs도 동일하게 텍스트 편집기로 열고 코드를 추가하신 후 내용을 한국어, 일어로 번역해주세요.
- IdentityErrorMessage.resx 파일을 Visual Studio에서 열어서 Access modifiers를 Public로 변경합니다.
- IdentityErrorDescriber를 Orverride하여 Resources를 사용하도록 작성하면 됩니다.
12345678910111213141516171819202122232425public
class
LocalizedIdentityErrorDescriber : IdentityErrorDescriber
{
public
override
IdentityError DuplicateEmail(
string
email) {
return
new
IdentityError { Code =
nameof
(DuplicateEmail), Description =
string
.Format(IdentityErrorMessages.DuplicateEmail, email) }; }
public
override
IdentityError DuplicateUserName(
string
userName) {
return
new
IdentityError { Code =
nameof
(DuplicateUserName), Description =
string
.Format(IdentityErrorMessages.DuplicateUserName, userName) }; }
public
override
IdentityError InvalidEmail(
string
email) {
return
new
IdentityError { Code =
nameof
(InvalidEmail), Description =
string
.Format(IdentityErrorMessages.InvalidEmail, email) }; }
public
override
IdentityError DuplicateRoleName(
string
role) {
return
new
IdentityError { Code =
nameof
(DuplicateRoleName), Description =
string
.Format(IdentityErrorMessages.DuplicateRoleName, role) }; }
public
override
IdentityError InvalidRoleName(
string
role) {
return
new
IdentityError { Code =
nameof
(InvalidRoleName), Description =
string
.Format(IdentityErrorMessages.InvalidRoleName, role) }; }
public
override
IdentityError InvalidToken() {
return
new
IdentityError { Code =
nameof
(InvalidToken), Description = IdentityErrorMessages.InvalidToken }; }
public
override
IdentityError InvalidUserName(
string
userName) {
return
new
IdentityError { Code =
nameof
(InvalidUserName), Description =
string
.Format(IdentityErrorMessages.InvalidUserName, userName) }; }
public
override
IdentityError LoginAlreadyAssociated() {
return
new
IdentityError { Code =
nameof
(LoginAlreadyAssociated), Description = IdentityErrorMessages.LoginAlreadyAssociated }; }
public
override
IdentityError PasswordMismatch() {
return
new
IdentityError { Code =
nameof
(PasswordMismatch), Description = IdentityErrorMessages.PasswordMismatch }; }
public
override
IdentityError PasswordRequiresDigit() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresDigit), Description = IdentityErrorMessages.PasswordRequiresDigit }; }
public
override
IdentityError PasswordRequiresLower() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresLower), Description = IdentityErrorMessages.PasswordRequiresLower }; }
public
override
IdentityError PasswordRequiresNonAlphanumeric() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresNonAlphanumeric), Description = IdentityErrorMessages.PasswordRequiresNonAlphanumeric }; }
public
override
IdentityError PasswordRequiresUniqueChars(
int
uniqueChars) {
return
new
IdentityError { Code =
nameof
(PasswordRequiresUniqueChars), Description =
string
.Format(IdentityErrorMessages.PasswordRequiresUniqueChars, uniqueChars) }; }
public
override
IdentityError PasswordRequiresUpper() {
return
new
IdentityError { Code =
nameof
(PasswordRequiresUpper), Description = IdentityErrorMessages.PasswordRequiresUpper }; }
public
override
IdentityError PasswordTooShort(
int
length) {
return
new
IdentityError { Code =
nameof
(PasswordTooShort), Description =
string
.Format(IdentityErrorMessages.PasswordTooShort, length) }; }
public
override
IdentityError UserAlreadyHasPassword() {
return
new
IdentityError { Code =
nameof
(UserAlreadyHasPassword), Description = IdentityErrorMessages.UserAlreadyHasPassword }; }
public
override
IdentityError UserAlreadyInRole(
string
role) {
return
new
IdentityError { Code =
nameof
(UserAlreadyInRole), Description =
string
.Format(IdentityErrorMessages.UserAlreadyInRole, role) }; }
public
override
IdentityError UserNotInRole(
string
role) {
return
new
IdentityError { Code =
nameof
(UserNotInRole), Description =
string
.Format(IdentityErrorMessages.UserNotInRole, role) }; }
public
override
IdentityError UserLockoutNotEnabled() {
return
new
IdentityError { Code =
nameof
(UserLockoutNotEnabled), Description = IdentityErrorMessages.UserLockoutNotEnabled }; }
public
override
IdentityError RecoveryCodeRedemptionFailed() {
return
new
IdentityError { Code =
nameof
(RecoveryCodeRedemptionFailed), Description = IdentityErrorMessages.RecoveryCodeRedemptionFailed }; }
public
override
IdentityError ConcurrencyFailure() {
return
new
IdentityError { Code =
nameof
(ConcurrencyFailure), Description = IdentityErrorMessages.ConcurrencyFailure }; }
public
override
IdentityError DefaultError() {
return
new
IdentityError { Code =
nameof
(DefaultError), Description = IdentityErrorMessages.DefaultError }; }
}
- 마지막으로 Startup.cs의 ConfigureServices를 열고 AddIdentity 메서드 다음에 아래와 같이 AddErrorDescriber 메서드를 추가해주시면 됩니다.
12services.AddIdentity<ApplicationUser, IdentityRole>()
.AddErrorDescriber<LocalizedIdentityErrorDescriber>();
방법3: Nuget-Package에서 Identity.Core 한국어 설치
누겟에서 검색어 Microsoft.AspNet.Identity.Core를 입력하시면 Microsoft.AspNet.Identity.Core.ko 패키지가 나타납니다. 이 패키지를 설치하면 지역화가 된다고 합니다. (주의: 아직 테스트 되지 않은 방법입니다. 실제로 동작하지 않을 수도 있습니다.)
테스트 방법
브라우저를 열고 설정에서 선호 언어를 변경하시면 해당 언어로 변경되어 나타납니다. 예를들어 IE에서는 [인터넷 옵션]의 [언어]에서 변경하실 수 있습니다.
'Web > ASP.NET Core' 카테고리의 다른 글
ASP.NET Core에 Vue앱 추가하기 (0) | 2023.11.15 |
---|---|
[ASP.NET Core] 배포 프로필 (.pubxml) (1) | 2022.04.01 |
Application State vs 전역 Static 변수 (0) | 2019.08.19 |
댓글
최근에 올라온 글
최근에 달린 댓글
TAG
- WPF
- .NET Standard
- Android
- Vue
- Xamarin.Forms eBook
- c#
- windows
- npm
- flutter
- ios
- material-ui
- Xamarin.Forms 요약
- ASP.NET Core
- Xamarin.Forms
- React
- Xamarin.iOS
- Xamarin
- TypeScript
- VisualStudio
- MS SQL
- Total
- Today
- Yesterday