feat(i18n): 시리즈/재생목록 하드코딩 문구를 I18n 키로 통일한다

This commit is contained in:
Yu Sung
2026-04-01 17:33:13 +09:00
parent c039931f34
commit 1ec56a1f15
27 changed files with 253 additions and 160 deletions

View File

@@ -201,38 +201,38 @@
- [x] `SodaLive/Sources/Content/Playlist/ContentPlaylistListViewModel.swift`
#### Group 6 (51-60)
- [ ] `SodaLive/Sources/Content/Playlist/Create/ContentPlaylistCreateView.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Create/ContentPlaylistCreateViewModel.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Create/PlaylistAddContentItemView.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Create/PlaylistAddContentView.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Create/PlaylistCreateContentView.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Detail/ContentPlaylistDetailView.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Detail/ContentPlaylistDetailViewModel.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Detail/PlaylistContentItemView.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Modify/ContentPlaylistModifyView.swift`
- [ ] `SodaLive/Sources/Content/Playlist/Modify/ContentPlaylistModifyViewModel.swift`
- [x] `SodaLive/Sources/Content/Playlist/Create/ContentPlaylistCreateView.swift`
- [x] `SodaLive/Sources/Content/Playlist/Create/ContentPlaylistCreateViewModel.swift`
- [x] `SodaLive/Sources/Content/Playlist/Create/PlaylistAddContentItemView.swift`
- [x] `SodaLive/Sources/Content/Playlist/Create/PlaylistAddContentView.swift`
- [x] `SodaLive/Sources/Content/Playlist/Create/PlaylistCreateContentView.swift`
- [x] `SodaLive/Sources/Content/Playlist/Detail/ContentPlaylistDetailView.swift`
- [x] `SodaLive/Sources/Content/Playlist/Detail/ContentPlaylistDetailViewModel.swift`
- [x] `SodaLive/Sources/Content/Playlist/Detail/PlaylistContentItemView.swift`
- [x] `SodaLive/Sources/Content/Playlist/Modify/ContentPlaylistModifyView.swift`
- [x] `SodaLive/Sources/Content/Playlist/Modify/ContentPlaylistModifyViewModel.swift`
#### Group 7 (61-70)
- [ ] `SodaLive/Sources/Content/Series/Content/SeriesContentAllView.swift`
- [ ] `SodaLive/Sources/Content/Series/Content/SeriesContentAllViewModel.swift`
- [ ] `SodaLive/Sources/Content/Series/Content/SeriesContentListItemView.swift`
- [ ] `SodaLive/Sources/Content/Series/DayOfWeekSeriesView.swift`
- [ ] `SodaLive/Sources/Content/Series/Detail/SeriesDetailHomeView.swift`
- [ ] `SodaLive/Sources/Content/Series/Detail/SeriesDetailIntroductionView.swift`
- [ ] `SodaLive/Sources/Content/Series/Detail/SeriesDetailView.swift`
- [ ] `SodaLive/Sources/Content/Series/Detail/SeriesDetailViewModel.swift`
- [ ] `SodaLive/Sources/Content/Series/Main/ByGenre/SeriesMainByGenreViewModel.swift`
- [ ] `SodaLive/Sources/Content/Series/Main/DayOfWeek/SeriesMainDayOfWeekView.swift`
- [x] `SodaLive/Sources/Content/Series/Content/SeriesContentAllView.swift`
- [x] `SodaLive/Sources/Content/Series/Content/SeriesContentAllViewModel.swift`
- [x] `SodaLive/Sources/Content/Series/Content/SeriesContentListItemView.swift`
- [x] `SodaLive/Sources/Content/Series/DayOfWeekSeriesView.swift`
- [x] `SodaLive/Sources/Content/Series/Detail/SeriesDetailHomeView.swift`
- [x] `SodaLive/Sources/Content/Series/Detail/SeriesDetailIntroductionView.swift`
- [x] `SodaLive/Sources/Content/Series/Detail/SeriesDetailView.swift`
- [x] `SodaLive/Sources/Content/Series/Detail/SeriesDetailViewModel.swift`
- [x] `SodaLive/Sources/Content/Series/Main/ByGenre/SeriesMainByGenreViewModel.swift`
- [x] `SodaLive/Sources/Content/Series/Main/DayOfWeek/SeriesMainDayOfWeekView.swift`
#### Group 8 (71-78)
- [ ] `SodaLive/Sources/Content/Series/Main/DayOfWeek/SeriesMainDayOfWeekViewModel.swift`
- [ ] `SodaLive/Sources/Content/Series/Main/Home/SeriesMainHomeView.swift`
- [ ] `SodaLive/Sources/Content/Series/Main/Home/SeriesMainHomeViewModel.swift`
- [ ] `SodaLive/Sources/Content/Series/Main/SeriesMainItemView.swift`
- [ ] `SodaLive/Sources/Content/Series/Main/SeriesMainView.swift`
- [ ] `SodaLive/Sources/Content/Series/SeriesItemView.swift`
- [ ] `SodaLive/Sources/Content/Series/SeriesListAllView.swift`
- [ ] `SodaLive/Sources/Content/Series/SeriesListAllViewModel.swift`
- [x] `SodaLive/Sources/Content/Series/Main/DayOfWeek/SeriesMainDayOfWeekViewModel.swift`
- [x] `SodaLive/Sources/Content/Series/Main/Home/SeriesMainHomeView.swift`
- [x] `SodaLive/Sources/Content/Series/Main/Home/SeriesMainHomeViewModel.swift`
- [x] `SodaLive/Sources/Content/Series/Main/SeriesMainItemView.swift`
- [x] `SodaLive/Sources/Content/Series/Main/SeriesMainView.swift`
- [x] `SodaLive/Sources/Content/Series/SeriesItemView.swift`
- [x] `SodaLive/Sources/Content/Series/SeriesListAllView.swift`
- [x] `SodaLive/Sources/Content/Series/SeriesListAllViewModel.swift`
### CustomView (3)
- [x] `SodaLive/Sources/CustomView/ChatTextFieldView.swift`
@@ -1087,3 +1087,40 @@
- 테스트 검증: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 test action 미구성 확인(코드 실패 아님, 스킴 제약).
- 수동 QA(문구 경로 수동 점검): Group 3~5 대상 파일 재스캔에서 사용자 노출 문자열의 `I18n.*` 경유를 확인했고, 예외(Preview/비노출 비교 문자열)만 잔존함을 확인했다.
- LSP 진단 참고: SourceKit 단독 해석 환경에서 외부 모듈/프로젝트 심볼(`Kingfisher`, `Moya`, `I18n`, `AppState` 등) 미해결 오류가 보고되나, 동일 변경셋은 `xcodebuild` 실컴파일 통과로 검증했다.
### 24차 구현 (Content 모듈 Group 6~8, 28개 파일 처리, 2026-04-01)
- 무엇/왜/어떻게:
- 무엇: `변경 대상 파일 전체 목록``Content` Group 6~8(플레이리스트 생성/수정/상세 + 시리즈 목록/상세/메인, 28개 파일)을 전수 점검하고, 런타임 사용자 노출 하드코딩 문구를 `I18n.*` 참조로 전환했다.
- 왜: Playlist/Series 구간에 화면 타이틀, 버튼, 상태 배지, 정렬 라벨, ViewModel 공통 오류 문구가 하드코딩 상태로 남아 있어 `I18n.swift` 단일 접근 원칙과 불일치했기 때문이다.
- 어떻게: `explore`/`librarian` 병렬 탐색 + `grep`/`ast_grep_search`/`read` 직접 점검으로 런타임 문자열과 Preview 샘플 문자열을 분리한 뒤, `I18n.swift``I18n.Content.Playlist`, `I18n.Playlist`, `I18n.Series`를 확장하고 Group 6~8 호출부를 최소 변경으로 치환했다.
- 실행 명령/도구:
- `task(subagent_type="explore", ...)` x2 (`bg_fa2a12ab`, `bg_56444808`)
- `task(subagent_type="librarian", ...)` x1 (`bg_fd44cf0e`)
- `background_output(task_id=...)` x3 (위 3개 task 결과 수집)
- `grep("\"[^\"]*[가-힣][^\"]*\"", include=*.swift, path=SodaLive/Sources/Content/{Playlist,Series})`
- `grep("\\bI18n\\.(Content|Series|Common)", include=*.swift, path=SodaLive/Sources/Content)`
- `ast_grep_search(pattern="Text(\"$TEXT\")", lang=swift, paths=[SodaLive/Sources/Content/Playlist,SodaLive/Sources/Content/Series])`
- `read(SodaLive/Sources/I18n/I18n.swift)` + 대상 파일 병렬 `read`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" -configuration Debug build`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive" test`
- `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" test`
- 결과:
- `I18n.swift` 확장:
- `I18n.Content.Playlist`에 생성/수정/상세 플로우용 키 추가(`createTitle`, `createSave`, `modifyTitle`, `modifyAction`, `titleLabel`, `descriptionLabel`, `addContentAction`, `close`, `selectionCount(_:)`, `createdDate(_:)`, `contentCount(_:)`, `play`, `shuffle`, 검증 문구 2종)
- `I18n.Playlist.deleteCompleted` 추가
- `I18n.Series`에 메인/상세/요일/상태 배지 키 추가(`title`, `completedSectionTitle`, `recommendedSectionTitle`, `byDaySectionTitle`, `voiceOnOnlyTitle`, `allEpisodesListen`, `allEpisodesTitle(_:)`, `registeredOrder`, `point`, `free`, 요일 8종, `age19Badge`, `publishing(_:)`)
- 치환 완료 파일(실치환 20개):
- Playlist: `ContentPlaylistCreateView`, `ContentPlaylistCreateViewModel`, `PlaylistAddContentView`, `ContentPlaylistDetailView`, `ContentPlaylistDetailViewModel`, `ContentPlaylistModifyView`, `ContentPlaylistModifyViewModel`
- Series: `SeriesContentAllView`, `SeriesContentAllViewModel`, `SeriesContentListItemView`, `DayOfWeekSeriesView`, `SeriesDetailHomeView`, `SeriesDetailView`, `SeriesDetailViewModel`, `SeriesMainByGenreViewModel`, `SeriesMainDayOfWeekView`, `SeriesMainDayOfWeekViewModel`, `SeriesMainHomeView`, `SeriesMainHomeViewModel`, `SeriesMainItemView`, `SeriesMainView`, `SeriesItemView`, `SeriesListAllView`, `SeriesListAllViewModel`
- 점검만 수행(실치환 없음, 체크 완료 8개):
- `PlaylistAddContentItemView.swift`, `PlaylistCreateContentView.swift`, `PlaylistContentItemView.swift` (런타임 하드코딩 없음, Preview 샘플만 존재)
- `SeriesDetailIntroductionView.swift` (런타임 사용자 노출 하드코딩 없음; 잔여 한글은 서버값 비교용 `"랜덤"` 분기만 존재)
- Group 6~8 체크박스 28개 `- [x]` 완료 반영.
- 재탐지 결과, 남은 한글 리터럴은 Playlist/Series Preview 샘플 데이터와 `SeriesDetailIntroductionView.swift`의 비노출 비교 문자열(`publishedDaysOfWeek == "랜덤"`)만 존재.
- 빌드 검증:
- `SodaLive-dev` Debug 빌드 성공(`** BUILD SUCCEEDED **`).
- `SodaLive` Debug 빌드는 병렬 실행 시 `XCBuildData/build.db` lock으로 1회 실패했으나, 단독 재실행에서 성공(`** BUILD SUCCEEDED **`).
- 테스트 검증: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 test action 미구성 확인(코드 실패 아님, 스킴 제약).
- 수동 QA(문구 경로 수동 점검): Group 6~8 대상 파일 재스캔에서 사용자 노출 문자열의 `I18n.*` 경유를 확인했고, 예외는 Preview/비노출 비교 문자열만 남김.
- LSP 진단 참고: SourceKit 단독 해석 환경에서 외부 모듈/프로젝트 심볼 미해결 오류(`Kingfisher`, `I18n`, `BaseView`, `AppState` 등)와 `I18n.swift`의 기존 `LanguageHeaderProvider` 미해결이 보고되나, 동일 변경셋은 `xcodebuild` 실컴파일 통과로 검증했다.