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

@@ -0,0 +1,181 @@
# 후원 랭킹·공용 카드 다국어 점검 보고서
## 1. 리뷰 정보
| 항목 | 내용 |
|---|---|
| 리뷰 대상 | Phase 3 / Task 3.2~3.3 및 직접 호출 경로 |
| 기준 commit 또는 working tree | `e46198f87a1b6a4357f5bb5b5358e8635383b3a6`; 사용자 소유 `project.pbxproj`, `CreatorChannelDonationRankingSection.swift` 변경은 리뷰 범위에서 보존 |
| 리뷰 일자 | 2026-08-26 |
| 리뷰어 | Codex |
| 기준 문서 | `docs/20260704_크리에이터_채널_후원_탭/prd.md`, `docs/20260704_크리에이터_채널_후원_탭/plan-task.md` |
| 리뷰 상태 | 판정 완료, 구현 대기 |
## 2. 리뷰 목적과 범위
### 목적
- `CreatorChannelDonationRankingSection``CreatorChannelDonationCard`의 런타임 고정 문구가 앱 언어 설정을 따르는지 확인한다.
- 두 컴포넌트의 직접 호출 경로에 같은 유형의 미적용 문구가 있는지 확인한다.
### 포함 범위
- 코드: `CreatorChannelDonationRankingSection.swift`, `CreatorChannelDonationCard.swift`
- 호출 경로: `CreatorChannelDonationTabView.swift`, `CreatorChannelDonationCountBar.swift`, `CreatorChannelDonationEmptyView.swift`, `CreatorChannelDonationFloatingButton.swift`, `CreatorChannelDonationSection.swift`, `CreatorChannelView.swift`
- 공용 경계: `DateParser.relativeTimeText`, 관련 `I18n` 정의
### 제외 범위
- `PreviewProvider`의 닉네임·메시지 등 개발용 fixture
- 후원 기능 밖의 크리에이터 채널 섹션과 기존 전역 I18n 문구 품질
- Swift·I18n 구현, Simulator 실행, 빌드
## 3. 판정 기준
런타임에서 사용자가 보는 고정 문구가 `I18n`을 거치지 않아 ko/en/ja 설정에 따라 바뀌지 않으면 확정 문제로 판정한다. 서버 데이터, 숫자 순위, URL, asset name과 Preview fixture는 하드코딩 다국어 대상에서 제외한다.
## 4. 검토한 근거
### 문서와 코드
- 요구사항: PRD `§5.3`, `§5.4`, `§7`
- 계획: 기존 `Task 3.2`, `Task 3.3`, 신규 `P7-R1`
- 코드: Ranking section의 title·action, 공용 card의 can pill·빈 메시지 fallback
- 호출 관계: 공용 card는 후원 탭과 홈 탭에서 모두 사용한다.
### 실행 환경
```text
OS: macOS 26.0 (25A354)
검증 방식: rg·sed·git diff 기반 정적 점검
Simulator/빌드: 사용자 지시에 따라 미실행
```
### 실행한 검증
| 명령 또는 수동 검증 | 결과 | 핵심 증거 |
|---|---|---|
| `rg -n --glob '*.swift' 'Text\(|I18n\.|relativeTimeText' <대상 및 호출 경로>` | 성공 | 랭킹 2곳, 카드 2곳의 런타임 하드코딩 확인 |
| `rg -n 'CreatorChannelDonationRankingSection\|CreatorChannelDonationCard' SodaLive/Sources` | 성공 | 후원 탭·홈 탭 직접 호출 위치 확인 |
| `sed -n`으로 관련 View와 `DateParser.swift`, `I18n.swift` 확인 | 성공 | count bar·empty·dialog·상대 시간은 이미 I18n 사용 |
| ko/en/ja Simulator 확인 | 불가 | 이번 작업은 문서 전용이며 코드 구현을 금지함 |
## 5. 발견 사항 요약
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|---|---|---|---|---|---|
| `REV-P3-001` | Medium | 확정 | 랭킹 title과 전체보기 action이 한국어로 고정됨 | `Task 7.1` | `P7-R1` |
| `REV-P3-002` | Medium | 확정 | 공용 카드의 can pill과 빈 메시지가 한국어로 고정됨 | `Task 7.1` | `P7-R1` |
## 6. 발견 사항 상세
### REV-P3-001 — 랭킹 title과 전체보기 action이 한국어로 고정됨
- **심각도:** Medium
- **상태:** 확정
- **관련 요구사항:** PRD `§5.3`
- **관련 계약:** 없음
- **소유 Task:** `Task 7.1` / `P7-R1`
**관찰 내용**
`CreatorChannelDonationRankingSection`의 title과 action label이 문자열 literal을 사용해 영어·일본어 설정에서도 한국어로 표시된다.
**근거**
- 코드: `CreatorChannelDonationRankingSection.swift:10`, `:22`
- 기존 I18n: `I18n.Explorer.donationRankingTitle`, `I18n.CreatorChannelHome.viewAll`
- 인터뷰 결정: title은 기존 `후원랭킹` 키를 재사용한다.
**재현 또는 검증 절차**
1. 소스에서 `Text("후원랭킹")`, `Text("전체보기")`를 확인한다.
2. 두 값이 `LanguageHeaderProvider.current`를 읽는 `I18n`을 거치지 않는 것을 확인한다.
3. 앱 언어 변경과 무관하게 literal이 유지되는 구조임을 판정한다.
**영향**
후원 랭킹이 표시되는 채널에서 영어·일본어 사용자에게 한국어 title과 action이 노출된다.
**권장 조치**
기존 `I18n.Explorer.donationRankingTitle``I18n.CreatorChannelHome.viewAll`을 직접 재사용한다. 신규 title·action 키는 추가하지 않는다.
**판정 기록**
- 2026-08-26 — 정적 코드와 기존 I18n 정의로 확정.
- 2026-08-26 — 사용자 인터뷰에서 기존 `후원랭킹` 키 재사용을 확정.
### REV-P3-002 — 공용 카드의 can pill과 빈 메시지가 한국어로 고정됨
- **심각도:** Medium
- **상태:** 확정
- **관련 요구사항:** PRD `§5.4`
- **관련 계약:** 없음
- **소유 Task:** `Task 7.1` / `P7-R1`
**관찰 내용**
`CreatorChannelDonationCard`의 can pill과 빈 `message` fallback이 한국어 literal을 조합한다. 이 카드는 후원 탭과 홈 탭에서 공용이므로 두 화면이 함께 영향을 받는다.
**근거**
- 코드: `CreatorChannelDonationCard.swift:60`, `:75`
- 호출: `CreatorChannelDonationTabView.swift:38`, `CreatorChannelDonationSection.swift:38`
- 기존 I18n: `I18n.LiveChat.canWithUnit(_:)`은 동일한 ko/en/ja can 형식을 제공한다.
- 인터뷰 결정: 공개 카드의 영어 fallback은 `Donated {can} cans.` 전용 문구를 사용한다.
**재현 또는 검증 절차**
1. 소스에서 `Text("\(donation.can)캔")``"\(can)캔을 후원하였습니다"`를 확인한다.
2. `message`가 공백이면 fallback이 런타임에 표시되는 것을 코드 경로로 확인한다.
3. 공용 카드의 두 호출 위치를 확인한다.
**영향**
영어·일본어 사용자에게 can 단위와 빈 메시지가 한국어로 표시되며, 홈 탭과 후원 탭에 동시에 노출된다.
**권장 조치**
can pill은 `I18n.LiveChat.canWithUnit(_:)`을 재사용한다. 빈 메시지만 `I18n.CreatorChannelDonation.defaultMessage(_:)`로 추가하고 ko `{can}캔을 후원하였습니다`, en `Donated {can} cans.`, ja `{can}canをサポートしました。`를 제공한다.
**판정 기록**
- 2026-08-26 — 정적 코드와 두 직접 호출 위치로 확정.
- 2026-08-26 — 사용자 인터뷰에서 카드 전용 fallback을 확정.
### 연결 경로 추가 점검
- `CreatorChannelDonationCountBar`: `I18n.CreatorChannelCommunity.totalLabel` 사용.
- `CreatorChannelDonationEmptyView`: empty 문구와 후원 action 모두 I18n 사용.
- `CreatorChannelDonationFloatingButton`: 사용자 노출 텍스트가 없는 icon-only 컴포넌트.
- `CreatorChannelDonationSection`: section·empty·후원 action 문구 모두 I18n 사용.
- `CreatorChannelView`: 연결된 후원 dialog 문구는 I18n 사용.
- `DateParser.relativeTimeText`: `I18n.Time`을 사용.
추가 확정 발견 사항은 없다.
## 7. 확정 항목의 plan·goal 전환
`plan-task.md``Phase 7`, `Task 7.1`, `P7-R1`을 추가했다. 사용자 지시에 따라 goal 생성과 구현은 수행하지 않았다.
## 8. 리뷰 종료 판정
| 판정 항목 | 결과 | 근거 |
|---|---|---|
| 리뷰 범위 전체 확인 | 충족 | 두 대상과 직접 호출·공용 시간 경계 확인 |
| 후보 항목 판정 완료 | 충족 | `REV-P3-001`, `REV-P3-002` 확정 |
| 확정 항목 plan 반영 | 충족 | `Phase 7 / Task 7.1 / P7-R1` |
| 보류 항목의 담당·재개 조건 기록 | 해당 없음 | 인터뷰 결정 완료 |
| 검증 명령과 결과 기록 | 충족 | 정적 점검 명령과 Simulator 미실행 사유 기록 |
**최종 결론:** 수정 goal 필요
**남은 항목:** `P7-R1`의 Swift·I18n 구현과 ko/en/ja Gate 검증. 이번 작업에서는 수행하지 않는다.
## 9. 수정 후 검증 기록
- 2026-08-26 (구현 전): 아직 구현하지 않아 기록 없음.
- 2026-08-26: `REV-P3-001`, `REV-P3-002``Task 7.1`에서 수정했다. 랭킹 title·전체보기 action·can pill은 확정된 기존 I18n을 재사용하고, 공용 카드 빈 메시지 fallback만 `I18n.CreatorChannelDonation.defaultMessage(_:)`로 추가했다.
- 2026-08-26: 변경 전 정적 계약은 랭킹과 카드 모두 exit 1, 변경 후 Phase 7 Gate와 `git diff --check`는 exit 0이었다. `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build``BUILD SUCCEEDED`, 독립 리뷰는 `APPROVED`였다.
- 2026-08-26: 사용자 요청에 따라 visual QA를 실행하지 않았다. 따라서 ko/en/ja 실제 화면 수동 검증은 미실행 상태로 `plan-task.md`에 남겼다.