Localize common UI components (bottom sheets)

Replace all hardcoded Korean text with i18n translation keys in
common bottom sheet components for email selection and download
type selection.

Components localized:
- email-bottom-sheet: Title, image save label, receive by email label,
  image requested snackbar message, close button alt, request button
- download-type-bottom-sheet: Title, download method selection labels,
  image/email alt texts, close button alt

Translation keys added to en.json:
- selectEmailAddress: "Select Email Address"
- imageSave: "Save as Image"
- receiveByEmail: "Receive by Email"
- mail: "Mail"
- image: "Image"
- request: "Request"
- imageRequested: "Image has been requested."
- selectDownloadMethod: "Select Download Method"

All bottom sheet UI text now supports internationalization.

🤖 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-31 12:33:30 +09:00
parent 1e65a67674
commit d0602dae1c
3 changed files with 35 additions and 23 deletions

View File

@@ -1,6 +1,7 @@
import { BottomSheetMotionDuration, BottomSheetMotionVaiants } from '@/entities/common/model/constant'; import { BottomSheetMotionDuration, BottomSheetMotionVaiants } from '@/entities/common/model/constant';
import { IMAGE_ROOT } from '@/shared/constants/common'; import { IMAGE_ROOT } from '@/shared/constants/common';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useTranslation } from 'react-i18next';
export interface DownloadTypeBottomSheetProps { export interface DownloadTypeBottomSheetProps {
bottomSheetOn: boolean; bottomSheetOn: boolean;
@@ -13,6 +14,7 @@ export const DownloadTypeBottomSheet = ({
setBottomSheetOn, setBottomSheetOn,
onSelectType onSelectType
}: DownloadTypeBottomSheetProps) => { }: DownloadTypeBottomSheetProps) => {
const { t } = useTranslation();
const onClickToClose = () => { const onClickToClose = () => {
setBottomSheetOn(false); setBottomSheetOn(false);
@@ -37,14 +39,14 @@ export const DownloadTypeBottomSheet = ({
> >
<div className="bottomsheet-header"> <div className="bottomsheet-header">
<div className="bottomsheet-title"> <div className="bottomsheet-title">
<h2> </h2> <h2>{t('common.selectDownloadMethod')}</h2>
<button <button
className="close-btn" className="close-btn"
type="button" type="button"
> >
<img <img
src={ IMAGE_ROOT + '/ico_close.svg' } src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기" alt={t('common.close')}
onClick={ () => onClickToClose() } onClick={ () => onClickToClose() }
/> />
</button> </button>
@@ -62,10 +64,10 @@ export const DownloadTypeBottomSheet = ({
<div className="mail-icon-bg"></div> <div className="mail-icon-bg"></div>
<img <img
src={ IMAGE_ROOT + '/ico_pic.svg' } src={ IMAGE_ROOT + '/ico_pic.svg' }
alt="이미지" alt={t('common.image')}
/> />
</div> </div>
<span className="label-text"> </span> <span className="label-text">{t('common.imageSave')}</span>
</div> </div>
<div <div
@@ -77,10 +79,10 @@ export const DownloadTypeBottomSheet = ({
<div className="mail-icon-bg"></div> <div className="mail-icon-bg"></div>
<img <img
src={ IMAGE_ROOT + '/ico_email.svg' } src={ IMAGE_ROOT + '/ico_email.svg' }
alt='메일' alt={t('common.mail')}
/> />
</div> </div>
<span className="label-text"> </span> <span className="label-text">{t('common.receiveByEmail')}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -5,6 +5,7 @@ import { motion } from 'framer-motion';
import { ChangeEvent, useState } from 'react'; import { ChangeEvent, useState } from 'react';
import { toPng } from 'html-to-image'; import { toPng } from 'html-to-image';
import { snackBar } from '@/shared/lib'; import { snackBar } from '@/shared/lib';
import { useTranslation } from 'react-i18next';
export interface EmailBottomSheetProps { export interface EmailBottomSheetProps {
bottomSheetOn: boolean; bottomSheetOn: boolean;
@@ -21,6 +22,7 @@ export const EmailBottomSheet = ({
sendEmail, sendEmail,
sendRequest sendRequest
}: EmailBottomSheetProps) => { }: EmailBottomSheetProps) => {
const { t } = useTranslation();
const optionsEmails = useStore.getState().UserStore.selectOptionsEmails; const optionsEmails = useStore.getState().UserStore.selectOptionsEmails;
const email = useStore.getState().UserStore.email; const email = useStore.getState().UserStore.email;
const [userEmail, setUserEmail] = useState<string>(email); const [userEmail, setUserEmail] = useState<string>(email);
@@ -32,14 +34,14 @@ export const EmailBottomSheet = ({
sendRequest(userEmail); sendRequest(userEmail);
}; };
const downloadImage = () => { const downloadImage = () => {
const app = document.getElementById('root') as HTMLElement; const app = document.getElementById('root') as HTMLElement;
toPng(app).then((image) => { toPng(app).then((image) => {
const link = document.createElement('a'); const link = document.createElement('a');
link.download = 'downloadImage.png'; link.download = 'downloadImage.png';
link.href = image; link.href = image;
link.click(); link.click();
snackBar('이미지가 요청 되었습니다.'); snackBar(t('common.imageRequested'));
}); });
}; };
const onDownloadImage = () => { const onDownloadImage = () => {
@@ -63,14 +65,14 @@ export const EmailBottomSheet = ({
> >
<div className="bottomsheet-header"> <div className="bottomsheet-header">
<div className="bottomsheet-title"> <div className="bottomsheet-title">
<h2> </h2> <h2>{t('common.selectEmailAddress')}</h2>
<button <button
className="close-btn" className="close-btn"
type="button" type="button"
> >
<img <img
src={ IMAGE_ROOT + '/ico_close.svg' } src={ IMAGE_ROOT + '/ico_close.svg' }
alt="닫기" alt={t('common.close')}
onClick={ () => onClickToClose() } onClick={ () => onClickToClose() }
/> />
</button> </button>
@@ -80,18 +82,18 @@ export const EmailBottomSheet = ({
<div className="bottomsheet-content"> <div className="bottomsheet-content">
<div className="email-section"> <div className="email-section">
{ !!imageSave && { !!imageSave &&
<div <div
className="email-label mb-10" className="email-label mb-10"
onClick={ onDownloadImage } onClick={ onDownloadImage }
> >
<div className="mail-icon"> <div className="mail-icon">
<div className="mail-icon-bg"></div> <div className="mail-icon-bg"></div>
<img <img
src={ IMAGE_ROOT + '/ico_pic.svg' } src={ IMAGE_ROOT + '/ico_pic.svg' }
alt="이미지" alt={t('common.image')}
/> />
</div> </div>
<span className="label-text"> </span> <span className="label-text">{t('common.imageSave')}</span>
</div> </div>
} }
{ !!sendEmail && { !!sendEmail &&
@@ -99,12 +101,12 @@ export const EmailBottomSheet = ({
<div className="email-label"> <div className="email-label">
<div className="mail-icon"> <div className="mail-icon">
<div className="mail-icon-bg"></div> <div className="mail-icon-bg"></div>
<img <img
src={ IMAGE_ROOT + '/ico_email.svg' } src={ IMAGE_ROOT + '/ico_email.svg' }
alt='메일' alt={t('common.mail')}
/> />
</div> </div>
<span className="label-text"> </span> <span className="label-text">{t('common.receiveByEmail')}</span>
</div> </div>
<div className="email-select"> <div className="email-select">
<div className="select-wrapper"> <div className="select-wrapper">
@@ -136,10 +138,10 @@ export const EmailBottomSheet = ({
<div className="bottomsheet-footer"> <div className="bottomsheet-footer">
<button <button
className="btn-50 btn-blue flex-1" className="btn-50 btn-blue flex-1"
type="button" type="button"
onClick={ onClickToRequest } onClick={ onClickToRequest }
></button> >{t('common.request')}</button>
</div> </div>
</motion.div> </motion.div>
</> </>

View File

@@ -27,7 +27,15 @@
"fri": "Fri", "fri": "Fri",
"sat": "Sat" "sat": "Sat"
}, },
"currencyUnit": "" "currencyUnit": "",
"selectEmailAddress": "Select Email Address",
"imageSave": "Save as Image",
"receiveByEmail": "Receive by Email",
"mail": "Mail",
"image": "Image",
"request": "Request",
"imageRequested": "Image has been requested.",
"selectDownloadMethod": "Select Download Method"
}, },
"menu": { "menu": {
"home": "Home", "home": "Home",