정산 및 거래 페이지 다국어화 및 통화 표기 개선

- 정산 페이지 다국어화 (정산조회, 정산내역 상세)
- 거래 페이지 다국어화 (거래내역 조회, 거래 취소, 거래내역 상세)
- 정산 엔티티 컴포넌트 다국어화 (list-wrap, list-item, amount-info-wrap)
- 정산 탭 컴포넌트 다국어화 (정산달력, 정산내역)
- 홈 화면 통화 표기 개선 (한국어: 999,999원 / 영어: ₩999,999)
- 정산 및 거래 페이지 통화 표기 개선 (prefix/suffix 동적 처리)
- 요일 번역 기능 (월요일-일요일 → Monday-Sunday)
- 번역 키 추가: settlement, transaction 네임스페이스

🤖 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 17:38:20 +09:00
parent f4963143aa
commit aedf5d3d8f
14 changed files with 278 additions and 144 deletions

View File

@@ -1,7 +1,8 @@
import { NumericFormat } from 'react-number-format';
import {
InfoWrapKeys,
AmountInfoWrapProps,
import { useTranslation } from 'react-i18next';
import {
InfoWrapKeys,
AmountInfoWrapProps,
SettlementPeriodType
} from '@/entities/settlement/model/types';
@@ -10,24 +11,26 @@ export const AmountInfoWrap = ({
amountInfo,
settlementAmount
}: AmountInfoWrapProps) => {
const { t, i18n } = useTranslation();
return (
<>
<div className="txn-section">
<div className="section-title"> </div>
<div className="section-title">{t('settlement.amountInfo')}</div>
{ (periodType === SettlementPeriodType.SETTLEMENT_DATE) &&
<ul className="kv-list">
<li className="kv-row">
<span className="k"> </span>
<span className="k">{t('settlement.totalTransactionAmount')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.totalTransactionAmount }
value={ amountInfo?.totalTransactionAmount }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
<NumericFormat
value={ amountInfo?.totalTransactionCount }
value={ amountInfo?.totalTransactionCount }
thousandSeparator
displayType="text"
prefix=' ('
@@ -36,16 +39,17 @@ export const AmountInfoWrap = ({
</span>
<ul className="txn-amount-detail">
<li>
<span>·&nbsp;&nbsp;</span>
<span>·&nbsp;&nbsp;{t('settlement.creditCard')}</span>
<span className="unset-child-span">
<NumericFormat
value={ amountInfo?.creditCardAmount }
value={ amountInfo?.creditCardAmount }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
<NumericFormat
value={ amountInfo?.creditCardCount }
value={ amountInfo?.creditCardCount }
thousandSeparator
displayType="text"
prefix=' ('
@@ -54,16 +58,17 @@ export const AmountInfoWrap = ({
</span>
</li>
<li>
<span>·&nbsp;&nbsp;</span>
<span>·&nbsp;&nbsp;{t('settlement.accountTransfer')}</span>
<span className="unset-child-span">
<NumericFormat
value={ amountInfo?.accountTransferAmount }
value={ amountInfo?.accountTransferAmount }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
<NumericFormat
value={ amountInfo?.accountTransferCount }
value={ amountInfo?.accountTransferCount }
thousandSeparator
displayType="text"
prefix=' ('
@@ -74,40 +79,40 @@ export const AmountInfoWrap = ({
</ul>
</li>
<li className="kv-row">
<span className="k">PG </span>
<span className="k">{t('settlement.totalPgFee')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.totalPgFee }
value={ amountInfo?.totalPgFee }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
<ul className="txn-amount-detail">
<li>
<span>·&nbsp;&nbsp;</span>
<span>·&nbsp;&nbsp;{t('settlement.paymentFee')}</span>
<span>
<NumericFormat
value={ amountInfo?.paymentFee }
value={ amountInfo?.paymentFee }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li>
<span>·&nbsp;&nbsp; </span>
<span>·&nbsp;&nbsp;{t('settlement.escrowFee')}</span>
<span>
<NumericFormat
value={ amountInfo?.escrowFee }
value={ amountInfo?.escrowFee }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li>
<span>·&nbsp;&nbsp; </span>
<span>·&nbsp;&nbsp;{t('settlement.authFee')}</span>
<span>
<NumericFormat
value={ amountInfo?.authFee }
value={ amountInfo?.authFee }
thousandSeparator
displayType="text"
></NumericFormat>
@@ -117,7 +122,7 @@ export const AmountInfoWrap = ({
<span>·&nbsp;&nbsp;VAT</span>
<span>
<NumericFormat
value={ amountInfo?.vatFee }
value={ amountInfo?.vatFee }
thousandSeparator
displayType="text"
></NumericFormat>
@@ -126,40 +131,40 @@ export const AmountInfoWrap = ({
</ul>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="k">{t('settlement.hold')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.holdAmount }
value={ amountInfo?.holdAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="k">{t('settlement.release')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.releaseAmount }
value={ amountInfo?.releaseAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="k">{t('settlement.offset')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.offsetAmount }
value={ amountInfo?.offsetAmount }
thousandSeparator
displayType="text"
></NumericFormat>
</span>
</li>
<li className="kv-row bolder">
<span className="k"></span>
<span className="k">{t('settlement.settlementAmount')}</span>
<span className="v">
<NumericFormat
value={ settlementAmount }
value={ settlementAmount }
thousandSeparator
displayType="text"
></NumericFormat>
@@ -167,49 +172,53 @@ export const AmountInfoWrap = ({
</li>
</ul>
}
{ (periodType === SettlementPeriodType.TRANSACTION_DATE) &&
{ (periodType === SettlementPeriodType.TRANSACTION_DATE) &&
<ul className="kv-list">
<li className="kv-row">
<span className="k"></span>
<span className="k">{t('settlement.transactionAmount')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.transactionAmount }
value={ amountInfo?.transactionAmount }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>
<li className="kv-row">
<span className="k"> </span>
<span className="k">{t('settlement.paymentFee')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.paymentFee }
value={ amountInfo?.paymentFee }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>
<li className="kv-row">
<span className="k"> </span>
<span className="k">{t('settlement.escrowFee')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.escrowFee }
value={ amountInfo?.escrowFee }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>
<li className="kv-row">
<span className="k"> </span>
<span className="k">{t('settlement.authFee')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.authFee }
value={ amountInfo?.authFee }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>
@@ -217,43 +226,47 @@ export const AmountInfoWrap = ({
<span className="k">VAT</span>
<span className="v">
<NumericFormat
value={ amountInfo?.vatFee }
value={ amountInfo?.vatFee }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>
<li className="kv-row">
<span className="k"></span>
<span className="k">{t('settlement.expectedSettlementAmount')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.settlementAmount }
value={ amountInfo?.settlementAmount }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>
<li className="kv-row">
<span className="k"> </span>
<span className="k">{t('settlement.preSettlementCancelOffset')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.preSettlementCancelOffset }
value={ amountInfo?.preSettlementCancelOffset }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>
<li className="kv-row bolder">
<span className="k"></span>
<span className="k">{t('settlement.settlementAmount')}</span>
<span className="v">
<NumericFormat
value={ amountInfo?.finalSettlementAmount }
value={ amountInfo?.finalSettlementAmount }
thousandSeparator
displayType="text"
suffix='원'
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
</li>

View File

@@ -3,6 +3,7 @@ import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import { ListItemProps, SettlementPeriodType } from '../model/types';
import moment from 'moment';
import { useTranslation } from 'react-i18next';
export const ListItem = ({
periodType,
@@ -17,6 +18,7 @@ export const ListItem = ({
transactionAmount
}: ListItemProps) => {
const { navigate } = useNavigate();
const { t, i18n } = useTranslation();
const onClickToNavigate = () => {
let detailId;
if(periodType === SettlementPeriodType.SETTLEMENT_DATE){
@@ -53,23 +55,24 @@ export const ListItem = ({
<>
<div className="transaction-title">{ `${approvalNumber}(${mid})` }</div>
<div className="transaction-details">
<span>{ (!!settlementDate)? '정산': (!!approvalDate)? '승인' : '' }</span>
<span>{ (!!settlementDate)? t('settlement.settled'): (!!approvalDate)? t('settlement.approved') : '' }</span>
<span className="separator">|</span>
<span> { moment(settlementDate).format('MM.DD') }</span>
<span>{t('settlement.settlementShort')} { moment(settlementDate).format('MM.DD') }</span>
<span className="separator">|</span>
<span> { moment(approvalDate).format('MM.DD') }</span>
<span>{t('settlement.approvalShort')} { moment(approvalDate).format('MM.DD') }</span>
</div>
</>
}
</div>
<div className="transaction-amount">
{
{
<NumericFormat
value={ settlementAmount || transactionAmount }
value={ settlementAmount || transactionAmount }
thousandSeparator
displayType="text"
suffix='원'
></NumericFormat>
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
}
</div>
</div>

View File

@@ -33,6 +33,7 @@ import { DefaultRequestPagination, SortTypeKeys } from '@/entities/common/model/
import { useStore } from '@/shared/model/store';
import { EmailBottomSheet } from '@/entities/common/ui/email-bottom-sheet';
import useIntersectionObserver from '@/widgets/intersection-observer';
import { useTranslation } from 'react-i18next';
export interface ListWrapProps {
startDateFromCalendar?: string;
@@ -44,6 +45,7 @@ export const ListWrap = ({
endDateFromCalendar
}: ListWrapProps) => {
const { navigate } = useNavigate();
const { t, i18n } = useTranslation();
const userMid = useStore.getState().UserStore.mid;
const [onActionIntersect, setOnActionIntersect] = useState<boolean>(false);
@@ -371,38 +373,39 @@ export const ListWrap = ({
readOnly={ true }
/>
<button className="filter-btn">
<img
src={ IMAGE_ROOT + '/ico_setting.svg' }
alt="검색옵션"
<img
src={ IMAGE_ROOT + '/ico_setting.svg' }
alt={t('transaction.searchOptions')}
onClick={ () => onClickToOpenFilter() }
/>
</button>
</div>
<button className="download-btn">
<img
<img
src={ IMAGE_ROOT + '/ico_download.svg' }
alt="다운로드"
alt={t('transaction.download')}
onClick={ () => onClickToDownloadExcel() }
/>
</button>
</div>
<div className="summary-label label"></div>
<div className="summary-label label">{t('settlement.settlementAmount')}</div>
<div className="summary-amount divTop">
<span className="amount-text">
<NumericFormat
value={ settlementAmount }
value={ settlementAmount }
thousandSeparator
displayType="text"
suffix={ '원' }
prefix={i18n.language === 'en' ? t('home.currencySymbol') : ''}
suffix={i18n.language === 'en' ? '' : t('home.currencyWon')}
></NumericFormat>
</span>
<button
onClick={ () => setIsOpenSummary(!isOpenSummary) }
>
<img
<img
className={`ic20 ${(isOpenSummary)? '': 'rot-180'}`}
src={ IMAGE_ROOT + '/ico_divTop_arrow.svg' }
alt="화살표"
src={ IMAGE_ROOT + '/ico_divTop_arrow.svg' }
alt={t('settlement.arrow')}
/>
</button>
</div>
@@ -445,14 +448,14 @@ export const ListWrap = ({
></SortTypeBox>
<div>
<div className="full-menu-keywords no-padding">
<span
<span
className={ `keyword-tag ${(periodType === SettlementPeriodType.SETTLEMENT_DATE)? 'active': ''}` }
onClick={ () => changePeriodType(SettlementPeriodType.SETTLEMENT_DATE) }
> </span>
<span
>{t('settlement.merchantBasis')}</span>
<span
className={ `keyword-tag ${(periodType === SettlementPeriodType.TRANSACTION_DATE)? 'active': ''}` }
onClick={ () => changePeriodType(SettlementPeriodType.TRANSACTION_DATE) }
> </span>
>{t('settlement.transactionBasis')}</span>
</div>
</div>
</div>

View File

@@ -1,14 +1,16 @@
import { PATHS } from '@/shared/constants/paths';
import { useNavigate } from '@/shared/lib/hooks/use-navigate';
import {
import {
SettlementTabKeys,
SettlementTabProps
} from '../model/types';
import { useTranslation } from 'react-i18next';
export const SettlementTab = ({
activeTab
}: SettlementTabProps) => {
const { navigate } = useNavigate();
const { t } = useTranslation();
const onClickToNavigation = (tab: SettlementTabKeys) => {
if(activeTab !== tab){
@@ -23,14 +25,14 @@ export const SettlementTab = ({
return(
<>
<div className="subTab">
<button
<button
className={`subtab-btn ${(activeTab === SettlementTabKeys.Calendar)? 'active': ''}` }
onClick={ () => onClickToNavigation(SettlementTabKeys.Calendar) }
></button>
<button
onClick={ () => onClickToNavigation(SettlementTabKeys.Calendar) }
>{t('settlement.calendar')}</button>
<button
className={`subtab-btn ${(activeTab === SettlementTabKeys.List)? 'active': ''}` }
onClick={ () => onClickToNavigation(SettlementTabKeys.List) }
></button>
onClick={ () => onClickToNavigation(SettlementTabKeys.List) }
>{t('settlement.history')}</button>
</div>
</>
);