diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 7b90825..85a72a7 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from 'next';
import { Noto_Sans_KR } from 'next/font/google';
import './globals.css';
+import { copy } from '@/shared/i18n';
import { Providers } from './providers';
// 1. Noto Sans KR 폰트 설정 (라틴어, 프랑스어, 한국어 등 다국어 지원 베이스)
@@ -12,8 +13,8 @@ const notoSans = Noto_Sans_KR({
});
export const metadata: Metadata = {
- title: 'VibeRoom - 당신만의 편안한 몰입 공간',
- description: '프리랜서와 온전한 집중이 필요한 분들을 위한 따뜻하고 구조화된 온라인 코워킹 스페이스. 작업 타이머, 세션 관리, 그리고 느슨한 연대를 통해 당신의 리듬을 찾아보세요.',
+ title: copy.metadata.title,
+ description: copy.metadata.description,
};
export default function RootLayout({
diff --git a/src/entities/media/api/mediaManifestApi.ts b/src/entities/media/api/mediaManifestApi.ts
index 83d0bd7..235f6cf 100644
--- a/src/entities/media/api/mediaManifestApi.ts
+++ b/src/entities/media/api/mediaManifestApi.ts
@@ -1,6 +1,7 @@
import { DEFAULT_MEDIA_MANIFEST } from '../model/mockMediaManifest';
import { normalizeMediaManifest } from '../model/resolveMediaAsset';
import type { MediaManifest } from '../model/types';
+import { copy } from '@/shared/i18n';
const MEDIA_MANIFEST_URL = process.env.NEXT_PUBLIC_MEDIA_MANIFEST_URL;
@@ -17,7 +18,7 @@ export const mediaManifestApi = {
});
if (!response.ok) {
- throw new Error('미디어 manifest를 불러오지 못했어요.');
+ throw new Error(copy.media.manifestLoadFailed);
}
const payload = (await response.json()) as Partial;
diff --git a/src/entities/plan/model/mockPlan.ts b/src/entities/plan/model/mockPlan.ts
index e5c1f43..e84d93c 100644
--- a/src/entities/plan/model/mockPlan.ts
+++ b/src/entities/plan/model/mockPlan.ts
@@ -1,23 +1,8 @@
import type { ProFeatureCard } from './types';
+import { copy } from '@/shared/i18n';
export const PRO_LOCKED_ROOM_IDS: string[] = [];
export const PRO_LOCKED_TIMER_LABELS: string[] = [];
export const PRO_LOCKED_SOUND_IDS: string[] = [];
-export const PRO_FEATURE_CARDS: ProFeatureCard[] = [
- {
- id: 'scene-packs',
- name: 'Scene Packs',
- description: '프리미엄 공간 묶음과 장면 변주',
- },
- {
- id: 'sound-packs',
- name: 'Sound Packs',
- description: '확장 사운드 프리셋 묶음',
- },
- {
- id: 'profiles',
- name: 'Profiles',
- description: '내 기본 세팅 저장/불러오기',
- },
-];
+export const PRO_FEATURE_CARDS: ProFeatureCard[] = [...copy.plan.proFeatureCards];
diff --git a/src/entities/scene/model/scenes.ts b/src/entities/scene/model/scenes.ts
index 521537a..11401cc 100644
--- a/src/entities/scene/model/scenes.ts
+++ b/src/entities/scene/model/scenes.ts
@@ -1,4 +1,5 @@
import type { CSSProperties } from 'react';
+import { copy } from '@/shared/i18n';
import type { SceneTheme } from './types';
const HUB_CURATION_ORDER = [
@@ -14,14 +15,14 @@ const HUB_RECOMMENDED_SCENE_COUNT = 3;
export const SCENE_THEMES: SceneTheme[] = [
{
id: 'rain-window',
- name: '비 오는 창가',
- description: '빗소리 위로 스탠드 조명이 부드럽게 번집니다.',
- tags: ['저자극', '감성'],
- recommendedSound: 'Rain Focus',
+ name: copy.scenes[0].name,
+ description: copy.scenes[0].description,
+ tags: [...copy.scenes[0].tags],
+ recommendedSound: copy.scenes[0].recommendedSound,
recommendedSoundPresetId: 'rain-focus',
recommendedTimerPresetId: '25-5',
- recommendedTime: '밤',
- vibeLabel: '잔잔함',
+ recommendedTime: copy.scenes[0].recommendedTime,
+ vibeLabel: copy.scenes[0].vibeLabel,
hubColor: '#D6E6F7',
cardPhotoUrl:
'https://images.pexels.com/photos/16763533/pexels-photo-16763533.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -36,14 +37,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'dawn-cafe',
- name: '새벽 카페',
- description: '첫 커피 향처럼 잔잔하고 따뜻한 좌석.',
- tags: ['감성', '딥워크'],
- recommendedSound: 'Cafe Murmur',
+ name: copy.scenes[1].name,
+ description: copy.scenes[1].description,
+ tags: [...copy.scenes[1].tags],
+ recommendedSound: copy.scenes[1].recommendedSound,
recommendedSoundPresetId: 'cafe-work',
recommendedTimerPresetId: '25-5',
- recommendedTime: '새벽',
- vibeLabel: '포근함',
+ recommendedTime: copy.scenes[1].recommendedTime,
+ vibeLabel: copy.scenes[1].vibeLabel,
hubColor: '#F5DDCB',
cardPhotoUrl:
'https://images.pexels.com/photos/18340237/pexels-photo-18340237.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -58,14 +59,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'quiet-library',
- name: '도서관',
- description: '넘기는 종이 소리만 들리는 정돈된 책상.',
- tags: ['저자극', '딥워크'],
- recommendedSound: 'Deep White',
+ name: copy.scenes[2].name,
+ description: copy.scenes[2].description,
+ tags: [...copy.scenes[2].tags],
+ recommendedSound: copy.scenes[2].recommendedSound,
recommendedSoundPresetId: 'deep-white',
recommendedTimerPresetId: '50-10',
- recommendedTime: '오후',
- vibeLabel: '몰입',
+ recommendedTime: copy.scenes[2].recommendedTime,
+ vibeLabel: copy.scenes[2].vibeLabel,
hubColor: '#DCE4D1',
cardPhotoUrl:
'https://images.pexels.com/photos/31390421/pexels-photo-31390421.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -80,14 +81,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'wave-sound',
- name: '파도 소리',
- description: '잔잔한 해변 위로 호흡을 고르는 공간.',
- tags: ['움직임 적음', '감성'],
- recommendedSound: 'Ocean Breath',
+ name: copy.scenes[3].name,
+ description: copy.scenes[3].description,
+ tags: [...copy.scenes[3].tags],
+ recommendedSound: copy.scenes[3].recommendedSound,
recommendedSoundPresetId: 'ocean-calm',
recommendedTimerPresetId: '25-5',
- recommendedTime: '밤',
- vibeLabel: '차분함',
+ recommendedTime: copy.scenes[3].recommendedTime,
+ vibeLabel: copy.scenes[3].vibeLabel,
hubColor: '#CFE9EA',
cardPhotoUrl:
'https://images.pexels.com/photos/12715501/pexels-photo-12715501.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -102,14 +103,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'green-forest',
- name: '숲',
- description: '바람이 나뭇잎을 스치는 소리로 마음을 낮춥니다.',
- tags: ['저자극', '움직임 적음'],
- recommendedSound: 'Forest Hush',
+ name: copy.scenes[4].name,
+ description: copy.scenes[4].description,
+ tags: [...copy.scenes[4].tags],
+ recommendedSound: copy.scenes[4].recommendedSound,
recommendedSoundPresetId: 'rain-focus',
recommendedTimerPresetId: '50-10',
- recommendedTime: '오전',
- vibeLabel: '맑음',
+ recommendedTime: copy.scenes[4].recommendedTime,
+ vibeLabel: copy.scenes[4].vibeLabel,
hubColor: '#D1E7C9',
cardPhotoUrl:
'https://images.pexels.com/photos/34503448/pexels-photo-34503448.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -124,14 +125,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'fireplace',
- name: '벽난로',
- description: '작은 불꽃이 주는 리듬으로 집중을 붙잡습니다.',
- tags: ['감성', '저자극'],
- recommendedSound: 'Fireplace',
+ name: copy.scenes[5].name,
+ description: copy.scenes[5].description,
+ tags: [...copy.scenes[5].tags],
+ recommendedSound: copy.scenes[5].recommendedSound,
recommendedSoundPresetId: 'fireplace',
recommendedTimerPresetId: '25-5',
- recommendedTime: '밤',
- vibeLabel: '온기',
+ recommendedTime: copy.scenes[5].recommendedTime,
+ vibeLabel: copy.scenes[5].vibeLabel,
hubColor: '#F2D4C0',
cardPhotoUrl:
'https://images.pexels.com/photos/14353716/pexels-photo-14353716.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -146,14 +147,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'city-night',
- name: '도시 야경',
- description: '유리창 너머 야경이 멀리 흐르는 고요한 밤.',
- tags: ['딥워크', '감성'],
- recommendedSound: 'Night Lo-fi',
+ name: copy.scenes[6].name,
+ description: copy.scenes[6].description,
+ tags: [...copy.scenes[6].tags],
+ recommendedSound: copy.scenes[6].recommendedSound,
recommendedSoundPresetId: 'deep-white',
recommendedTimerPresetId: '50-10',
- recommendedTime: '심야',
- vibeLabel: '고요함',
+ recommendedTime: copy.scenes[6].recommendedTime,
+ vibeLabel: copy.scenes[6].vibeLabel,
hubColor: '#D9D3ED',
cardPhotoUrl:
'https://images.pexels.com/photos/17663181/pexels-photo-17663181.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -168,14 +169,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'snow-mountain',
- name: '설산',
- description: '차분한 공기와 선명한 수평선이 머리를 맑게 합니다.',
- tags: ['움직임 적음', '딥워크'],
- recommendedSound: 'Cold Wind',
+ name: copy.scenes[7].name,
+ description: copy.scenes[7].description,
+ tags: [...copy.scenes[7].tags],
+ recommendedSound: copy.scenes[7].recommendedSound,
recommendedSoundPresetId: 'deep-white',
recommendedTimerPresetId: '50-10',
- recommendedTime: '새벽',
- vibeLabel: '선명함',
+ recommendedTime: copy.scenes[7].recommendedTime,
+ vibeLabel: copy.scenes[7].vibeLabel,
hubColor: '#D8E7F3',
cardPhotoUrl:
'https://images.pexels.com/photos/34340672/pexels-photo-34340672.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -190,14 +191,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'sun-window',
- name: '창가',
- description: '햇살이 들어오는 간결한 책상, 부담 없는 시작.',
- tags: ['저자극', '딥워크'],
- recommendedSound: 'Soft Daylight',
+ name: copy.scenes[8].name,
+ description: copy.scenes[8].description,
+ tags: [...copy.scenes[8].tags],
+ recommendedSound: copy.scenes[8].recommendedSound,
recommendedSoundPresetId: 'silent',
recommendedTimerPresetId: '25-5',
- recommendedTime: '오후',
- vibeLabel: '가벼움',
+ recommendedTime: copy.scenes[8].recommendedTime,
+ vibeLabel: copy.scenes[8].vibeLabel,
hubColor: '#F6EDC7',
cardPhotoUrl:
'https://images.pexels.com/photos/34833126/pexels-photo-34833126.jpeg?auto=compress&cs=tinysrgb&w=1400',
@@ -212,14 +213,14 @@ export const SCENE_THEMES: SceneTheme[] = [
},
{
id: 'outer-space',
- name: '우주',
- description: '별빛만 남긴 어둠 속에서 깊게 잠수합니다.',
- tags: ['딥워크', '감성'],
- recommendedSound: 'Deep Drone',
+ name: copy.scenes[9].name,
+ description: copy.scenes[9].description,
+ tags: [...copy.scenes[9].tags],
+ recommendedSound: copy.scenes[9].recommendedSound,
recommendedSoundPresetId: 'deep-white',
recommendedTimerPresetId: '90-20',
- recommendedTime: '심야',
- vibeLabel: '깊음',
+ recommendedTime: copy.scenes[9].recommendedTime,
+ vibeLabel: copy.scenes[9].vibeLabel,
hubColor: '#D4DCF4',
cardPhotoUrl:
'https://images.pexels.com/photos/18537868/pexels-photo-18537868.jpeg?auto=compress&cs=tinysrgb&w=1400',
diff --git a/src/entities/session/model/mockSession.ts b/src/entities/session/model/mockSession.ts
index 7f9a3fa..daf16a5 100644
--- a/src/entities/session/model/mockSession.ts
+++ b/src/entities/session/model/mockSession.ts
@@ -7,90 +7,24 @@ import type {
SoundPreset,
TimerPreset,
} from './types';
+import { copy } from '@/shared/i18n';
-export const TODAY_ONE_LINER = '오늘의 한 줄: 완벽보다 시작, 한 조각이면 충분해요.';
+export const TODAY_ONE_LINER = copy.session.todayOneLiner;
-export const GOAL_CHIPS: GoalChip[] = [
- { id: 'mail-3', label: '메일 3개' },
- { id: 'doc-1p', label: '문서 1p' },
- { id: 'code-1-function', label: '코딩 1함수' },
- { id: 'tidy-10m', label: '정리 10분' },
- { id: 'reading-15m', label: '독서 15분' },
- { id: 'resume-1paragraph', label: '이력서 1문단' },
-];
+export const GOAL_CHIPS: GoalChip[] = [...copy.session.goalChips];
-export const CHECK_IN_PHRASES: CheckInPhrase[] = [
- { id: 'arrived', text: '지금 들어왔어요' },
- { id: 'sprint-25', text: '25분만 달릴게요' },
- { id: 'on-break', text: '휴식 중' },
- { id: 'back-focus', text: '다시 집중!' },
- { id: 'slow-day', text: '오늘은 천천히' },
-];
+export const CHECK_IN_PHRASES: CheckInPhrase[] = [...copy.session.checkInPhrases];
-export const REACTION_OPTIONS: ReactionOption[] = [
- { id: 'thumbs-up', emoji: '👍', label: '응원해요' },
- { id: 'fire', emoji: '🔥', label: '집중 모드' },
- { id: 'clap', emoji: '👏', label: '잘하고 있어요' },
- { id: 'heart-hands', emoji: '🫶', label: '연결되어 있어요' },
-];
+export const REACTION_OPTIONS: ReactionOption[] = [...copy.session.reactionOptions];
-export const SOUND_PRESETS: SoundPreset[] = [
- { id: 'deep-white', label: 'Deep White' },
- { id: 'rain-focus', label: 'Rain Focus' },
- { id: 'cafe-work', label: 'Cafe Work' },
- { id: 'ocean-calm', label: 'Ocean Calm' },
- { id: 'fireplace', label: 'Fireplace' },
- { id: 'silent', label: 'Silent' },
-];
+export const SOUND_PRESETS: SoundPreset[] = [...copy.session.soundPresets];
-export const TIMER_PRESETS: TimerPreset[] = [
- { id: '25-5', label: '25/5', focusMinutes: 25, breakMinutes: 5 },
- { id: '50-10', label: '50/10', focusMinutes: 50, breakMinutes: 10 },
- { id: '90-20', label: '90/20', focusMinutes: 90, breakMinutes: 20 },
- { id: 'custom', label: '커스텀' },
-];
+export const TIMER_PRESETS: TimerPreset[] = [...copy.session.timerPresets];
-export const DISTRACTION_DUMP_PLACEHOLDER = [
- '디자인 QA 요청 확인',
- '세금계산서 발행 메모',
- '오후 미팅 질문 1개 정리',
-];
+export const DISTRACTION_DUMP_PLACEHOLDER = [...copy.session.distractionDumpPlaceholder];
-export const TODAY_STATS: FocusStatCard[] = [
- { id: 'today-focus', label: '오늘 집중 시간', value: '2h 40m', delta: '+35m' },
- { id: 'today-cycles', label: '완료한 사이클', value: '5회', delta: '+1' },
- { id: 'today-entry', label: '입장 횟수', value: '3회', delta: '유지' },
-];
+export const TODAY_STATS: FocusStatCard[] = [...copy.session.todayStats];
-export const WEEKLY_STATS: FocusStatCard[] = [
- { id: 'week-focus', label: '최근 7일 집중 시간', value: '14h 20m', delta: '+2h 10m' },
- { id: 'week-best-day', label: '최고 몰입일', value: '수요일', delta: '3h 30m' },
- { id: 'week-consistency', label: '연속 달성', value: '4일', delta: '+1일' },
-];
+export const WEEKLY_STATS: FocusStatCard[] = [...copy.session.weeklyStats];
-export const RECENT_THOUGHTS: RecentThought[] = [
- {
- id: 'thought-1',
- text: '내일 미팅 전에 제안서 첫 문단만 다시 다듬기',
- sceneName: '도서관',
- capturedAt: '방금 전',
- },
- {
- id: 'thought-2',
- text: '기획 문서의 핵심 흐름을 한 문장으로 정리해두기',
- sceneName: '비 오는 창가',
- capturedAt: '24분 전',
- },
- {
- id: 'thought-3',
- text: '오후에 확인할 이슈 번호만 메모하고 지금 작업 복귀',
- sceneName: '숲',
- capturedAt: '1시간 전',
- },
- {
- id: 'thought-4',
- text: '리뷰 코멘트는 오늘 17시 이후에 한 번에 처리',
- sceneName: '벽난로',
- capturedAt: '어제',
- },
-];
+export const RECENT_THOUGHTS: RecentThought[] = [...copy.session.recentThoughts];
diff --git a/src/features/admin/api/adminApi.ts b/src/features/admin/api/adminApi.ts
index 6d2fd5a..3f8ffd2 100644
--- a/src/features/admin/api/adminApi.ts
+++ b/src/features/admin/api/adminApi.ts
@@ -1,4 +1,5 @@
import type { AuthResponse } from '@/features/auth/types';
+import { copy } from '@/shared/i18n';
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8080';
@@ -57,14 +58,14 @@ const parseErrorMessage = async (response: Response) => {
const contentType = response.headers.get('content-type') ?? '';
if (!contentType.includes('application/json')) {
- return `요청 실패: ${response.status}`;
+ return copy.common.requestFailed(response.status);
}
try {
const payload = (await response.json()) as ApiErrorPayload;
- return payload.message ?? payload.error ?? `요청 실패: ${response.status}`;
+ return payload.message ?? payload.error ?? copy.common.requestFailed(response.status);
} catch {
- return `요청 실패: ${response.status}`;
+ return copy.common.requestFailed(response.status);
}
};
diff --git a/src/features/auth/components/SocialLoginGroup.tsx b/src/features/auth/components/SocialLoginGroup.tsx
index 2b194ca..6113634 100644
--- a/src/features/auth/components/SocialLoginGroup.tsx
+++ b/src/features/auth/components/SocialLoginGroup.tsx
@@ -1,6 +1,7 @@
"use client";
import { GoogleOAuthProvider } from "@react-oauth/google";
+import { copy } from '@/shared/i18n';
import { useSocialLogin } from "../hooks/useSocialLogin";
const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || "";
@@ -46,7 +47,7 @@ const SocialLoginButtons = () => {
fill="#EA4335"
/>
- {isLoading ? "연결 중..." : "Google로 계속하기"}
+ {isLoading ? copy.auth.social.connecting : copy.auth.social.continueWithGoogle}
{/* 2. Apple 로그인 (react-apple-signin-auth 연동) */}
diff --git a/src/features/auth/hooks/useSocialLogin.ts b/src/features/auth/hooks/useSocialLogin.ts
index 537e38b..5ac8465 100644
--- a/src/features/auth/hooks/useSocialLogin.ts
+++ b/src/features/auth/hooks/useSocialLogin.ts
@@ -2,6 +2,7 @@ import { useGoogleLogin } from '@react-oauth/google';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import appleAuthHelpers from 'react-apple-signin-auth';
+import { copy } from '@/shared/i18n';
import { useAuthStore } from '@/store/useAuthStore';
import { authApi } from '../api/authApi';
@@ -58,7 +59,7 @@ export const useSocialLogin = () => {
router.push('/app');
} catch (err) {
console.error(`[${provider}] 로그인 실패:`, err);
- setError('로그인에 실패했습니다. 다시 시도해 주세요.');
+ setError(copy.auth.errors.loginFailed);
} finally {
setIsLoading(false);
}
@@ -73,7 +74,7 @@ export const useSocialLogin = () => {
handleSocialLogin('google', tokenResponse.access_token);
},
onError: () => {
- setError('구글 로그인에 실패했습니다. 팝업 차단 여부를 확인해 주세요.');
+ setError(copy.auth.errors.googleFailed);
},
});
@@ -99,12 +100,12 @@ export const useSocialLogin = () => {
},
onError: (err: AppleSignInError) => {
console.error('Apple SignIn error:', err);
- setError('애플 로그인 중 오류가 발생했습니다.');
+ setError(copy.auth.errors.appleFailed);
},
});
} catch (err) {
console.error(err);
- setError('애플 로그인 초기화 실패');
+ setError(copy.auth.errors.appleInitFailed);
}
};
@@ -116,7 +117,7 @@ export const useSocialLogin = () => {
if (response?.accessToken) {
handleSocialLogin('facebook', response.accessToken);
} else {
- setError('페이스북 로그인에 실패했습니다.');
+ setError(copy.auth.errors.facebookFailed);
}
};
diff --git a/src/features/exit-hold/ui/ExitHoldButton.tsx b/src/features/exit-hold/ui/ExitHoldButton.tsx
index 3e99726..97f3545 100644
--- a/src/features/exit-hold/ui/ExitHoldButton.tsx
+++ b/src/features/exit-hold/ui/ExitHoldButton.tsx
@@ -1,6 +1,7 @@
'use client';
import type { KeyboardEvent } from 'react';
+import { copy } from '@/shared/i18n';
import { cn } from '@/shared/lib/cn';
import { useHoldToConfirm } from '../model/useHoldToConfirm';
@@ -39,7 +40,7 @@ export const ExitHoldButton = ({
return (
);
diff --git a/src/features/focus-session/model/useFocusSessionEngine.ts b/src/features/focus-session/model/useFocusSessionEngine.ts
index c803101..317c432 100644
--- a/src/features/focus-session/model/useFocusSessionEngine.ts
+++ b/src/features/focus-session/model/useFocusSessionEngine.ts
@@ -1,6 +1,7 @@
'use client';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { copy } from '@/shared/i18n';
import {
focusSessionApi,
type CompleteFocusSessionRequest,
@@ -96,7 +97,7 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
return applySession(session);
} catch (nextError) {
const message =
- nextError instanceof Error ? nextError.message : '세션 엔진과 동기화하지 못했어요.';
+ nextError instanceof Error ? nextError.message : copy.focusSession.syncFailed;
setError(message);
return null;
} finally {
@@ -188,7 +189,7 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
startSession: async (payload) => {
const session = await runMutation(
() => focusSessionApi.startSession(payload),
- '세션을 시작하지 못했어요.',
+ copy.focusSession.startFailed,
);
return applySession(session);
@@ -200,7 +201,7 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
const session = await runMutation(
() => focusSessionApi.pauseSession(),
- '세션을 일시정지하지 못했어요.',
+ copy.focusSession.pauseFailed,
);
return applySession(session);
@@ -212,7 +213,7 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
const session = await runMutation(
() => focusSessionApi.resumeSession(),
- '세션을 다시 시작하지 못했어요.',
+ copy.focusSession.resumeFailed,
);
return applySession(session);
@@ -224,7 +225,7 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
const session = await runMutation(
() => focusSessionApi.restartCurrentPhase(),
- '현재 페이즈를 다시 시작하지 못했어요.',
+ copy.focusSession.restartPhaseFailed,
);
return applySession(session);
@@ -236,7 +237,7 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
const session = await runMutation(
() => focusSessionApi.completeSession(payload),
- '세션을 완료 처리하지 못했어요.',
+ copy.focusSession.completeFailed,
);
if (session) {
@@ -252,7 +253,7 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
const result = await runMutation(
() => focusSessionApi.abandonSession(),
- '세션을 종료하지 못했어요.',
+ copy.focusSession.abandonFailed,
);
if (result === null) {
diff --git a/src/features/inbox/ui/InboxList.tsx b/src/features/inbox/ui/InboxList.tsx
index 789acd0..071024f 100644
--- a/src/features/inbox/ui/InboxList.tsx
+++ b/src/features/inbox/ui/InboxList.tsx
@@ -1,4 +1,5 @@
import type { RecentThought } from '@/entities/session';
+import { copy } from '@/shared/i18n';
import { cn } from '@/shared/lib/cn';
interface InboxListProps {
@@ -17,7 +18,7 @@ export const InboxList = ({ thoughts, onCompleteThought, onDeleteThought, classN
className,
)}
>
- 지금은 비어 있어요. 집중 중 떠오른 생각을 여기로 주차할 수 있어요.
+ {copy.space.inbox.empty}
);
}
@@ -51,14 +52,14 @@ export const InboxList = ({ thoughts, onCompleteThought, onDeleteThought, classN
: 'border-white/20 bg-white/8 text-white/76 hover:bg-white/14',
)}
>
- {thought.isCompleted ? '완료됨' : '완료'}
+ {thought.isCompleted ? copy.space.inbox.completed : copy.space.inbox.complete}
diff --git a/src/features/paywall-sheet/ui/ManagePlanSheetContent.tsx b/src/features/paywall-sheet/ui/ManagePlanSheetContent.tsx
index 25e846a..d03d864 100644
--- a/src/features/paywall-sheet/ui/ManagePlanSheetContent.tsx
+++ b/src/features/paywall-sheet/ui/ManagePlanSheetContent.tsx
@@ -1,3 +1,5 @@
+import { copy } from '@/shared/i18n';
+
interface ManagePlanSheetContentProps {
onClose: () => void;
onManage: () => void;
@@ -12,8 +14,8 @@ export const ManagePlanSheetContent = ({
return (