# 일본어 string_resource 반영 PRD ## 문서 정보 | 항목 | 내용 | |---|---| | 문서 상태 | 구현 기준 확정 | | 작성일 | `2026-08-11` | | 최종 수정일 | `2026-08-11` | | 대상 제품 | SodaLive iOS 일본어 문자열 리소스 | | 작성자·결정권자 | 작성자: Sisyphus / 결정권자: 제품·iOS 담당자 | | 관련 API Contract | 해당 없음 | | 관련 구현 계획 | `docs/20260811_일본어_string_resource_반영/plan-task.md` | | 관련 원본 | `docs/20260811_일본어_string_resource_반영/kr_jp_string_resource.csv` | | 관련 review | 없음 | ### 요구사항 상태 | 상태 | 의미 | 구현 처리 | |---|---|---| | 확정 | CSV와 현재 iOS 문자열 구조만으로 구현 기준을 정할 수 있음 | `plan-task.md`의 Task와 완료 증거로 추적 | | 미결 | 제품·번역·키 매핑 결정이 더 필요함 | Open Questions에 기록하고 임의 구현 금지 | | 제외 | 이번 작업에서 구현하지 않음 | Non-Goals와 Decision Log에 기록 | ### 문서 우선순위와 갱신 순서 1. CSV의 KR/JP 원문은 이 PRD의 입력 기준으로 사용한다. 2. `SodaLive/Sources/I18n/I18n.swift`의 기존 `pick(ko:en:ja:)` 구조를 우선 유지한다. 3. `{{키워드}}의 오디오`처럼 `{{...}}`, `{...}`, `n%`, `n위`, `0:00` 형태로 런타임 값이 들어가는 CSV 문구는 Swift interpolation 문구와 정규화 매칭한다. 4. CSV 셀 안의 실제 줄바꿈과 HTML br 표기는 문자열 그대로 반영하지 않고 Swift 문자열 줄바꿈 escape `\n`으로 변환한다. 5. CSV와 구현 구조가 충돌하면 Decision Log → 요구사항 → `plan-task.md` 순서로 갱신한다. 6. 확정된 결정 밖의 추정 번역, 추정 영어 문구, 추정 키는 구현하지 않는다. ## 1. Overview `kr_jp_string_resource.csv`에 정리된 한국어-일본어 문구를 SodaLive iOS 앱의 문자열 리소스에 반영해 일본어 환경에서 사용자 노출 문구를 최신 번역으로 표시한다. 현재 앱은 `SodaLive/Sources/I18n/I18n.swift`의 하드코딩 맵과 `pick(ko:en:ja:)` 헬퍼를 통해 언어별 문자열을 선택한다. 이 작업은 코드 구현 전 PRD와 실행 계획만 작성하며, 실제 `I18n.swift` 수정은 후속 승인 후 진행한다. ## 2. Problem Statement 현재 사용자는 다음 문제를 겪는다. - 일본어 번역 CSV가 앱 문자열 리소스에 아직 반영되지 않아 일본어 UI 문구가 최신 번역 기준과 다를 수 있다. - CSV에는 개행 문구, placeholder 문구, 오탈자 후보가 섞여 있어 임의 치환 시 포맷 깨짐이나 잘못된 일본어 노출 위험이 있다. - `I18n.swift`는 `ko`, `en`, `ja`를 함께 요구하므로 CSV에 없는 영어 문구를 임의 생성하면 기존 영어 UX가 변할 수 있다. 문제를 해결했다는 판단은 CSV의 확정 가능한 JP 값이 `I18n.swift`에 반영되고, 일본어 선택 시 해당 문구가 표시되며, 빌드가 성공하는 것으로 한다. ## 3. Goals ### 3.1 제품 목표 - CSV 데이터 242행 중 기존 한국어 리소스가 확인된 KR/JP 문구만 iOS 일본어 문자열에 반영한다. - 기존 `I18n.swift`에 동일 KR 문구가 있거나 placeholder 정규화 후 같은 문구로 판정되는 항목은 기존 `en` 값을 유지하고 `ja` 값만 CSV 기준으로 갱신한다. - 동일 KR 문구가 없는 CSV 항목은 신규 리소스로 추가하지 않는다. - 개행 33행과 placeholder 유사 12행은 기존 한국어 리소스가 있는 경우에만 CSV 셀 안의 실제 줄바꿈을 Swift 문자열 `\n`으로 변환하고 함수 인자 순서를 보존해 반영한다. - CSV에 HTML br 표기가 있으면 literal이 아니라 Swift 문자열 `\n`으로 변환해 반영한다. - 같은 KR 또는 같은 정규화 KR이 여러 `I18n` 항목에 중복되어 있고 기존 JP가 서로 다르면 CSV JP를 우선해 같은 값으로 반영한다. ### 3.2 UX 목표 - 일본어 환경에서 홈, 콘텐츠, 대화, 마이페이지, 인증, 구매, 보관함 등 CSV가 포함한 주요 화면 문구가 자연스럽게 표시된다. - placeholder가 포함된 문구는 실제 값 삽입 후 일본어 문장 순서가 깨지지 않는다. - CSV의 `しいシリーズ` 오탈자 후보는 `新しいシリーズ`로 보정해 반영한다. ## 4. Non-Goals - 이번 요청에서는 코드, 리소스, Xcode 프로젝트 설정을 수정하지 않는다. - String Catalog(`.xcstrings`) 도입이나 `I18n.swift` 구조 개편은 하지 않는다. - CSV에 없는 영어 번역을 새로 작성하지 않는다. - 기존 한국어 리소스가 없는 CSV 항목을 신규 리소스로 추가하지 않는다. - 서버 API, CMS, 백엔드 번역 리소스는 변경하지 않는다. - 일본어 폰트, 레이아웃, 줄바꿈 UI 디자인 조정은 이 작업의 범위가 아니다. ## 5. Target Users and Permissions | 사용자 | 목표 | 주요 작업 | 사용 환경 | |---|---|---|---| | 일본어 앱 사용자 | 일본어 UI 문구를 최신 번역으로 확인 | 앱 탐색, 콘텐츠 소비, 대화, 구매, 인증 | iOS 앱, 언어 설정 `ja` 또는 시스템 일본어 | | iOS 개발자 | CSV 기준으로 안전하게 문자열 반영 | 문자열 매핑, 빌드 검증, 수동 QA | Xcode, `SodaLive.xcworkspace` | | 제품·번역 담당자 | 확정된 일본어 반영 범위 확인 | 오탈자 보정과 제외 기준 승인 | PRD/계획문서 리뷰 | 권한 요구사항은 해당 없음이다. 단, 인증/구매/성인 관련 문구는 실제 기능 동작을 바꾸지 않고 표시 문자열만 바꾼다. ## 6. 핵심 사용자 흐름 1. 사용자가 앱 언어를 일본어로 설정하거나 시스템 언어가 일본어인 상태에서 앱을 실행한다. 2. 앱은 `LanguageHeaderProvider.current` 결과가 `ja`일 때 `I18n.pick`의 일본어 문자열을 선택한다. 3. 사용자는 홈, 콘텐츠, 대화, 마이페이지, 인증/구매 화면에서 CSV 기준 일본어 문구를 본다. 4. placeholder 문구는 실제 크리에이터명, 이메일, 요일, 퍼센트 등 런타임 값과 함께 자연스럽게 표시된다. ## 7. 정보 구조와 라우팅 별도 route 변경은 없다. 문자열 반영 대상은 기존 화면과 모듈에 종속된다. ```text SodaLive/Sources/I18n/I18n.swift I18n.Module.ScreenOrDomain.Role ``` 역할 중심 키 이름을 유지한다. 이번 작업에서는 기존 한국어 리소스가 없는 CSV 항목의 신규 키를 추가하지 않으며, 공통 네임스페이스 승격도 하지 않는다. ## 8. 기능 요구사항 ### 8.1 CSV 입력과 매핑 | ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 | |---|---|---|---|---| | `JSR-001` | 확정 | `kr_jp_string_resource.csv`의 `KR`, `JP` 컬럼을 입력 기준으로 사용한다. | CSV가 242개 데이터 행, KR 누락 0건, JP 누락 0건으로 파싱된다. | `P1-T1` | | `JSR-002` | 확정 | 기존 `I18n.swift`에 동일 KR literal이 있거나 placeholder 정규화 후 매칭되는 항목은 `ja` 값만 CSV 기준으로 갱신한다. | 기존 `en` 값과 호출부는 변경되지 않는다. 현재 스캔 기준 exact 103행, placeholder 정규화 추가 0행으로 총 103행이 매핑 후보다. | `P1-T2`, `P2-T1` | | `JSR-003` | 제외 | 동일 KR literal 또는 placeholder 정규화 매칭이 없는 139개 CSV 항목은 신규 키로 추가하지 않는다. | 기존 한국어 리소스가 없는 항목은 `I18n.swift`와 호출부를 변경하지 않는다. | `P1-T3`, `P2-T2` | | `JSR-004` | 확정 | CSV 셀 안의 실제 줄바꿈과 HTML br 표기는 Swift 문자열 줄바꿈 escape `\n`으로 변환한다. | 일본어 `\n` 위치가 CSV와 동일하거나 제품 승인된 위치로 반영되며, HTML br 표기가 앱 문자열에 그대로 남지 않는다. | `P2-T1` | | `JSR-005` | 확정 | placeholder 유사 12개 문구는 앱 내에서 변경 가능한 리소스 후보로 보고 Swift interpolation과 정규화 매칭한다. | 정규화 매칭되는 기존 리소스는 Swift 함수 인자 순서를 보존해 반영하고, 정규화 후에도 기존 리소스가 없으면 신규 키를 추가하지 않고 제외한다. | `P1-T3`, `P2-T1` | | `JSR-006` | 확정 | CSV의 `しいシリーズ` JP 오탈자는 `新しいシリーズ`로 보정한다. | 해당 KR이 기존 한국어 리소스와 매칭될 때만 보정 JP를 반영한다. | `P1-T3`, `P2-T1` | | `JSR-007` | 확정 | 같은 KR 또는 같은 정규화 KR이 여러 `I18n` 항목에 중복되어 있고 기존 JP가 다르면 CSV JP를 우선한다. | 현재 스캔 기준 중복 KR의 기존 JP 상이 항목 12건은 CSV JP로 통일한다. | `P1-T2`, `P2-T1` | ### 8.2 품질과 검증 | ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 | |---|---|---|---|---| | `QA-001` | 확정 | 문자열 변경 후 두 앱 스킴 Debug 빌드를 실행한다. | `SodaLive`, `SodaLive-dev` Debug 빌드가 `** BUILD SUCCEEDED **`로 끝난다. | `P2-GATE` | | `QA-002` | 확정 | 테스트 스킴 제약을 확인한다. | 테스트 액션 미구성 상태면 실패가 코드 실패가 아님을 Progress에 기록한다. | `P2-GATE` | | `QA-003` | 확정 | 일본어 언어 선택 상태에서 대표 화면 수동 QA를 수행한다. | CSV 대표 문구, 개행, placeholder 표시를 스크린별로 확인하고 결과를 Progress에 남긴다. | `P2-GATE` | | `QA-004` | 확정 | 민감 정보나 SDK 입력값을 번역 대상으로 오인하지 않는다. | 인증 토큰, API path, Bootpay/SDK 고정값은 변경하지 않는다. | `P2-T1` | ## 9. UI/UX Expectations - 기존 화면 레이아웃과 컴포넌트 구조를 유지한다. - 일본어 번역이 길어져도 이번 작업에서는 레이아웃을 임의 조정하지 않는다. 잘림이 발견되면 후속 UI 이슈로 기록한다. - 개행이 포함된 문구는 CSV 의도를 우선하고, 화면에서 부자연스러운 경우 제품·번역 담당자 확인 후 보정한다. ## 10. API 계약 해당 없음. 이 작업은 클라이언트 로컬 문자열 리소스 반영이다. ## 11. 보안과 데이터 취급 - 인증 헤더, 토큰 저장소, `UserDefaultsKey.token` 관련 로직은 변경하지 않는다. - 이메일 placeholder 문구는 예시 이메일을 문서나 테스트 fixture에 하드코딩하지 않는다. - 구매/결제 SDK에 전달되는 고정 문자열은 사용자 노출 문구가 아닌 경우 번역하지 않는다. ## 12. 성능과 품질 요구사항 - 런타임 성능 요구사항은 변경하지 않는다. - 신규 dependency를 추가하지 않는다. - 문자열 선택 방식은 기존 `I18n.pick` 구조를 유지한다. - 검증은 정적 매핑 점검, Xcode 빌드, 일본어 대표 화면 수동 QA로 수행한다. ## 13. 성공 기준 ### 13.1 기능 수용 기준 - [x] CSV 242행의 처리 상태가 `기존 키 갱신`, `placeholder 정규화 후 기존 키 갱신`, `오탈자 보정 후 기존 키 갱신`, `기존 리소스 없음으로 제외` 중 하나로 분류된다. - [x] 확정 항목의 일본어 문구가 `I18n.swift`에 반영된다. - [x] placeholder와 개행 문구가 깨지지 않는다. - [x] CSV 셀 안의 실제 줄바꿈과 HTML br 표기는 문자열 그대로가 아니라 Swift 문자열 `\n`으로 반영된다. - [x] 중복 KR 또는 중복 정규화 KR의 JP는 CSV JP 우선으로 정리된다. - [x] 기존 한국어 리소스가 없는 항목은 구현하지 않고 제외 사유가 문서화된다. ### 13.2 품질 수용 기준 - [x] `SodaLive` Debug 빌드가 성공한다. - [x] `SodaLive-dev` Debug 빌드가 성공한다. - [x] 테스트 액션 실행 가능 여부와 결과가 기록된다. - [x] 일본어 언어 설정에서 대표 화면 수동 QA가 완료된다. ### 13.3 추적성 완료 기준 - [x] 모든 확정 요구사항이 `plan-task.md`의 Goal과 연결된다. - [x] 모든 제외 항목에 제외 근거와 영향 Goal이 있다. - [x] 구현 결과와 검증 기록은 `plan-task.md` Progress에 누적된다. ## 14. Open Questions | ID | 상태 | 결정 필요 사항 | 현재 권고 | 결정 주체 | 결정 기한/시점 | 영향 Goal | |---|---|---|---|---|---|---| | `OQ-001` | 확정 | CSV 물리 line 281~283의 JP `最近見たシリーズはありません。\nしいシリーズを見つけましょう!`에서 `しいシリーズ`가 오탈자인지 확인이 필요했다. | `新しいシリーズを見つけましょう!`로 보정한다. | 사용자 | 확정 완료 | `P1-T3`, `P2-T1` | | `OQ-002` | 확정 | `{{장르}}`, `{{크리에이터이름}}`, `{email}`, `{요일}`, `n%`, `n위`, `0:00` 토큰을 Swift 함수 인자로 변환할지 결정이 필요했다. | 기존 한국어 리소스가 있는 항목만 함수 인자로 변환하고, 기존 한국어 리소스가 없는 항목은 반영하지 않는다. | 사용자 | 확정 완료 | `P1-T3`, `P2-T1` | | `OQ-003` | 확정 | CSV KR 원문 중 `메세지`, `메거진` 같은 한국어 오탈자 후보를 보정할지 결정이 필요했다. | 한국어 리소스는 보정하지 않고 JP만 반영한다. | 사용자 | 확정 완료 | `P1-T3`, `P2-T1` | | `OQ-004` | 확정 | 기존 `I18n.swift`에 동일 KR literal이 없는 139개 항목을 신규 키로 추가할지 결정이 필요했다. | 기존 한국어 리소스가 없는 항목은 추가하지 않는다. | 사용자 | 확정 완료 | `P1-T3`, `P2-T2` | | `OQ-005` | 확정 | 신규 키 추가 시 CSV에 없는 `en` 값을 어떻게 채울지 결정이 필요했다. | 없는 리소스는 추가하지 않으므로 신규 `en` 작성도 하지 않는다. | 사용자 | 확정 완료 | `P2-T2` | | `OQ-006` | 확정 | `{{키워드}}의 오디오`처럼 `{{...}}` 형태로 들어간 CSV 문구를 기존 앱 리소스 매핑 후보로 볼지 결정이 필요했다. | 앱 내에서 변경 가능한 리소스이므로 Swift interpolation 문구와 정규화 매칭한다. | 사용자 | 확정 완료 | `P1-T2`, `P2-T1` | | `OQ-007` | 확정 | 중복 KR 항목의 기존 JP가 서로 다를 때 어떤 값을 우선할지 결정이 필요했다. | CSV JP를 우선 반영한다. | 사용자 | 확정 완료 | `P1-T2`, `P2-T1` | | `OQ-008` | 확정 | CSV에 HTML br 표기가 있을 때 앱 문자열에 그대로 반영할지 결정이 필요했다. | HTML br 표기는 literal이 아니라 Swift 문자열 줄바꿈 `\n`으로 변환한다. | 사용자 | 확정 완료 | `P1-T1`, `P2-T1` | | `OQ-009` | 확정 | CSV 셀 안의 실제 줄바꿈을 앱 문자열에 어떤 형태로 반영할지 결정이 필요했다. | CSV 실제 줄바꿈은 Swift 문자열 줄바꿈 escape `\n`으로 변환한다. | 사용자 | 확정 완료 | `P1-T1`, `P2-T1` | ## 15. 요구사항 추적표 | 요구사항 범위 | API Contract | 계획 Phase | Goal | 자동 검증 | 수동 검증 | |---|---|---:|---|---|---| | `JSR-001` | 해당 없음 | 1 | `P1-T1` | CSV 파싱 명령 | CSV 행 수와 누락 확인 | | `JSR-002` | 해당 없음 | 1, 2 | `P1-T2`, `P2-T1` | KR literal 매칭 스크립트, 빌드 | 일본어 대표 화면 확인 | | `JSR-003~007` | 해당 없음 | 1, 2 | `P1-T2`, `P1-T3`, `P2-T1`, `P2-T2` | placeholder 정규화/개행/중복 JP 점검 스크립트 | 제외 목록과 보정 JP 리뷰 | | `QA-001~004` | 해당 없음 | 2 | `P2-GATE` | `xcodebuild` | 언어 설정 `ja` 수동 QA | ## 16. Decision Log | 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항·계약·Goal | |---|---|---|---|---|---| | `2026-08-11` | `DEC-001` | 확정 | 이번 요청에서는 PRD와 `plan-task.md`만 생성하고 앱 코드는 수정하지 않는다. | 사용자 직접 지시 | 전체 | | `2026-08-11` | `DEC-002` | 확정 | 일본어 문자열 반영의 기본 대상은 `SodaLive/Sources/I18n/I18n.swift`로 둔다. | 현재 코드의 `I18n.pick(ko:en:ja:)` 구조 확인 | `JSR-002`, `P2-T1` | | `2026-08-11` | `DEC-003` | 폐기 | 신규 키 추가는 영어 기준과 호출부가 확인된 항목으로 제한한다. | 사용자 결정으로 기존 한국어 리소스가 없는 항목은 추가하지 않기로 변경 | `JSR-003`, `OQ-004`, `OQ-005` | | `2026-08-11` | `DEC-004` | 확정 | `しいシリーズ`는 `新しいシリーズ`로 보정한다. | 사용자 확인 | `JSR-006`, `OQ-001`, `P2-T1` | | `2026-08-11` | `DEC-005` | 확정 | placeholder 문구는 기존 한국어 리소스가 있는 항목만 Swift 함수 인자로 변환한다. | 사용자 결정 | `JSR-005`, `OQ-002`, `P2-T1` | | `2026-08-11` | `DEC-006` | 확정 | 한국어 리소스 원문은 보정하지 않고 JP만 반영한다. | 사용자 결정 | `OQ-003`, `P2-T1` | | `2026-08-11` | `DEC-007` | 확정 | 기존 한국어 리소스가 없는 CSV 항목은 신규 리소스로 추가하지 않는다. | 사용자 결정 | `JSR-003`, `OQ-004`, `OQ-005`, `P2-T2` | | `2026-08-11` | `DEC-008` | 확정 | `{{...}}`, `{...}`, `n%`, `n위`, `0:00` 형태 placeholder는 Swift interpolation과 정규화해 매핑 후보를 판정한다. | 사용자 결정과 재스캔 결과 | `JSR-002`, `JSR-005`, `OQ-006`, `P1-T2` | | `2026-08-11` | `DEC-009` | 확정 | 같은 KR 또는 같은 정규화 KR의 기존 JP가 여러 값이면 CSV JP를 우선 반영한다. | 사용자 결정과 중복 JP 재스캔 결과 | `JSR-007`, `OQ-007`, `P2-T1` | | `2026-08-11` | `DEC-010` | 확정 | HTML br 표기는 앱 문자열에 그대로 반영하지 않고 줄바꿈 `\n`으로 변환한다. | 사용자 결정 | `JSR-004`, `OQ-008`, `P2-T1` | | `2026-08-11` | `DEC-011` | 확정 | CSV 셀 안의 실제 줄바꿈은 Swift 문자열 줄바꿈 escape `\n`으로 변환한다. | 사용자 결정 | `JSR-004`, `OQ-009`, `P2-T1` | ## 17. 변경 관리 요구사항 변경 시 다음을 확인한다. - [x] Decision Log에 변경 이유와 날짜를 기록했다. - [x] 관련 요구사항 상태·본문·수용 기준을 갱신했다. - [x] `plan-task.md`의 범위·Files·Interfaces·체크박스·완료 증거를 코드 변경 전에 갱신했다. - [x] 기존 Progress와 검증 기록을 삭제하거나 덮어쓰지 않았다.