String Catalog가 적용되지 않는 부분을 I18n 파일에 언어별로 하드코딩 하여 보완
This commit is contained in:
@@ -80,6 +80,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
" %lld" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
" OFF" : {
|
" OFF" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -4065,18 +4068,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"모집중" : {
|
"모집완료" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "translated",
|
||||||
"value" : "Recruiting"
|
"value" : "Recruitment closed"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ja" : {
|
"ja" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "translated",
|
||||||
"value" : "募集中"
|
"value" : "募集終了"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4097,18 +4100,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"모집완료" : {
|
"모집중" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "translated",
|
||||||
"value" : "Recruitment closed"
|
"value" : "Recruiting"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ja" : {
|
"ja" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "translated",
|
"state" : "translated",
|
||||||
"value" : "募集終了"
|
"value" : "募集中"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6721,6 +6724,102 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"이벤트 참여하기" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Join the event"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ja" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "イベントに参加する"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"이용약관" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Terms of service"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ja" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "利用規約"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"인기" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Popular"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ja" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "人気"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"인기순" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "By popularity"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ja" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "人気順"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"인증완료" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Verification completed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ja" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "認証完了"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"일" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Sun"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ja" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "日"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"이메일" : {
|
"이메일" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -6801,38 +6900,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"이벤트 참여하기" : {
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Join the event"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ja" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "イベントに参加する"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"이용약관" : {
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Terms of service"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ja" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "利用規約"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"이전화" : {
|
"이전화" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -6849,22 +6916,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"인기" : {
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Popular"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ja" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "人気"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"인기 시리즈" : {
|
"인기 시리즈" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -6945,54 +6996,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"인기순" : {
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "By popularity"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ja" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "人気順"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"인증완료" : {
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Verification completed"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ja" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "認証完了"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"일" : {
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Sun"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ja" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "日"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"일간 랭킹" : {
|
"일간 랭킹" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -9635,4 +9638,4 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version" : "1.1"
|
"version" : "1.1"
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ struct HomeLatestContentView: View {
|
|||||||
let contentList: [AudioContentMainItem]
|
let contentList: [AudioContentMainItem]
|
||||||
|
|
||||||
let selectTheme: (String) -> Void
|
let selectTheme: (String) -> Void
|
||||||
@State private var selectedTheme = "전체"
|
@State private var selectedTheme = I18n.Category.all
|
||||||
|
|
||||||
let rows = [
|
let rows = [
|
||||||
GridItem(.flexible(), alignment: .leading),
|
GridItem(.flexible(), alignment: .leading),
|
||||||
|
|||||||
@@ -40,10 +40,10 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
@Published var recommendContentList: [AudioContentMainItem] = []
|
@Published var recommendContentList: [AudioContentMainItem] = []
|
||||||
|
|
||||||
private let sortType = [
|
private let sortType = [
|
||||||
"매출": ContentRankingSortType.REVENUE,
|
I18n.RankingSort.revenue: ContentRankingSortType.REVENUE,
|
||||||
"판매량": ContentRankingSortType.SALES_COUNT,
|
I18n.RankingSort.salesVolume: ContentRankingSortType.SALES_COUNT,
|
||||||
"댓글": ContentRankingSortType.COMMENT_COUNT,
|
I18n.RankingSort.comments: ContentRankingSortType.COMMENT_COUNT,
|
||||||
"좋아요": ContentRankingSortType.LIKE_COUNT
|
I18n.RankingSort.likes: ContentRankingSortType.LIKE_COUNT
|
||||||
]
|
]
|
||||||
|
|
||||||
func fetchData() {
|
func fetchData() {
|
||||||
@@ -67,7 +67,7 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
if let data = decoded.data, decoded.success {
|
if let data = decoded.data, decoded.success {
|
||||||
self.liveList = data.liveList
|
self.liveList = data.liveList
|
||||||
self.creatorRanking = data.creatorRanking
|
self.creatorRanking = data.creatorRanking
|
||||||
self.latestContentThemeList = ["전체"] + data.latestContentThemeList
|
self.latestContentThemeList = [I18n.Category.all] + data.latestContentThemeList
|
||||||
self.latestContentList = data.latestContentList
|
self.latestContentList = data.latestContentList
|
||||||
self.eventBannerList = data.bannerList
|
self.eventBannerList = data.bannerList
|
||||||
self.originalAudioDramaList = data.originalAudioDramaList
|
self.originalAudioDramaList = data.originalAudioDramaList
|
||||||
@@ -82,13 +82,13 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
self.errorMessage = message
|
self.errorMessage = message
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
func getLatestContentByTheme(theme: String) {
|
func getLatestContentByTheme(theme: String) {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
|
|
||||||
repository.getLatestContentByTheme(theme: theme == "전체" ? "" : theme)
|
repository.getLatestContentByTheme(theme: theme == I18n.Category.all ? "" : theme)
|
||||||
.sink { result in
|
.sink { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .finished:
|
case .finished:
|
||||||
@@ -121,13 +121,13 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
self.errorMessage = message
|
self.errorMessage = message
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,13 +160,13 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
self.errorMessage = message
|
self.errorMessage = message
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,13 +198,13 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
self.errorMessage = message
|
self.errorMessage = message
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,13 +236,13 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
self.errorMessage = message
|
self.errorMessage = message
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,13 +274,13 @@ final class HomeTabViewModel: ObservableObject {
|
|||||||
if let message = decoded.message {
|
if let message = decoded.message {
|
||||||
self.errorMessage = message
|
self.errorMessage = message
|
||||||
} else {
|
} else {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
}
|
}
|
||||||
|
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
self.errorMessage = I18n.Common.commonError
|
||||||
self.isShowPopup = true
|
self.isShowPopup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,13 @@ struct HomeWeeklyChartView: View {
|
|||||||
let contentList: [GetAudioContentRankingItem]
|
let contentList: [GetAudioContentRankingItem]
|
||||||
let onTapSort: (String) -> Void
|
let onTapSort: (String) -> Void
|
||||||
|
|
||||||
let sortList = ["매출", "판매량", "댓글", "좋아요"]
|
let sortList = [
|
||||||
@State private var selectedSort = "매출"
|
I18n.RankingSort.revenue,
|
||||||
|
I18n.RankingSort.salesVolume,
|
||||||
|
I18n.RankingSort.comments,
|
||||||
|
I18n.RankingSort.likes
|
||||||
|
]
|
||||||
|
@State private var selectedSort = I18n.RankingSort.revenue
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
|
|||||||
66
SodaLive/Sources/I18n/I18n.swift
Normal file
66
SodaLive/Sources/I18n/I18n.swift
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// I18n.swift
|
||||||
|
// SodaLive
|
||||||
|
//
|
||||||
|
// Created by Junie (AI) on 2025/12/17.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
// MARK: - I18n 네임스페이스
|
||||||
|
// String Catalog를 사용하지 않는 컨텍스트에서 사용할 하드코딩 맵 기반 i18n.
|
||||||
|
// 기준 언어 선택은 LanguageHeaderProvider.current("ko"|"en"|"ja").
|
||||||
|
enum I18n {
|
||||||
|
enum Common {
|
||||||
|
// 기본 샘플들
|
||||||
|
static var apply: String { pick(ko: "적용", en: "Apply", ja: "適用") }
|
||||||
|
static var confirm: String { pick(ko: "확인", en: "Confirm", ja: "確認") }
|
||||||
|
static var cancel: String { pick(ko: "취소", en: "Cancel", ja: "キャンセル") }
|
||||||
|
|
||||||
|
// 설정
|
||||||
|
static var settings: String { pick(ko: "설정", en: "Settings", ja: "設定") }
|
||||||
|
|
||||||
|
static var commonError: String { pick(ko: "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다.", en: "Settings", ja: "設定") }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Category {
|
||||||
|
static var all: String { pick(ko: "전체", en: "All", ja: "すべて") }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RankingSort {
|
||||||
|
// 분석/지표 등
|
||||||
|
static var revenue: String { pick(ko: "매출", en: "Revenue", ja: "売上高") }
|
||||||
|
static var salesVolume: String { pick(ko: "판매량", en: "Sales", ja: "販売量") }
|
||||||
|
static var comments: String { pick(ko: "댓글", en: "Comments", ja: "コメント") }
|
||||||
|
static var likes: String { pick(ko: "좋아요", en: "Likes", ja: "いいね") }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Tab {
|
||||||
|
// 탭/도메인
|
||||||
|
static var character: String { pick(ko: "캐릭터", en: "Character", ja: "キャラクター") }
|
||||||
|
static var work: String { pick(ko: "작품", en: "Work", ja: "作品") }
|
||||||
|
static var talk: String { pick(ko: "톡", en: "Talk", ja: "トーク") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - 내부 헬퍼
|
||||||
|
@inline(__always)
|
||||||
|
private func pick(ko: String, en: String, ja: String) -> String {
|
||||||
|
switch LanguageHeaderProvider.current {
|
||||||
|
case "ko": return ko
|
||||||
|
case "ja": return ja
|
||||||
|
default: return en
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
사용 예시 (ViewModel, Service 등 Text 이외 컨텍스트):
|
||||||
|
|
||||||
|
// ViewModel 내부
|
||||||
|
let title = I18n.Common.all
|
||||||
|
|
||||||
|
// View 내부(Text 대신 다른 UI 요소 라벨 등)
|
||||||
|
let menuLabel = I18n.Common.settings
|
||||||
|
|
||||||
|
주의: 기존에 Text("...")와 같은 String Catalog 사용부는 그대로 유지합니다.
|
||||||
|
*/
|
||||||
Reference in New Issue
Block a user