KEY-IN 결제 페이지 다국어 지원 추가

KEY-IN 결제 관련 모든 페이지에 대한 다국어 지원을 추가했습니다.

변경사항:
- 목록 페이지: 페이지 타이틀 다국어화
- 결제 신청 페이지: 모든 폼 레이블, 버튼, 에러 메시지 다국어화
- 성공 페이지: 성공 메시지, 버튼 다국어화

번역 키 추가:
- 폼 레이블: merchant, productName, productPrice, buyerName, buyerEmail, buyerPhoneNumber, cardNumber, expiryDate, installmentPeriod, lumpSum, orderNumber
- 성공/실패 메시지: requestSuccess, requestFailed, requestError
- 성공 페이지: paymentRequestComplete, resultLabel, arsRequestComplete, confirm
- 기타: phoneNumberPlaceholder, fullCancel, postCancel

중복 keyIn 섹션 제거 및 통합 완료

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jay Sheen
2025-11-03 17:04:04 +09:00
parent 42424d164a
commit 4771e43010
5 changed files with 81 additions and 37 deletions

View File

@@ -890,6 +890,31 @@
"paymentMethod": "Payment Method", "paymentMethod": "Payment Method",
"requestFailed": "Request failed." "requestFailed": "Request failed."
}, },
"keyIn": {
"title": "KEY-IN Payment",
"paymentRequest": "Payment Request",
"merchant": "Merchant",
"productName": "Product Name",
"productPrice": "Product Price",
"buyerName": "Buyer Name",
"buyerEmail": "Buyer Email",
"buyerPhoneNumber": "Buyer Phone Number",
"phoneNumberPlaceholder": "Enter without -",
"cardNumber": "Card Number",
"expiryDate": "Expiry Date (MM/YY)",
"installmentPeriod": "Installment Period",
"lumpSum": "Lump Sum",
"orderNumber": "Order Number",
"requestSuccess": "KEY-IN payment request successful.",
"requestFailed": "Payment request failed.",
"requestError": "An error occurred during payment request",
"paymentRequestComplete": "Payment request completed.",
"resultLabel": "Result",
"arsRequestComplete": "ARS request processing complete",
"confirm": "Confirm",
"fullCancel": "Full Cancel",
"postCancel": "Post Cancel"
},
"sms": { "sms": {
"title": "SMS Payment Notification", "title": "SMS Payment Notification",
"virtualAccountRequest": "Virtual Account Request", "virtualAccountRequest": "Virtual Account Request",
@@ -1155,11 +1180,6 @@
"sendCancel": "Send Cancel", "sendCancel": "Send Cancel",
"progressStatus": "Progress Status" "progressStatus": "Progress Status"
}, },
"keyIn": {
"fullCancel": "Pre-cancel",
"partialCancel": "Post-cancel",
"productPrice": "Product Price"
},
"infoWrap": { "infoWrap": {
"paymentInfo": "Payment Information", "paymentInfo": "Payment Information",
"buyerName": "Buyer Name", "buyerName": "Buyer Name",

View File

@@ -890,6 +890,31 @@
"paymentMethod": "결제 방식", "paymentMethod": "결제 방식",
"requestFailed": "신청을 실패하였습니다." "requestFailed": "신청을 실패하였습니다."
}, },
"keyIn": {
"title": "KEY-IN 결제",
"paymentRequest": "결제 신청",
"merchant": "가맹점",
"productName": "상품명",
"productPrice": "상품가격",
"buyerName": "구매자명",
"buyerEmail": "구매자 이메일",
"buyerPhoneNumber": "구매자 전화번호",
"phoneNumberPlaceholder": "- 제외하고 입력",
"cardNumber": "카드번호",
"expiryDate": "유효기간(월/년)",
"installmentPeriod": "할부 기간",
"lumpSum": "일시불",
"orderNumber": "주문번호",
"requestSuccess": "KEY-IN 결제 신청을 성공하였습니다.",
"requestFailed": "결제 신청에 실패했습니다.",
"requestError": "결제 요청 중 오류가 발생했습니다",
"paymentRequestComplete": "결제 신청이 완료되었습니다.",
"resultLabel": "결과",
"arsRequestComplete": "ARS 요청 처리 완료",
"confirm": "확인",
"fullCancel": "전취소",
"postCancel": "후취소"
},
"sms": { "sms": {
"title": "SMS 결제 통보", "title": "SMS 결제 통보",
"virtualAccountRequest": "가상계좌 요청", "virtualAccountRequest": "가상계좌 요청",
@@ -1155,11 +1180,6 @@
"sendCancel": "발송취소", "sendCancel": "발송취소",
"progressStatus": "진행상태" "progressStatus": "진행상태"
}, },
"keyIn": {
"fullCancel":"전취소",
"postCancel": "후취소",
"productPrice": "상품가격"
},
"infoWrap": { "infoWrap": {
"paymentInfo": "결제 정보", "paymentInfo": "결제 정보",
"buyerName": "구매자명", "buyerName": "구매자명",

View File

@@ -50,7 +50,7 @@ export const KeyInPaymentPage = () => {
const [maxAmount, setMaxAmount] = useState<number>(); const [maxAmount, setMaxAmount] = useState<number>();
const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false); const [emailBottomSheetOn, setEmailBottomSheetOn] = useState<boolean>(false);
useSetHeaderTitle('KEY-IN 결제'); useSetHeaderTitle(t('additionalService.keyIn.title'));
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false); useSetFooterMode(false);
useSetOnBack(() => { useSetOnBack(() => {

View File

@@ -16,8 +16,10 @@ import { Dialog } from '@/shared/ui/dialogs/dialog';
import { useStore } from '@/shared/model/store'; import { useStore } from '@/shared/model/store';
import { snackBar } from '@/shared/lib'; import { snackBar } from '@/shared/lib';
import { NumericFormat, PatternFormat } from 'react-number-format'; import { NumericFormat, PatternFormat } from 'react-number-format';
import { useTranslation } from 'react-i18next';
export const KeyInPaymentRequestPage = () => { export const KeyInPaymentRequestPage = () => {
const { t } = useTranslation();
const { navigate } = useNavigate(); const { navigate } = useNavigate();
const location = useLocation(); const location = useLocation();
@@ -41,7 +43,7 @@ export const KeyInPaymentRequestPage = () => {
const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation(); const { mutateAsync: keyInApply } = useExtensionKeyinApplyMutation();
useSetHeaderTitle('KEY-IN 결제'); useSetHeaderTitle(t('additionalService.keyIn.title'));
useSetHeaderType(HeaderType.LeftArrow); useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false); useSetFooterMode(false);
useSetOnBack(() => { useSetOnBack(() => {
@@ -87,25 +89,25 @@ export const KeyInPaymentRequestPage = () => {
if (rs.status && rs.data?.success) { if (rs.status && rs.data?.success) {
// 성공: 화면 유지 & 입력 내용 초기화 // 성공: 화면 유지 & 입력 내용 초기화
snackBar("KEY-IN 결제 신청을 성공하였습니다.") snackBar(t('additionalService.keyIn.requestSuccess'))
resetForm(); resetForm();
} else { } else {
// 실패: 화면 유지 & 입력 내용 유지 // 실패: 화면 유지 & 입력 내용 유지
const errorMessage = rs.data?.resultMessage || const errorMessage = rs.data?.resultMessage ||
rs.error?.message || rs.error?.message ||
'결제 신청에 실패했습니다.'; t('additionalService.keyIn.requestFailed');
console.log('최종 errorMessage:', errorMessage); console.log('최종 errorMessage:', errorMessage);
// HTML 태그 제거 // HTML 태그 제거
const cleanMessage = errorMessage.replace(/<br\s*\/?>/gi, ' ').trim(); const cleanMessage = errorMessage.replace(/<br\s*\/?>/gi, ' ').trim();
snackBar(`[실패] ${cleanMessage}`); snackBar(`[${t('common.failed')}] ${cleanMessage}`);
} }
}).catch((error) => { }).catch((error) => {
console.error('결제 실패:', error); console.error('결제 실패:', error);
const errorMessage = error?.response?.data?.data?.resultMessage || const errorMessage = error?.response?.data?.data?.resultMessage ||
error?.response?.data?.error?.message || error?.response?.data?.error?.message ||
error?.message || error?.message ||
'결제 요청 중 오류가 발생했습니다'; t('additionalService.keyIn.requestError');
snackBar(`[실패] ${errorMessage}`); snackBar(`[${t('common.failed')}] ${errorMessage}`);
}); });
}; };
@@ -152,7 +154,7 @@ export const KeyInPaymentRequestPage = () => {
<div className="option-list"> <div className="option-list">
<div className="billing-form gap-16"> <div className="billing-form gap-16">
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.merchant')} <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<select <select
value={mid} value={mid}
@@ -171,7 +173,7 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.productName')} <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="text" type="text"
@@ -182,7 +184,7 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.productPrice')} <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<NumericFormat <NumericFormat
value={amount} value={amount}
@@ -198,7 +200,7 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.buyerName')} <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="text" type="text"
@@ -209,7 +211,7 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.buyerEmail')} <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="email" type="email"
@@ -221,12 +223,12 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.buyerPhoneNumber')} <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="tel" type="tel"
value={phoneNumber} value={phoneNumber}
placeholder='- 제외하고 입력' placeholder={t('additionalService.keyIn.phoneNumberPlaceholder')}
onChange={(e: ChangeEvent<HTMLInputElement>) => { onChange={(e: ChangeEvent<HTMLInputElement>) => {
const onlyNumbers = e.target.value.replace(/[^0-9]/g, ''); const onlyNumbers = e.target.value.replace(/[^0-9]/g, '');
setPhoneNumber(onlyNumbers); setPhoneNumber(onlyNumbers);
@@ -240,7 +242,7 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.cardNumber')} <span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<PatternFormat <PatternFormat
value={cardNo1} value={cardNo1}
@@ -284,7 +286,7 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label">(/)<span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.expiryDate')}<span>*</span></div>
<div className="billing-field" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}> <div className="billing-field" style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<PatternFormat <PatternFormat
placeholder='MM' placeholder='MM'
@@ -326,14 +328,14 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"> <span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.installmentPeriod')}<span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<select <select
disabled={amount < 50000} disabled={amount < 50000}
value={instmnt} value={instmnt}
onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmnt(e.target.value)} onChange={(e: ChangeEvent<HTMLSelectElement>) => setInstmnt(e.target.value)}
> >
<option value="00"></option> <option value="00">{t('additionalService.keyIn.lumpSum')}</option>
{/* {amount >= 50000 && ( {/* {amount >= 50000 && (
<> <>
<option value="02">2개월</option> <option value="02">2개월</option>
@@ -354,7 +356,7 @@ export const KeyInPaymentRequestPage = () => {
</div> </div>
<div className="billing-row"> <div className="billing-row">
<div className="billing-label"><span>*</span></div> <div className="billing-label">{t('additionalService.keyIn.orderNumber')}<span>*</span></div>
<div className="billing-field"> <div className="billing-field">
<input <input
type="text" type="text"
@@ -370,7 +372,7 @@ export const KeyInPaymentRequestPage = () => {
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={() => onClickToRequest()} onClick={() => onClickToRequest()}
disabled={!isFormValid()} disabled={!isFormValid()}
> </button> >{t('additionalService.keyIn.paymentRequest')}</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,11 +1,13 @@
import { PATHS } from '@/shared/constants/paths'; import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate'; import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { useTranslation } from 'react-i18next';
import { HeaderType } from '@/entities/common/model/types'; import { HeaderType } from '@/entities/common/model/types';
import { import {
useSetHeaderType, useSetHeaderType,
useSetFooterMode, useSetFooterMode,
} from '@/widgets/sub-layout/use-sub-layout'; } from '@/widgets/sub-layout/use-sub-layout';
export const KeyInPaymentRequestSuccessPage = () => { export const KeyInPaymentRequestSuccessPage = () => {
const { t } = useTranslation();
const { navigate } = useNavigate(); const { navigate } = useNavigate();
useSetHeaderType(HeaderType.NoHeader); useSetHeaderType(HeaderType.NoHeader);
@@ -19,23 +21,23 @@ export const KeyInPaymentRequestSuccessPage = () => {
<> <>
<div className="success-page" > <div className="success-page" >
<div className="success-body"> <div className="success-body">
<div <div
className="success-icon" className="success-icon"
aria-hidden="true" aria-hidden="true"
></div> ></div>
<h1 className="success-title"> <h1 className="success-title">
<span>KEY-IN </span><br/> <span>{t('additionalService.keyIn.title')}</span><br/>
<span> .</span> <span>{t('additionalService.keyIn.paymentRequestComplete')}</span>
</h1> </h1>
<div className="success-result"> <div className="success-result">
<p className="result-text"> : [0000] ARS </p> <p className="result-text">{t('additionalService.keyIn.resultLabel')} : [0000] {t('additionalService.keyIn.arsRequestComplete')}</p>
</div> </div>
</div> </div>
<div className="apply-row"> <div className="apply-row">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
onClick={ () => onClickToNavigate() } onClick={ () => onClickToNavigate() }
></button> >{t('additionalService.keyIn.confirm')}</button>
</div> </div>
</div> </div>
</> </>