링크결제 신청 페이지 다국어 지원 추가

- 링크결제 신청, 확인, 완료 페이지 현지화
- 메시지 미리보기 텍스트 번역
- 에러 메시지 및 버튼 다국어 적용
- 한글/영문 번역 키 추가

🤖 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 15:58:16 +09:00
parent 7b5f93d737
commit 405b6f1e38
5 changed files with 47 additions and 25 deletions

View File

@@ -1043,6 +1043,15 @@
"applyTitle": "Link Payment Request",
"messagePreview": "Message Preview",
"separateApprovalTitle": "Separate Approval Detail",
"previous": "Previous",
"next": "Next",
"requestProcessingError": "Unable to process request.",
"requestError": "An error occurred during request",
"confirmSendMessage": "Please confirm\nthe message to be sent",
"paymentRequestComplete": "Payment request has been completed.",
"merchantName": "Merchant Name",
"customerGreeting": "Hello, {buyerName}!",
"paymentGuideMessage": "NICEPAYMENTS Co., Ltd. is notifying you\nof the payment details.\nYou can check the details and proceed with payment by accessing the URL below.",
"resendSuccess": "Resend successful.",
"resendFailed": "Resend failed.",
"resendError": "An error occurred during resend.",

View File

@@ -1043,6 +1043,15 @@
"applyTitle": "링크결제 신청",
"messagePreview": "메시지 미리보기",
"separateApprovalTitle": "분리승인 상세",
"previous": "이전",
"next": "다음",
"requestProcessingError": "요청을 처리할 수 없습니다.",
"requestError": "요청 중 오류가 발생했습니다",
"confirmSendMessage": "발송 메시지를\n최종 확인하세요",
"paymentRequestComplete": "결제 신청이 완료되었습니다.",
"merchantName": "가맹점 상호",
"customerGreeting": "{buyerName} 고객님, 안녕하세요?",
"paymentGuideMessage": "나이스페이먼츠 주식회사에서\n결제하실 내역 안내드립니다.\n아래 URL로 접속하시면 상세 내역 확인과 결제 진행이 가능합니다.",
"resendSuccess": "재발송을 성공하였습니다.",
"resendFailed": "재발송을 실패하였습니다.",
"resendError": "재발송 중 오류가 발생했습니다.",

View File

