chore(l10n): shield DEBUG-only strings from Xcode auto-resave pollution

- Xcode 백그라운드 인덱싱이 IOS 카탈로그를 재저장하며 DEBUG 전용 문자열(시드 이름·메모) 18키를 stale로 잘못 마킹하는 오염이 두 번 재발 → 해당 키들을 extractionState: manual로 마킹해 Xcode·xcstringstool 모두 건드리지 않게 방어(sync 후 유지 확인, 런타임 번역 무영향)
- CLAUDE.md §2.3에 오염 증상·복원법·manual 규칙 기재, §1 현재 상태에 실기기 확인 완료된 최근 수정 라운드 반영
- 검증: Debug 빌드 + sync 후 카탈로그 9종 ALL CLEAN, Store 빌드 성공

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CkLDi8Lr21vGqo4SjZaTp
This commit is contained in:
songyc macbook 2026-07-18 10:01:42 +09:00
parent dbbbfb8506
commit 7c8e882cda
2 changed files with 21 additions and 1 deletions

View File

@ -16,7 +16,7 @@
| 번들 ID | `com.yechan.HaruDanim` / App Group `group.com.yechan.HaruDanim` / CloudKit `iCloud.com.yechan.HaruDanim` |
| 수익 모델 | 부분 유료화. 무료 한도(행동 10·목표 2·목표당 다짐 3) + 프리미엄 결제 시 해제 |
| 결제 상품 | `com.yechan.HaruDanim.premium.monthly`(월 5,000원) / `.yearly`(년 50,000원) / `.lifetime`(80,000원) — 임시 가격, App Store Connect 등록은 아직 안 됨 |
| 현재 상태 (2026-07-17) | **기능 동결(release freeze)** — 첫 배포 후보(RC)는 커밋 `f05e611`(버전 1.0 (1)). 이후 실사용 보고 기반 수정 라운드가 진행됨(전부 커밋·푸시·실기기 확인 완료): l10n 누락 일괄·ja 앱 이름 'Haru Danim' 통일·워치 컴플리케이션 추천 캡 제거(§11)·⑥ 위젯 종료 버튼(§10)·진행률 환산 캡+수행일 집계+수행일 아님 표기(§4.2)·파일명/CSV 헤더 현지화(§7)·워치 컴플리케이션 목표 필터(§6.4·§11, 사용자 승인 소기능). **App Store 등록 자료는 `Marketing/`에 완비**(설명·키워드·구독 메타·스크린샷 원본/합성판, README에 재생성 절차 — 앱 변경이 자료에 영향 주면 요청 없이 함께 갱신할 것). **사업자 등록 완료, 통신판매업 신고 처리 대기** — 처리되면 ASC 등록·유료 계약 진행(순서는 Marketing/README 체크리스트). 사용자는 계속 실사용 테스트 중이며 버그 보고 시: 최소 변경 + 시뮬레이터 재검증 + l10n 루틴(§2.3) + Debug/Store(워치 파일이면 워치까지) 빌드 + 커밋·푸시 |
| 현재 상태 (2026-07-17) | **기능 동결(release freeze)** — 첫 배포 후보(RC)는 커밋 `f05e611`(버전 1.0 (1)). 이후 실사용 보고 기반 수정 라운드가 진행됨(전부 커밋·푸시·실기기 확인 완료): l10n 누락 일괄·ja 앱 이름 'Haru Danim' 통일·워치 컴플리케이션 추천 캡 제거(§11)·⑥ 위젯 종료 버튼(§10)·진행률 환산 캡+수행일 집계+수행일 아님 표기(§4.2)·파일명/CSV 헤더 현지화(§7)·워치 컴플리케이션 목표 필터(§6.4·§11, 사용자 승인 소기능)·기록 시각 입력 상시 휠 다이얼+분 절사(§6.5)·일기 달력 기분 사진 백레이어(§6.7)·다짐 없는 목표 '다짐 없음' 표기(§4.3)·워치 측정 중 행 탭 종료(§11)·도움말 예시 스크린샷 18장(§6.8)·설정 하루 시작 시간 접힘 행(§6.5). **App Store 등록 자료는 `Marketing/`에 완비**(설명·키워드·구독 메타·스크린샷 원본/합성판, README에 재생성 절차 — 앱 변경이 자료에 영향 주면 요청 없이 함께 갱신할 것). **사업자 등록 완료, 통신판매업 신고 처리 대기** — 처리되면 ASC 등록·유료 계약 진행(순서는 Marketing/README 체크리스트). 사용자는 계속 실사용 테스트 중이며 버그 보고 시: 최소 변경 + 시뮬레이터 재검증 + l10n 루틴(§2.3) + Debug/Store(워치 파일이면 워치까지) 빌드 + 커밋·푸시 |
| 남은 배포 작업 | App Store Connect 상품 3종 등록(구독 그룹 + 비소모성, 유료 앱 계약), **CloudKit 프로덕션 스키마 배포**(대시보드 Deploy Schema to Production — DiaryTemplate 등 새 레코드 타입/필드는 개발 환경에만 자동 생성되므로 출시 전 필수), 실기기 검증(펜슬 필기감·캘린더 권한), App Store 배포. 코드 측 잔여 없음 — `ITSAppUsesNonExemptEncryption=NO` 등록 완료, **개인정보 매니페스트(PrivacyInfo.xcprivacy) 4개 번들 완비**(UserDefaults CA92.1·1C8F.1, 수집·트래킹 없음 — 위젯·워치위젯 폴더 것은 앱·워치 앱 타깃에서 membershipException으로 중복 복사 제외), 결제 화면 약관 링크 완료(개인정보처리방침 `Docs/PRIVACY.md` ko/en/ja는 `github.com/notalentprogrammer/HaruDanim` main의 PRIVACY.md로 게시됨, 이용약관은 Apple 표준 EULA URL). ASC 등록 시 앱 설명에도 두 링크 기재 + '앱 개인정보 보호'는 "데이터 수집 안 함" 선택 |
---
@ -83,6 +83,8 @@ xcrun xcstringstool sync Widgets/Localizable.xcstrings --stringsdata "${widget_f
문구를 **수정**했을 때는 옛 키가 `extractionState: stale`로 남는다 — sync 후 stale 항목을 삭제해 카탈로그를 청소할 것 (missing과 함께 stale도 확인).
⚠️ **Xcode 자동 재저장 오염**: Xcode가 열려 있으면 백그라운드 인덱싱이 IOS 카탈로그를 재직렬화하며 **DEBUG 전용 문자열(시드 이름·메모)을 stale로 잘못 마킹**한다(실제 발생 — 대량 diff + stale 18키). 방어: 해당 키들은 `extractionState: manual`로 마킹돼 있어 Xcode·sync 모두 건드리지 않는다(sync 유지 확인됨). **커밋 전 체크에서 갑작스러운 대량 stale이 보이면 코드 탓이 아니라 이 오염 — `git checkout -- IOS/Localizable.xcstrings`로 복원**하고, 새 DEBUG 전용 문자열을 추가하면 manual로 마킹할 것.
⚠️ **카탈로그는 타깃별로 따로다** — Shared 파일의 문자열이라도 위젯·워치 타깃에서 쓰이면 Xcode가 빌드 시 그 타깃의 카탈로그(`Widgets/Localizable.xcstrings`, 워치 앱, `IOS/InfoPlist.xcstrings`)에도 추출한다. IOS 카탈로그만 채우면 위젯·워치 화면은 미번역으로 남으므로, 빌드 후 **모든 카탈로그의 missing을 확인**할 것.
용어 통일: 다짐=Quest/クエスト, 행동=Action, 꼬리표=Tag. `String(format:)`은 카탈로그로 추출되지 않으므로 사용자 노출 문구에 금지 (`Format.countAverage` 참고).

