계정 관리 페이지 및 컴포넌트 다국어화 완료

- 계정 관리 페이지 전체 다국어화 (8개 페이지)
  * 사용자 관리: 계정 추가, 메뉴 권한, 계정 정보, 로그인 인증정보
  * 비밀번호 관리: 로그인/취소 비밀번호 변경
- 계정 엔티티 컴포넌트 다국어화
  * account-tab: 사용자 관리/비밀번호 관리 탭
  * account-user-tab: 로그인 인증정보/계정권한 서브탭
  * password-manage-wrap: 비밀번호 변경 버튼
  * user-manage-wrap: 등록 현황, 사용자 추가 버튼
  * user-login-auth-info-wrap: 이메일/휴대폰 관리 인터페이스
- 계정 추가 페이지 상세 다국어화
  * 폼 라벨: 사용자ID, 비밀번호, 로그인 범위
  * 본인인증 정보 입력 섹션
  * 유효성 검사 메시지
  * 성공/실패 알림 메시지
- 메뉴 권한 페이지 다국어화
  * 권한 설정 안내 메시지
  * 저장/실행/다운로드 권한 라벨
  * 탭 변경 시 초기화 안내
- 번역 키 추가: account 네임스페이스 50개 키
- 모든 폼, 버튼, 알림 메시지 일관된 다국어 지원

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-10-29 18:14:40 +09:00
parent 9b193ee6f9
commit 3f0ab49a3d
15 changed files with 226 additions and 100 deletions

View File