@@ -1,3 +1,4 @@
import { useTranslation } from 'react-i18next';
import { HeaderType } from '@/entities/common/model/types';
import { useSetFooterMode, useSetHeaderTitle, useSetHeaderType } from '@/widgets/sub-layout/use-sub-layout';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
@@ -9,13 +10,14 @@ import { ExtensionLinkPayRequestParams, ExtensionLinkPayRequestResponse, LinkPay
import { snackBar } from '@/shared/lib';
export const LinkPaymentApplyConfirmPage = () => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const location = useLocation();
const formData: LinkPaymentFormData = location.state?.formData;
const { mutateAsync: linkPayRequest } = useExtensionLinkPayRequestMutation();
useSetHeaderTitle('메시지 미리보기');
useSetHeaderTitle(t('additionalService.linkPayment.messagePreview'));
useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false);
@@ -53,16 +55,16 @@ export const LinkPaymentApplyConfirmPage = () => {
navigate(PATHS.additionalService.linkPayment.confirmSuccess);
} else {
// 일반 에러 메시지
const errorMessage = rs.error?.message || '요청을 처리할 수 없습니다.';
snackBar(`[실패] ${errorMessage}`);
const errorMessage = rs.error?.message || t('additionalService.linkPayment.requestProcessingError');
snackBar(`[${t('common.failed')}] ${errorMessage}`);
}
})
.catch((error) => {
// 네트워크 에러 등 예외 상황
const errorMessage = error?.response?.data?.error?.message ||
error?.message ||
'요청 중 오류가 발생했습니다';
snackBar(`[실패] ${errorMessage}`);
t('additionalService.linkPayment.requestError');
snackBar(`[${t('common.failed')}] ${errorMessage}`);
});
};
@@ -76,20 +78,18 @@ export const LinkPaymentApplyConfirmPage = () => {
<div className="sub-wrap">
<div className="preview-body">
<div className="attention-icon" aria-hidden="true">
<img src={IMAGE_ROOT + '/ico_alert.svg'} alt="주의" />
<img src={IMAGE_ROOT + '/ico_alert.svg'} alt={t('common.confirm')} />
</div>
<h1 className="preview-title"> <br /> </h1>
<h1 className="preview-title">{t('additionalService.linkPayment.confirmSendMessage')}</h1>
<div className="preview-result">
<p className="preview-text">
{formData.buyerName} , ?<br />
<br />
.<br />
URL로 .<br /><br />
{t('additionalService.linkPayment.customerGreeting', { buyerName: formData.buyerName })}<br />
{t('additionalService.linkPayment.paymentGuideMessage')}<br /><br />
!$&#123;pay_url&#125;<br /><br />
<b>
상호 : 나이스페이먼 <br />
: {formData.goodsName}<br />
: {formData.amount.toLocaleString()}
{t('additionalService.linkPayment.merchantName')} : <br />
{t('transaction.fields.productName')} : {formData.goodsName}<br />
{t('transaction.fields.amount')} : {formData.amount.toLocaleString()}{t('common.currencyUnit')}
</b>
</p>
</div>
@@ -100,11 +100,11 @@ export const LinkPaymentApplyConfirmPage = () => {
<button
className="btn-50 btn-darkgray flex-1"
onClick={() => onClickToBack()}
></button>
>{t('additionalService.linkPayment.previous')}</button>
<button
className="btn-50 btn-blue flex-3"
onClick={() => onClickToConfirm()}
> </button>
>{t('additionalService.linkPay.paymentRequest')}</button>
</div>
</main>
</>

View File

@@ -1,4 +1,5 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { LinkPaymentStep1 } from '@/entities/additional-service/ui/link-payment/apply/link-payment-step1';
import { LinkPaymentStep2 } from '@/entities/additional-service/ui/link-payment/apply/link-payment-step2';
import { HeaderType } from '@/entities/common/model/types';
@@ -14,6 +15,7 @@ import moment from 'moment';
export const LinkPaymentApplyPage = () => {
const { t } = useTranslation();
const { navigate } = useNavigate();
const midOptionsWithoutGids = useStore.getState().UserStore.selectOptionsMidsWithoutGids;
@@ -43,7 +45,7 @@ export const LinkPaymentApplyPage = () => {
linkContentType: LinkContentType.BASIC
});
useSetHeaderTitle('링크결제 신청');
useSetHeaderTitle(t('additionalService.linkPayment.applyTitle'));
useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false);
@@ -144,7 +146,7 @@ export const LinkPaymentApplyPage = () => {
className="btn-50 btn-blue flex-1"
onClick={() => onClickToChangeTab()}
disabled={!isStep1Valid()}
></button>
>{t('additionalService.linkPayment.next')}</button>
</div>
}
{(processStep === ProcessStep.Two) &&
@@ -152,12 +154,12 @@ export const LinkPaymentApplyPage = () => {
<button
className="btn-50 btn-darkgray flex-1"
onClick={() => onClickToBack()}
></button>
>{t('additionalService.linkPayment.previous')}</button>
<button
className="btn-50 btn-blue flex-3"
onClick={() => onClickToChangeTab()}
disabled={!isStep2Valid()}
> </button>
>{t('additionalService.linkPay.paymentRequest')}</button>
</div>
}
</div>

View File

@@ -1,12 +1,14 @@
import { useTranslation } from 'react-i18next';
import { HeaderType } from '@/entities/common/model/types';
import { useSetFooterMode, useSetHeaderTitle, useSetHeaderType } from '@/widgets/sub-layout/use-sub-layout';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { PATHS } from "@/shared/constants/paths";
export const LinkPaymentApplySuccessPage = () => {
const { t } = useTranslation();
const { navigate } = useNavigate();
useSetHeaderTitle('링크결제 신청');
useSetHeaderTitle(t('additionalService.linkPayment.applyTitle'));
useSetHeaderType(HeaderType.LeftArrow);
useSetFooterMode(false);
@@ -20,15 +22,15 @@ export const LinkPaymentApplySuccessPage = () => {
<div className="success-body">
<div className="success-icon" aria-hidden="true"></div>
<h1 className="success-title">
<span></span><br/>
<span> .</span>
<span>{t('additionalService.linkPayment.title')}</span><br/>
<span>{t('additionalService.linkPayment.paymentRequestComplete')}</span>
</h1>
</div>
<div className="apply-row">
<button
<button
className="btn-50 btn-blue flex-1"
onClick={() => onClickToHome()}
></button>
>{t('common.confirm')}</button>
</div>
</div>
</>