From 39027eeb4ad6c8f41a3bb6375bfe4471208584d0 Mon Sep 17 00:00:00 2001 From: songyc macbook Date: Fri, 17 Jul 2026 02:09:36 +0900 Subject: [PATCH] chore(debug): localize demo seed names for locale marketing screenshots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 데모 시드(-seedDemo·-diarySeed)의 행동·꼬리표·목표 이름과 메모·할 일을 String(localized:)로 — 마케팅 스크린샷을 en/ja 로케일로 찍을 때 한국어 데이터가 박히지 않게 (DEBUG 전용, ko 기본 동작 불변) - 인텐트 스모크 테스트의 이름 조회도 현지화 경유로 바꿔 어느 로케일에서든 동작 - 신규 17키 en/ja 번역 완비 (카탈로그 783키 missing/stale 0), Debug·Store 빌드 성공 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7 --- myApp/HaruDanim/IOS/Core/DebugSeed.swift | 44 ++-- myApp/HaruDanim/IOS/Localizable.xcstrings | 272 ++++++++++++++++++++++ myApp/HaruDanim/IOS/Views/DiaryView.swift | 4 +- 3 files changed, 297 insertions(+), 23 deletions(-) diff --git a/myApp/HaruDanim/IOS/Core/DebugSeed.swift b/myApp/HaruDanim/IOS/Core/DebugSeed.swift index b71a48c..109aa02 100644 --- a/myApp/HaruDanim/IOS/Core/DebugSeed.swift +++ b/myApp/HaruDanim/IOS/Core/DebugSeed.swift @@ -3,6 +3,8 @@ // Haru_Danim // // 개발 검증용 데모 데이터. 런치 인자 `-seedDemo YES`가 있을 때만 동작. (DEBUG 전용) +// 시드 이름·메모는 String(localized:) — 마케팅 스크린샷용으로 실행 로케일(-AppleLanguages)을 따른다. +// 이름으로 찾는 인자(-autoStart, -openStatsFor, -excludeActions, -endGoalYesterday)는 그 로케일의 이름을 넘길 것. // #if DEBUG @@ -53,7 +55,7 @@ enum DebugSeed { func entity(_ name: String) -> ActionEntity? { IntentStore.actions().first { $0.name == name }.map(ActionEntity.init) } - guard let running = entity("달리기"), let water = entity("물 마시기") else { + guard let running = entity(String(localized: "달리기")), let water = entity(String(localized: "물 마시기")) else { log("준비", "실패 — 데모 행동 없음 (-seedDemo 필요)") return } @@ -470,28 +472,28 @@ enum DebugSeed { let existing = (try? context.fetchCount(FetchDescriptor())) ?? 0 guard existing == 0 else { return } - let study = Tag(name: "공부", colorHex: "#4A7A9D") - let workout = Tag(name: "운동", colorHex: "#9D5B4A") - let life = Tag(name: "생활", colorHex: "#2F6B4F") + let study = Tag(name: String(localized: "공부"), colorHex: "#4A7A9D") + let workout = Tag(name: String(localized: "운동"), colorHex: "#9D5B4A") + let life = Tag(name: String(localized: "생활"), colorHex: "#2F6B4F") context.insert(study) context.insert(workout) context.insert(life) - let reading = Action(name: "독서", symbolName: "book.fill", trackingType: .time, sortOrder: 0) + let reading = Action(name: String(localized: "독서"), symbolName: "book.fill", trackingType: .time, sortOrder: 0) reading.tags = [study] reading.isFavorite = true reading.promptsForNote = true - let english = Action(name: "영어 공부", symbolName: "graduationcap.fill", trackingType: .time, sortOrder: 1) + let english = Action(name: String(localized: "영어 공부"), symbolName: "graduationcap.fill", trackingType: .time, sortOrder: 1) english.tags = [study] - let running = Action(name: "달리기", symbolName: "figure.run", trackingType: .time, sortOrder: 2) + let running = Action(name: String(localized: "달리기"), symbolName: "figure.run", trackingType: .time, sortOrder: 2) running.tags = [workout] - let pushup = Action(name: "팔굽혀펴기", symbolName: "dumbbell.fill", trackingType: .count, sortOrder: 3) + let pushup = Action(name: String(localized: "팔굽혀펴기"), symbolName: "dumbbell.fill", trackingType: .count, sortOrder: 3) pushup.tags = [workout] - let water = Action(name: "물 마시기", symbolName: "drop.fill", trackingType: .count, sortOrder: 4) + let water = Action(name: String(localized: "물 마시기"), symbolName: "drop.fill", trackingType: .count, sortOrder: 4) water.tags = [life] water.promptsForNote = true // '이하 유지' 다짐 검증용 (하루 1시간 이하 목표, 일부러 초과하는 날 포함) - let video = Action(name: "영상 시청", symbolName: "play.rectangle.fill", trackingType: .time, sortOrder: 5) + let video = Action(name: String(localized: "영상 시청"), symbolName: "play.rectangle.fill", trackingType: .time, sortOrder: 5) video.tags = [life] for action in [reading, english, running, pushup, water, video] { context.insert(action) @@ -522,7 +524,7 @@ enum DebugSeed { } // 자정을 걸치는 세션 (하루 경계 분할 확인용) + 메모 표시 확인용 let crossing = TimeSession(action: reading, startAt: at(daysAgo: 1, hour: 23, minute: 20), endAt: at(daysAgo: 0, hour: 0, minute: 40)) - crossing.note = "자기 전에 소설 읽음. 재밌어서 늦게 잠" + crossing.note = String(localized: "자기 전에 소설 읽음. 재밌어서 늦게 잠") context.insert(crossing) // 진행 중 세션 context.insert(TimeSession(action: reading, startAt: now.addingTimeInterval(-25 * 60))) @@ -538,12 +540,12 @@ enum DebugSeed { } // 메모가 달린 횟수 기록 (기록 탭 메모 표시 확인용) let notedWater = CountEntry(action: water, timestamp: at(daysAgo: 0, hour: 20)) - notedWater.note = "자기 전 물 한 컵" + notedWater.note = String(localized: "자기 전 물 한 컵") context.insert(notedWater) // 목표 + 다짐 let toeic = Goal( - title: "토익 700점 이상 받기", + title: String(localized: "토익 700점 이상 받기"), symbolName: "graduationcap.fill", colorHex: "#4A7A9D", startDate: cal.date(byAdding: .day, value: -10, to: now)!, @@ -559,7 +561,7 @@ enum DebugSeed { context.insert(englishQuest) let health = Goal( - title: "건강한 생활 습관 만들기", + title: String(localized: "건강한 생활 습관 만들기"), symbolName: "heart.fill", colorHex: "#2F6B4F", startDate: cal.date(byAdding: .day, value: -20, to: now)!, @@ -603,7 +605,7 @@ enum DebugSeed { // 세 번째 목표 (모음 탭 다중 목표 카드 검증용) let habit = Goal( - title: "매일 밤 독서 습관", + title: String(localized: "매일 밤 독서 습관"), symbolName: "book.fill", colorHex: "#9D5B4A", startDate: cal.date(byAdding: .day, value: -5, to: now)!, @@ -620,7 +622,7 @@ enum DebugSeed { // 네 번째 목표 (모음 탭 목표 카드 개수 제한 해제 검증용) let run = Goal( - title: "꾸준한 달리기", + title: String(localized: "꾸준한 달리기"), symbolName: "figure.run", colorHex: "#4A7A9D", startDate: cal.date(byAdding: .day, value: -14, to: now)!, @@ -638,7 +640,7 @@ enum DebugSeed { // 다섯 번째 목표: 최근 시작 + 초과한 날 없는 '이하 유지' 다짐 // (연속 계산이 목표 시작일 이전으로 새지 않는지 검증용 — 기대값 연속 4일, 버그면 401일) let screen = Goal( - title: "스크린 타임 관리", + title: String(localized: "스크린 타임 관리"), symbolName: "iphone", colorHex: "#4A7A9D", startDate: cal.date(byAdding: .day, value: -3, to: now)!, @@ -657,7 +659,7 @@ enum DebugSeed { // 기록: 오늘 07:30(창 안)+08:10(창 밖 — 집계 제외돼 하루 100%가 200%로 뻥튀기되면 버그), // 어제 08:30(창 밖 → 그날 실패), 그저께 07:00(창 안). // 기대값: 하루 진행률 100%, 연속 1일(어제 실패로 끊김), streak-dump에 deadline=480. - let wake = Action(name: "일찍 일어나기", symbolName: "sunrise.fill", trackingType: .count, sortOrder: 6) + let wake = Action(name: String(localized: "일찍 일어나기"), symbolName: "sunrise.fill", trackingType: .count, sortOrder: 6) wake.tags = [life] context.insert(wake) context.insert(CountEntry(action: wake, timestamp: at(daysAgo: 0, hour: 7, minute: 30))) @@ -665,7 +667,7 @@ enum DebugSeed { context.insert(CountEntry(action: wake, timestamp: at(daysAgo: 1, hour: 8, minute: 30))) context.insert(CountEntry(action: wake, timestamp: at(daysAgo: 2, hour: 7, minute: 0))) let morning = Goal( - title: "아침 루틴 지키기", + title: String(localized: "아침 루틴 지키기"), symbolName: "sunrise.fill", colorHex: "#D9A621", startDate: cal.date(byAdding: .day, value: -7, to: now)!, @@ -688,7 +690,7 @@ enum DebugSeed { // 완료된 목표 (완료 목표 분리 화면 검증용 — 달성 1개 + 미달성 1개) let sleep = Goal( - title: "일찍 자기 챌린지", + title: String(localized: "일찍 자기 챌린지"), symbolName: "moon.zzz.fill", colorHex: "#2F6B4F", startDate: cal.date(byAdding: .day, value: -60, to: now)!, @@ -698,7 +700,7 @@ enum DebugSeed { sleep.sortOrder = 6 context.insert(sleep) let diet = Goal( - title: "한 달 다이어트", + title: String(localized: "한 달 다이어트"), symbolName: "fork.knife", colorHex: "#9D5B4A", startDate: cal.date(byAdding: .day, value: -50, to: now)!, diff --git a/myApp/HaruDanim/IOS/Localizable.xcstrings b/myApp/HaruDanim/IOS/Localizable.xcstrings index 4f68e9f..1cf58fc 100644 --- a/myApp/HaruDanim/IOS/Localizable.xcstrings +++ b/myApp/HaruDanim/IOS/Localizable.xcstrings @@ -1582,6 +1582,22 @@ } } }, + "건강한 생활 습관 만들기": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Build healthy habits" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "健康的な生活習慣をつくる" + } + } + } + }, "건너뛰기": { "localizations": { "en": { @@ -1614,6 +1630,22 @@ } } }, + "공부": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Study" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "勉強" + } + } + } + }, "공유": { "localizations": { "en": { @@ -2613,6 +2645,22 @@ } } }, + "꾸준한 달리기": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Run consistently" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "コツコツ走る" + } + } + } + }, "끝": { "localizations": { "en": { @@ -3846,6 +3894,22 @@ } } }, + "독서 30분": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Read for 30 minutes" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "読書30分" + } + } + } + }, "동기화": { "localizations": { "en": { @@ -4124,6 +4188,22 @@ } } }, + "매일 밤 독서 습관": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Nightly reading habit" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "毎晩の読書習慣" + } + } + } + }, "매주": { "localizations": { "en": { @@ -5091,6 +5171,22 @@ } } }, + "물 2리터 마시기": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Drink 2L of water" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "水を2L飲む" + } + } + } + }, "물 마시기": { "localizations": { "en": { @@ -6180,6 +6276,22 @@ } } }, + "스크린 타임 관리": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Manage screen time" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "スクリーンタイム管理" + } + } + } + }, "습관이나 할 일을 '행동'으로 등록하면\n버튼 한 번으로 시간과 횟수를 기록할 수 있어요.": { "localizations": { "en": { @@ -6741,6 +6853,22 @@ } } }, + "아침 루틴 지키기": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Keep a morning routine" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "朝のルーティンを守る" + } + } + } + }, "애플 펜슬로 자유롭게 쓰고 그려 보세요": { "localizations": { "en": { @@ -7077,6 +7205,22 @@ } } }, + "영어 공부": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "English study" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "英語の勉強" + } + } + } + }, "예: 토익 700점 이상 받기": { "localizations": { "en": { @@ -7221,6 +7365,22 @@ } } }, + "오늘은 여기까지!\n내일은 더 일찍 시작하자.": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "That's it for today!\nStart earlier tomorrow." + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "今日はここまで!\n明日はもっと早く始めよう。" + } + } + } + }, "오른쪽 위 '배치 편집'을 누르면 버튼이 흔들리며 드래그로 순서를 바꿀 수 있어요. 한 줄에 몇 개를 놓을지도 고를 수 있어요. '완료'를 누르면 저장되고, 이 순서는 위젯의 기본 표시 순서에도 쓰여요.": { "localizations": { "en": { @@ -8573,6 +8733,70 @@ } } }, + "일찍 일어나기": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Wake up early" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "早起き" + } + } + } + }, + "일찍 자기 챌린지": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Early bedtime challenge" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "早寝チャレンジ" + } + } + } + }, + "자기 전 물 한 컵": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "A glass of water before bed" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "寝る前に水を一杯" + } + } + } + }, + "자기 전에 소설 읽음. 재밌어서 늦게 잠": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Read a novel before bed — so good I stayed up late" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "寝る前に小説を読んだ。面白くて夜更かし" + } + } + } + }, "자연": { "localizations": { "en": { @@ -8669,6 +8893,22 @@ } } }, + "저녁 달리기": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Evening run" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "夜ランニング" + } + } + } + }, "저장": { "localizations": { "en": { @@ -10190,6 +10430,22 @@ } } }, + "토익 700점 이상 받기": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "Score 700+ on TOEIC" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "TOEIC 700点以上を取る" + } + } + } + }, "통계": { "localizations": { "en": { @@ -11253,6 +11509,22 @@ } } }, + "한 달 다이어트": { + "localizations": { + "en": { + "stringUnit": { + "state": "translated", + "value": "One-month diet" + } + }, + "ja": { + "stringUnit": { + "state": "translated", + "value": "1か月ダイエット" + } + } + } + }, "한 달 단위": { "localizations": { "en": { diff --git a/myApp/HaruDanim/IOS/Views/DiaryView.swift b/myApp/HaruDanim/IOS/Views/DiaryView.swift index 33b1774..70a3bfe 100644 --- a/myApp/HaruDanim/IOS/Views/DiaryView.swift +++ b/myApp/HaruDanim/IOS/Views/DiaryView.swift @@ -265,7 +265,7 @@ struct DiaryRootView: View { let entry = DiaryEntry(dayKey: key) entry.moodEmoji = "🙂" context.insert(entry) - let todoTexts = ["물 2리터 마시기", "독서 30분", "저녁 달리기"] + let todoTexts = [String(localized: "물 2리터 마시기"), String(localized: "독서 30분"), String(localized: "저녁 달리기")] for (index, text) in todoTexts.enumerated() { let todo = DiaryTodo(text: text, sortOrder: index) todo.isDone = index == 0 @@ -286,7 +286,7 @@ struct DiaryRootView: View { arrow.page = page context.insert(arrow) let textBox = DiaryPageItem(kind: .text) - textBox.text = "오늘은 여기까지!\n내일은 더 일찍 시작하자." + textBox.text = String(localized: "오늘은 여기까지!\n내일은 더 일찍 시작하자.") textBox.colorHex = "#3A3A3A" textBox.centerX = 0.42; textBox.centerY = 0.62; textBox.widthRatio = 0.5 textBox.page = page