From bceec46ebc66f54d24cd51a277a829d1c6f85145 Mon Sep 17 00:00:00 2001 From: Yu Sung Date: Wed, 1 Apr 2026 13:52:02 +0900 Subject: [PATCH] =?UTF-8?q?feat(i18n):=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=20?= =?UTF-8?q?=EB=A3=B8=20=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=EB=A5=BC=20I18n=20=ED=82=A4=EB=A1=9C=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SodaLive/Sources/I18n/I18n.swift | 229 ++++++++++++++++++ ...LiveRoomRouletteDonationChatItemView.swift | 4 +- .../Live/Room/Create/LiveRoomCreateView.swift | 52 ++-- .../Create/Tag/LiveRoomCreateTagView.swift | 6 +- .../Tag/LiveRoomCreateTagViewModel.swift | 4 +- .../Live/Room/Detail/LiveDetailView.swift | 20 +- .../Room/Detail/LiveDetailViewModel.swift | 8 +- .../LiveRoomDonationMessageDialog.swift | 8 +- .../LiveRoomDonationMessageItemView.swift | 2 +- .../LiveRoomDonationRankingDialog.swift | 6 +- .../LiveRoomDonationRankingItemView.swift | 6 +- .../LiveRoomDonationRankingTotalCanView.swift | 8 +- .../Dialog/LiveRoomHeartRankingDialog.swift | 10 +- .../Dialog/LiveRoomHeartRankingItemView.swift | 2 +- .../Room/Dialog/LiveRoomInfoEditDialog.swift | 24 +- .../Dialog/LiveRoomNoChattingDialogView.swift | 8 +- .../Room/Dialog/LiveRoomProfileDialog.swift | 4 +- .../Dialog/LiveRoomProfileItemTitleView.swift | 8 +- .../Dialog/LiveRoomProfilesDialogView.swift | 12 +- .../LiveRoomUserProfileDialogView.swift | 10 +- .../Live/Room/Edit/LiveRoomEditView.swift | 26 +- .../Room/Edit/LiveRoomEditViewModel.swift | 18 +- .../Sources/Live/Room/LiveRoomViewModel.swift | 193 ++++++++------- .../Room/Menu/LiveRoomMenuSelectView.swift | 6 +- .../Live/Room/Menu/MenuSettingsView.swift | 6 +- .../Room/Menu/MenuSettingsViewModel.swift | 16 +- .../Config/RouletteSettingsOptionView.swift | 6 +- .../Config/RouletteSettingsView.swift | 22 +- .../Config/RouletteSettingsViewModel.swift | 48 ++-- .../Routlette/RoulettePreviewDialog.swift | 12 +- .../Button/LiveRoomNewChatView.swift | 2 +- .../View/LiveRoomInputChatView.swift | 2 +- .../Sources/Live/Room/V2/LiveRoomViewV2.swift | 10 +- .../Live/SectionCommunityPostView.swift | 2 +- .../Live/SectionLatestFinishedLiveView.swift | 2 +- docs/20260331_하드코딩텍스트_I18n통일계획.md | 93 ++++--- 36 files changed, 571 insertions(+), 324 deletions(-) diff --git a/SodaLive/Sources/I18n/I18n.swift b/SodaLive/Sources/I18n/I18n.swift index 450a02e..c46a4d6 100644 --- a/SodaLive/Sources/I18n/I18n.swift +++ b/SodaLive/Sources/I18n/I18n.swift @@ -1690,6 +1690,147 @@ enum I18n { static var enterPeopleRange: String { pick(ko: "인원을 3~999명 사이로 입력해주세요.", en: "Please enter the number of people between 3 and 999.", ja: "人数を3~999名の間で入力してください。") } static var enterPaidPriceMin30: String { pick(ko: "유료 라이브는 30캔 이상 설정해주세요.", en: "For paid live, set at least 30 cans.", ja: "有料ライブは30can以上で設定してください。") } static var enterPassword6: String { pick(ko: "방 입장 비밀번호 6자리를 입력해 주세요.", en: "Please enter a 6-digit room entry password.", ja: "入室パスワード(6桁)を入力してください。") } + + static var createLiveTitle: String { pick(ko: "라이브 만들기", en: "Create live", ja: "ライブを作成") } + static var fetchRecentData: String { pick(ko: "최근 데이터 가져오기", en: "Load recent data", ja: "最近のデータを読み込む") } + static var thumbnail: String { pick(ko: "썸네일", en: "Thumbnail", ja: "サムネイル") } + static var creatorEntrySetting: String { pick(ko: "크리에이터 입장 설정", en: "Creator entry setting", ja: "クリエイター入場設定") } + static var openLiveAction: String { pick(ko: "라이브 오픈하기", en: "Open live", ja: "ライブを開始") } + + static var titleLabel: String { pick(ko: "제목", en: "Title", ja: "タイトル") } + static var titlePlaceholder: String { pick(ko: "라이브 제목을 입력하세요", en: "Enter live title", ja: "ライブタイトルを入力してください") } + static var interestsLabel: String { pick(ko: "관심사", en: "Interests", ja: "関心事") } + static var selectInterestsAction: String { pick(ko: "관심사 선택", en: "Select interests", ja: "関心事を選択") } + static var noticeLabel: String { pick(ko: "공지", en: "Notice", ja: "お知らせ") } + static func noticeCount(_ count: Int) -> String { + pick(ko: "\(count)자", en: "\(count) chars", ja: "\(count)字") + } + static var noticeLimitSuffix: String { pick(ko: " / 1000자", en: " / 1000 chars", ja: " / 1000字") } + + static var timeSettingLabel: String { pick(ko: "시간설정", en: "Time setting", ja: "時間設定") } + static var reservationDateLabel: String { pick(ko: "예약 날짜", en: "Reservation date", ja: "予約日") } + static var reservationTimeLabel: String { pick(ko: "예약 시간", en: "Reservation time", ja: "予約時間") } + static var participantLimitLabel: String { pick(ko: "참여인원 설정", en: "Participant limit", ja: "参加人数設定") } + static var participantLimitPlaceholder: String { pick(ko: "최대 인원 999명", en: "Max 999 participants", ja: "最大999人") } + static var confirmButton: String { pick(ko: "확인", en: "Confirm", ja: "確認") } + + static var visibilityLabel: String { pick(ko: "공개 설정", en: "Visibility", ja: "公開設定") } + static var roomPasswordTitle: String { pick(ko: "방 비밀번호 입력", en: "Enter room password", ja: "入室パスワード入力") } + static var roomPasswordPlaceholder: String { pick(ko: "방 입장 비밀번호 6자리를 입력해 주세요.", en: "Enter 6-digit room password", ja: "入室パスワード6桁を入力してください") } + static var ageRestrictionLabel: String { pick(ko: "연령 제한", en: "Age restriction", ja: "年齢制限") } + static var ticketPriceLabel: String { pick(ko: "티켓 가격", en: "Ticket price", ja: "チケット価格") } + static var canUnit: String { pick(ko: "캔", en: "cans", ja: "can") } + static func priceOption(_ price: Int) -> String { + pick( + ko: price == 0 ? "무료" : "\(price) 캔", + en: price == 0 ? "Free" : "\(price) cans", + ja: price == 0 ? "無料" : "\(price)can" + ) + } + + static var tagSelectionTitle: String { pick(ko: "관심사 선택", en: "Select interests", ja: "関心事を選択") } + static var tagSelectionSubtitle: String { pick(ko: "최대 3개까지 선택 가능합니다.", en: "You can select up to 3.", ja: "最大3つまで選択できます。") } + static var tagConfirmButton: String { pick(ko: "확인", en: "Confirm", ja: "確認") } + + static var menuTitle: String { pick(ko: "메뉴", en: "Menu", ja: "メニュー") } + static var menuActivatePrompt: String { pick(ko: "메뉴를 활성화 하시겠습니까?", en: "Activate menu?", ja: "メニューを有効化しますか?") } + static var menuPlaceholder: String { pick(ko: "메뉴판을 작성해주세요.", en: "Please write the menu board.", ja: "メニュー表を入力してください。") } + static var saveMenuAction: String { pick(ko: "저장하기", en: "Save", ja: "保存する") } + static var menuSavedMessage: String { pick(ko: "저장되었습니다.", en: "Saved.", ja: "保存されました。") } + + static var editLiveTitle: String { pick(ko: "라이브 수정", en: "Edit live", ja: "ライブ編集") } + static var editAction: String { pick(ko: "수정하기", en: "Edit", ja: "編集する") } + static var entryMessageLabel: String { pick(ko: "입장메시지", en: "Entry message", ja: "入場メッセージ") } + static var noChangesMessage: String { pick(ko: "변경사항이 없습니다.", en: "No changes.", ja: "変更事項がありません。") } + static var editSuccessMessage: String { pick(ko: "라이브 정보가 수정되었습니다.", en: "Live info has been updated.", ja: "ライブ情報を更新しました。") } + static var editFailedMessage: String { + pick( + ko: "라이브 정보를 수정하지 못했습니다.\n다시 시도해 주세요.", + en: "Failed to update live info.\nPlease try again.", + ja: "ライブ情報を更新できませんでした。\nもう一度お試しください。" + ) + } + + static var donationHistoryTitle: String { pick(ko: "후원 히스토리", en: "Donation history", ja: "後援履歴") } + static var donationHistoryCopied: String { pick(ko: "후원 히스토리가 복사되었습니다.", en: "Donation history copied.", ja: "後援履歴をコピーしました。") } + static var donationHistoryEmpty: String { pick(ko: "후원 히스토리가 없습니다.", en: "No donation history.", ja: "後援履歴がありません。") } + static var closeAction: String { pick(ko: "닫기", en: "Close", ja: "閉じる") } + + static var donationRankingTitle: String { pick(ko: "현재 라이브 후원랭킹", en: "Current live donation ranking", ja: "現在のライブ後援ランキング") } + static var heartRankingTitle: String { pick(ko: "현재 라이브 하트랭킹", en: "Current live heart ranking", ja: "現在のライブハートランキング") } + static var totalLabel: String { pick(ko: "전체", en: "Total", ja: "全体") } + static var peopleUnit: String { pick(ko: "명", en: "people", ja: "人") } + static var sumLabel: String { pick(ko: "합계", en: "Sum", ja: "合計") } + static var normalLabel: String { pick(ko: "일반", en: "Normal", ja: "一般") } + static var secretLabel: String { pick(ko: "비밀", en: "Secret", ja: "秘密") } + static var heartLabel: String { pick(ko: "하트", en: "Heart", ja: "ハート") } + + static var noChattingTitle: String { pick(ko: "채팅금지", en: "Chat ban", ja: "チャット禁止") } + static var noChattingQuestion: String { pick(ko: "3분간 채팅금지를 하겠습니까?", en: "Ban chat for 3 minutes?", ja: "3分間チャットを禁止しますか?") } + static var profileTitle: String { pick(ko: "프로필", en: "Profile", ja: "プロフィール") } + static var inviteSpeakerAction: String { pick(ko: "스피커로 초대", en: "Invite as speaker", ja: "スピーカーに招待") } + static var changeListenerAction: String { pick(ko: "리스너 변경", en: "Switch to listener", ja: "リスナーへ変更") } + static var staffReleaseAction: String { pick(ko: "스탭 해제", en: "Release staff", ja: "スタッフ解除") } + static var staffAssignAction: String { pick(ko: "스탭 지정", en: "Assign staff", ja: "スタッフ指定") } + static var kickOutAction: String { pick(ko: "내보내기", en: "Kick out", ja: "退場") } + static var noChattingAction: String { pick(ko: "3분간 채팅금지", en: "3-min chat ban", ja: "3分間チャット禁止") } + static var shortNoChattingAction: String { pick(ko: "채금", en: "Mute", ja: "チャ禁") } + static var requestSpeakerAction: String { pick(ko: "스피커 요청하기", en: "Request speaker", ja: "スピーカー要請") } + static var participantTitle: String { pick(ko: "참여자", en: "Participants", ja: "参加者") } + static var staffTitle: String { pick(ko: "스탭", en: "Staff", ja: "スタッフ") } + static var speakerTitle: String { pick(ko: "스피커", en: "Speaker", ja: "スピーカー") } + static var listenerTitle: String { pick(ko: "리스너", en: "Listener", ja: "リスナー") } + + static var rouletteSettingsTitle: String { pick(ko: "룰렛 설정", en: "Roulette settings", ja: "ルーレット設定") } + static var rouletteActivatePrompt: String { pick(ko: "룰렛을 활성화 하시겠습니까?", en: "Activate roulette?", ja: "ルーレットを有効化しますか?") } + static var rouletteCanSettingTitle: String { pick(ko: "룰렛 금액 설정", en: "Roulette amount", ja: "ルーレット金額設定") } + static var rouletteCanPlaceholder: String { pick(ko: "룰렛 금액을 입력해 주세요 (최소 5캔)", en: "Enter roulette amount (min 5 cans)", ja: "ルーレット金額を入力してください(最小5can)") } + static var rouletteOptionSettingTitle: String { pick(ko: "룰렛 옵션 설정", en: "Roulette options", ja: "ルーレットオプション設定") } + static var rouletteOptionLimitNotice: String { pick(ko: "※ 룰렛 옵션은 최소 2개,\n최대 10개까지 설정할 수 있습니다.", en: "※ You can set 2 to 10 options.", ja: "※ ルーレットオプションは2個以上10個以下で設定できます。") } + static var rouletteProbabilitySum: String { pick(ko: "옵션 확률 합계", en: "Total option probability", ja: "オプション確率合計") } + static var roulettePreviewAction: String { pick(ko: "미리보기", en: "Preview", ja: "プレビュー") } + static var rouletteCompleteAction: String { pick(ko: "설정완료", en: "Complete", ja: "設定完了") } + static var roulettePreviewTitle: String { pick(ko: "룰렛 미리보기", en: "Roulette preview", ja: "ルーレットプレビュー") } + static func rouletteSpinWithCan(_ can: Int) -> String { + pick(ko: "\(can)캔으로 룰렛 돌리기", en: "Spin roulette with \(can) cans", ja: "\(can)canでルーレットを回す") + } + static func rouletteOptionTitle(_ index: Int) -> String { pick(ko: "옵션 \(index + 1)", en: "Option \(index + 1)", ja: "オプション \(index + 1)") } + static var rouletteDeleteAction: String { pick(ko: "삭제", en: "Delete", ja: "削除") } + static var rouletteOptionPlaceholder: String { pick(ko: "옵션을 입력하세요", en: "Enter option", ja: "オプションを入力してください") } + static var rouletteOptionEmptyError: String { pick(ko: "옵션은 빈칸일 수 없습니다.", en: "Options cannot be empty.", ja: "オプションは空欄にできません。") } + static var rouletteProbabilityInvalidError: String { pick(ko: "확률이 100%가 아닙니다", en: "Probability is not 100%.", ja: "確率が100%ではありません。") } + static var rouletteNoChangesMessage: String { pick(ko: "변동사항이 없습니다.", en: "No changes.", ja: "変更事項がありません。") } + static var rouletteNeedFirstMessage: String { pick(ko: "룰렛 1을 먼저 설정하세요", en: "Set Roulette 1 first.", ja: "先にルーレット1を設定してください。") } + static var rouletteNeedFirstAndSecondMessage: String { pick(ko: "룰렛 1과 룰렛 2를 먼저 설정하세요", en: "Set Roulette 1 and 2 first.", ja: "先にルーレット1と2を設定してください。") } + static func rouletteSetAsSuccess(_ title: String) -> String { pick(ko: "\(title)로 설정하였습니다.", en: "Set as \(title).", ja: "\(title)に設定しました。") } + static func rouletteSetSuccess(_ title: String) -> String { pick(ko: "\(title)을 설정했습니다.", en: "\(title) has been set.", ja: "\(title)を設定しました。") } + static func rouletteCreatedSuccess(_ title: String) -> String { pick(ko: "\(title)을 생성했습니다.", en: "\(title) has been created.", ja: "\(title)を作成しました。") } + static func rouletteActivatedSuccess(_ title: String) -> String { pick(ko: "\(title)을 활성화 했습니다.", en: "\(title) has been activated.", ja: "\(title)を有効化しました。") } + static func rouletteDeactivatedSuccess(_ title: String) -> String { pick(ko: "\(title)을 비활성화 했습니다.", en: "\(title) has been deactivated.", ja: "\(title)を無効化しました。") } + static func rouletteChangedSuccess(_ title: String) -> String { pick(ko: "\(title)을 변경했습니다.", en: "\(title) has been changed.", ja: "\(title)を変更しました。") } + static var rouletteUnavailableError: String { pick(ko: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요.", en: "Roulette is unavailable. Please try again.", ja: "ルーレットを利用できません。もう一度お試しください。") } + + static var newChatLabel: String { pick(ko: "새로운 채팅", en: "New chat", ja: "新しいチャット") } + static var communitySectionTitle: String { pick(ko: "커뮤니티", en: "Community", ja: "コミュニティ") } + static var latestFinishedSectionTitle: String { pick(ko: "최근 종료한 라이브", en: "Recently ended live", ja: "最近終了したライブ") } + static var noticeTag: String { pick(ko: "[방송공지]", en: "[Notice]", ja: "[お知らせ]") } + static var menuTag: String { pick(ko: "[메뉴판]", en: "[Menu]", ja: "[メニュー表]") } + + static var detailViewChannel: String { pick(ko: "채널보기", en: "View channel", ja: "チャンネルを見る") } + static var detailEdit: String { pick(ko: "수정", en: "Edit", ja: "編集") } + static var detailStartLive: String { pick(ko: "라이브 시작", en: "Start live", ja: "ライブ開始") } + static var detailReservationDelete: String { pick(ko: "예약삭제", en: "Delete reservation", ja: "予約削除") } + static var detailReservationDone: String { pick(ko: "예약완료", en: "Reserved", ja: "予約完了") } + static var detailReservationAction: String { pick(ko: "예약하기", en: "Reserve", ja: "予約する") } + static var detailJoinNow: String { pick(ko: "지금 참여하기", en: "Join now", ja: "今すぐ参加") } + static var detailReservationParticipant: String { pick(ko: "예약자", en: "Reserved users", ja: "予約者") } + static var detailParticipant: String { pick(ko: "참가자", en: "Participants", ja: "参加者") } + static var detailCollapse: String { pick(ko: "닫기", en: "Close", ja: "閉じる") } + static var detailExpand: String { pick(ko: "펼쳐보기", en: "Expand", ja: "もっと見る") } + + static var speakerRequestSent: String { pick(ko: "스피커 요청을 보냈습니다.\n잠시만 기다려 주세요.", en: "Speaker request sent.\nPlease wait a moment.", ja: "スピーカー要請を送信しました。\nしばらくお待ちください。") } + static var speakerCapacityExceeded: String { pick(ko: "스피커 정원을 초과했습니다.", en: "Speaker capacity exceeded.", ja: "スピーカー定員を超えました。") } + static func remainingNoChattingMessage(_ seconds: Int) -> String { pick(ko: "\(seconds)초 동안 채팅하실 수 없습니다", en: "You cannot chat for \(seconds) seconds.", ja: "\(seconds)秒間チャットできません。") } } enum LiveRoom { @@ -1742,6 +1883,85 @@ enum I18n { static var kickOutTitle: String { pick(ko: "내보내기", en: "Kick out", ja: "退場させる") } static var kickOutConfirm: String { pick(ko: "내보내기", en: "Kick out", ja: "退場させる") } + static func kickOutQuestion(_ nickname: String) -> String { + pick(ko: "\(nickname)님을 내보내시겠어요?", en: "Kick out \(nickname)?", ja: "\(nickname)さんを退出させますか?") + } + static func kickedOutMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님을 내보냈습니다.", en: "\(nickname) has been removed.", ja: "\(nickname)さんを退出させました。") + } + static func staffReleasedMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님을 스탭에서 해제했어요.", en: "\(nickname) has been removed from staff.", ja: "\(nickname)さんのスタッフ権限を解除しました。") + } + static func changedToListenerMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님을 리스너로 변경했어요.", en: "\(nickname) was changed to listener.", ja: "\(nickname)さんをリスナーに変更しました。") + } + static func assignedStaffMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님을 스탭으로 지정했습니다.", en: "\(nickname) was assigned as staff.", ja: "\(nickname)さんをスタッフに指定しました。") + } + static func noChattingAppliedMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님을 3분간 채팅금지를 하였습니다.", en: "\(nickname) has been chat-banned for 3 minutes.", ja: "\(nickname)さんを3分間チャット禁止にしました。") + } + static func noChattingByCreatorMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님이 3분간 채팅을 금지하였습니다.", en: "\(nickname) has muted your chat for 3 minutes.", ja: "\(nickname)さんが3分間チャットを禁止しました。") + } + static var noChattingReleasedMessage: String { pick(ko: "채팅금지가 해제되었습니다.", en: "Chat ban has been lifted.", ja: "チャット禁止が解除されました。") } + + static var becameSpeakerMessage: String { pick(ko: "스피커가 되었어요!", en: "You are now a speaker!", ja: "スピーカーになりました!") } + static var atLeastOneCanDonationMessage: String { pick(ko: "1캔 이상 후원하실 수 있습니다.", en: "You can donate 1 can or more.", ja: "1can以上後援できます。") } + static var donationFailedMessage: String { + pick( + ko: "후원에 실패했습니다.\n다시 후원해주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다.", + en: "Donation failed.\nPlease try donating again.\nIf the problem persists, contact customer support.", + ja: "後援に失敗しました。\nもう一度後援してください。\n問題が続く場合はカスタマーサポートへお問い合わせください。" + ) + } + static var donationRefundFailedMessage: String { + pick( + ko: "후원에 실패한 캔이 환불되지 않았습니다\n고객센터로 문의해주세요.", + en: "Failed donation cans were not refunded.\nPlease contact customer support.", + ja: "後援失敗分のcanが返金されませんでした。\nカスタマーサポートへお問い合わせください。" + ) + } + static var donationStatusFetchFailed: String { + pick(ko: "후원현황을 가져오지 못했습니다\n다시 시도해 주세요.", en: "Failed to load donation status.\nPlease try again.", ja: "後援状況を取得できませんでした。\nもう一度お試しください。") + } + static var heartRankingFetchFailed: String { + pick(ko: "하트 랭킹을 가져오지 못했습니다\n다시 시도해 주세요.", en: "Failed to load heart ranking.\nPlease try again.", ja: "ハートランキングを取得できませんでした。\nもう一度お試しください。") + } + + static var liveEndedMessage: String { pick(ko: "라이브가 종료되었습니다.", en: "The live has ended.", ja: "ライブが終了しました。") } + static func speakerRequestQuestion(_ nickname: String) -> String { + pick(ko: "\(nickname)님이 스피커 요청을 했어요!\n스피커로 초대할까요?", en: "\(nickname) requested to be a speaker.\nInvite as speaker?", ja: "\(nickname)さんがスピーカーを要請しました。\nスピーカーに招待しますか?") + } + static var skipAction: String { pick(ko: "건너뛰기", en: "Skip", ja: "スキップ") } + static var maybeLaterAction: String { pick(ko: "다음에요", en: "Maybe later", ja: "あとで") } + static var joinAsSpeakerAction: String { pick(ko: "스피커로 참여하기", en: "Join as speaker", ja: "スピーカーとして参加") } + static func kickedOutByCreatorMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님이 라이브에서 내보냈습니다.", en: "\(nickname) removed you from the live.", ja: "\(nickname)さんがライブから退出させました。") + } + static var kickedOutByHostMessage: String { pick(ko: "방장님이 라이브에서 내보냈습니다.", en: "Host removed you from the live.", ja: "配信者がライブから退出させました。") } + static func assignedStaffByCreatorMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님이 스탭으로 지정했습니다.", en: "\(nickname) assigned you as staff.", ja: "\(nickname)さんがあなたをスタッフに指定しました。") + } + static var assignedStaffByHostMessage: String { pick(ko: "방장님이 스탭으로 지정했습니다", en: "Host assigned you as staff.", ja: "配信者があなたをスタッフに指定しました。") } + static func releasedStaffByCreatorMessage(_ nickname: String) -> String { + pick(ko: "\(nickname)님이 스탭에서 해제했습니다.", en: "\(nickname) removed your staff role.", ja: "\(nickname)さんがあなたのスタッフ権限を解除しました。") + } + static var releasedStaffByHostMessage: String { pick(ko: "방장님이 스탭에서 해제했습니다.", en: "Host removed your staff role.", ja: "配信者があなたのスタッフ権限を解除しました。") } + static func invitePrivateLiveMessage(_ nickname: String, _ shareUrl: String, _ password: String) -> String { + pick( + ko: "\(nickname)님이 귀하를 보이스온 비공개라이브에 초대하였습니다.\n※ 라이브 참여: \(shareUrl)\n(입장 비밀번호: \(password))", + en: "\(nickname) invited you to a private VoiceOn live.\n※ Join live: \(shareUrl)\n(Entry password: \(password))", + ja: "\(nickname)さんがあなたをVoiceOn非公開ライブに招待しました。\n※ ライブ参加: \(shareUrl)\n(入場パスワード: \(password))" + ) + } + static func invitePublicLiveMessage(_ nickname: String, _ shareUrl: String) -> String { + pick( + ko: "\(nickname)님이 귀하를 보이스온 공개라이브에 초대하였습니다.\n※ 라이브 참여: \(shareUrl)", + en: "\(nickname) invited you to a public VoiceOn live.\n※ Join live: \(shareUrl)", + ja: "\(nickname)さんがあなたをVoiceOn公開ライブに招待しました。\n※ ライブ参加: \(shareUrl)" + ) + } static var leaveButton: String { pick(ko: "나가기", en: "Leave", ja: "退出") } static var endButton: String { pick(ko: "라이브 종료", en: "End live", ja: "ライブ終了") } @@ -1764,6 +1984,7 @@ enum I18n { static var chatFreezeOnStatusMessageForListener: String { pick(ko: "“🧊 모두들 얼음!” 채팅창이 얼었습니다.", en: "\"🧊 Freeze, everyone!\" The chat is now frozen.", ja: "「🧊 みんなフリーズ!」チャットが凍結されました。") } static var chatFreezeOffStatusMessage: String { pick(ko: "“💧땡! “ 채팅창 얼리기가 해제되었습니다.", en: "\"💧 Ding!\" Chat freeze has been lifted.", ja: "「💧 たん!」チャット凍結が解除されました。") } static var chatFreezeBlockedMessage: String { pick(ko: "🧊 채팅창이 얼었습니다.", en: "🧊 The chat is now frozen.", ja: "🧊 チャットが凍結されました。") } + static var chatInputPlaceholder: String { pick(ko: "채팅을 입력하세요", en: "Enter a chat message", ja: "チャットを入力してください") } static var chatDeleteTitle: String { pick(ko: "채팅 삭제", en: "Delete chat", ja: "チャット削除") } } @@ -1968,6 +2189,14 @@ enum I18n { pick(ko: "스탭", en: "Staff", ja: "スタッフ") } + static var rouletteResultQuestionSuffix: String { + pick(ko: "님이 룰렛에 당첨된 건?", en: " hit on the roulette?", ja: "さんがルーレットで当たったのは?") + } + + static var rouletteWinSuffix: String { + pick(ko: " 당첨!", en: " won!", ja: " 当選!") + } + static var donationMemberSuffix: String { pick(ko: "님이", en: "", ja: "さんが") } diff --git a/SodaLive/Sources/Live/Room/Chat/LiveRoomRouletteDonationChatItemView.swift b/SodaLive/Sources/Live/Room/Chat/LiveRoomRouletteDonationChatItemView.swift index 3d622de..a0e61bd 100644 --- a/SodaLive/Sources/Live/Room/Chat/LiveRoomRouletteDonationChatItemView.swift +++ b/SodaLive/Sources/Live/Room/Chat/LiveRoomRouletteDonationChatItemView.swift @@ -40,7 +40,7 @@ struct LiveRoomRouletteDonationChatItemView: View { .appFont(size: 12) .foregroundColor(.white) - Text("님의 룰렛 결과?") + Text(I18n.LiveChat.rouletteResultQuestionSuffix) .appFont(size: 12, weight: .light) .foregroundColor(.white) } @@ -51,7 +51,7 @@ struct LiveRoomRouletteDonationChatItemView: View { + - Text(" 당첨!") + Text(I18n.LiveChat.rouletteWinSuffix) .appFont(size: 15) .foregroundColor(.white) } diff --git a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift index 28c434b..48955d4 100644 --- a/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift +++ b/SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift @@ -51,7 +51,7 @@ struct LiveRoomCreateView: View { .resizable() .frame(width: 20, height: 20) - Text("라이브 만들기") + Text(I18n.CreateLive.createLiveTitle) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.grayee) } @@ -59,7 +59,7 @@ struct LiveRoomCreateView: View { Spacer() if viewModel.isShowGetRecentInfoButton { - Text("최근 데이터 가져오기") + Text(I18n.CreateLive.fetchRecentData) .appFont(size: 12, weight: .medium) .foregroundColor(Color.button) .padding(.vertical, 8) @@ -81,7 +81,7 @@ struct LiveRoomCreateView: View { ScrollView(.vertical, showsIndicators: false) { VStack(spacing: 0) { VStack(spacing: 0) { - Text("썸네일") + Text(I18n.CreateLive.thumbnail) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .padding(.horizontal, 13.3) @@ -167,7 +167,7 @@ struct LiveRoomCreateView: View { .padding(.top, 33.3) VStack(spacing: 13.3) { - Text("크리에이터 입장 설정") + Text(I18n.CreateLive.creatorEntrySetting) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) @@ -235,7 +235,7 @@ struct LiveRoomCreateView: View { } } }) { - Text("라이브 오픈하기") + Text(I18n.CreateLive.openLiveAction) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.white) .frame(width: screenSize().width - 26.7, height: 50) @@ -357,13 +357,13 @@ struct LiveRoomCreateView: View { @ViewBuilder func TitleInputView() -> some View { VStack(spacing: 0) { - Text("제목") + Text(I18n.CreateLive.titleLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .padding(.horizontal, 13.3) .frame(width: screenSize().width, alignment: .leading) - TextField("라이브 제목을 입력하세요", text: $viewModel.title) + TextField(I18n.CreateLive.titlePlaceholder, text: $viewModel.title) .autocapitalization(.none) .disableAutocorrection(true) .appFont(size: 13.3, weight: .medium) @@ -383,7 +383,7 @@ struct LiveRoomCreateView: View { @ViewBuilder func TagSelectView() -> some View { VStack(alignment: .leading, spacing: 13.3) { - Text("관심사") + Text(I18n.CreateLive.interestsLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) @@ -391,7 +391,7 @@ struct LiveRoomCreateView: View { hideKeyboard() isShowSelectTagView = true }) { - Text("관심사 선택") + Text(I18n.CreateLive.selectInterestsAction) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.button) .padding(.vertical, 13.7) @@ -434,16 +434,16 @@ struct LiveRoomCreateView: View { func ContentInputView() -> some View { VStack(spacing: 13.3) { HStack(spacing: 0) { - Text("공지") + Text(I18n.CreateLive.noticeLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) Spacer() - Text("\(viewModel.content.count)자") + Text(I18n.CreateLive.noticeCount(viewModel.content.count)) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.mainRed) - Text(" / 1000자") + Text(I18n.CreateLive.noticeLimitSuffix) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.gray77) } @@ -463,7 +463,7 @@ struct LiveRoomCreateView: View { @ViewBuilder func TimeSettingView() -> some View { VStack(spacing: 0) { - Text("시간설정") + Text(I18n.CreateLive.timeSettingLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) @@ -524,7 +524,7 @@ struct LiveRoomCreateView: View { func ReservationDateTimeView(buttonWidth: CGFloat) -> some View { HStack(spacing: 13.3) { VStack(alignment: .leading, spacing: 6.7) { - Text("예약 날짜") + Text(I18n.CreateLive.reservationDateLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayee) @@ -544,7 +544,7 @@ struct LiveRoomCreateView: View { } VStack(alignment: .leading, spacing: 6.7) { - Text("예약 시간") + Text(I18n.CreateLive.reservationTimeLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayee) @@ -571,12 +571,12 @@ struct LiveRoomCreateView: View { @ViewBuilder func NumberOfPeopleLimitView() -> some View { VStack(spacing: 13.3) { - Text("참여인원 설정") + Text(I18n.CreateLive.participantLimitLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) - TextField("최대 인원 999명", text: $viewModel.numberOfPeople) + TextField(I18n.CreateLive.participantLimitPlaceholder, text: $viewModel.numberOfPeople) .autocapitalization(.none) .disableAutocorrection(true) .multilineTextAlignment(.center) @@ -608,7 +608,7 @@ struct LiveRoomCreateView: View { .frame(width: proxy.size.width) Button(action: { self.isShowSelectDateView = false }) { - Text("확인") + Text(I18n.CreateLive.confirmButton) .appFont(size: 16) .foregroundColor(Color.grayee) .padding(.vertical, 10) @@ -639,7 +639,7 @@ struct LiveRoomCreateView: View { .frame(width: proxy.size.width - 53.4) Button(action: { self.isShowSelectTimeView = false }) { - Text("확인") + Text(I18n.CreateLive.confirmButton) .appFont(size: 16) .foregroundColor(Color.grayee) .padding(.vertical, 10) @@ -656,7 +656,7 @@ struct LiveRoomCreateView: View { @ViewBuilder func RoomTypeSettingView() -> some View { VStack(spacing: 0) { - Text("공개 설정") + Text(I18n.CreateLive.visibilityLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) @@ -709,12 +709,12 @@ struct LiveRoomCreateView: View { @ViewBuilder func RoomPasswordView() -> some View { VStack(spacing: 13.3) { - Text("방 비밀번호 입력") + Text(I18n.CreateLive.roomPasswordTitle) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) - TextField("방 입장 비밀번호 6자리를 입력해 주세요.", text: $viewModel.password) + TextField(I18n.CreateLive.roomPasswordPlaceholder, text: $viewModel.password) .autocapitalization(.none) .disableAutocorrection(true) .multilineTextAlignment(.center) @@ -732,7 +732,7 @@ struct LiveRoomCreateView: View { @ViewBuilder func AdultSettingView() -> some View { VStack(spacing: 13.3) { - Text("연령 제한") + Text(I18n.CreateLive.ageRestrictionLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) @@ -828,7 +828,7 @@ struct LiveRoomCreateView: View { @ViewBuilder func PriceSettingView() -> some View { VStack(spacing: 13.3) { - Text("티켓 가격") + Text(I18n.CreateLive.ticketPriceLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) .frame(width: screenSize().width - 26.7, alignment: .leading) @@ -861,7 +861,7 @@ struct LiveRoomCreateView: View { Spacer() - Text("캔") + Text(I18n.CreateLive.canUnit) .appFont(size: 14.7, weight: .medium) .foregroundColor(Color.button) } @@ -878,7 +878,7 @@ struct LiveRoomCreateView: View { @ViewBuilder func PriceButtonView(price: Int, buttonWidth: CGFloat) -> some View { HStack(spacing: 6.7) { - Text(price == 0 ? "무료" : "\(price) 캔") + Text(I18n.CreateLive.priceOption(price)) .appFont(size: 14.7, weight: viewModel.price == price ? .bold : .medium) .foregroundColor(viewModel.price == price ? Color.button : Color.gray77) } diff --git a/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagView.swift b/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagView.swift index 29b49aa..29f4fd0 100644 --- a/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagView.swift +++ b/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagView.swift @@ -29,11 +29,11 @@ struct LiveRoomCreateTagView: View { VStack(spacing: 0) { HStack(alignment: .top, spacing: 0) { VStack(alignment: .leading, spacing: 6.7) { - Text("관심사 선택") + Text(I18n.CreateLive.tagSelectionTitle) .appFont(size: 18.3, weight: .bold) .foregroundColor(.white) - Text("최대 3개까지 선택 가능합니다.") + Text(I18n.CreateLive.tagSelectionSubtitle) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "777777")) } @@ -100,7 +100,7 @@ struct LiveRoomCreateTagView: View { .padding(.horizontal, 20) .padding(.top, 26.7) - Text("확인") + Text(I18n.CreateLive.tagConfirmButton) .appFont(size: 18.3, weight: .bold) .foregroundColor(.white) .padding(.vertical, 16) diff --git a/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagViewModel.swift b/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagViewModel.swift index e5324d3..10a886a 100644 --- a/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagViewModel.swift +++ b/SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagViewModel.swift @@ -44,13 +44,13 @@ final class LiveRoomCreateTagViewModel: 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 } } diff --git a/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift b/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift index 8a4021d..6c2b028 100644 --- a/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift +++ b/SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift @@ -110,7 +110,7 @@ struct LiveDetailView: View { .frame(width: 26.7, height: 26.7) .padding(.leading, 6.7) } else { - Text("무료") + Text(I18n.CreateContent.free) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color(hex: "eeeeee")) } @@ -185,7 +185,7 @@ struct LiveDetailView: View { .resizable() .frame(width: 13.3, height: 13.3) - Text("채널보기") + Text(I18n.CreateLive.detailViewChannel) .appFont(size: 12, weight: .medium) .foregroundColor(Color.white) .onTapGesture { @@ -278,7 +278,7 @@ struct LiveDetailView: View { if room.manager.id == UserDefaults.int(forKey: .userId) { VStack(spacing: 16.7) { HStack(spacing: 13.3) { - Text("수정") + Text(I18n.CreateLive.detailEdit) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.white) .padding(.vertical, 16) @@ -294,7 +294,7 @@ struct LiveDetailView: View { AppState.shared.setAppStep(step: .modifyLive(room: room)) } - Text("라이브 시작") + Text(I18n.CreateLive.detailStartLive) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.white) .padding(.vertical, 16) @@ -307,7 +307,7 @@ struct LiveDetailView: View { } } - Text("예약삭제") + Text(I18n.CreateLive.detailReservationDelete) .appFont(size: 14, weight: .medium) .foregroundColor(Color(hex: "ff5c49")) .padding(5.3) @@ -323,7 +323,7 @@ struct LiveDetailView: View { } .frame(width: screenSize().width - 26.7) } else if room.isPaid { - Text("예약완료") + Text(I18n.CreateLive.detailReservationDone) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color(hex: "777777")) .padding(.vertical, 16) @@ -336,7 +336,7 @@ struct LiveDetailView: View { onClickReservation() AppState.shared.back() } label: { - Text("예약하기") + Text(I18n.CreateLive.detailReservationAction) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.white) .padding(.vertical, 16) @@ -351,7 +351,7 @@ struct LiveDetailView: View { onClickParticipant() AppState.shared.back() } label: { - Text("지금 참여하기") + Text(I18n.CreateLive.detailJoinNow) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.white) .padding(.vertical, 16) @@ -369,7 +369,7 @@ struct LiveDetailView: View { private func ParticipantView(room: GetRoomDetailResponse) -> some View { if isExpandParticipantArea { HStack(spacing: 0) { - Text(room.channelName.isNullOrBlank() ? "예약자" : "참가자") + Text(room.channelName.isNullOrBlank() ? I18n.CreateLive.detailReservationParticipant : I18n.CreateLive.detailParticipant) .appFont(size: 12, weight: .medium) .foregroundColor(Color.graybb) @@ -450,7 +450,7 @@ struct LiveDetailView: View { .resizable() .frame(width: 20, height: 20) - Text(isExpandParticipantArea ? "닫기" : "펼쳐보기") + Text(isExpandParticipantArea ? I18n.CreateLive.detailCollapse : I18n.CreateLive.detailExpand) .appFont(size: 12, weight: .medium) .foregroundColor(Color.graybb) } diff --git a/SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift b/SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift index 6351abf..c9bd666 100644 --- a/SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift +++ b/SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift @@ -49,14 +49,14 @@ final class LiveDetailViewModel: ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { print(error) - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowPopup = true } @@ -96,13 +96,13 @@ final class LiveDetailViewModel: 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 } } diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift index a9bbd76..9c04b04 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift @@ -25,7 +25,7 @@ struct LiveRoomDonationMessageDialog: View { VStack(spacing: 0) { HStack(spacing: 0) { - Text("후원 히스토리") + Text(I18n.CreateLive.donationHistoryTitle) .appFont(size: 14.7, weight: .bold) .foregroundColor(Color(hex: "eeeeee")) @@ -35,7 +35,7 @@ struct LiveRoomDonationMessageDialog: View { Spacer() - Text("닫기") + Text(I18n.CreateLive.closeAction) .appFont(size: 14.7, weight: .light) .foregroundColor(Color(hex: "eeeeee")) .onTapGesture { isShowing = false } @@ -52,14 +52,14 @@ struct LiveRoomDonationMessageDialog: View { } .onTapGesture { UIPasteboard.general.string = donationMessage.donationMessage - self.viewModel.errorMessage = "후원 히스토리가 복사되었습니다." + self.viewModel.errorMessage = I18n.CreateLive.donationHistoryCopied self.viewModel.isShowPopup = true } } } .padding(.top, 18.7) } else { - Text("후원 히스토리가 없습니다.") + Text(I18n.CreateLive.donationHistoryEmpty) .appFont(size: 14.7, weight: .medium) .foregroundColor(Color(hex: "eeeeee")) .padding(.top, 30) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageItemView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageItemView.swift index 0a15c54..58fe0b0 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageItemView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageItemView.swift @@ -16,7 +16,7 @@ struct LiveRoomDonationMessageItemView: View { var body: some View { HStack(alignment: .top, spacing: 0) { VStack(alignment: .leading, spacing: 8) { - Text("\(message.nickname)님이") + Text("\(message.nickname)\(I18n.LiveChat.donationMemberSuffix)") .appFont(size: 13.3, weight: .medium) .foregroundColor(.white) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingDialog.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingDialog.swift index 83e90de..10c934f 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingDialog.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingDialog.swift @@ -18,7 +18,7 @@ struct LiveRoomDonationRankingDialog: View { ZStack { VStack(spacing: 0) { HStack(spacing: 0) { - Text("현재 라이브 후원랭킹") + Text(I18n.CreateLive.donationRankingTitle) .appFont(size: 14.7, weight: .bold) .foregroundColor(Color.grayee) @@ -33,7 +33,7 @@ struct LiveRoomDonationRankingDialog: View { .padding(.top, 25) HStack(spacing: 0) { - Text("전체") + Text(I18n.CreateLive.totalLabel) .appFont(size: 14.7, weight: .medium) .foregroundColor(Color.grayee) @@ -42,7 +42,7 @@ struct LiveRoomDonationRankingDialog: View { .foregroundColor(Color.button) .padding(.leading, 6.7) - Text("명") + Text(I18n.CreateLive.peopleUnit) .appFont(size: 12, weight: .medium) .foregroundColor(Color.gray77) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingItemView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingItemView.swift index 216cb88..5411b43 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingItemView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingItemView.swift @@ -55,7 +55,7 @@ struct LiveRoomDonationRankingItemView: View { .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.button) - Text("캔") + Text(I18n.CreateLive.canUnit) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "eeeeee")) } @@ -63,7 +63,7 @@ struct LiveRoomDonationRankingItemView: View { if item.secretCan > 0 { HStack(spacing: 4) { - Text("비밀") + Text(I18n.CreateLive.secretLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.gray11) .padding(.horizontal, 3.3) @@ -75,7 +75,7 @@ struct LiveRoomDonationRankingItemView: View { .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "fedc00")) - Text("캔") + Text(I18n.CreateLive.canUnit) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "eeeeee")) } diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingTotalCanView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingTotalCanView.swift index 2de588c..a7e675e 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingTotalCanView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingTotalCanView.swift @@ -14,7 +14,7 @@ struct LiveRoomDonationRankingTotalCanView: View { var body: some View { HStack(alignment: .center, spacing: 0) { - Text("합계") + Text(I18n.CreateLive.sumLabel) .appFont(size: 13.3, weight: .bold) .foregroundColor(Color.grayd2) @@ -23,7 +23,7 @@ struct LiveRoomDonationRankingTotalCanView: View { .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayd2) - Text("일반") + Text(I18n.CreateLive.normalLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.button) @@ -31,7 +31,7 @@ struct LiveRoomDonationRankingTotalCanView: View { .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayd2) - Text("비밀") + Text(I18n.CreateLive.secretLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "fedc00")) @@ -55,7 +55,7 @@ struct LiveRoomDonationRankingTotalCanView: View { .foregroundColor(Color(hex: "fedc00")) } - Text("캔") + Text(I18n.CreateLive.canUnit) .appFont(size: 10.7, weight: .medium) .foregroundColor(Color.graybb) .padding(.leading, 4) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingDialog.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingDialog.swift index 55226f5..9454021 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingDialog.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingDialog.swift @@ -22,7 +22,7 @@ struct LiveRoomHeartRankingDialog: View { ZStack { VStack(spacing: 0) { HStack(spacing: 0) { - Text("현재 라이브 하트랭킹") + Text(I18n.CreateLive.heartRankingTitle) .appFont(size: 14.7, weight: .bold) .foregroundColor(Color.grayee) @@ -34,7 +34,7 @@ struct LiveRoomHeartRankingDialog: View { if let heartStatus = heartStatus { HStack(alignment: .center, spacing: 0) { - Text("합계") + Text(I18n.CreateLive.sumLabel) .appFont(size: 13.3, weight: .bold) .foregroundColor(Color.grayd2) @@ -44,7 +44,7 @@ struct LiveRoomHeartRankingDialog: View { .appFont(size: 14, weight: .medium) .foregroundColor(Color.button) - Text("하트") + Text(I18n.CreateLive.heartLabel) .appFont(size: 10.7, weight: .medium) .foregroundColor(Color.graybb) .padding(.leading, 4) @@ -56,7 +56,7 @@ struct LiveRoomHeartRankingDialog: View { .padding(.top, 25) HStack(spacing: 0) { - Text("전체") + Text(I18n.CreateLive.totalLabel) .appFont(size: 14.7, weight: .medium) .foregroundColor(Color.grayee) @@ -65,7 +65,7 @@ struct LiveRoomHeartRankingDialog: View { .foregroundColor(Color.button) .padding(.leading, 6.7) - Text("명") + Text(I18n.CreateLive.peopleUnit) .appFont(size: 12, weight: .medium) .foregroundColor(Color.gray77) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingItemView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingItemView.swift index c16fa43..3f8c22a 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingItemView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingItemView.swift @@ -55,7 +55,7 @@ struct LiveRoomHeartRankingItemView: View { .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.button) - Text("하트") + Text(I18n.CreateLive.heartLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayee) } diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomInfoEditDialog.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomInfoEditDialog.swift index 09d448f..c991618 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomInfoEditDialog.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomInfoEditDialog.swift @@ -18,7 +18,7 @@ struct LiveRoomInfoEditDialog: View { @State private var isAdult = false @State private var isEntryMessageEnabled = true - let placeholder = "라이브 공지를 입력하세요" + let placeholder = I18n.CreateLive.noticePlaceholder @StateObject var viewModel: LiveRoomViewModel @@ -62,7 +62,7 @@ struct LiveRoomInfoEditDialog: View { ScrollView(.vertical, showsIndicators: false) { VStack(alignment: .leading, spacing: 0) { HStack(spacing: 0) { - Text("라이브 수정") + Text(I18n.CreateLive.editLiveTitle) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.grayee) @@ -131,12 +131,12 @@ struct LiveRoomInfoEditDialog: View { if UserDefaults.bool(forKey: .auth) { VStack(alignment: .leading, spacing: 8) { - Text("연령제한") + Text(I18n.CreateLive.ageRestrictionLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) HStack(spacing: 0) { - Text("19세 이상") + Text(I18n.CreateLive.over19) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayee) @@ -163,7 +163,7 @@ struct LiveRoomInfoEditDialog: View { .padding(.top, 33.3) HStack(spacing: 0) { - Text("입장메시지") + Text(I18n.CreateLive.entryMessageLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) @@ -179,7 +179,7 @@ struct LiveRoomInfoEditDialog: View { .padding(.top, 33.3) HStack(spacing: 13.3) { - Text("취소") + Text(I18n.Common.cancel) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.button) .padding(.vertical, 16) @@ -195,7 +195,7 @@ struct LiveRoomInfoEditDialog: View { isShowing = false } - Text("수정하기") + Text(I18n.CreateLive.editAction) .appFont(size: 18.3, weight: .bold) .foregroundColor(.white) .padding(.vertical, 16) @@ -251,11 +251,11 @@ struct LiveRoomInfoEditDialog: View { @ViewBuilder func TitleInputView() -> some View { VStack(alignment: .leading, spacing: 0) { - Text("제목") + Text(I18n.CreateLive.titleLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) - TextField("라이브 제목을 입력하세요", text: $title) + TextField(I18n.CreateLive.titlePlaceholder, text: $title) .autocapitalization(.none) .disableAutocorrection(true) .appFont(size: 13.3, weight: .medium) @@ -276,16 +276,16 @@ struct LiveRoomInfoEditDialog: View { func ContentInputView() -> some View { VStack(spacing: 13.3) { HStack(spacing: 0) { - Text("공지") + Text(I18n.CreateLive.noticeLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) Spacer() - Text("\(notice.count)자") + Text(I18n.CreateLive.noticeCount(notice.count)) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.mainRed) - Text(" / 1000자") + Text(I18n.CreateLive.noticeLimitSuffix) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.gray77) } diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomNoChattingDialogView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomNoChattingDialogView.swift index aa32856..3eb880c 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomNoChattingDialogView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomNoChattingDialogView.swift @@ -22,7 +22,7 @@ struct LiveRoomNoChattingDialogView: View { .frame(width: screenSize().width, height: screenSize().height) VStack(spacing: 21) { - Text("채팅금지") + Text(I18n.CreateLive.noChattingTitle) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color(hex: "bbbbbb")) @@ -43,12 +43,12 @@ struct LiveRoomNoChattingDialogView: View { .foregroundColor(Color(hex: "bbbbbb")) } - Text("3분간 채팅금지를 하겠습니까?") + Text(I18n.CreateLive.noChattingQuestion) .appFont(size: 15, weight: .medium) .foregroundColor(Color(hex: "bbbbbb")) HStack(spacing: 13.3) { - Text("취소") + Text(I18n.Common.cancel) .appFont(size: 15.3, weight: .bold) .foregroundColor(Color.button) .padding(.vertical, 16) @@ -61,7 +61,7 @@ struct LiveRoomNoChattingDialogView: View { ) .onTapGesture { cancelAction() } - Text("확인") + Text(I18n.Common.confirm) .appFont(size: 15.3, weight: .bold) .foregroundColor(Color(hex: "ffffff")) .padding(.vertical, 16) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileDialog.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileDialog.swift index c421799..b2b64f7 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileDialog.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileDialog.swift @@ -51,7 +51,7 @@ struct LiveRoomProfileDialog: View { if isSpeaker { if profileInfo.role == .LISTENER, let onClickInviteSpeaker = onClickInviteSpeaker { - Text("스피커로 초대") + Text(I18n.CreateLive.inviteSpeakerAction) .appFont(size: 10, weight: .medium) .foregroundColor(.button) .padding(.horizontal, 15.4) @@ -66,7 +66,7 @@ struct LiveRoomProfileDialog: View { if (memberId == creatorId || memberId == profileInfo.id) && profileInfo.id != creatorId && profileInfo.role == .SPEAKER, let onClickChangeListener = onClickChangeListener { - Text("리스너로 변경") + Text(I18n.CreateLive.changeListenerAction) .appFont(size: 10, weight: .medium) .foregroundColor(.button) .padding(.horizontal, 15.4) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileItemTitleView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileItemTitleView.swift index 3d2593b..0ab7c8d 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileItemTitleView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileItemTitleView.swift @@ -132,7 +132,7 @@ struct LiveRoomProfileItemUserView: View { Spacer() if role == .LISTENER && isStaff { - Text("스피커로 초대") + Text(I18n.CreateLive.inviteSpeakerAction) .appFont(size: 10, weight: .medium) .foregroundColor(.white) .padding(.horizontal, 5.5) @@ -149,7 +149,7 @@ struct LiveRoomProfileItemUserView: View { } if role == .SPEAKER && (userId == UserDefaults.int(forKey: .userId) || isStaff) { - Text("리스너로 변경") + Text(I18n.CreateLive.changeListenerAction) .appFont(size: 10, weight: .medium) .foregroundColor(.white) .padding(.horizontal, 5.5) @@ -162,7 +162,7 @@ struct LiveRoomProfileItemUserView: View { } if role != .MANAGER && creatorId == UserDefaults.int(forKey: .userId) { - Text("채금") + Text(I18n.CreateLive.shortNoChattingAction) .appFont(size: 10, weight: .medium) .foregroundColor(.white) .padding(.horizontal, 5.5) @@ -206,7 +206,7 @@ struct LiveRoomProfileRequestSpeakerView: View { HStack(spacing: 6.7) { Spacer() Image("ic_request_speak") - Text("스피커 요청하기") + Text(I18n.CreateLive.requestSpeakerAction) .appFont(size: 13.3, weight: .bold) .foregroundColor(.white) Spacer() diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfilesDialogView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfilesDialogView.swift index 649eb0d..45d8390 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfilesDialogView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomProfilesDialogView.swift @@ -35,7 +35,7 @@ struct LiveRoomProfilesDialogView: View { self.profiles.append( AnyView( LiveRoomProfileItemTitleView( - title: "스탭", + title: I18n.CreateLive.staffTitle, count: roomInfo.managerList.count, totalCount: nil ) @@ -71,7 +71,7 @@ struct LiveRoomProfilesDialogView: View { self.profiles.append( AnyView( LiveRoomProfileItemTitleView( - title: "스피커", + title: I18n.CreateLive.speakerTitle, count: roomInfo.speakerList.count - 1, totalCount: roomInfo.totalAvailableParticipantsCount ) @@ -127,7 +127,7 @@ struct LiveRoomProfilesDialogView: View { self.profiles.append( AnyView( LiveRoomProfileItemTitleView( - title: "리스너", + title: I18n.CreateLive.listenerTitle, count: nil, totalCount: nil ) @@ -150,10 +150,10 @@ struct LiveRoomProfilesDialogView: View { onClickInviteSpeaker: { if viewModel.liveRoomInfo!.speakerList.count <= 5 { viewModel.inviteSpeaker(peerId: $0) - viewModel.popupContent = "스피커 요청을 보냈습니다.\n잠시만 기다려 주세요." + viewModel.popupContent = I18n.CreateLive.speakerRequestSent viewModel.isShowPopup = true } else { - viewModel.errorMessage = "스피커 정원을 초과했습니다." + viewModel.errorMessage = I18n.CreateLive.speakerCapacityExceeded viewModel.isShowErrorPopup = true } }, @@ -173,7 +173,7 @@ struct LiveRoomProfilesDialogView: View { ZStack { VStack(spacing: 16.7) { HStack(spacing: 0) { - Text("참여자") + Text(I18n.CreateLive.participantTitle) .appFont(size: 15, weight: .bold) .foregroundColor(Color.grayee) diff --git a/SodaLive/Sources/Live/Room/Dialog/LiveRoomUserProfileDialogView.swift b/SodaLive/Sources/Live/Room/Dialog/LiveRoomUserProfileDialogView.swift index 8a88fca..9daf768 100644 --- a/SodaLive/Sources/Live/Room/Dialog/LiveRoomUserProfileDialogView.swift +++ b/SodaLive/Sources/Live/Room/Dialog/LiveRoomUserProfileDialogView.swift @@ -29,7 +29,7 @@ struct LiveRoomUserProfileDialogView: View { ZStack { VStack(spacing: 0) { HStack(spacing: 0) { - Text("프로필") + Text(I18n.CreateLive.profileTitle) .appFont(size: 15, weight: .bold) .foregroundColor(Color.grayee) @@ -91,7 +91,7 @@ struct LiveRoomUserProfileDialogView: View { HStack(spacing: 8) { if let isSpeaker = userProfile.isSpeaker { - Text(isSpeaker ? "리스너 변경" : "스피커 초대") + Text(isSpeaker ? I18n.CreateLive.changeListenerAction : I18n.CreateLive.inviteSpeakerAction) .appFont(size: 15, weight: .bold) .foregroundColor(Color.button) .frame(maxWidth: .infinity) @@ -114,7 +114,7 @@ struct LiveRoomUserProfileDialogView: View { } if let isManager = userProfile.isManager { - Text(isManager ? "스탭 해제" : "스탭 지정") + Text(isManager ? I18n.CreateLive.staffReleaseAction : I18n.CreateLive.staffAssignAction) .appFont(size: 15, weight: .bold) .foregroundColor(Color.button) .frame(maxWidth: .infinity) @@ -138,7 +138,7 @@ struct LiveRoomUserProfileDialogView: View { if (userProfile.isSpeaker != nil && !viewModel.isEqualToStaffId(creatorId: userProfile.userId)) || (userProfile.isSpeaker != nil && userProfile.isManager != nil) { - Text("내보내기") + Text(I18n.CreateLive.kickOutAction) .appFont(size: 15, weight: .bold) .foregroundColor(Color.button) .frame(maxWidth: .infinity) @@ -159,7 +159,7 @@ struct LiveRoomUserProfileDialogView: View { .padding(.top, 21.3) if let _ = userProfile.isManager { - Text("3분간 채팅금지") + Text(I18n.CreateLive.noChattingAction) .appFont(size: 15, weight: .bold) .foregroundColor(Color.button) .frame(maxWidth: .infinity) diff --git a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift index 88d0fc6..8a28220 100644 --- a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift +++ b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift @@ -27,7 +27,7 @@ struct LiveRoomEditView: View { BaseView(isLoading: $viewModel.isLoading) { ZStack { VStack(spacing: 0) { - DetailNavigationBar(title: "라이브 수정") + DetailNavigationBar(title: I18n.CreateLive.editLiveTitle) ScrollView(.vertical, showsIndicators: false) { VStack(spacing: 0) { @@ -53,7 +53,7 @@ struct LiveRoomEditView: View { } if !viewModel.isLoading { - Text("라이브 수정") + Text(I18n.CreateLive.editLiveTitle) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.white) .frame(width: screenSize().width - 26.7, height: 50) @@ -94,13 +94,13 @@ struct LiveRoomEditView: View { @ViewBuilder func TitleInputView() -> some View { VStack(spacing: 0) { - Text("제목") + Text(I18n.CreateLive.titleLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color(hex: "eeeeee")) .padding(.horizontal, 13.3) .frame(width: screenSize().width, alignment: .leading) - TextField("라이브 제목을 입력하세요", text: $viewModel.title) + TextField(I18n.CreateLive.titlePlaceholder, text: $viewModel.title) .autocapitalization(.none) .disableAutocorrection(true) .appFont(size: 13.3, weight: .medium) @@ -121,16 +121,16 @@ struct LiveRoomEditView: View { func ContentInputView() -> some View { VStack(spacing: 13.3) { HStack(spacing: 0) { - Text("공지") + Text(I18n.CreateLive.noticeLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color(hex: "eeeeee")) Spacer() - Text("\(viewModel.notice.count)자") + Text(I18n.CreateLive.noticeCount(viewModel.notice.count)) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "ff5c49")) - Text(" / 1000자") + Text(I18n.CreateLive.noticeLimitSuffix) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "777777")) } @@ -151,7 +151,7 @@ struct LiveRoomEditView: View { func ReservationDateTimeView(buttonWidth: CGFloat) -> some View { HStack(spacing: 13.3) { VStack(alignment: .leading, spacing: 6.7) { - Text("예약 날짜") + Text(I18n.CreateLive.reservationDateLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "eeeeee")) @@ -171,7 +171,7 @@ struct LiveRoomEditView: View { } VStack(alignment: .leading, spacing: 6.7) { - Text("예약 시간") + Text(I18n.CreateLive.reservationTimeLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "eeeeee")) @@ -198,12 +198,12 @@ struct LiveRoomEditView: View { @ViewBuilder func NumberOfPeopleLimitView() -> some View { VStack(spacing: 13.3) { - Text("참여인원 설정") + Text(I18n.CreateLive.participantLimitLabel) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color(hex: "eeeeee")) .frame(width: screenSize().width - 26.7, alignment: .leading) - TextField("최대 인원 999명", text: $viewModel.numberOfPeople) + TextField(I18n.CreateLive.participantLimitPlaceholder, text: $viewModel.numberOfPeople) .autocapitalization(.none) .disableAutocorrection(true) .multilineTextAlignment(.center) @@ -285,7 +285,7 @@ struct LiveRoomEditView: View { .frame(width: proxy.size.width) Button(action: { self.isShowSelectDateView = false }) { - Text("확인") + Text(I18n.CreateLive.confirmButton) .appFont(size: 16) .foregroundColor(Color(hex: "eeeeee")) .padding(.vertical, 10) @@ -316,7 +316,7 @@ struct LiveRoomEditView: View { .frame(width: proxy.size.width - 53.4) Button(action: { self.isShowSelectTimeView = false }) { - Text("확인") + Text(I18n.CreateLive.confirmButton) .appFont(size: 16) .foregroundColor(Color(hex: "eeeeee")) .padding(.vertical, 10) diff --git a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift index 6147c0b..ce4919f 100644 --- a/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift +++ b/SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift @@ -51,7 +51,7 @@ final class LiveRoomEditViewModel: ObservableObject { } } - let placeholder = "라이브 공지를 입력하세요" + let placeholder = I18n.CreateLive.noticePlaceholder var room: GetRoomDetailResponse? = nil { didSet { @@ -103,7 +103,7 @@ final class LiveRoomEditViewModel: ObservableObject { request.beginDateTimeString == nil && request.genderRestriction == nil ) { - self.errorMessage = "변경사항이 없습니다." + self.errorMessage = I18n.CreateLive.noChangesMessage self.isShowPopup = true isLoading = false return @@ -135,7 +135,7 @@ final class LiveRoomEditViewModel: ObservableObject { let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { - self.errorMessage = "라이브 정보가 수정되었습니다." + self.errorMessage = I18n.CreateLive.editSuccessMessage self.isShowPopup = true DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { @@ -146,19 +146,19 @@ final class LiveRoomEditViewModel: ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "라이브 정보를 수정 하지 못했습니다.\n다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.CreateLive.editFailedMessage } self.isShowPopup = true } } catch { - self.errorMessage = "라이브 정보를 수정 하지 못했습니다.\n다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.CreateLive.editFailedMessage self.isShowPopup = true } } .store(in: &subscription) } else { - self.errorMessage = "라이브 정보를 수정 하지 못했습니다.\n다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.CreateLive.editFailedMessage self.isShowPopup = true self.isLoading = false } @@ -167,20 +167,20 @@ final class LiveRoomEditViewModel: ObservableObject { private func validate() -> Bool { if title.trimmingCharacters(in: .whitespaces).isEmpty { - self.errorMessage = "제목을 입력해 주세요." + self.errorMessage = I18n.CreateLive.enterTitle self.isShowPopup = true return false } let notice = notice.trimmingCharacters(in: .whitespacesAndNewlines) != placeholder ? notice : "" if notice.isEmpty && notice.count < 5 { - self.errorMessage = "공지를 5자 이상 입력해주세요." + self.errorMessage = I18n.CreateLive.enterNoticeMin5 self.isShowPopup = true return false } guard let numberOfPeople = Int(numberOfPeople), (numberOfPeople >= 3 && numberOfPeople <= 999) else { - self.errorMessage = "인원을 3~999명 사이로 입력해주세요." + self.errorMessage = I18n.CreateLive.enterPeopleRange self.isShowPopup = true return false } diff --git a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift index 258823b..79b885f 100644 --- a/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift +++ b/SodaLive/Sources/Live/Room/LiveRoomViewModel.swift @@ -133,7 +133,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { @Published var kickOutDesc = "" @Published var kickOutId = 0 { didSet { - kickOutDesc = "\(getUserNicknameAndProfileUrl(accountId: kickOutId).nickname)님을 내보내시겠어요?" + kickOutDesc = I18n.LiveRoom.kickOutQuestion(getUserNicknameAndProfileUrl(accountId: kickOutId).nickname) } } @@ -579,13 +579,13 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError } self.isShowErrorPopup = true } } catch { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } @@ -665,7 +665,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError } self.isShowErrorPopup = true @@ -674,7 +674,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.isLoading = false } catch { self.isLoading = false - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } } @@ -726,7 +726,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.popupContent = I18n.LiveRoom.chatFreezeBlockedMessage self.isShowPopup = true } else if isNoChatting { - self.popupContent = "\(remainingNoChattingTime)초 동안 채팅하실 수 없습니다" + self.popupContent = I18n.CreateLive.remainingNoChattingMessage(remainingNoChattingTime) self.isShowPopup = true } else if !chatMessage.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { let chatId = UUID().uuidString @@ -887,10 +887,10 @@ final class LiveRoomViewModel: NSObject, ObservableObject { func donation(can: Int, message: String = "", isSecret: Bool = false) { if isSecret && can < 10 { - popupContent = "비밀 미션은 최소 10캔 이상부터 이용이 가능합니다." + popupContent = I18n.LiveRoom.secretMissionMinimumCanMessage isShowPopup = true } else if can < 1 { - popupContent = "1캔 이상 후원하실 수 있습니다." + popupContent = I18n.LiveRoom.atLeastOneCanDonationMessage isShowPopup = true } else { isLoading = true @@ -916,9 +916,9 @@ final class LiveRoomViewModel: NSObject, ObservableObject { var rawMessage = "" if isSecret { - rawMessage = "\(can)캔으로 비밀미션을 보냈습니다.🤫" + rawMessage = I18n.LiveChat.canWithUnit(can) + I18n.LiveChat.secretMissionDonationSuffix } else { - rawMessage = "\(can)캔을 후원하셨습니다.💰🪙" + rawMessage = I18n.LiveChat.canWithUnit(can) + I18n.LiveChat.donationSuffix } let donationRawMessage = LiveRoomChatRawMessage( @@ -986,14 +986,14 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.popupContent = message } else { - self.popupContent = "후원에 실패했습니다.\n다시 후원해주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.popupContent = I18n.LiveRoom.donationFailedMessage } self.isShowPopup = true } } catch { self.isLoading = false - self.popupContent = "후원에 실패했습니다.\n다시 후원해주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.popupContent = I18n.LiveRoom.donationFailedMessage self.isShowPopup = true } } @@ -1022,20 +1022,20 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.isLoading = false if decoded.success { - self.popupContent = "후원에 실패했습니다.\n다시 후원해주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.popupContent = I18n.LiveRoom.donationFailedMessage self.isShowPopup = true } else { if let message = decoded.message { self.errorMessage = message } else { - self.popupContent = "후원에 실패한 캔이 환불되지 않았습니다\n고객센터로 문의해주세요." + self.popupContent = I18n.LiveRoom.donationRefundFailedMessage } self.isShowPopup = true } } catch { self.isLoading = false - self.popupContent = "후원에 실패한 캔이 환불되지 않았습니다\n고객센터로 문의해주세요." + self.popupContent = I18n.LiveRoom.donationRefundFailedMessage self.isShowPopup = true } } @@ -1045,7 +1045,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { func inviteSpeaker(peerId: Int) { agora.sendMessageToPeer(peerId: String(peerId), rawMessage: LiveRoomRequestType.INVITE_SPEAKER.rawValue.data(using: .utf8)!) { [unowned self] _, error in if error == nil { - self.popupContent = "스피커 요청을 보냈습니다.\n잠시만 기다려 주세요." + self.popupContent = I18n.CreateLive.speakerRequestSent self.isShowPopup = true } } @@ -1061,9 +1061,9 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self?.getRoomInfo() } - self.popupContent = "\(getUserNicknameAndProfileUrl(accountId: peerId).nickname)님을 스탭에서 해제했어요." + self.popupContent = I18n.LiveRoom.staffReleasedMessage(getUserNicknameAndProfileUrl(accountId: peerId).nickname) } else { - self.popupContent = "\(getUserNicknameAndProfileUrl(accountId: peerId).nickname)님을 리스너로 변경했어요." + self.popupContent = I18n.LiveRoom.changedToListenerMessage(getUserNicknameAndProfileUrl(accountId: peerId).nickname) } self.isShowPopup = true @@ -1161,7 +1161,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if decoded.success { self.role = .SPEAKER self.agora.setRole(role: .broadcaster) - self.popupContent = "스피커가 되었어요!" + self.popupContent = I18n.LiveRoom.becameSpeakerMessage self.isShowPopup = true self.isMute = false self.getRoomInfo() @@ -1257,11 +1257,11 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.agora.sendRawMessageToGroup(rawMessage: editRoomInfoMessage) } else { - self.errorMessage = decoded.message ?? "라이브 정보를 수정하지 못했습니다.\n다시 시도해 주세요." + self.errorMessage = decoded.message ?? I18n.CreateLive.editFailedMessage self.isShowErrorPopup = true } } catch { - self.errorMessage = "라이브 정보를 수정하지 못했습니다.\n다시 시도해 주세요." + self.errorMessage = I18n.CreateLive.editFailedMessage self.isShowErrorPopup = true } } @@ -1270,13 +1270,13 @@ final class LiveRoomViewModel: NSObject, ObservableObject { func selectMenuPreset(selectedMenuPreset: SelectedMenu) { if menuList.isEmpty && (selectedMenuPreset == .MENU_2 || selectedMenuPreset == .MENU_3) { - errorMessage = "메뉴 1을 먼저 설정하세요" + errorMessage = I18n.MissionMenu.needMenu1First isShowPopup = true return } if menuList.count == 1 && selectedMenuPreset == .MENU_3 { - errorMessage = "메뉴 1과 메뉴 2를 먼저 설정하세요" + errorMessage = I18n.MissionMenu.needMenu1And2First isShowPopup = true return } @@ -1342,14 +1342,14 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { onFailure() - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } @@ -1366,22 +1366,19 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let shareUrl = createOneLinkUrlWithURLComponents(params: params) { if liveRoomInfo.isPrivateRoom { - shareMessage = "\(UserDefaults.string(forKey: .nickname))님이 귀하를 보이스온 비공개라이브에 초대하였습니다.\n" + - "※ 라이브 참여: \(shareUrl)\n" + - "(입장 비밀번호: \(liveRoomInfo.password!))" + shareMessage = I18n.LiveRoom.invitePrivateLiveMessage(UserDefaults.string(forKey: .nickname), shareUrl, liveRoomInfo.password ?? "") } else { - shareMessage = "\(UserDefaults.string(forKey: .nickname))님이 귀하를 보이스온 공개라이브에 초대하였습니다.\n" + - "※ 라이브 참여: \(shareUrl)" + shareMessage = I18n.LiveRoom.invitePublicLiveMessage(UserDefaults.string(forKey: .nickname), shareUrl) } isShowShareView = true } else { - self.errorMessage = "공유링크를 생성하지 못했습니다.\n다시 시도해 주세요." + self.errorMessage = I18n.MemberChannel.shareLinkCreateFailed self.isShowErrorPopup = true return } } else { - self.errorMessage = "공유링크를 생성하지 못했습니다.\n다시 시도해 주세요." + self.errorMessage = I18n.MemberChannel.shareLinkCreateFailed self.isShowErrorPopup = true return } @@ -1409,7 +1406,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if decoded.success { let nickname = self.getUserNicknameAndProfileUrl(accountId: targetUserId).nickname self.agora.sendMessageToPeer(peerId: String(targetUserId), rawMessage: LiveRoomRequestType.KICK_OUT.rawValue.data(using: .utf8)!) { [unowned self] _, _ in - self.popupContent = "\(nickname)님을 내보냈습니다." + self.popupContent = I18n.LiveRoom.kickedOutMessage(nickname) self.isShowPopup = true } self.deleteChatsByUserId(userId: targetUserId) @@ -1459,12 +1456,12 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let data = decoded.data, decoded.success { self.donationStatus = data } else { - self.errorMessage = "후원현황을 가져오지 못했습니다\n다시 시도해 주세요." + self.errorMessage = I18n.LiveRoom.donationStatusFetchFailed self.isShowPopup = true } } catch { self.isLoading = false - self.errorMessage = "후원현황을 가져오지 못했습니다\n다시 시도해 주세요." + self.errorMessage = I18n.LiveRoom.donationStatusFetchFailed self.isShowPopup = true } } @@ -1492,12 +1489,12 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let data = decoded.data, decoded.success { self.heartStatus = data } else { - self.errorMessage = "하트 랭킹을 가져오지 못했습니다\n다시 시도해 주세요." + self.errorMessage = I18n.LiveRoom.heartRankingFetchFailed self.isShowPopup = true } } catch { self.isLoading = false - self.errorMessage = "하트 랭킹을 가져오지 못했습니다\n다시 시도해 주세요." + self.errorMessage = I18n.LiveRoom.heartRankingFetchFailed self.isShowPopup = true } } @@ -1547,13 +1544,13 @@ final class LiveRoomViewModel: NSObject, 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 } } @@ -1599,13 +1596,13 @@ final class LiveRoomViewModel: NSObject, 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 } } @@ -1721,21 +1718,21 @@ final class LiveRoomViewModel: NSObject, ObservableObject { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse<[LiveRoomDonationMessage]>.self, from: responseData) - if let data = decoded.data, decoded.success { - self.donationMessageList.removeAll() - self.donationMessageList.append(contentsOf: data) - self.donationMessageCount = data.count - } else { - if let message = decoded.message { - self.errorMessage = message + if let data = decoded.data, decoded.success { + self.donationMessageList.removeAll() + self.donationMessageList.append(contentsOf: data) + self.donationMessageCount = data.count } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." - } + if let message = decoded.message { + self.errorMessage = message + } else { + self.errorMessage = I18n.Common.commonError + } self.isShowPopup = true } } catch { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } @@ -1766,11 +1763,11 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.donationMessageList.removeAll() self.donationMessageList.append(contentsOf: filteredDonationMessageList) } else { - self.errorMessage = "메시지를 삭제하지 못했습니다.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } catch { - self.errorMessage = "메시지를 삭제하지 못했습니다.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } @@ -1795,20 +1792,20 @@ final class LiveRoomViewModel: NSObject, ObservableObject { let jsonDecoder = JSONDecoder() let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData) - if let data = decoded.data, decoded.success { - userProfile = data - isShowUserProfilePopup = true - } else { - if let message = decoded.message { - self.errorMessage = message + if let data = decoded.data, decoded.success { + userProfile = data + isShowUserProfilePopup = true } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." - } + if let message = decoded.message { + self.errorMessage = message + } else { + self.errorMessage = I18n.Common.commonError + } self.isShowPopup = true } } catch { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } @@ -1837,19 +1834,19 @@ final class LiveRoomViewModel: NSObject, ObservableObject { getRoomInfo() setManagerMessage() - self.popupContent = "\(getUserNicknameAndProfileUrl(accountId: userId).nickname)님을 스탭으로 지정했습니다." + self.popupContent = I18n.LiveRoom.assignedStaffMessage(getUserNicknameAndProfileUrl(accountId: userId).nickname) self.isShowPopup = true } 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 } } @@ -1875,7 +1872,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { func setNoChatting() { agora.sendMessageToPeer(peerId: String(noChattingUserId), rawMessage: LiveRoomRequestType.NO_CHATTING.rawValue.data(using: .utf8)!) { [unowned self] _, error in if error == nil { - self.popupContent = "\(noChattingUserNickname)님을 3분간 채팅금지를 하였습니다." + self.popupContent = I18n.LiveRoom.noChattingAppliedMessage(noChattingUserNickname) self.isShowPopup = true DispatchQueue.main.asyncAfter(deadline: .now() + 3) { @@ -1919,7 +1916,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { - self.reportMessage = "차단하였습니다." + self.reportMessage = I18n.MemberChannel.userBlocked self.getUserProfile(userId: reportUserId) onSuccess(reportUserId) @@ -1930,13 +1927,13 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.reportMessage = message } else { - self.reportMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.reportMessage = I18n.Common.commonError } } self.isShowReportPopup = true } catch { - self.reportMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.reportMessage = I18n.Common.commonError self.isShowReportPopup = true } } @@ -1964,7 +1961,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { - self.reportMessage = "차단이 해제 되었습니다." + self.reportMessage = I18n.MemberChannel.userUnblocked self.getUserProfile(userId: reportUserId) self.reportUserId = 0 self.reportUserNickname = "" @@ -1973,20 +1970,20 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.reportMessage = message } else { - self.reportMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.reportMessage = I18n.Common.commonError } } self.isShowReportPopup = true } catch { - self.reportMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.reportMessage = I18n.Common.commonError self.isShowReportPopup = true } } .store(in: &subscription) } - func report(type: ReportType, reason: String = "프로필 신고") { + func report(type: ReportType, reason: String = I18n.Dialog.MemberProfile.reportProfile) { isLoading = true let request = ReportRequest(type: type, reason: reason, reportedMemberId: reportUserId, cheersId: nil, audioContentId: nil) @@ -2013,12 +2010,12 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.reportMessage = message } else { - self.reportMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.reportMessage = I18n.Common.commonError } self.isShowReportPopup = true } catch { - self.reportMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.reportMessage = I18n.Common.commonError self.isShowReportPopup = true } } @@ -2037,7 +2034,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { private func startNoChatting() { isNoChatting = true remainingNoChattingTime = noChattingTime - popupContent = "\(self.getUserNicknameAndProfileUrl(accountId: liveRoomInfo!.creatorId).nickname)님이 3분간 채팅을 금지하였습니다." + popupContent = I18n.LiveRoom.noChattingByCreatorMessage(self.getUserNicknameAndProfileUrl(accountId: liveRoomInfo!.creatorId).nickname) isShowPopup = true startCountDown() @@ -2056,7 +2053,7 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.isNoChatting = false self.timer?.cancel() self.removeNoChatRoom() - self.popupContent = "채팅금지가 해제되었습니다." + self.popupContent = I18n.LiveRoom.noChattingReleasedMessage self.isShowPopup = true } } @@ -2217,12 +2214,12 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "룰렛을 사용할 수 없습니다. 다시 시도해 주세요." + self.errorMessage = I18n.CreateLive.rouletteUnavailableError } self.isShowErrorPopup = true } } catch { - self.errorMessage = "룰렛을 사용할 수 없습니다. 다시 시도해 주세요." + self.errorMessage = I18n.CreateLive.rouletteUnavailableError self.isShowErrorPopup = true } } @@ -2260,12 +2257,12 @@ final class LiveRoomViewModel: NSObject, ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "룰렛을 사용할 수 없습니다. 다시 시도해 주세요." + self.errorMessage = I18n.CreateLive.rouletteUnavailableError } self.isShowErrorPopup = true } } catch { - self.errorMessage = "룰렛을 사용할 수 없습니다. 다시 시도해 주세요." + self.errorMessage = I18n.CreateLive.rouletteUnavailableError self.isShowErrorPopup = true } } @@ -2367,20 +2364,20 @@ final class LiveRoomViewModel: NSObject, ObservableObject { self.isLoading = false if decoded.success { - self.popupContent = "후원에 실패했습니다.\n다시 후원해주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.popupContent = I18n.LiveRoom.donationFailedMessage self.isShowPopup = true } else { if let message = decoded.message { self.errorMessage = message } else { - self.popupContent = "후원에 실패한 캔이 환불되지 않았습니다\n고객센터로 문의해주세요." + self.popupContent = I18n.LiveRoom.donationRefundFailedMessage } self.isShowPopup = true } } catch { self.isLoading = false - self.popupContent = "후원에 실패한 캔이 환불되지 않았습니다\n고객센터로 문의해주세요." + self.popupContent = I18n.LiveRoom.donationRefundFailedMessage self.isShowPopup = true } } @@ -2978,7 +2975,7 @@ extension LiveRoomViewModel: AgoraRtcEngineDelegate { // 라이브 종료 self.deInitAgoraEngine() self.liveRoomInfo = nil - AppState.shared.errorMessage = "라이브가 종료되었습니다." + AppState.shared.errorMessage = I18n.LiveRoom.liveEndedMessage AppState.shared.isShowErrorPopup = true AppState.shared.roomId = 0 } else { @@ -3023,18 +3020,18 @@ extension LiveRoomViewModel: AgoraRtmClientDelegate { } if rawMessageString == LiveRoomRequestType.REQUEST_SPEAKER.rawValue { - self.popupContent = "\(nickname)님이 스피커 요청을 했어요!\n스퍼커로 초대할까요?" - self.popupCancelTitle = "건너뛰기" + self.popupContent = I18n.LiveRoom.speakerRequestQuestion(nickname) + self.popupCancelTitle = I18n.LiveRoom.skipAction self.popupCancelAction = { self.isShowPopup = false } - self.popupConfirmTitle = "스피커로 초대" + self.popupConfirmTitle = I18n.CreateLive.inviteSpeakerAction self.popupConfirmAction = { self.isShowPopup = false if self.liveRoomInfo!.speakerList.count <= 5 { self.requestSpeakerAllow(publisher) } else { - self.errorMessage = "스피커 정원이 초과되었습니다." + self.errorMessage = I18n.CreateLive.speakerCapacityExceeded self.isShowErrorPopup = true } } @@ -3043,12 +3040,12 @@ extension LiveRoomViewModel: AgoraRtmClientDelegate { } if rawMessageString == LiveRoomRequestType.INVITE_SPEAKER.rawValue && self.role == .LISTENER { - self.popupContent = "스피커로 초대되었어요" - self.popupCancelTitle = "다음에요" + self.popupContent = I18n.CreateLive.inviteSpeakerAction + self.popupCancelTitle = I18n.LiveRoom.maybeLaterAction self.popupCancelAction = { self.isShowPopup = false } - self.popupConfirmTitle = "스피커로 참여하기" + self.popupConfirmTitle = I18n.LiveRoom.joinAsSpeakerAction self.popupConfirmAction = { self.isShowPopup = false self.setSpeaker() @@ -3064,9 +3061,9 @@ extension LiveRoomViewModel: AgoraRtmClientDelegate { if rawMessageString == LiveRoomRequestType.KICK_OUT.rawValue { if let roomInfo = self.liveRoomInfo { - self.popupContent = "\(self.getUserNicknameAndProfileUrl(accountId: roomInfo.creatorId).nickname)님이 라이브에서 내보냈습니다." + self.popupContent = I18n.LiveRoom.kickedOutByCreatorMessage(self.getUserNicknameAndProfileUrl(accountId: roomInfo.creatorId).nickname) } else { - self.popupContent = "방장님이 라이브에서 내보냈습니다." + self.popupContent = I18n.LiveRoom.kickedOutByHostMessage } self.isShowPopup = true @@ -3085,18 +3082,18 @@ extension LiveRoomViewModel: AgoraRtmClientDelegate { } if let roomInfo = self.liveRoomInfo { - self.popupContent = "\(self.getUserNicknameAndProfileUrl(accountId: roomInfo.creatorId).nickname)님이 스탭으로 지정했습니다." + self.popupContent = I18n.LiveRoom.assignedStaffByCreatorMessage(self.getUserNicknameAndProfileUrl(accountId: roomInfo.creatorId).nickname) } else { - self.popupContent = "방장님이 스탭으로 지정했습니다" + self.popupContent = I18n.LiveRoom.assignedStaffByHostMessage } self.isShowPopup = true } if rawMessageString == LiveRoomRequestType.RELEASE_MANAGER.rawValue { if let roomInfo = self.liveRoomInfo { - self.popupContent = "\(self.getUserNicknameAndProfileUrl(accountId: roomInfo.creatorId).nickname)님이 스탭에서 해제했습니다." + self.popupContent = I18n.LiveRoom.releasedStaffByCreatorMessage(self.getUserNicknameAndProfileUrl(accountId: roomInfo.creatorId).nickname) } else { - self.popupContent = "방장님이 스탭에서 해제했습니다." + self.popupContent = I18n.LiveRoom.releasedStaffByHostMessage } self.isShowPopup = true } diff --git a/SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift b/SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift index 70ef863..232f9b0 100644 --- a/SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift +++ b/SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift @@ -18,12 +18,12 @@ struct LiveRoomMenuSelectView: View { var body: some View { VStack(alignment: .leading, spacing: 0) { - Text("메뉴") + Text(I18n.CreateLive.menuTitle) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color(hex: "eeeeee")) HStack(spacing: 0) { - Text("메뉴를 활성화 하시겠습니까?") + Text(I18n.CreateLive.menuActivatePrompt) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color(hex: "eeeeee")) @@ -72,7 +72,7 @@ struct LiveRoomMenuSelectView: View { TextViewWrapper( text: $menu, - placeholder: "메뉴판을 작성해주세요.", + placeholder: I18n.CreateLive.menuPlaceholder, textColorHex: "eeeeee", backgroundColorHex: "303030" ) diff --git a/SodaLive/Sources/Live/Room/Menu/MenuSettingsView.swift b/SodaLive/Sources/Live/Room/Menu/MenuSettingsView.swift index 7323541..0f04c3e 100644 --- a/SodaLive/Sources/Live/Room/Menu/MenuSettingsView.swift +++ b/SodaLive/Sources/Live/Room/Menu/MenuSettingsView.swift @@ -16,7 +16,7 @@ struct MenuSettingsView: View { var body: some View { BaseView(isLoading: $viewModel.isLoading) { VStack(spacing: 13.3) { - DetailNavigationBar(title: "메뉴 설정") { + DetailNavigationBar(title: I18n.MemberChannel.menuSettings) { isShowing = false } @@ -52,7 +52,7 @@ struct MenuSettingsView: View { TextViewWrapper( text: $viewModel.menu, - placeholder: "메뉴판을 작성해주세요.", + placeholder: I18n.CreateLive.menuPlaceholder, textColorHex: "eeeeee", backgroundColorHex: "303030" ) @@ -60,7 +60,7 @@ struct MenuSettingsView: View { .cornerRadius(6.7) .padding(.horizontal, 13.3) - Text("저장하기") + Text(I18n.CreateLive.saveMenuAction) .appFont(size: 18.3, weight: .bold) .foregroundColor(.white) .padding(.vertical, 16) diff --git a/SodaLive/Sources/Live/Room/Menu/MenuSettingsViewModel.swift b/SodaLive/Sources/Live/Room/Menu/MenuSettingsViewModel.swift index c2716d4..dba3af2 100644 --- a/SodaLive/Sources/Live/Room/Menu/MenuSettingsViewModel.swift +++ b/SodaLive/Sources/Live/Room/Menu/MenuSettingsViewModel.swift @@ -27,13 +27,13 @@ final class MenuSettingsViewModel: ObservableObject { func selectMenuPreset(selectedMenuPreset: SelectedMenu) { if menuList.isEmpty && (selectedMenuPreset == .MENU_2 || selectedMenuPreset == .MENU_3) { - errorMessage = "메뉴 1을 먼저 설정하세요" + errorMessage = I18n.MissionMenu.needMenu1First isShowPopup = true return } if menuList.count == 1 && selectedMenuPreset == .MENU_3 { - errorMessage = "메뉴 1과 메뉴 2를 먼저 설정하세요" + errorMessage = I18n.MissionMenu.needMenu1And2First isShowPopup = true return } @@ -82,14 +82,14 @@ final class MenuSettingsViewModel: ObservableObject { if let message = decoded.message { self.errorMessage = message } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError } self.isShowPopup = true } } catch { onFailure() - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowPopup = true } } @@ -98,7 +98,7 @@ final class MenuSettingsViewModel: ObservableObject { func saveMenu() { if selectedMenuText == menu { - self.errorMessage = "저장되었습니다." + self.errorMessage = I18n.CreateLive.menuSavedMessage self.isShowPopup = true return } @@ -122,20 +122,20 @@ final class MenuSettingsViewModel: ObservableObject { let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData) if decoded.success { - self.errorMessage = "저장되었습니다." + self.errorMessage = I18n.CreateLive.menuSavedMessage self.isShowPopup = true self.getAllMenuPreset(selectedMenu: self.selectedMenu ?? .MENU_1) {} } 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 } } diff --git a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift index 7ca394c..0617ab4 100644 --- a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift +++ b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift @@ -19,14 +19,14 @@ struct RouletteSettingsOptionView: View { var body: some View { VStack(spacing: 6.7) { HStack(spacing: 0) { - Text("옵션 \(index + 1)") + Text(I18n.CreateLive.rouletteOptionTitle(index)) .appFont(size: 14.7, weight: .medium) .foregroundColor(Color(hex: "eeeeee")) Spacer() if index > 1 { - Text("삭제") + Text(I18n.CreateLive.rouletteDeleteAction) .appFont(size: 14.7, weight: .medium) .foregroundColor(Color(hex: "ff5c49")) .onTapGesture { onClickDelete() } @@ -34,7 +34,7 @@ struct RouletteSettingsOptionView: View { } HStack(spacing: 8) { - TextField("옵션을 입력하세요", text: $option.title) + TextField(I18n.CreateLive.rouletteOptionPlaceholder, text: $option.title) .autocapitalization(.none) .disableAutocorrection(true) .appFont(size: 13.3, weight: .medium) diff --git a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift index b824edd..6e6510d 100644 --- a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift +++ b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift @@ -28,7 +28,7 @@ struct RouletteSettingsView: View { GeometryReader { proxy in BaseView(isLoading: $viewModel.isLoading) { VStack(spacing: 0) { - DetailNavigationBar(title: String(localized: "룰렛 설정")) { + DetailNavigationBar(title: I18n.CreateLive.rouletteSettingsTitle) { isShowing = false } @@ -73,7 +73,7 @@ struct RouletteSettingsView: View { if availableActive { HStack(spacing: 0) { - Text("룰렛을 활성화 하시겠습니까?") + Text(I18n.CreateLive.rouletteActivatePrompt) .appFont(size: 16, weight: .bold) .foregroundColor(Color.grayee) @@ -90,12 +90,12 @@ struct RouletteSettingsView: View { } VStack(alignment: .leading, spacing: 13.3) { - Text("룰렛 금액 설정") + Text(I18n.CreateLive.rouletteCanSettingTitle) .appFont(size: 16, weight: .bold) .foregroundColor(Color.grayee) HStack(spacing: 8) { - TextField("룰렛 금액을 입력해 주세요 (최소 5캔)", text: Binding( + TextField(I18n.CreateLive.rouletteCanPlaceholder, text: Binding( get: { self.viewModel.canText }, @@ -117,7 +117,7 @@ struct RouletteSettingsView: View { Spacer() - Text("캔") + Text(I18n.CreateLive.canUnit) .appFont(size: 16.7, weight: .bold) .foregroundColor(Color.grayee) } @@ -126,12 +126,12 @@ struct RouletteSettingsView: View { .id("roulette_can_input") VStack(alignment: .leading, spacing: 21.3) { - Text("룰렛 옵션 설정") + Text(I18n.CreateLive.rouletteOptionSettingTitle) .appFont(size: 16, weight: .bold) .foregroundColor(Color.grayee) HStack(spacing: 0) { - Text("※ 룰렛 옵션은 최소 2개,\n최대 10개까지 설정할 수 있습니다.") + Text(I18n.CreateLive.rouletteOptionLimitNotice) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.mainRed) @@ -144,7 +144,7 @@ struct RouletteSettingsView: View { .padding(.top, 26.7) HStack(spacing: 0) { - Text("옵션 확률 합계") + Text(I18n.CreateLive.rouletteProbabilitySum) .appFont(size: 14.7, weight: .medium) .foregroundColor(Color.grayee) @@ -186,7 +186,7 @@ struct RouletteSettingsView: View { Spacer() HStack(spacing: 13.3) { - Text("미리보기") + Text(I18n.CreateLive.roulettePreviewAction) .appFont(size: 18.3, weight: .bold) .foregroundColor(Color.button) .padding(.vertical, 16) @@ -200,7 +200,7 @@ struct RouletteSettingsView: View { viewModel.onClickPreview() } - Text("설정완료") + Text(I18n.CreateLive.rouletteCompleteAction) .appFont(size: 18.3, weight: .bold) .foregroundColor(.white) .padding(.vertical, 16) @@ -232,7 +232,7 @@ struct RouletteSettingsView: View { if let preview = viewModel.previewData, viewModel.isShowPreview { RoulettePreviewDialog( isShowing: $viewModel.isShowPreview, - title: "룰렛 미리보기", + title: I18n.CreateLive.roulettePreviewTitle, onClickSpin: nil, previewList: [preview] ) diff --git a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift index b26e293..4df3b10 100644 --- a/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift +++ b/SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift @@ -86,11 +86,11 @@ final class RouletteSettingsViewModel: ObservableObject { rouletteList.append(contentsOf: data) selectRoulette(selectedRoulette: .ROULETTE_1) } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } } catch { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } } @@ -104,7 +104,7 @@ final class RouletteSettingsViewModel: ObservableObject { for option in options { if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { isLoading = false - errorMessage = "옵션은 빈칸일 수 없습니다." + errorMessage = I18n.CreateLive.rouletteOptionEmptyError isShowErrorPopup = true return } @@ -137,7 +137,7 @@ final class RouletteSettingsViewModel: ObservableObject { for option in options { if option.title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { isLoading = false - errorMessage = "옵션은 빈칸일 수 없습니다." + errorMessage = I18n.CreateLive.rouletteOptionEmptyError isShowErrorPopup = true return false } @@ -149,7 +149,7 @@ final class RouletteSettingsViewModel: ObservableObject { if totalPercentage > Float(100.1) || totalPercentage <= Float(99.99) { isLoading = false - errorMessage = "확률이 100%가 아닙니다" + errorMessage = I18n.CreateLive.rouletteProbabilityInvalidError isShowErrorPopup = true return false } @@ -170,23 +170,23 @@ final class RouletteSettingsViewModel: ObservableObject { switch (self.selectedRoulette) { case .ROULETTE_2: - selectedRouletteTitle = "룰렛 2" + selectedRouletteTitle = I18n.Common.roulette2 case .ROULETTE_3: - selectedRouletteTitle = "룰렛 3" + selectedRouletteTitle = I18n.Common.roulette3 default: - selectedRouletteTitle = "룰렛 1" + selectedRouletteTitle = I18n.Common.roulette1 } if availableActive { if isActive { - successMessage = "\(selectedRouletteTitle)로 설정하였습니다." + successMessage = I18n.CreateLive.rouletteSetAsSuccess(selectedRouletteTitle) } else { - successMessage = "\(selectedRouletteTitle)을 설정했습니다." + successMessage = I18n.CreateLive.rouletteSetSuccess(selectedRouletteTitle) } } else { - successMessage = "\(selectedRouletteTitle)을 생성했습니다." + successMessage = I18n.CreateLive.rouletteCreatedSuccess(selectedRouletteTitle) } let request = CreateRouletteRequest(can: can, isActive: isActive, items: items) @@ -209,11 +209,11 @@ final class RouletteSettingsViewModel: ObservableObject { if decoded.success { onSuccess(isActive, successMessage) } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } } catch { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } } @@ -230,7 +230,7 @@ final class RouletteSettingsViewModel: ObservableObject { let selectedRoulette = rouletteList[selectedRoulette!.rawValue] if selectedRoulette.isActive == isActive && selectedRoulette.can == can && selectedRoulette.items == items { - self.errorMessage = "변동사항이 없습니다." + self.errorMessage = I18n.CreateLive.rouletteNoChangesMessage self.isShowErrorPopup = true self.isLoading = false return @@ -241,23 +241,23 @@ final class RouletteSettingsViewModel: ObservableObject { switch (self.selectedRoulette) { case .ROULETTE_2: - selectedRouletteTitle = "룰렛 2" + selectedRouletteTitle = I18n.Common.roulette2 case .ROULETTE_3: - selectedRouletteTitle = "룰렛 3" + selectedRouletteTitle = I18n.Common.roulette3 default: - selectedRouletteTitle = "룰렛 1" + selectedRouletteTitle = I18n.Common.roulette1 } if availableActive { if isActive { - successMessage = "\(selectedRouletteTitle)을 활성화 했습니다." + successMessage = I18n.CreateLive.rouletteActivatedSuccess(selectedRouletteTitle) } else { - successMessage = "\(selectedRouletteTitle)을 비활성화 했습니다." + successMessage = I18n.CreateLive.rouletteDeactivatedSuccess(selectedRouletteTitle) } } else { - successMessage = "\(selectedRouletteTitle)을 변경했습니다." + successMessage = I18n.CreateLive.rouletteChangedSuccess(selectedRouletteTitle) } let request = UpdateRouletteRequest(id: rouletteId, can: can, isActive: isActive, items: items) @@ -280,11 +280,11 @@ final class RouletteSettingsViewModel: ObservableObject { if decoded.success { onSuccess(isActive, successMessage) } else { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } } catch { - self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다." + self.errorMessage = I18n.Common.commonError self.isShowErrorPopup = true } } @@ -293,13 +293,13 @@ final class RouletteSettingsViewModel: ObservableObject { func selectRoulette(selectedRoulette: SelectedRoulette) { if rouletteList.isEmpty && (selectedRoulette == .ROULETTE_2 || selectedRoulette == .ROULETTE_3) { - errorMessage = "룰렛 1을 먼저 설정하세요" + errorMessage = I18n.CreateLive.rouletteNeedFirstMessage isShowErrorPopup = true return } if rouletteList.count == 1 && selectedRoulette == .ROULETTE_3 { - errorMessage = "룰렛 1과 룰렛 2를 먼저 설정하세요" + errorMessage = I18n.CreateLive.rouletteNeedFirstAndSecondMessage isShowErrorPopup = true return } diff --git a/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift b/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift index e6d93f3..5822063 100644 --- a/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift +++ b/SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift @@ -24,7 +24,7 @@ struct RoulettePreviewDialog: View { if previewList.count > 1 { HStack(spacing: 13.3) { SelectedButtonView( - title: "룰렛 1", + title: I18n.Common.roulette1, isActive: true, isSelected: selectedRoulette == .ROULETTE_1 ) @@ -35,7 +35,7 @@ struct RoulettePreviewDialog: View { } SelectedButtonView( - title: "룰렛 2", + title: I18n.Common.roulette2, isActive: true, isSelected: selectedRoulette == .ROULETTE_2, checkImage: "ic_select_check_black", @@ -51,7 +51,7 @@ struct RoulettePreviewDialog: View { if previewList.count > 2 { SelectedButtonView( - title: "룰렛 3", + title: I18n.Common.roulette3, isActive: true, isSelected: selectedRoulette == .ROULETTE_3, bgSelectedColor: Color(hex: "ff14d9"), @@ -68,7 +68,7 @@ struct RoulettePreviewDialog: View { } HStack(spacing: 0) { - Text(title ?? "룰렛") + Text(title ?? I18n.CreateLive.roulettePreviewTitle) .appFont(size: 18.3, weight: .bold) .foregroundColor(.white) @@ -109,7 +109,7 @@ struct RoulettePreviewDialog: View { .padding(.horizontal, 13.3) HStack(spacing: 13.3) { - Text("취소") + Text(I18n.Common.cancel) .appFont(size: 16, weight: .bold) .foregroundColor( selectedRoulette == .ROULETTE_2 ? Color(hex: "ffcb14") : @@ -131,7 +131,7 @@ struct RoulettePreviewDialog: View { isShowing = false } - Text("\(previewList[selectedRoulette.rawValue].can)캔으로 룰렛 돌리기") + Text(I18n.CreateLive.rouletteSpinWithCan(previewList[selectedRoulette.rawValue].can)) .appFont(size: 16, weight: .bold) .foregroundColor(selectedRoulette == .ROULETTE_2 ? .black : .white) .padding(.vertical, 16) diff --git a/SodaLive/Sources/Live/Room/V2/Component/Button/LiveRoomNewChatView.swift b/SodaLive/Sources/Live/Room/V2/Component/Button/LiveRoomNewChatView.swift index ad99b3c..bf916c8 100644 --- a/SodaLive/Sources/Live/Room/V2/Component/Button/LiveRoomNewChatView.swift +++ b/SodaLive/Sources/Live/Room/V2/Component/Button/LiveRoomNewChatView.swift @@ -17,7 +17,7 @@ struct LiveRoomNewChatView: View { HStack(spacing: 6.7) { Image("ic_bottom_white") - Text("새로운 채팅") + Text(I18n.CreateLive.newChatLabel) .appFont(size: 13.3, weight: .medium) .foregroundColor(Color.grayee) } diff --git a/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInputChatView.swift b/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInputChatView.swift index 6ba4be4..ff9e8b0 100644 --- a/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInputChatView.swift +++ b/SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInputChatView.swift @@ -17,7 +17,7 @@ struct LiveRoomInputChatView: View { var body: some View { HStack(spacing: 6.7) { - ChatTextFieldView(text: $chatMessage, placeholder: "채팅을 입력하세요", isEnabled: !isInputDisabled) { + ChatTextFieldView(text: $chatMessage, placeholder: I18n.LiveRoom.chatInputPlaceholder, isEnabled: !isInputDisabled) { if sendMessage(chatMessage) { chatMessage = "" } diff --git a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift index 7236455..df88d79 100644 --- a/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift +++ b/SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift @@ -56,7 +56,7 @@ struct LiveRoomViewV2: View { } if viewModel.isNoChatting { - return "\(viewModel.remainingNoChattingTime)초 동안 채팅하실 수 없습니다" + return I18n.CreateLive.remainingNoChattingMessage(viewModel.remainingNoChattingTime) } return I18n.LiveRoom.chatFreezeBlockedMessage @@ -494,7 +494,7 @@ struct LiveRoomViewV2: View { .padding(.leading, 13.3) VStack(alignment: .leading, spacing: 8) { - Text("[방송공지]") + Text(I18n.CreateLive.noticeTag) .appFont(size: 11.3, weight: .bold) .foregroundColor(.white) @@ -529,7 +529,7 @@ struct LiveRoomViewV2: View { ScrollView(.vertical) { VStack(alignment: .leading, spacing: 8) { - Text("[메뉴판]") + Text(I18n.CreateLive.menuTag) .appFont(size: 11.3, weight: .bold) .foregroundColor(.white) @@ -1104,10 +1104,10 @@ struct LiveRoomViewV2: View { private func inviteSpeaker(peerId: Int) { if viewModel.liveRoomInfo!.speakerList.count <= 5 { viewModel.inviteSpeaker(peerId: peerId) - self.viewModel.popupContent = "스피커 요청을 보냈습니다.\n잠시만 기다려 주세요." + self.viewModel.popupContent = I18n.CreateLive.speakerRequestSent self.viewModel.isShowPopup = true } else { - viewModel.popupContent = "스피커 정원을 초과했습니다." + viewModel.popupContent = I18n.CreateLive.speakerCapacityExceeded viewModel.isShowPopup = true } } diff --git a/SodaLive/Sources/Live/SectionCommunityPostView.swift b/SodaLive/Sources/Live/SectionCommunityPostView.swift index 218eb8c..0333490 100644 --- a/SodaLive/Sources/Live/SectionCommunityPostView.swift +++ b/SodaLive/Sources/Live/SectionCommunityPostView.swift @@ -14,7 +14,7 @@ struct SectionCommunityPostView: View { var body: some View { VStack(spacing: 16) { HStack(spacing: 0) { - Text("커뮤니티") + Text(I18n.CreateLive.communitySectionTitle) .appFont(size: 24, weight: .bold) .foregroundColor(.button) diff --git a/SodaLive/Sources/Live/SectionLatestFinishedLiveView.swift b/SodaLive/Sources/Live/SectionLatestFinishedLiveView.swift index 4ddd27e..3863244 100644 --- a/SodaLive/Sources/Live/SectionLatestFinishedLiveView.swift +++ b/SodaLive/Sources/Live/SectionLatestFinishedLiveView.swift @@ -16,7 +16,7 @@ struct SectionLatestFinishedLiveView: View { var body: some View { VStack(alignment: .leading, spacing: 16) { HStack(spacing: 0) { - Text("최근 종료한 라이브") + Text(I18n.CreateLive.latestFinishedSectionTitle) .appFont(size: 24, weight: .bold) .foregroundColor(.white) } diff --git a/docs/20260331_하드코딩텍스트_I18n통일계획.md b/docs/20260331_하드코딩텍스트_I18n통일계획.md index dfa5c31..dbbde39 100644 --- a/docs/20260331_하드코딩텍스트_I18n통일계획.md +++ b/docs/20260331_하드코딩텍스트_I18n통일계획.md @@ -343,48 +343,48 @@ - [x] `SodaLive/Sources/Live/Room/Chat/LiveRoomJoinChatItemView.swift` #### Group 3 (21-30) -- [ ] `SodaLive/Sources/Live/Room/Chat/LiveRoomRouletteDonationChatItemView.swift` -- [ ] `SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift` -- [ ] `SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagView.swift` -- [ ] `SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagViewModel.swift` -- [ ] `SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift` -- [ ] `SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageItemView.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingDialog.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingItemView.swift` +- [x] `SodaLive/Sources/Live/Room/Chat/LiveRoomRouletteDonationChatItemView.swift` +- [x] `SodaLive/Sources/Live/Room/Create/LiveRoomCreateView.swift` +- [x] `SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagView.swift` +- [x] `SodaLive/Sources/Live/Room/Create/Tag/LiveRoomCreateTagViewModel.swift` +- [x] `SodaLive/Sources/Live/Room/Detail/LiveDetailView.swift` +- [x] `SodaLive/Sources/Live/Room/Detail/LiveDetailViewModel.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageDialog.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationMessageItemView.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingDialog.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingItemView.swift` #### Group 4 (31-40) -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingTotalCanView.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingDialog.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingItemView.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomInfoEditDialog.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomNoChattingDialogView.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileDialog.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileItemTitleView.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomProfilesDialogView.swift` -- [ ] `SodaLive/Sources/Live/Room/Dialog/LiveRoomUserProfileDialogView.swift` -- [ ] `SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomDonationRankingTotalCanView.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingDialog.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomHeartRankingItemView.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomInfoEditDialog.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomNoChattingDialogView.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileDialog.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomProfileItemTitleView.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomProfilesDialogView.swift` +- [x] `SodaLive/Sources/Live/Room/Dialog/LiveRoomUserProfileDialogView.swift` +- [x] `SodaLive/Sources/Live/Room/Edit/LiveRoomEditView.swift` #### Group 5 (41-50) -- [ ] `SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift` -- [ ] `SodaLive/Sources/Live/Room/LiveRoomViewModel.swift` -- [ ] `SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift` -- [ ] `SodaLive/Sources/Live/Room/Menu/MenuSettingsView.swift` -- [ ] `SodaLive/Sources/Live/Room/Menu/MenuSettingsViewModel.swift` -- [ ] `SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift` -- [ ] `SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift` -- [ ] `SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift` -- [ ] `SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift` -- [ ] `SodaLive/Sources/Live/Room/V2/Component/Button/LiveRoomNewChatView.swift` +- [x] `SodaLive/Sources/Live/Room/Edit/LiveRoomEditViewModel.swift` +- [x] `SodaLive/Sources/Live/Room/LiveRoomViewModel.swift` +- [x] `SodaLive/Sources/Live/Room/Menu/LiveRoomMenuSelectView.swift` +- [x] `SodaLive/Sources/Live/Room/Menu/MenuSettingsView.swift` +- [x] `SodaLive/Sources/Live/Room/Menu/MenuSettingsViewModel.swift` +- [x] `SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsOptionView.swift` +- [x] `SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsView.swift` +- [x] `SodaLive/Sources/Live/Room/Routlette/Config/RouletteSettingsViewModel.swift` +- [x] `SodaLive/Sources/Live/Room/Routlette/RoulettePreviewDialog.swift` +- [x] `SodaLive/Sources/Live/Room/V2/Component/Button/LiveRoomNewChatView.swift` #### Group 6 (51-56) -- [ ] `SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoGuestView.swift` -- [ ] `SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoHostView.swift` -- [ ] `SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInputChatView.swift` -- [ ] `SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift` -- [ ] `SodaLive/Sources/Live/SectionCommunityPostView.swift` -- [ ] `SodaLive/Sources/Live/SectionLatestFinishedLiveView.swift` +- [x] `SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoGuestView.swift` +- [x] `SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInfoHostView.swift` +- [x] `SodaLive/Sources/Live/Room/V2/Component/View/LiveRoomInputChatView.swift` +- [x] `SodaLive/Sources/Live/Room/V2/LiveRoomViewV2.swift` +- [x] `SodaLive/Sources/Live/SectionCommunityPostView.swift` +- [x] `SodaLive/Sources/Live/SectionLatestFinishedLiveView.swift` ### Main (3) - [x] `SodaLive/Sources/Main/EventPopupDialogView.swift` @@ -930,3 +930,24 @@ - `SodaLive-dev` Debug 빌드는 병렬 실행 시 `build.db` lock으로 1회 실패 후, 단독 재실행에서 성공(`** BUILD SUCCEEDED **`). - 테스트 검증: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 테스트 액션 미구성 확인(코드 실패 아님, 스킴 제약). - LSP 진단: SourceKit 단독 해석 환경에서 외부 모듈/프로젝트 심볼 미해결 오류(`RefreshableScrollView`, `Kingfisher`, `AppState` 등)가 보고되나, 동일 변경셋은 `xcodebuild` 실컴파일 통과로 검증 완료. + +### 19차 구현 (Live 모듈 Group 3~6 마감 보정, 2026-04-01) +- 무엇/왜/어떻게: + - 무엇: Live Group 3~6 마감 단계에서 남아 있던 컴파일 오류(`I18n` 경로 오참조)를 수정하고, 체크리스트와 검증 기록을 최신화했다. + - 왜: 기존 치환 반영 이후 `LiveRoomViewModel.swift`의 일부 i18n 경로가 실제 `I18n.swift` 네임스페이스와 불일치해 빌드를 막고 있었기 때문이다. + - 어떻게: 오류 라인(1919, 1964, 1986)을 `I18n.swift` 정의와 대조해 정확한 경로로 교정한 뒤, `SodaLive`/`SodaLive-dev` Debug 빌드와 test 액션 상태를 재검증했다. +- 실행 명령/도구: + - `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` + - `read`/`grep`로 `LiveRoomViewModel.swift`, `I18n.swift`, 계획 문서 대조 +- 결과: + - `LiveRoomViewModel.swift` 경로 교정 완료: + - `I18n.LiveRoomPassword.MemberProfile.reportProfile` → `I18n.Dialog.MemberProfile.reportProfile` + - `I18n.ChannelManagement.userBlocked` → `I18n.MemberChannel.userBlocked` + - `I18n.ChannelManagement.userUnblocked` → `I18n.MemberChannel.userUnblocked` + - Live Group 3~6 체크박스 36개 `- [x]` 반영 완료. + - 빌드 검증: `SodaLive`, `SodaLive-dev` Debug 빌드 모두 오류 없이 완료(경고만 존재). + - 테스트 검증: 두 스킴 모두 `Scheme ... is not currently configured for the test action.`로 test action 미구성 확인(코드 실패 아님, 스킴 제약). + - LSP 진단 참고: 단일 파일 진단 시 `No such module 'Moya'`가 보고되나, SourceKit 단독 해석 한계이며 실제 `xcodebuild` 컴파일은 통과했다.