diff --git a/core/ui/src/main/kotlin/com/afternote/core/ui/calendar/BottomSheetCalendar.kt b/core/ui/src/main/kotlin/com/afternote/core/ui/calendar/BottomSheetCalendar.kt
index 088bfa63c1..7e8a35a25a 100644
--- a/core/ui/src/main/kotlin/com/afternote/core/ui/calendar/BottomSheetCalendar.kt
+++ b/core/ui/src/main/kotlin/com/afternote/core/ui/calendar/BottomSheetCalendar.kt
@@ -34,6 +34,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.selected
@@ -177,7 +178,7 @@ fun DatePickerContent(
verticalAlignment = Alignment.CenterVertically,
) {
Text(
- text = "${currentYear}년 ${currentMonth}월",
+ text = stringResource(R.string.core_ui_calendar_year_month, currentYear, currentMonth),
style = AfternoteDesign.typography.bodySmallR,
color = AfternoteDesign.colors.gray9,
modifier = Modifier.weight(1f),
@@ -240,7 +241,7 @@ fun CalendarGridContent(
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
- val dayLabels = listOf("일", "월", "화", "수", "목", "금", "토")
+ val dayLabels = stringArrayResource(R.array.core_ui_calendar_day_labels)
Row(modifier = Modifier.fillMaxWidth()) {
dayLabels.forEach { label ->
Text(
diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml
index c7c6650282..980b7b4307 100644
--- a/core/ui/src/main/res/values/strings.xml
+++ b/core/ui/src/main/res/values/strings.xml
@@ -35,6 +35,18 @@
다시 시도하기
설정
+
+ %1$d년 %2$d월
+
+ - 일
+ - 월
+ - 화
+ - 수
+ - 목
+ - 금
+ - 토
+
수신자 선택
이름으로 검색하기
diff --git a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/detail/MemorialDetailScreen.kt b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/detail/MemorialDetailScreen.kt
index d8b2fbf258..cc9ff5b7a9 100644
--- a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/detail/MemorialDetailScreen.kt
+++ b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/detail/MemorialDetailScreen.kt
@@ -297,7 +297,7 @@ private fun VideoCard(
content = {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text(
- text = "장례식에 남길 영상",
+ text = stringResource(R.string.afternote_editor_funeral_video_label),
style =
AfternoteDesign.typography.textField.copy(
fontWeight = FontWeight.Medium,
@@ -328,7 +328,8 @@ private fun VideoThumbnail(thumbnailUrl: String?) {
if (!thumbnailUrl.isNullOrBlank()) {
AsyncImage(
model = thumbnailUrl,
- contentDescription = "장례식에 남길 영상 썸네일",
+ contentDescription =
+ stringResource(R.string.afternote_content_description_memorial_video_thumbnail),
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
@@ -354,7 +355,7 @@ private fun VideoThumbnail(thumbnailUrl: String?) {
// 재생 아이콘
Image(
painter = painterResource(R.drawable.feature_afternote_ic_playback),
- contentDescription = "영상 재생",
+ contentDescription = stringResource(R.string.content_description_video_play),
modifier =
Modifier
.align(Alignment.Center)
@@ -380,7 +381,7 @@ private fun PlaylistCard(
content = {
Column {
Text(
- text = "추억 플레이리스트",
+ text = stringResource(R.string.afternote_editor_playlist_screen_title),
style =
AfternoteDesign.typography.textField.copy(
fontWeight = FontWeight.Medium,
@@ -393,7 +394,7 @@ private fun PlaylistCard(
}
Spacer(Modifier.height(8.dp))
Text(
- text = "현재 ${songCount}개의 노래가 담겨 있습니다.",
+ text = stringResource(R.string.afternote_detail_playlist_song_count, songCount),
style =
AfternoteDesign.typography.bodySmallR.copy(
color = AfternoteDesign.colors.black,
diff --git a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/editor/EditorSectionLabel.kt b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/editor/EditorSectionLabel.kt
index ebe6c87acf..81a4999f06 100644
--- a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/editor/EditorSectionLabel.kt
+++ b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/editor/EditorSectionLabel.kt
@@ -43,14 +43,14 @@ fun EditorSectionLabel(
fontWeight = FontWeight.Medium,
),
) {
- val requiredMarkerDescription =
- stringResource(R.string.afternote_editor_semantics_required_field)
+ val requiredFieldDescription =
+ stringResource(R.string.afternote_editor_semantics_required_field_description, text)
Row(
modifier =
modifier.semantics(mergeDescendants = true) {
if (isRequired) {
- contentDescription = "$text, $requiredMarkerDescription"
+ contentDescription = requiredFieldDescription
}
},
verticalAlignment = Alignment.CenterVertically,
diff --git a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/home/HomeHeaderSection.kt b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/home/HomeHeaderSection.kt
index 70e0f27c2a..d21f9acc51 100644
--- a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/home/HomeHeaderSection.kt
+++ b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/author/home/HomeHeaderSection.kt
@@ -14,11 +14,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.afternote.core.ui.AfternoteOutlinedCard
import com.afternote.core.ui.AfternoteSectionHeader
import com.afternote.core.ui.icon.RightArrowIcon
import com.afternote.core.ui.theme.AfternoteDesign
+import com.afternote.feature.afternote.presentation.R
/**
* NEXT STEP 카드에 필요한 값 묶음.
@@ -52,7 +54,7 @@ internal fun HomeHeaderSection(
.padding(horizontal = 25.dp),
) {
Text(
- text = "애프터노트",
+ text = stringResource(R.string.afternote_home_title),
style = AfternoteDesign.typography.h1,
color = AfternoteDesign.colors.gray9,
)
@@ -82,7 +84,7 @@ private fun NextStepCard(
modifier = modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(4.dp),
) {
- AfternoteSectionHeader(title = "NEXT STEP")
+ AfternoteSectionHeader(title = stringResource(R.string.afternote_home_next_step_section_title))
AfternoteOutlinedCard(
onClick = onClick,
contentPadding = PaddingValues(start = 16.dp, top = 16.dp, bottom = 16.dp, end = 20.dp),
diff --git a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/receiver/detail/MemorialReceivedDetailScreen.kt b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/receiver/detail/MemorialReceivedDetailScreen.kt
index b977f59a16..d1d35e51b7 100644
--- a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/receiver/detail/MemorialReceivedDetailScreen.kt
+++ b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/receiver/detail/MemorialReceivedDetailScreen.kt
@@ -31,6 +31,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
@@ -82,7 +83,7 @@ fun MemorialReceivedDetailScreen(
// → 탑바가 상태바(시계·배터리) 밑에서 시작(겹침 방지). 동적 인셋이라 회전·분할화면에도 대응.
Column(modifier = Modifier.statusBarsPadding()) {
DetailTopBar(
- title = "故 ${senderName}님의 애프터노트",
+ title = stringResource(R.string.afternote_receiver_detail_title, senderName),
onBackClick = { onBackClick() },
)
}
@@ -117,7 +118,6 @@ fun MemorialReceivedDetailScreen(
},
playlistContent = {
MemorialPlaylist(
- label = "추억 플레이리스트",
songCount = songCount,
albumCovers = albumCovers,
onCardClick = onNavigateToPlaylist,
@@ -143,7 +143,7 @@ fun MemorialReceivedDetailScreen(
Spacer(modifier = Modifier.height(70.dp))
AfternoteButton(
- text = "애프터노트 확인하기",
+ text = stringResource(R.string.afternote_receiver_detail_confirm),
onClick = onNavigateToFullList,
type = AfternoteButtonType.Default,
)
@@ -153,14 +153,13 @@ fun MemorialReceivedDetailScreen(
}
}
-private const val LABEL_VIDEO_SECTION = "장례식에 남길 영상"
-
@Composable
private fun ReceiverVideoSection(
memorialVideoUrl: String? = null,
memorialThumbnailUrl: String? = null,
) {
val context = LocalContext.current
+ val noVideoAppMessage = stringResource(R.string.receiver_memorial_video_no_app)
Column(modifier = Modifier.fillMaxWidth()) {
ReceiverSectionHeader()
Spacer(modifier = Modifier.height(12.dp))
@@ -190,7 +189,7 @@ private fun ReceiverVideoSection(
Toast
.makeText(
context,
- "영상을 재생할 수 있는 앱이 없습니다.",
+ noVideoAppMessage,
Toast.LENGTH_SHORT,
).show()
},
@@ -211,7 +210,9 @@ private fun ReceiverVideoSection(
) {
Icon(
painter = painterResource(R.drawable.receiver_ic_play_arrow),
- contentDescription = "Play",
+ // 영상이 없을 때만 그리는 플레이스홀더다. clickable 이 없어 재생 액션이 없으므로
+ // 라벨을 붙이면 없는 어포던스를 알린다. 맥락은 위 ReceiverSectionHeader 가 읽어 준다.
+ contentDescription = null,
tint = AfternoteDesign.colors.white,
modifier =
Modifier
@@ -295,7 +296,8 @@ private fun ReceiverMemorialVideoThumbnail(thumbnailUrl: String?) {
if (!thumbnailUrl.isNullOrBlank()) {
AsyncImage(
model = thumbnailUrl,
- contentDescription = "장례식에 남길 영상 썸네일",
+ contentDescription =
+ stringResource(R.string.afternote_content_description_memorial_video_thumbnail),
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
@@ -317,7 +319,7 @@ private fun ReceiverMemorialVideoThumbnail(thumbnailUrl: String?) {
)
Image(
painter = painterResource(R.drawable.feature_afternote_ic_playback),
- contentDescription = "영상 재생",
+ contentDescription = stringResource(R.string.content_description_video_play),
modifier =
Modifier
.align(Alignment.Center)
@@ -327,7 +329,7 @@ private fun ReceiverMemorialVideoThumbnail(thumbnailUrl: String?) {
}
@Composable
-private fun ReceiverSectionHeader(title: String = LABEL_VIDEO_SECTION) {
+private fun ReceiverSectionHeader(title: String = stringResource(R.string.afternote_editor_funeral_video_label)) {
Text(
text = title,
style =
diff --git a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/shared/detail/song/MemorialPlaylist.kt b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/shared/detail/song/MemorialPlaylist.kt
index 1cfaf96627..410ec9bf4b 100644
--- a/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/shared/detail/song/MemorialPlaylist.kt
+++ b/feature/afternote/presentation/src/main/kotlin/com/afternote/feature/afternote/presentation/shared/detail/song/MemorialPlaylist.kt
@@ -50,7 +50,7 @@ import com.afternote.feature.afternote.presentation.shared.model.AlbumCover
@Composable
fun MemorialPlaylist(
modifier: Modifier = Modifier,
- label: String = "추억 플레이리스트",
+ label: String = stringResource(R.string.afternote_editor_playlist_screen_title),
songCount: Int = 0,
albumCovers: List = emptyList(),
onCardClick: (() -> Unit)? = null,
@@ -133,7 +133,7 @@ private fun MemorialPlaylistCardContent(
)
Spacer(modifier = Modifier.size(24.dp))
Text(
- text = "현재 ${songCount}개의 노래가 담겨 있습니다.",
+ text = stringResource(R.string.afternote_detail_playlist_song_count, songCount),
style =
AfternoteDesign.typography.bodySmallR.copy(
color = AfternoteDesign.colors.black,
diff --git a/feature/afternote/presentation/src/main/res/values/strings.xml b/feature/afternote/presentation/src/main/res/values/strings.xml
index 1419e07612..04f38832ce 100644
--- a/feature/afternote/presentation/src/main/res/values/strings.xml
+++ b/feature/afternote/presentation/src/main/res/values/strings.xml
@@ -4,7 +4,7 @@
홈
기록
타임 레터
- 애프터노트
+ 애프터노트
홈 (준비 중)
안녕하세요, %1$s님
@@ -168,6 +168,7 @@
%d명에게
아래로
영상 재생
+ 장례식에 남길 영상 썸네일
마지막 인사말을 입력해주세요
확인
@@ -222,7 +223,7 @@
드롭다운
추가
더보기
- 필수 항목
+ %1$s, 필수 항목
장례식에 남길 영상
영상 변경
영상 추가
@@ -241,6 +242,13 @@
사진 삭제
영상 삭제
카메라를 사용할 수 없습니다.
+
+ 현재 %1$d개의 노래가 담겨 있습니다.
+ NEXT STEP
+
+ 故 %1$s님의 애프터노트
+ 애프터노트 확인하기
고인이 사후 정리하고자 하는 데이터입니다.
diff --git a/feature/onboarding/presentation/src/main/java/com/afternote/feature/onboarding/presentation/terms/TermsDetailScreen.kt b/feature/onboarding/presentation/src/main/java/com/afternote/feature/onboarding/presentation/terms/TermsDetailScreen.kt
index c6bf26f6ba..e77426cac1 100644
--- a/feature/onboarding/presentation/src/main/java/com/afternote/feature/onboarding/presentation/terms/TermsDetailScreen.kt
+++ b/feature/onboarding/presentation/src/main/java/com/afternote/feature/onboarding/presentation/terms/TermsDetailScreen.kt
@@ -50,27 +50,27 @@ fun TermsDetailScreen(
// 각 약관 섹션들 (반복되는 구조는 별도 컴포저블로 분리하여 가독성 확보)
TermsSectionText(
- title = "1. 서비스 이용약관",
+ title = stringResource(R.string.onboarding_terms_detail_section_1_title),
content = stringResource(R.string.onboarding_terms_detail_section_1),
)
TermsSectionText(
- title = "2. 개인정보 수집 및 이용 동의",
+ title = stringResource(R.string.onboarding_terms_detail_section_2_title),
content = stringResource(R.string.onboarding_terms_detail_section_2),
)
TermsSectionText(
- title = "3. 기록 및 콘텐츠 저장에 대한 안내",
+ title = stringResource(R.string.onboarding_terms_detail_section_3_title),
content = stringResource(R.string.onboarding_terms_detail_section_3),
)
TermsSectionText(
- title = "4. 계정 및 데이터 관리",
+ title = stringResource(R.string.onboarding_terms_detail_section_4_title),
content = stringResource(R.string.onboarding_terms_detail_section_4),
)
TermsSectionText(
- title = "5. 서비스 변경 및 종료",
+ title = stringResource(R.string.onboarding_terms_detail_section_5_title),
content = stringResource(R.string.onboarding_terms_detail_section_5),
)
TermsSectionText(
- title = "6. 동의 철회",
+ title = stringResource(R.string.onboarding_terms_detail_section_6_title),
content = stringResource(R.string.onboarding_terms_detail_section_6),
)
diff --git a/feature/onboarding/presentation/src/main/res/values/strings.xml b/feature/onboarding/presentation/src/main/res/values/strings.xml
index 230695399a..7b7a6d656d 100644
--- a/feature/onboarding/presentation/src/main/res/values/strings.xml
+++ b/feature/onboarding/presentation/src/main/res/values/strings.xml
@@ -100,4 +100,11 @@
애프터노트에서의\n프로필을 설정해주세요
이름을 지정해주세요
회원가입 완료
+
+ 1. 서비스 이용약관
+ 2. 개인정보 수집 및 이용 동의
+ 3. 기록 및 콘텐츠 저장에 대한 안내
+ 4. 계정 및 데이터 관리
+ 5. 서비스 변경 및 종료
+ 6. 동의 철회
diff --git a/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/AfternoteSection.kt b/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/AfternoteSection.kt
index 7ef83765c3..fe1d8b69de 100644
--- a/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/AfternoteSection.kt
+++ b/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/AfternoteSection.kt
@@ -45,8 +45,8 @@ fun AfternoteSection(
description = stringResource(R.string.receiver_home_afternote_section_desc),
countLine =
rememberCountLine(
- prefix = "${countText(totalCount)}개",
- suffix = "의 애프터노트가 있습니다.",
+ prefix = stringResource(R.string.receiver_home_afternote_count_prefix, countText(totalCount)),
+ suffix = stringResource(R.string.receiver_home_afternote_count_suffix),
),
buttonText = stringResource(R.string.receiver_home_afternote_section_button),
onButtonClick = onGoClick,
diff --git a/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/MindRecordSection.kt b/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/MindRecordSection.kt
index 266d778521..bdbb94fad2 100644
--- a/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/MindRecordSection.kt
+++ b/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/MindRecordSection.kt
@@ -29,8 +29,9 @@ fun MindRecordSection(
description = stringResource(R.string.receiver_home_mindrecord_section_desc),
countLine =
rememberCountLine(
- prefix = "${countText(summary?.totalCount)}개 ",
- suffix = "마음의 기록이 있습니다.",
+ prefix =
+ stringResource(R.string.receiver_home_mindrecord_count_prefix, countText(summary?.totalCount)),
+ suffix = stringResource(R.string.receiver_home_mindrecord_count_suffix),
),
buttonText = stringResource(R.string.receiver_home_mindrecord_section_button),
onButtonClick = onGoClick,
diff --git a/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/TimeLetterSection.kt b/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/TimeLetterSection.kt
index 52243a6d0a..e8e8174962 100644
--- a/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/TimeLetterSection.kt
+++ b/feature/receiver/presentation/src/main/kotlin/com/afternote/feature/receiver/presentation/home/component/TimeLetterSection.kt
@@ -18,8 +18,9 @@ fun TimeLetterSection(
description = stringResource(R.string.receiver_home_timeletter_section_desc),
countLine =
rememberCountLine(
- prefix = "${countText(totalCount)}개 ",
- suffix = "라이프 이벤트 레터가 있습니다.",
+ prefix =
+ stringResource(R.string.receiver_home_timeletter_count_prefix, countText(totalCount)),
+ suffix = stringResource(R.string.receiver_home_timeletter_count_suffix),
),
buttonText = stringResource(R.string.receiver_home_timeletter_section_button),
onButtonClick = onGoClick,
diff --git a/feature/receiver/presentation/src/main/res/values/strings.xml b/feature/receiver/presentation/src/main/res/values/strings.xml
index 55eeca7a51..da532b4d6e 100644
--- a/feature/receiver/presentation/src/main/res/values/strings.xml
+++ b/feature/receiver/presentation/src/main/res/values/strings.xml
@@ -131,4 +131,12 @@
제출하신 서류를 확인 중입니다.\n빠르게 검토하여 열람하실 수 있도록 안내드리겠습니다.
받은 기록함으로 돌아가기
수신자 인증 진행도 4단계 중 %1$d단계
+
+ "%1$s개 "
+ 마음의 기록이 있습니다.
+ "%1$s개 "
+ 라이프 이벤트 레터가 있습니다.
+ %1$s개
+ 의 애프터노트가 있습니다.