View File

@ -1583,6 +1583,7 @@
}
},
"건강한 생활 습관 만들기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -1631,6 +1632,7 @@
}
},
"공부": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -2646,6 +2648,7 @@
}
},
"꾸준한 달리기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -3911,6 +3914,7 @@
}
},
"독서 30분": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -4205,6 +4209,7 @@
}
},
"매일 밤 독서 습관": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -5188,6 +5193,7 @@
}
},
"물 2리터 마시기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -5844,6 +5850,7 @@
}
},
"새해 다짐 정리하기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -6309,6 +6316,7 @@
}
},
"스크린 타임 관리": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -6886,6 +6894,7 @@
}
},
"아침 루틴 지키기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -7238,6 +7247,7 @@
}
},
"영어 공부": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -7398,6 +7408,7 @@
}
},
"오늘은 여기까지!\n내일은 더 일찍 시작하자.": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -8766,6 +8777,7 @@
}
},
"일찍 일어나기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -8782,6 +8794,7 @@
}
},
"일찍 자기 챌린지": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -8798,6 +8811,7 @@
}
},
"자기 전 물 한 컵": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -8814,6 +8828,7 @@
}
},
"자기 전에 소설 읽음. 재밌어서 늦게 잠": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -8926,6 +8941,7 @@
}
},
"저녁 달리기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -10479,6 +10495,7 @@
}
},
"토익 700점 이상 받기": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
@ -11558,6 +11575,7 @@
}
},
"한 달 다이어트": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {