티스토리 뷰
반응형
.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
public 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." }; } }
한글화 후 IdentityErrorDescriber 예시public 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 메서드를 추가해주시면 됩니다.
services.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의 파일을 텍스트 에디터로 열고 아래 코드를 추가해주세요.
<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.resx 파일을 VisualStudio에서 파일을 열면 아래와 같이 나타납니다. - IdentityErrorMessages.ko-KR.rexs과 IdentityErrorMessages.ja-JP.rexs도 동일하게 텍스트 편집기로 열고 코드를 추가하신 후 내용을 한국어, 일어로 번역해주세요.
- IdentityErrorMessage.resx 파일을 Visual Studio에서 열어서 Access modifiers를 Public로 변경합니다.
- IdentityErrorDescriber를 Orverride하여 Resources를 사용하도록 작성하면 됩니다.
public 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 메서드를 추가해주시면 됩니다.
services.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
- flutter
- Android
- Xamarin.Forms 요약
- .NET Standard
- Vue
- Xamarin.Forms eBook
- Xamarin
- MS SQL
- VisualStudio
- StringComparison
- React
- ASP.NET Core
- npm
- Xamarin.Forms
- WPF
- c#
- Xamarin.iOS
- ios
- TypeScript
- material-ui
- Total
- Today
- Yesterday