feat(i18n): 콘텐츠 상세/댓글 하드코딩 문구를 I18n 키로 통일한다

This commit is contained in:
Yu Sung
2026-04-01 16:50:56 +09:00
parent a90996603b
commit c039931f34
30 changed files with 503 additions and 202 deletions

View File

@@ -21,11 +21,11 @@ struct ContentModifyView: View {
GeometryReader { proxy in
ZStack {
VStack(spacing: 0) {
DetailNavigationBar(title: "콘텐츠 수정")
DetailNavigationBar(title: I18n.CreateContent.modifyTitle)
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 0) {
Text("썸네일")
Text(I18n.CreateContent.thumbnail)
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color(hex: "eeeeee"))
.frame(maxWidth: .infinity, alignment: .leading)
@@ -82,12 +82,12 @@ struct ContentModifyView: View {
.padding(.top, 26.7)
VStack(spacing: 0) {
Text("제목")
Text(I18n.CreateContent.titleLabel)
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color(hex: "eeeeee"))
.frame(maxWidth: .infinity, alignment: .leading)
TextField("제목을 입력하세요", text: $viewModel.title)
TextField(I18n.CreateContent.titlePlaceholder, text: $viewModel.title)
.autocapitalization(.none)
.disableAutocorrection(true)
.appFont(size: 13.3, weight: .medium)
@@ -100,16 +100,16 @@ struct ContentModifyView: View {
.padding(.top, 13.3)
HStack(spacing: 0) {
Text("내용")
Text(I18n.CreateContent.contentLabel)
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color(hex: "eeeeee"))
Spacer()
Text("\(viewModel.detail.count)")
Text(I18n.CreateContent.characterCount(viewModel.detail.count))
.appFont(size: 13.3, weight: .medium)
.foregroundColor(Color(hex: "ff5c49"))
Text(" / 최대 500자")
Text(I18n.CreateContent.max500CharactersSuffix)
.appFont(size: 13.3, weight: .medium)
.foregroundColor(Color(hex: "777777"))
}
@@ -125,13 +125,13 @@ struct ContentModifyView: View {
.cornerRadius(6.7)
.padding(.top, 13.3)
Text("태그")
Text(I18n.CreateContent.tagLabel)
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color.grayee)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.top, 26.7)
TextField("예: #연애 #커버곡", text: $viewModel.hashtags)
TextField(I18n.CreateContent.tagPlaceholderExample, text: $viewModel.hashtags)
.autocapitalization(.none)
.disableAutocorrection(true)
.appFont(size: 13.3, weight: .medium)
@@ -152,19 +152,19 @@ struct ContentModifyView: View {
.padding(.top, 26.7)
VStack(spacing: 13.3) {
Text("포인트 사용")
Text(I18n.CreateContent.pointUsageTitle)
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color.grayee)
.frame(maxWidth: .infinity, alignment: .leading)
HStack(spacing: 13.3) {
SelectButtonView(title: "가능", isChecked: viewModel.isPointAvailable) {
SelectButtonView(title: I18n.CreateContent.available, isChecked: viewModel.isPointAvailable) {
if !viewModel.isPointAvailable {
viewModel.isPointAvailable = true
}
}
SelectButtonView(title: "불가능", isChecked: !viewModel.isPointAvailable) {
SelectButtonView(title: I18n.CreateContent.unavailable, isChecked: !viewModel.isPointAvailable) {
if viewModel.isPointAvailable {
viewModel.isPointAvailable = false
}
@@ -176,26 +176,26 @@ struct ContentModifyView: View {
if viewModel.isAdultShowUi {
VStack(spacing: 13.3) {
Text("연령 제한")
Text(I18n.CreateContent.ageRestrictionTitle)
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color(hex: "eeeeee"))
.frame(maxWidth: .infinity, alignment: .leading)
HStack(spacing: 13.3) {
SelectButtonView(title: "전체 연령", isChecked: !viewModel.isAdult) {
SelectButtonView(title: I18n.CreateContent.allAges, isChecked: !viewModel.isAdult) {
if viewModel.isAdult {
viewModel.isAdult = false
}
}
SelectButtonView(title: "19세 이상", isChecked: viewModel.isAdult) {
SelectButtonView(title: I18n.CreateContent.over19, isChecked: viewModel.isAdult) {
if !viewModel.isAdult {
viewModel.isAdult = true
}
}
}
Text("성인콘텐츠를 전체관람가로 등록할 시 발생하는 법적 책임은 회사와 상관없이 콘텐츠를 등록한 본인에게 있습니다.\n콘텐츠 내용은 물론 제목도 19금 여부를 체크해 주시기 바랍니다.")
Text(I18n.CreateContent.adultLegalNotice)
.appFont(size: 13.3, weight: .medium)
.foregroundColor(Color(hex: "DD4500"))
.frame(maxWidth: .infinity, alignment: .leading)
@@ -206,19 +206,19 @@ struct ContentModifyView: View {
}
VStack(spacing: 13.3) {
Text("댓글 가능 여부")
Text(I18n.CreateContent.commentAvailabilityTitle)
.appFont(size: 16.7, weight: .bold)
.foregroundColor(Color(hex: "eeeeee"))
.frame(maxWidth: .infinity, alignment: .leading)
HStack(spacing: 13.3) {
SelectButtonView(title: "댓글 가능", isChecked: viewModel.isAvailableComment) {
SelectButtonView(title: I18n.CreateContent.commentAllowed, isChecked: viewModel.isAvailableComment) {
if !viewModel.isAvailableComment {
viewModel.isAvailableComment = true
}
}
SelectButtonView(title: "댓글 불가", isChecked: !viewModel.isAvailableComment) {
SelectButtonView(title: I18n.CreateContent.commentNotAllowed, isChecked: !viewModel.isAvailableComment) {
if viewModel.isAvailableComment {
viewModel.isAvailableComment = false
}
@@ -230,7 +230,7 @@ struct ContentModifyView: View {
VStack(spacing: 0) {
HStack(alignment: .top, spacing: 0) {
Text("수정")
Text(I18n.CreateContent.modifyAction)
.appFont(size: 18.3, weight: .bold)
.foregroundColor(Color.white)
.frame(height: 50)

View File

@@ -31,7 +31,7 @@ final class ContentModifyViewModel: ObservableObject {
@Published var isAdultShowUi = false
var contentId: Int = 0
var placeholder = "내용을 입력하세요"
var placeholder = I18n.CreateContent.uploadContentDescriptionHint
func getAudioContentDetail(onFailure: (() -> Void)? = nil) {
audioContent = nil
@@ -68,13 +68,13 @@ final class ContentModifyViewModel: 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
}
}
@@ -112,7 +112,7 @@ final class ContentModifyViewModel: ObservableObject {
mimeType: "image/*")
)
} else {
errorMessage = "커버이미지를 업로드 하지 못했습니다.\n다시 선택해 주세요"
errorMessage = I18n.CreateContent.coverImageUploadFailed
isShowPopup = true
isLoading = false
return
@@ -139,26 +139,26 @@ final class ContentModifyViewModel: ObservableObject {
let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
if decoded.success {
self.errorMessage = "콘텐츠가 수정되었습니다."
self.errorMessage = I18n.CreateContent.modifySuccess
self.isShowPopup = true
onSuccess()
} else {
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
}
}
.store(in: &subscription)
} else {
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
self.errorMessage = I18n.Common.commonError
self.isShowPopup = true
self.isLoading = false
}
@@ -167,13 +167,13 @@ final class ContentModifyViewModel: ObservableObject {
private func validateData() -> Bool {
if title != audioContent!.title && title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
errorMessage = "제목을 입력해 주세요."
errorMessage = I18n.CreateContent.titleRequired
isShowPopup = true
return false
}
if detail != audioContent!.detail && (detail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || detail.count < 5) {
errorMessage = "내용을 5자 이상 입력해 주세요."
errorMessage = I18n.CreateContent.detailMinLengthRequired
isShowPopup = true
return false
}