fix(donation): 후원 문구에 다국어를 적용한다

This commit is contained in:
Yu Sung
2026-08-26 13:18:27 +09:00
parent e46198f87a
commit e3642b3f1b
6 changed files with 267 additions and 8 deletions

View File

@@ -15,6 +15,7 @@ Figma 참조:
- 기존 홈 탭에는 채널 후원 요약 섹션과 후원하기 액션이 있지만, 후원 탭 전용 API, 랭킹 섹션, 스크롤 페이징이 없다.
- 후원 후 홈 탭 후원 섹션은 갱신되지만, 후원 탭이 구현되면 후원 탭 목록도 함께 갱신되어야 한다.
- 후원 탭 empty 문구와 `후원하기` 버튼이 한국어로 하드코딩되어 앱 언어 설정에 맞게 표시되지 않는다.
- 후원 랭킹 title·전체보기 action과 공용 후원 카드의 can 표기·빈 메시지 fallback이 한국어로 하드코딩되어 영어·일본어 설정에서도 한국어가 노출된다.
## 3. Goals
- `CreatorChannelTab.donation` 선택 시 후원 탭 API를 호출하고 응답 데이터로 화면을 구성한다.
@@ -30,6 +31,7 @@ Figma 참조:
- `donationCount == 0` empty 상태에서는 하단 고정 후원하기 버튼을 숨긴다.
- `donationCount != 0 || !rankings.isEmpty`이면 홈 탭 plus button 위치에 icon-only 후원하기 버튼을 표시한다.
- 후원 성공 후 후원 탭 데이터와 홈 탭 데이터가 갱신되어야 한다.
- 후원 랭킹과 공용 후원 카드의 고정 UI 문구는 기존 I18n을 우선 재사용하고, 재사용할 수 없는 빈 메시지 fallback만 `I18n.CreatorChannelDonation`에 추가한다.
## 4. Non-Goals
- 크리에이터 채널 공통 shell, header, sticky tab-bar 동작을 다시 설계하지 않는다.
@@ -92,12 +94,12 @@ data class CreatorChannelDonationResponse(
- `rankings`가 있으면 Figma `290:9097``665:19056` 기준의 카드로 표시한다.
- 후원 랭킹은 최대 8명만 표시하고, 한 줄에 4명씩 표시한다.
- 카드 배경은 `Color.gray900`, corner radius는 14pt, 내부 padding과 item 간격은 14pt 기준을 사용한다.
- title은 `후원 랭킹`을 표시한다.
- title은 기존 `I18n.Explorer.donationRankingTitle`을 재사용해 한국어 `후원랭킹`, 영어 `Donation ranking`, 일본어 `後援ランキング`을 표시한다.
- item은 75pt 원형 프로필, 중앙 정렬 닉네임, 프로필 하단에 rank number overlay를 표시한다.
- 랭킹 번호는 응답 배열 순서 기준으로 `index + 1`을 표시한다.
- 닉네임은 1줄 말줄임 처리한다.
- `profileImage``DownsampledKFImage`로 표시하고, 비어 있거나 실패하면 기존 프로필 placeholder 관례를 따른다.
- Figma의 `전체보기` 버튼을 표시한다.
- Figma의 `전체보기` 버튼은 기존 `I18n.CreatorChannelHome.viewAll`을 재사용한다.
- `전체보기` 터치 시 기존 `AppStep.userProfileDonationAll(userId:)`로 이동해 `UserProfileDonationAllView`를 연다.
- `userId`에는 현재 크리에이터 채널의 `creatorId`를 전달한다.
@@ -109,7 +111,7 @@ data class CreatorChannelDonationResponse(
- `createdAtUtc` 상대 시간
- `can`
- `message`
- 후원 금액 pill은 기존 can icon과 `{can}캔` 형식을 사용한다.
- 후원 금액 pill은 기존 can icon과 `I18n.LiveChat.canWithUnit(_:)`을 재사용해 ko/en/ja 단위 표기를 적용한다.
- 카드 상단 배경색은 홈 탭 후원 카드의 `can` 구간 색상을 재사용한다.
- `1...50`: `#E2E2E2`
- `51...100`: `#73EE01`
@@ -117,7 +119,10 @@ data class CreatorChannelDonationResponse(
- `501...`: `#FF4C3C`
- `can >= 501`인 후원 item은 상단 영역에서 `nickname`을 white, 상대 시간을 `gray100`으로 표시한다.
- 그 외 후원 `can` 구간의 `nickname`과 상대 시간 글자색은 기존 표시 색상을 유지한다.
- `message`가 빈 문자열이면 기존 홈 탭과 동일하게 `{can}캔을 후원하였습니다`표시한다.
- `message`가 빈 문자열이면 홈 탭과 후원 탭에서 공용 `I18n.CreatorChannelDonation.defaultMessage(_:)`사용한다.
- 한국어: `{can}캔을 후원하였습니다`
- 영어: `Donated {can} cans.`
- 일본어: `{can}canをサポートしました。`
- 서버 응답에 비밀 후원 여부가 없으므로, 클라이언트는 서버가 내려준 `nickname`, `profileImageUrl`, `message`를 그대로 표시한다.
### 5.5 Pagination
@@ -162,6 +167,8 @@ data class CreatorChannelDonationResponse(
- `rankings`가 있으면 `후원 랭킹` 카드에 프로필 그리드와 rank number가 표시된다.
- `후원 랭킹` 카드의 `전체보기`를 터치하면 `UserProfileDonationAllView`로 이동한다.
- `donations` 목록은 기존 홈 탭 후원 카드와 같은 후원 금액별 상단 컬러, can pill, 상대 시간, 메시지 표시 규칙을 따른다.
- 앱 언어가 ko/en/ja일 때 후원 랭킹 title·전체보기 action·can pill·빈 메시지 fallback이 해당 언어로 표시된다.
- 공용 `CreatorChannelDonationCard`를 사용하는 홈 탭과 후원 탭에서 동일한 다국어 결과가 표시된다.
- 목록 하단 도달 시 `hasNext == true`이면 다음 페이지가 append된다.
- `rankings.isEmpty && donationCount == 0`이면 Figma `290:9009` empty view가 표시되고, 하단 고정 후원하기 버튼은 숨겨진다.
- Empty 문구가 지정된 ko/en/ja 값과 줄바꿈으로 표시되고, 버튼 문구는 기존 `I18n.ContentDetail.DonationDialog.title`을 사용한다.
@@ -179,6 +186,8 @@ data class CreatorChannelDonationResponse(
- 후원 item UI는 기존 홈 탭 구현과 중복을 줄이기 위해 공용 컴포넌트로 추출하거나, 홈/후원 탭 양쪽에서 같은 하위 컴포넌트를 사용하도록 최소 범위로 조정한다.
- 신규 문구가 필요하면 `SodaLive/Sources/I18n/I18n.swift`에 ko/en/ja를 추가한다.
- Empty 문구는 `pick(ko:en:ja:)`로 관리하고, 후원 버튼은 기존 `I18n.ContentDetail.DonationDialog.title`을 재사용한다. 신규 후원 버튼 문구, route, API, dependency는 추가하지 않는다.
- 랭킹 title은 `I18n.Explorer.donationRankingTitle`, 전체보기는 `I18n.CreatorChannelHome.viewAll`, can pill은 `I18n.LiveChat.canWithUnit(_:)`을 재사용한다.
- 빈 후원 메시지 fallback만 `I18n.CreatorChannelDonation.defaultMessage(_:)`로 추가하며 신규 dependency나 공용 formatter abstraction은 만들지 않는다.
- 프로젝트 설정 변경은 신규 Swift 파일 target 등록이 필요한 경우에만 수행한다.
## 8. Open Questions
@@ -190,3 +199,13 @@ data class CreatorChannelDonationResponse(
- 2026-07-04: Figma `get_design_context``get_screenshot`으로 empty view `290:9009`를 확인했다.
- 2026-07-04: `UserProfileDonationAllView``AppStep.userProfileDonationAll(userId:)` 기존 라우팅을 확인해 랭킹 전체보기 재사용 경계를 정했다.
- 2026-08-14: 사용자 인터뷰로 후원 탭 empty 문구의 ko/en/ja 값을 확정했다. `후원하기`는 기존 `I18n.ContentDetail.DonationDialog.title`을 재사용하며 이번 작업에서는 Swift 구현을 수행하지 않는다.
- 2026-08-26: `CreatorChannelDonationRankingSection`, 공용 `CreatorChannelDonationCard`, 두 컴포넌트의 호출 경로를 정적 점검해 런타임 하드코딩 4곳을 확정했다. Preview fixture의 샘플 문구는 런타임 제품 문구가 아니므로 제외했다.
- 2026-08-26: 사용자 인터뷰로 랭킹 title은 기존 `I18n.Explorer.donationRankingTitle`을 재사용하고, 빈 후원 메시지는 카드 전용 ko/en/ja 문구를 추가하기로 결정했다. 이번 작업에서는 문서만 갱신하고 Swift·I18n 구현과 빌드는 수행하지 않는다.
- 2026-08-26: Phase 7의 다국어 요구사항을 구현했다. `§5.3`, `§5.4`, `§6`, `§7`의 랭킹 title·전체보기·can pill·빈 메시지 fallback과 홈·후원 탭 공용 적용을 정적 계약, Debug 빌드, 독립 리뷰로 확인했다. 이 PRD에는 체크박스 항목이 없으며, 구현 체크 상태는 `plan-task.md` Phase 7에 기록했다. 사용자 요청에 따라 visual QA는 실행하지 않았다.
## 10. Decision Log
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 범위 |
|---|---|---|---|---|---|
| 2026-08-26 | DEC-DONATION-I18N-001 | 확정 | 랭킹 title은 기존 `I18n.Explorer.donationRankingTitle`을 재사용한다. | 사용자 인터뷰에서 기존 `후원랭킹` 표기를 선택했다. | Ranking section |
| 2026-08-26 | DEC-DONATION-I18N-002 | 확정 | 빈 후원 메시지는 `I18n.CreatorChannelDonation.defaultMessage(_:)` 전용 문구로 관리한다. | 공개 카드에서 `You donated`가 작성자를 오인하게 하므로 사용자 인터뷰에서 전용 문구를 선택했다. | Home·Donation 공용 card |