@@ -1,13 +1,15 @@
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
AccountTabKeys,
AccountTabProps
import {
AccountTabKeys,
AccountTabProps
} from '../model/types';
export const AccountTab = ({
activeTab
}: AccountTabProps) => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const onClickToNavigation = (tab: AccountTabKeys) => {
@@ -23,14 +25,14 @@ export const AccountTab = ({
return(
<>
<div className="subTab">
<button
<button
className={`subtab-btn ${(activeTab === AccountTabKeys.UserManage)? 'active': ''}` }
onClick={ () => onClickToNavigation(AccountTabKeys.UserManage) }
> </button>
<button
onClick={ () => onClickToNavigation(AccountTabKeys.UserManage) }
>{t('account.userManagement')}</button>
<button
className={`subtab-btn ${(activeTab === AccountTabKeys.PasswordManage)? 'active': ''}` }
onClick={ () => onClickToNavigation(AccountTabKeys.PasswordManage) }
> </button>
onClick={ () => onClickToNavigation(AccountTabKeys.PasswordManage) }
>{t('account.passwordManagement')}</button>
</div>
</>
);

View File

@@ -1,8 +1,9 @@
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
import {
AccountUserTabKeys,
AccountUserTabProps
AccountUserTabProps
} from '../model/types';
export const AccountUserTab = ({
@@ -12,6 +13,7 @@ export const AccountUserTab = ({
idCL,
status,
}: AccountUserTabProps) => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const onClickToNavigation = (tab: AccountUserTabKeys) => {
@@ -41,14 +43,14 @@ export const AccountUserTab = ({
return(
<>
<div className="subTab">
<button
<button
className={`subtab-btn ${(activeTab === AccountUserTabKeys.LoginAuthInfo)? 'active': ''}` }
onClick={ () => onClickToNavigation(AccountUserTabKeys.LoginAuthInfo) }
> </button>
<button
onClick={ () => onClickToNavigation(AccountUserTabKeys.LoginAuthInfo) }
>{t('account.loginAuthInfo')}</button>
<button
className={`subtab-btn ${(activeTab === AccountUserTabKeys.AccountAuth)? 'active': ''}` }
onClick={ () => onClickToNavigation( AccountUserTabKeys.AccountAuth) }
></button>
onClick={ () => onClickToNavigation( AccountUserTabKeys.AccountAuth) }
>{t('account.accountPermission')}</button>
</div>
</>
);

View File

@@ -1,7 +1,9 @@
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
export const PasswordManageWrap = () => {
const { t } = useTranslation();
const { navigate } = useNavigate();
return (
@@ -9,16 +11,16 @@ export const PasswordManageWrap = () => {
<div className="ing-list">
<div className="pwd-manage mt-20">
<div className="pwd-buttons">
<button
<button
className="btn-44 btn-white pwd-btn"
type="button"
onClick={ () => navigate(PATHS.account.password.modifyLoginPassword) }
> </button>
<button
>{t('account.changeLoginPassword')}</button>
<button
className="btn-44 btn-white pwd-btn"
type="button"
onClick={ () => navigate(PATHS.account.password.modifyCancelPassword) }
> </button>
>{t('account.changeCancelPassword')}</button>
</div>
</div>
</div>

View File

@@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next';
import { UserFindAuthMethodParams, UserAuthMethodData, AuthMethodModifyItem } from '@/entities/user/model/types';
import { useUserFindAuthMethodMutation } from '@/entities/user/api/use-user-find-authmethod-mutation';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
@@ -13,6 +14,7 @@ export const UserLoginAuthInfoWrap = ({
idCL,
status,
}: UserFindAuthMethodParams) => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const [pageParam] = useState(DEFAULT_PAGE_PARAM);
const [authMethodData, setAuthMethodData] = useState<UserAuthMethodData>();
@@ -26,7 +28,7 @@ export const UserLoginAuthInfoWrap = ({
const { mutateAsync: userFindAuthMethod } = useUserFindAuthMethodMutation();
const { mutateAsync: userModifyAuthMethod } = useUserModifyAuthMethodMutation({
onSuccess: () => {
snackBar('사용자 정보가 성공적으로 저장되었습니다.');
snackBar(t('account.userInfoSavedSuccessfully'));
navigate(PATHS.account.user.manage, {
state: {
mid: mid,
@@ -34,7 +36,7 @@ export const UserLoginAuthInfoWrap = ({
});
},
onError: (error) => {
snackBar(error?.response?.data?.message || '사용자 정보 저장에 실패했습니다.');
snackBar(error?.response?.data?.message || t('account.userInfoSaveFailed'));
}
});
@@ -395,11 +397,11 @@ export const UserLoginAuthInfoWrap = ({
<div className="settings-login-auth pb-86">
<div className="group">
<div className="group-header">
<div className="title"> </div>
<div className="title">{t('account.emailAddress')}</div>
<button
className="ic20 plus"
type="button"
aria-label="추가"
aria-label={t('common.add')}
onClick={handleAddEmail}
disabled={!isEmailAddButtonEnabled()}
></button>
@@ -415,7 +417,7 @@ export const UserLoginAuthInfoWrap = ({
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
aria-label={t('common.delete')}
onClick={() => handleRemoveExistingEmail(index)}
disabled={!isDeleteButtonEnabled()}
></button>
@@ -433,7 +435,7 @@ export const UserLoginAuthInfoWrap = ({
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
aria-label={t('common.delete')}
onClick={() => handleRemoveNewEmail(index)}
disabled={!isDeleteButtonEnabled()}
></button>
@@ -443,11 +445,11 @@ export const UserLoginAuthInfoWrap = ({
<div className="group">
<div className="group-header">
<div className="title"> </div>
<div className="title">{t('account.phoneNumber')}</div>
<button
className="ic20 plus"
type="button"
aria-label="추가"
aria-label={t('common.add')}
onClick={handleAddPhone}
disabled={!isPhoneAddButtonEnabled()}
></button>
@@ -457,13 +459,13 @@ export const UserLoginAuthInfoWrap = ({
<input
type="tel"
value={phone.content}
placeholder="휴대폰 번호 입력"
placeholder={t('account.enterPhoneNumber')}
readOnly
/>
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
aria-label={t('common.delete')}
onClick={() => handleRemoveExistingPhone(index)}
disabled={!isDeleteButtonEnabled()}
></button>
@@ -474,20 +476,20 @@ export const UserLoginAuthInfoWrap = ({
<input
type="tel"
value={phone}
placeholder="휴대폰 번호 입력"
placeholder={t('account.enterPhoneNumber')}
onChange={(e) => handleNewPhoneChange(index, e.target.value)}
readOnly={readOnlyPhones.has(index) || index !== editablePhoneIndex}
/>
<button
className="icon-btn minus"
type="button"
aria-label="삭제"
aria-label={t('common.delete')}
onClick={() => handleRemoveNewPhone(index)}
disabled={!isDeleteButtonEnabled()}
></button>
</div>
))}
<div className="notice-bar"> .</div>
<div className="notice-bar">{t('account.tabChangeResetNotice')}</div>
</div>
</div>
<div className="apply-row">
@@ -496,7 +498,7 @@ export const UserLoginAuthInfoWrap = ({
disabled={!isSaveButtonEnabled()}
onClick={handleSave}
>
{t('common.save')}
</button>
</div>
</div>

View File

@@ -1,4 +1,5 @@
import { ChangeEvent, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { DEFAULT_PAGE_PARAM } from '@/entities/common/model/constant';
@@ -8,6 +9,7 @@ import { UserListItem } from '@/entities/user/model/types';
import { useStore } from '@/shared/model/store';
export const UserManageWrap = () => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const midOptions = useStore.getState().UserStore.selectOptionsMids;
const userMid = useStore.getState().UserStore.mid;
@@ -60,7 +62,7 @@ export const UserManageWrap = () => {
</select>
</div>
<div className="ing-title"> </div>
<div className="ing-title">{t('account.registrationStatus')}</div>
</div>
<div style={{ flex: 1, overflow: 'hidden', minHeight: 0 }}>
@@ -76,7 +78,7 @@ export const UserManageWrap = () => {
<button
className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigation() }
> </button>
>{t('account.addUser')}</button>
</div>
</div>
</>