feat(i18n): 메시지 모듈 하드코딩 문구를 I18n 키로 통일한다
This commit is contained in:
@@ -2274,6 +2274,152 @@ If you block this user, the following features will be restricted.
|
||||
}
|
||||
}
|
||||
|
||||
enum Message {
|
||||
static var title: String {
|
||||
pick(ko: "메시지", en: "Messages", ja: "メッセージ")
|
||||
}
|
||||
|
||||
static var autoDeleteNotice: String {
|
||||
pick(
|
||||
ko: "※ 보관하지 않은 받은 메시지는 3일 후, 자동 삭제됩니다.",
|
||||
en: "※ Unarchived received messages are automatically deleted after 3 days.",
|
||||
ja: "※ 保管していない受信メッセージは3日後に自動削除されます。"
|
||||
)
|
||||
}
|
||||
|
||||
enum Tab {
|
||||
static var text: String {
|
||||
pick(ko: "문자", en: "Text", ja: "テキスト")
|
||||
}
|
||||
|
||||
static var voice: String {
|
||||
pick(ko: "음성", en: "Voice", ja: "音声")
|
||||
}
|
||||
}
|
||||
|
||||
enum FilterTab {
|
||||
static var received: String {
|
||||
pick(ko: "받은 메시지", en: "Received", ja: "受信")
|
||||
}
|
||||
|
||||
static var sent: String {
|
||||
pick(ko: "보낸 메시지", en: "Sent", ja: "送信")
|
||||
}
|
||||
|
||||
static var archive: String {
|
||||
pick(ko: "보관함", en: "Archived", ja: "保管済み")
|
||||
}
|
||||
}
|
||||
|
||||
enum Text {
|
||||
static var emptyState: String {
|
||||
pick(
|
||||
ko: "메시지가 없습니다.\n친구들과 소통해보세요!",
|
||||
en: "No messages.\nStart chatting with friends!",
|
||||
ja: "メッセージがありません。\n友だちとコミュニケーションしてみましょう!"
|
||||
)
|
||||
}
|
||||
|
||||
enum SelectRecipient {
|
||||
static var title: String {
|
||||
pick(ko: "받는 사람 검색", en: "Search recipient", ja: "受信者を検索")
|
||||
}
|
||||
|
||||
static var nicknamePlaceholder: String {
|
||||
pick(ko: "닉네임을 입력해주세요", en: "Enter a nickname", ja: "ニックネームを入力してください")
|
||||
}
|
||||
}
|
||||
|
||||
enum Write {
|
||||
static var title: String {
|
||||
pick(ko: "새로운 메시지", en: "New message", ja: "新しいメッセージ")
|
||||
}
|
||||
|
||||
static var recipientLabel: String {
|
||||
pick(ko: "받는 사람", en: "Recipient", ja: "受信者")
|
||||
}
|
||||
}
|
||||
|
||||
enum Detail {
|
||||
static var receivedTitle: String {
|
||||
pick(ko: "받은 메시지 상세", en: "Received message details", ja: "受信メッセージ詳細")
|
||||
}
|
||||
|
||||
static var sentTitle: String {
|
||||
pick(ko: "보낸 메시지 상세", en: "Sent message details", ja: "送信メッセージ詳細")
|
||||
}
|
||||
|
||||
static var keptTitle: String {
|
||||
pick(ko: "저장한 메시지 상세", en: "Archived message details", ja: "保管メッセージ詳細")
|
||||
}
|
||||
|
||||
static var dateFormat: String {
|
||||
pick(
|
||||
ko: "yyyy년 MM월 dd일 E요일 HH:mm",
|
||||
en: "yyyy-MM-dd E HH:mm",
|
||||
ja: "yyyy年MM月dd日(E) HH:mm"
|
||||
)
|
||||
}
|
||||
|
||||
static var reply: String {
|
||||
pick(ko: "답장", en: "Reply", ja: "返信")
|
||||
}
|
||||
|
||||
static var keep: String {
|
||||
pick(ko: "보관", en: "Archive", ja: "保管")
|
||||
}
|
||||
|
||||
static var alreadyKept: String {
|
||||
pick(ko: "이미 보관된 메시지 입니다", en: "This message is already archived.", ja: "このメッセージはすでに保管済みです。")
|
||||
}
|
||||
|
||||
static var deleteFailed: String {
|
||||
pick(
|
||||
ko: "메시지를 삭제하지 못했습니다\n잠시 후 다시 시도해 주세요.",
|
||||
en: "Could not delete the message.\nPlease try again later.",
|
||||
ja: "メッセージを削除できませんでした。\nしばらくしてからもう一度お試しください。"
|
||||
)
|
||||
}
|
||||
|
||||
static var deleteSuccess: String {
|
||||
pick(ko: "삭제되었습니다.", en: "Deleted.", ja: "削除されました。")
|
||||
}
|
||||
|
||||
static var keepFailed: String {
|
||||
pick(
|
||||
ko: "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요.",
|
||||
en: "Could not archive the message.\nPlease try again later.",
|
||||
ja: "メッセージを保管できませんでした。\nしばらくしてからもう一度お試しください。"
|
||||
)
|
||||
}
|
||||
|
||||
static var keepSuccess: String {
|
||||
pick(ko: "보관되었습니다.", en: "Archived.", ja: "保管されました。")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Voice {
|
||||
enum Sound {
|
||||
static var permissionDenied: String {
|
||||
pick(
|
||||
ko: "권한을 허용하지 않으시면 음성메시지 서비스를 이용하실 수 없습니다.",
|
||||
en: "You cannot use voice messages unless microphone permission is allowed.",
|
||||
ja: "権限を許可しない場合、音声メッセージサービスを利用できません。"
|
||||
)
|
||||
}
|
||||
|
||||
static var commonError: String {
|
||||
pick(
|
||||
ko: "오류가 발생했습니다. 다시 시도해 주세요.",
|
||||
en: "An error occurred. Please try again.",
|
||||
ja: "エラーが発生しました。もう一度お試しください。"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Series {
|
||||
static var new: String { pick(ko: "신작", en: "New", ja: "新作") }
|
||||
static var complete: String { pick(ko: "완결", en: "Completed", ja: "完結") }
|
||||
|
||||
@@ -13,7 +13,7 @@ struct MessageFilterTabView: View {
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 6.7) {
|
||||
Text("받은 메시지")
|
||||
Text(I18n.Message.FilterTab.received)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color(hex: currentFilterTab == .receive ? "3bb9f1" : "777777"))
|
||||
.padding(.horizontal, 25)
|
||||
@@ -31,7 +31,7 @@ struct MessageFilterTabView: View {
|
||||
}
|
||||
}
|
||||
|
||||
Text("보낸 메시지")
|
||||
Text(I18n.Message.FilterTab.sent)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color(hex: currentFilterTab == .sent ? "3bb9f1" : "777777"))
|
||||
.padding(.horizontal, 25)
|
||||
@@ -49,7 +49,7 @@ struct MessageFilterTabView: View {
|
||||
}
|
||||
}
|
||||
|
||||
Text("보관함")
|
||||
Text(I18n.Message.FilterTab.archive)
|
||||
.appFont(size: 12, weight: .medium)
|
||||
.foregroundColor(Color(hex: currentFilterTab == .keep ? "3bb9f1" : "777777"))
|
||||
.padding(.horizontal, 25)
|
||||
|
||||
@@ -17,11 +17,11 @@ struct MessageView: View {
|
||||
Color.black
|
||||
|
||||
VStack {
|
||||
DetailNavigationBar(title: String(localized: "메시지"))
|
||||
DetailNavigationBar(title: I18n.Message.title)
|
||||
|
||||
Tab()
|
||||
|
||||
Text("※ 보관하지 않은 받은 메시지는 3일 후, 자동 삭제됩니다.")
|
||||
Text(I18n.Message.autoDeleteNotice)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.padding(.top, 20)
|
||||
|
||||
@@ -50,7 +50,7 @@ struct MessageView: View {
|
||||
}
|
||||
}) {
|
||||
VStack(spacing: 0) {
|
||||
Text("문자")
|
||||
Text(I18n.Message.Tab.text)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: viewModel.currentTab == .text ? "eeeeee" : "777777"))
|
||||
.frame(width: tabWidth, height: 50)
|
||||
@@ -69,7 +69,7 @@ struct MessageView: View {
|
||||
}
|
||||
}) {
|
||||
VStack(spacing: 0) {
|
||||
Text("음성")
|
||||
Text(I18n.Message.Tab.voice)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: viewModel.currentTab == .voice ? "eeeeee" : "777777"))
|
||||
.frame(width: tabWidth, height: 50)
|
||||
|
||||
@@ -28,11 +28,11 @@ struct TextMessageDetailView: View {
|
||||
VStack(spacing: 0) {
|
||||
switch messageBox {
|
||||
case .receive:
|
||||
DetailNavigationBar(title: "받은 메시지 상세") { back() }
|
||||
DetailNavigationBar(title: I18n.Message.Text.Detail.receivedTitle) { back() }
|
||||
case .sent:
|
||||
DetailNavigationBar(title: "보낸 메시지 상세") { back() }
|
||||
DetailNavigationBar(title: I18n.Message.Text.Detail.sentTitle) { back() }
|
||||
case .keep:
|
||||
DetailNavigationBar(title: "저장한 메시지 상세") { back() }
|
||||
DetailNavigationBar(title: I18n.Message.Text.Detail.keptTitle) { back() }
|
||||
}
|
||||
|
||||
HStack(spacing: 13.3) {
|
||||
@@ -70,7 +70,7 @@ struct TextMessageDetailView: View {
|
||||
|
||||
Text(messageItem.date.convertDateFormat(
|
||||
from: "yyyy-MM-dd hh:mm:ss",
|
||||
to: "yyyy년 MM월 dd일 E요일 HH:mm"
|
||||
to: I18n.Message.Text.Detail.dateFormat
|
||||
))
|
||||
.appFont(size: 15, weight: .medium)
|
||||
.foregroundColor(Color(hex: "bbbbbb"))
|
||||
@@ -93,7 +93,7 @@ struct TextMessageDetailView: View {
|
||||
|
||||
if messageBox == .receive {
|
||||
HStack(spacing: 6.7) {
|
||||
Text("답장")
|
||||
Text(I18n.Message.Text.Detail.reply)
|
||||
.appFont(size: 14.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
.frame(
|
||||
@@ -106,7 +106,7 @@ struct TextMessageDetailView: View {
|
||||
AppState.shared.setAppStep(step: .writeTextMessage(userId: messageItem.senderId, nickname: messageItem.senderNickname))
|
||||
}
|
||||
|
||||
Text("보관")
|
||||
Text(I18n.Message.Text.Detail.keep)
|
||||
.appFont(size: 14.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "3bb9f1"))
|
||||
.frame(
|
||||
@@ -117,15 +117,15 @@ struct TextMessageDetailView: View {
|
||||
.cornerRadius(6.7)
|
||||
.onTapGesture {
|
||||
if messageItem.isKept {
|
||||
viewModel.errorMessage = "이미 보관된 메시지 입니다"
|
||||
viewModel.errorMessage = I18n.Message.Text.Detail.alreadyKept
|
||||
viewModel.isShowPopup = true
|
||||
return
|
||||
} else {
|
||||
viewModel.keepTextMessage()
|
||||
}
|
||||
}
|
||||
|
||||
Text("삭제")
|
||||
|
||||
Text(I18n.Common.delete)
|
||||
.appFont(size: 14.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "3bb9f1"))
|
||||
.frame(
|
||||
@@ -141,7 +141,7 @@ struct TextMessageDetailView: View {
|
||||
.frame(width: screenSize().width - 26.7)
|
||||
.padding(.vertical, 26.7)
|
||||
} else {
|
||||
Text("삭제")
|
||||
Text(I18n.Common.delete)
|
||||
.appFont(size: 14.7, weight: .bold)
|
||||
.foregroundColor(Color(hex: "3bb9f1"))
|
||||
.frame(
|
||||
|
||||
@@ -24,7 +24,7 @@ final class TextMessageDetailViewModel: ObservableObject {
|
||||
|
||||
func deleteMessage(onSuccess: @escaping () -> Void) {
|
||||
if messageId <= 0 {
|
||||
errorMessage = "메시지를 삭제하지 못했습니다\n잠시 후 다시 시도해 주세요."
|
||||
errorMessage = I18n.Message.Text.Detail.deleteFailed
|
||||
isShowPopup = true
|
||||
return
|
||||
}
|
||||
@@ -48,7 +48,7 @@ final class TextMessageDetailViewModel: ObservableObject {
|
||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||
|
||||
if decoded.success {
|
||||
self.errorMessage = "삭제되었습니다."
|
||||
self.errorMessage = I18n.Message.Text.Detail.deleteSuccess
|
||||
self.isShowPopup = true
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
onSuccess()
|
||||
@@ -58,13 +58,13 @@ final class TextMessageDetailViewModel: ObservableObject {
|
||||
self.errorMessage = message
|
||||
self.isShowPopup = true
|
||||
} else {
|
||||
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
|
||||
self.errorMessage = I18n.Message.Text.Detail.deleteFailed
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
|
||||
self.errorMessage = I18n.Message.Text.Detail.deleteFailed
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ final class TextMessageDetailViewModel: ObservableObject {
|
||||
|
||||
func keepTextMessage() {
|
||||
if messageId <= 0 {
|
||||
errorMessage = "메시지를 저장하지 못했습니다\n잠시 후 다시 시도해 주세요."
|
||||
errorMessage = I18n.Message.Text.Detail.keepFailed
|
||||
isShowPopup = true
|
||||
return
|
||||
}
|
||||
@@ -96,20 +96,20 @@ final class TextMessageDetailViewModel: ObservableObject {
|
||||
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
|
||||
|
||||
if decoded.success {
|
||||
self.errorMessage = "보관되었습니다."
|
||||
self.errorMessage = I18n.Message.Text.Detail.keepSuccess
|
||||
self.isShowPopup = true
|
||||
} else {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
self.isShowPopup = true
|
||||
} else {
|
||||
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
|
||||
self.errorMessage = I18n.Message.Text.Detail.keepFailed
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "메시지를 보관하지 못했습니다.\n잠시 후 다시 시도해 주세요."
|
||||
self.errorMessage = I18n.Message.Text.Detail.keepFailed
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ struct SelectRecipientView: View {
|
||||
var body: some View {
|
||||
BaseView {
|
||||
VStack(spacing: 20) {
|
||||
DetailNavigationBar(title: String(localized: "받는 사람 검색")) {
|
||||
DetailNavigationBar(title: I18n.Message.Text.SelectRecipient.title) {
|
||||
isShowing = false
|
||||
}
|
||||
|
||||
TextField("닉네임을 입력해주세요", text: $viewModel.searchNickname)
|
||||
TextField(I18n.Message.Text.SelectRecipient.nicknamePlaceholder, text: $viewModel.searchNickname)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
|
||||
@@ -51,13 +51,13 @@ final class SelectRecipientViewModel: ObservableObject {
|
||||
DEBUG_LOG("message: \(message)")
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -86,13 +86,13 @@ final class SelectRecipientViewModel: ObservableObject {
|
||||
if let message = decoded.message {
|
||||
self.errorMessage = message
|
||||
} else {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
}
|
||||
|
||||
self.isShowPopup = true
|
||||
}
|
||||
} catch {
|
||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
self.errorMessage = I18n.Common.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ struct TextMessageView: View {
|
||||
.resizable()
|
||||
.frame(width: 60, height: 60)
|
||||
|
||||
Text("메시지가 없습니다.\n친구들과 소통해보세요!")
|
||||
Text(I18n.Message.Text.emptyState)
|
||||
.multilineTextAlignment(.center)
|
||||
.appFont(size: 10.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: "bbbbbb"))
|
||||
|
||||
@@ -21,19 +21,19 @@ struct TextMessageWriteView: View {
|
||||
BaseView(isLoading: $viewModel.isLoading) {
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 0) {
|
||||
Text("취소")
|
||||
Text(I18n.Common.cancel)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: "3bb9f1").opacity(0))
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("새로운 메시지")
|
||||
Text(I18n.Message.Text.Write.title)
|
||||
.appFont(size: 18.3, weight: .bold)
|
||||
.foregroundColor(Color(hex: "eeeeee"))
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("취소")
|
||||
Text(I18n.Common.cancel)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: "3bb9f1"))
|
||||
.onTapGesture {
|
||||
@@ -51,7 +51,7 @@ struct TextMessageWriteView: View {
|
||||
Spacer()
|
||||
|
||||
HStack(spacing: 13.3) {
|
||||
Text("받는 사람")
|
||||
Text(I18n.Message.Text.Write.recipientLabel)
|
||||
.appFont(size: 16.7, weight: .medium)
|
||||
.foregroundColor(Color(hex: "777777"))
|
||||
|
||||
|
||||
@@ -36,14 +36,14 @@ class SoundManager: NSObject, ObservableObject {
|
||||
audioSession.requestRecordPermission() { [weak self] allowed in
|
||||
DispatchQueue.main.async {
|
||||
if !allowed {
|
||||
self?.errorMessage = "권한을 허용하지 않으시면 음성메시지 서비스를 이용하실 수 없습니다."
|
||||
self?.errorMessage = I18n.Message.Voice.Sound.permissionDenied
|
||||
self?.isShowPopup = true
|
||||
self?.onClose = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
|
||||
errorMessage = I18n.Message.Voice.Sound.commonError
|
||||
isShowPopup = true
|
||||
onClose = true
|
||||
}
|
||||
@@ -71,7 +71,7 @@ class SoundManager: NSObject, ObservableObject {
|
||||
}
|
||||
isRecording = true
|
||||
} catch {
|
||||
errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
|
||||
errorMessage = I18n.Message.Voice.Sound.commonError
|
||||
isShowPopup = true
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ class SoundManager: NSObject, ObservableObject {
|
||||
|
||||
self.duration = self.player.duration
|
||||
} catch {
|
||||
self.errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
|
||||
self.errorMessage = I18n.Message.Voice.Sound.commonError
|
||||
self.isShowPopup = true
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ class SoundManager: NSObject, ObservableObject {
|
||||
try FileManager.default.removeItem(at: getAudioFileURL())
|
||||
duration = 0
|
||||
} catch {
|
||||
errorMessage = "오류가 발생했습니다. 다시 시도해 주세요."
|
||||
errorMessage = I18n.Message.Voice.Sound.commonError
|
||||
isShowPopup = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,16 +393,16 @@
|
||||
|
||||
### Message (13)
|
||||
#### Group 1 (1-10)
|
||||
- [ ] `SodaLive/Sources/Message/MessageFilterTabView.swift`
|
||||
- [ ] `SodaLive/Sources/Message/MessageView.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Text/Detail/TextMessageDetailView.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Text/Detail/TextMessageDetailViewModel.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Text/SelectRecipient/SelectRecipientView.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Text/SelectRecipient/SelectRecipientViewModel.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Text/TextMessageView.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Text/Write/TextMessageWriteView.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Voice/SoundManager.swift`
|
||||
- [ ] `SodaLive/Sources/Message/Voice/VoiceMessageItemView.swift`
|
||||
- [x] `SodaLive/Sources/Message/MessageFilterTabView.swift`
|
||||
- [x] `SodaLive/Sources/Message/MessageView.swift`
|
||||
- [x] `SodaLive/Sources/Message/Text/Detail/TextMessageDetailView.swift`
|
||||
- [x] `SodaLive/Sources/Message/Text/Detail/TextMessageDetailViewModel.swift`
|
||||
- [x] `SodaLive/Sources/Message/Text/SelectRecipient/SelectRecipientView.swift`
|
||||
- [x] `SodaLive/Sources/Message/Text/SelectRecipient/SelectRecipientViewModel.swift`
|
||||
- [x] `SodaLive/Sources/Message/Text/TextMessageView.swift`
|
||||
- [x] `SodaLive/Sources/Message/Text/Write/TextMessageWriteView.swift`
|
||||
- [x] `SodaLive/Sources/Message/Voice/SoundManager.swift`
|
||||
- [x] `SodaLive/Sources/Message/Voice/VoiceMessageItemView.swift`
|
||||
|
||||
#### Group 2 (11-13)
|
||||
- [ ] `SodaLive/Sources/Message/Voice/VoiceMessageView.swift`
|
||||
@@ -746,3 +746,32 @@
|
||||
- 빌드 검증: `SodaLive`, `SodaLive-dev` Debug 빌드 모두 성공(`** BUILD SUCCEEDED **`).
|
||||
- 테스트 검증: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 테스트 액션 미구성 확인(코드 실패 아님, 스킴 제약).
|
||||
- LSP 진단: SourceKit 단독 해석 환경에서 외부 모듈/심볼(`Kingfisher`, `RichText`, 앱 내부 타입) 미해결 오류가 대량 보고되나, 동일 변경셋은 `xcodebuild` 실컴파일 통과로 검증 완료.
|
||||
|
||||
### 13차 구현 (Message 모듈 Group 1, 10개 파일 처리, 2026-03-31)
|
||||
- 무엇/왜/어떻게:
|
||||
- 무엇: `변경 대상 파일 전체 목록`의 `Message` Group 1(10개 파일)에서 사용자 노출 하드코딩 문구를 `I18n.*` 참조로 전환하고 체크박스를 완료 처리.
|
||||
- 왜: Message 탭/필터/상세/수신자 검색/텍스트 작성/녹음 오류 메시지에 하드코딩 문자열이 남아 있어 `I18n.swift` 단일 접근 원칙과 불일치했기 때문.
|
||||
- 어떻게: explore/librarian 병렬 탐색 + `grep`/`ast_grep_search` 직접 점검으로 치환 범위를 확정하고, `I18n.swift`에 `I18n.Message` 네임스페이스를 추가한 뒤 Group 1 파일 호출부를 치환.
|
||||
- 실행 명령/도구:
|
||||
- `task(subagent_type="explore", ...)` x2 (`bg_21246137`, `bg_bc8d6ca7`)
|
||||
- `task(subagent_type="librarian", ...)` x2 (`bg_fdbe065d`, `bg_ce19e89c`)
|
||||
- `grep("\"[^\"]*[가-힣][^\"]*\"", include=*.swift, path=SodaLive/Sources/Message)`
|
||||
- `grep("NSLocalizedString\\(|String\\(localized:|LocalizedStringKey\\(", include=*.swift, path=SodaLive/Sources/Message)`
|
||||
- `ast_grep_search(pattern="Text(\"$TEXT\")", lang=swift, paths=[SodaLive/Sources/Message])`
|
||||
- `lsp_diagnostics(filePath=변경 파일 전체)`
|
||||
- `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.Message`(`Tab`, `FilterTab`, `Text.SelectRecipient`, `Text.Write`, `Text.Detail`, `Voice.Sound`) 키셋 추가.
|
||||
- Oracle 후속 보정: `TextMessageDetailViewModel` 삭제 실패 fallback 키를 `keepFailed` → `deleteFailed`로 수정, `TextMessageWriteView` 수신자 라벨을 placeholder 키와 분리(`I18n.Message.Text.Write.recipientLabel`), Message 보관 관련 영문/일문 용어를 `Archive/Archived` 기준으로 통일.
|
||||
- 실치환 파일: `MessageFilterTabView.swift`, `MessageView.swift`, `TextMessageDetailView.swift`, `TextMessageDetailViewModel.swift`, `SelectRecipientView.swift`, `SelectRecipientViewModel.swift`, `TextMessageView.swift`, `TextMessageWriteView.swift`, `SoundManager.swift`.
|
||||
- 점검만 수행(실치환 없음): `VoiceMessageItemView.swift` (사용자 노출 한글 하드코딩 없음, 시간 표기 `00:00` 숫자 포맷만 존재).
|
||||
- Message Group 1 체크박스 10개 `- [x]` 완료 반영.
|
||||
- Group 1 재탐지 결과 한글 리터럴은 `TextMessageDetailView.swift` Preview 샘플 2건(`"누군가"`, `"테스터"`)만 잔존.
|
||||
- `TextMessageDetailView` 날짜 표기는 기존 `convertDateFormat` 경로를 유지해 현재 기기 locale 기준으로 출력됨(앱 언어 설정과 다른 locale일 경우 혼합 표기 가능성은 후속 정리 체크포인트로 유지).
|
||||
- Message 모듈 내 `String(localized:)`/`NSLocalizedString`/`LocalizedStringKey` 직접 참조 0건 확인.
|
||||
- 빌드 검증: `SodaLive`, `SodaLive-dev` Debug 빌드 모두 성공(`** BUILD SUCCEEDED **`).
|
||||
- 테스트 검증: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 테스트 액션 미구성 확인(코드 실패 아님, 스킴 제약).
|
||||
- LSP 진단: SourceKit 단독 해석 환경에서 외부 모듈/프로젝트 심볼 미해결 오류(`Kingfisher`, `MessageRepository` 등)가 보고되나, 동일 변경셋은 `xcodebuild` 실컴파일 통과로 검증 완료.
|
||||
|
||||
Reference in New Issue
Block a user