From ebe5c342c9587fd657d187bba9076e6bbc100911 Mon Sep 17 00:00:00 2001 From: klaus Date: Mon, 1 Dec 2025 16:32:53 +0900 Subject: [PATCH] =?UTF-8?q?ChatRoom=20=EB=AC=B8=EC=9E=90=EC=97=B4=20?= =?UTF-8?q?=EB=A6=AC=EC=86=8C=EC=8A=A4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChatBackgroundPickerDialogFragment.kt | 2 +- .../chat/talk/room/ChatMessageAdapter.kt | 3 +- .../chat/talk/room/ChatRoomActivity.kt | 47 +++++++++++-------- .../fragment_chat_background_picker.xml | 4 +- .../layout/fragment_chat_room_more_dialog.xml | 15 +++--- .../main/res/layout/item_chat_ai_message.xml | 2 +- .../res/layout/item_chat_background_image.xml | 2 +- .../res/layout/item_chat_quota_notice.xml | 7 +-- app/src/main/res/values-en/strings.xml | 30 ++++++++++++ app/src/main/res/values-ja/strings.xml | 30 ++++++++++++ app/src/main/res/values/strings.xml | 30 ++++++++++++ 11 files changed, 136 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatBackgroundPickerDialogFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatBackgroundPickerDialogFragment.kt index 794fa322..e98d78bc 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatBackgroundPickerDialogFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatBackgroundPickerDialogFragment.kt @@ -76,7 +76,7 @@ class ChatBackgroundPickerDialogFragment : DialogFragment() { private fun setupUi() { binding.ivClose.setOnClickListener { dismiss() } - binding.tvTitle.text = "배경 사진 선택" + binding.tvTitle.setText(R.string.chat_background_picker_title) binding.rvGrid.layoutManager = GridLayoutManager(requireContext(), 3) adapter = BgAdapter { item -> diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt index 6f0092db..b68cff28 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatMessageAdapter.kt @@ -583,7 +583,8 @@ class ChatMessageAdapter : RecyclerView.Adapter() { // 접근성: 다국어 대응 val ctx = itemView.context val messageWord = ctx.getString(R.string.a11y_message_word) - val spokenMain = if (isImageMsg) "이미지" else binding.tvMessage.text + val imageWord = ctx.getString(R.string.a11y_image) + val spokenMain = if (isImageMsg) imageWord else binding.tvMessage.text itemView.contentDescription = buildString { if (!isGrouped && !binding.tvName.text.isNullOrEmpty()) { append(binding.tvName.text) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt index 9e33a5e5..1a468891 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/talk/room/ChatRoomActivity.kt @@ -104,8 +104,11 @@ class ChatRoomActivity : BaseActivity( binding.ivBackgroundProfile.setImageResource(R.drawable.ic_placeholder_profile) // 배경은 서버 응답 수신 시 적용 (기본은 플레이스홀더 유지) // 배지는 기본 Clone으로 둔다가 실제 값으로 갱신 (디자인 기본 배경도 clone) - binding.tvCharacterTypeBadge.text = "Clone" + val badge = getString(R.string.chat_character_type_clone) + binding.tvCharacterTypeBadge.text = badge binding.tvCharacterTypeBadge.setBackgroundResource(R.drawable.bg_character_status_clone) + binding.ivProfile.contentDescription = + getString(R.string.chat_profile_image_content_description, badge) } } @@ -130,14 +133,15 @@ class ChatRoomActivity : BaseActivity( // 타입 배지 텍스트 및 배경 val (badgeText, badgeBg) = when (info.characterType) { - CharacterType.CLONE -> "Clone" to R.drawable.bg_character_status_clone - CharacterType.CHARACTER -> "Character" to R.drawable.bg_character_status_character + CharacterType.CLONE -> getString(R.string.chat_character_type_clone) to R.drawable.bg_character_status_clone + CharacterType.CHARACTER -> getString(R.string.chat_character_type_character) to R.drawable.bg_character_status_character } binding.tvCharacterTypeBadge.text = badgeText binding.tvCharacterTypeBadge.setBackgroundResource(badgeBg) // 접근성 - binding.ivProfile.contentDescription = "$badgeText 프로필 이미지" + binding.ivProfile.contentDescription = + getString(R.string.chat_profile_image_content_description, badgeText) // 5.4: 캐릭터 타입에 맞춰 안내 메시지 텍스트 갱신 updateNoticeText() @@ -384,7 +388,7 @@ class ChatRoomActivity : BaseActivity( // 실패: 타이핑 인디케이터 제거 및 FAILED로 업데이트 chatAdapter.hideTypingIndicator() updateUserMessageStatus(localId, MessageStatus.FAILED) - showToast(error.message ?: "메시지 전송에 실패했습니다.") + showToast(error.message ?: getString(R.string.chat_send_failed)) }) compositeDisposable.add(disposable) } @@ -445,7 +449,7 @@ class ChatRoomActivity : BaseActivity( chatAdapter.hideTypingIndicator() val now = System.currentTimeMillis() - val replyText = "안녕하세요! \"$userContent\"에 대한 답변입니다." + val replyText = getString(R.string.chat_mock_ai_reply, userContent) val aiMsg = ChatMessage( messageId = now, message = replyText, @@ -473,7 +477,7 @@ class ChatRoomActivity : BaseActivity( SharedPreferenceManager.can = newCan binding.tvCanBadge.text = newCan.moneyFormat() }, { err -> - showToast(err.message ?: "결제에 실패했습니다.") + showToast(err.message ?: getString(R.string.chat_quota_purchase_failed)) }) ) } @@ -665,7 +669,7 @@ class ChatRoomActivity : BaseActivity( }, { error -> isLoading = false // 오프라인/실패 시: 로컬 데이터가 이미 표시되어 있으면 그대로 유지 - showToast(error.message ?: "채팅방 데이터를 불러오지 못했습니다.") + showToast(error.message ?: getString(R.string.chat_room_load_failed)) }) compositeDisposable.add(networkDisposable) } @@ -776,7 +780,7 @@ class ChatRoomActivity : BaseActivity( ) }, { error -> isLoading = false - showToast(error.message ?: "이전 메시지를 불러오지 못했습니다.") + showToast(error.message ?: getString(R.string.chat_previous_messages_load_failed)) }) compositeDisposable.add(disposable) @@ -793,15 +797,15 @@ class ChatRoomActivity : BaseActivity( if (message.mine || !isLock) return val priceText = message.price?.toString() ?: "0" - val title = "잠금된 메시지" - val desc = "이 메시지를 ${priceText}캔으로 잠금해제 하시겠습니까?" + val title = getString(R.string.chat_locked_message_title) + val desc = getString(R.string.chat_locked_message_desc, priceText) SodaDialog( activity = this, layoutInflater = this.layoutInflater, title = title, desc = desc, - confirmButtonTitle = "잠금해제", + confirmButtonTitle = getString(R.string.chat_locked_message_confirm), confirmButtonClick = { val token = "Bearer ${SharedPreferenceManager.token}" val disposable = chatRepository.purchaseMessage( @@ -820,11 +824,11 @@ class ChatRoomActivity : BaseActivity( chatAdapter.setItems(items) } }, { error -> - showToast(error.message ?: "구매에 실패했습니다.") + showToast(error.message ?: getString(R.string.chat_purchase_message_failed)) }) compositeDisposable.add(disposable) }, - cancelButtonTitle = "취소", + cancelButtonTitle = getString(R.string.cancel), cancelButtonClick = { /* no-op */ } ).show(resources.displayMetrics.widthPixels) } @@ -903,19 +907,22 @@ class ChatRoomActivity : BaseActivity( } fun onResetChatRequested() { - val title = "대화 초기화" - val desc = "지금까지의 대화가 모두 초기화 되고 새롭게 대화를 시작합니다." + val title = getString(R.string.chat_reset_title) + val desc = getString(R.string.chat_reset_desc) SodaDialog( activity = this, layoutInflater = this.layoutInflater, title = title, desc = desc, - confirmButtonTitle = "30캔으로 초기화", + confirmButtonTitle = getString( + R.string.chat_reset_confirm, + getString(R.string.chat_reset_can_price) + ), confirmButtonClick = { val loadingDialog = LoadingDialog(this, layoutInflater) loadingDialog.show( screenWidth, - "대화 초기화 중..." + getString(R.string.chat_reset_loading) ) val token = "Bearer ${SharedPreferenceManager.token}" @@ -933,11 +940,11 @@ class ChatRoomActivity : BaseActivity( startActivity(intent) finish() }, { error -> - showToast(error.message ?: "대화 초기화에 실패했어요.") + showToast(error.message ?: getString(R.string.chat_reset_failed)) }) compositeDisposable.add(disposable) }, - cancelButtonTitle = "취소", + cancelButtonTitle = getString(R.string.cancel), cancelButtonClick = { /* no-op */ } ).show(resources.displayMetrics.widthPixels) } diff --git a/app/src/main/res/layout/fragment_chat_background_picker.xml b/app/src/main/res/layout/fragment_chat_background_picker.xml index 4bed8265..7c1619cd 100644 --- a/app/src/main/res/layout/fragment_chat_background_picker.xml +++ b/app/src/main/res/layout/fragment_chat_background_picker.xml @@ -20,7 +20,7 @@ android:id="@+id/iv_close" android:layout_width="24dp" android:layout_height="24dp" - android:contentDescription="닫기" + android:contentDescription="@string/a11y_close" android:src="@drawable/ic_back" /> diff --git a/app/src/main/res/layout/fragment_chat_room_more_dialog.xml b/app/src/main/res/layout/fragment_chat_room_more_dialog.xml index 141cf8b7..44ede99a 100644 --- a/app/src/main/res/layout/fragment_chat_room_more_dialog.xml +++ b/app/src/main/res/layout/fragment_chat_room_more_dialog.xml @@ -34,7 +34,7 @@ android:ellipsize="end" android:fontFamily="@font/pretendard_bold" android:maxLines="1" - android:text="대화 설정" + android:text="@string/chat_more_title" android:textColor="#FFFFFFFF" android:textSize="20sp" app:layout_constraintEnd_toEndOf="parent" @@ -69,7 +69,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:fontFamily="@font/pretendard_bold" - android:text="배경 이미지" + android:text="@string/chat_more_background_label" android:textColor="#B0BEC5" android:textSize="18sp" /> @@ -98,7 +98,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="배경 이미지 변경" + android:text="@string/chat_more_background_change" android:textColor="#B0BEC5" android:textSize="18sp" /> @@ -131,7 +131,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="대화 초기화" + android:text="@string/chat_reset_title" android:textColor="#B0BEC5" android:textSize="18sp" /> @@ -144,8 +144,9 @@ @@ -153,7 +154,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_regular" - android:text="지금까지의 대화가 모두 초기화 되고, 이용자가 새로운 캐릭터가 되어 새롭게 대화를 시작합니다." + android:text="@string/chat_reset_desc" android:textColor="#B3FFFFFF" android:textSize="14sp" /> @@ -181,7 +182,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="30" + android:text="@string/chat_reset_can_price" android:textColor="#263238" android:textSize="16sp" /> diff --git a/app/src/main/res/layout/item_chat_ai_message.xml b/app/src/main/res/layout/item_chat_ai_message.xml index 665561fd..281df1c0 100644 --- a/app/src/main/res/layout/item_chat_ai_message.xml +++ b/app/src/main/res/layout/item_chat_ai_message.xml @@ -137,7 +137,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="눌러서 잠금해제" + android:text="@string/chat_unlock_image_hint" android:textColor="@android:color/white" android:textSize="18sp" /> diff --git a/app/src/main/res/layout/item_chat_background_image.xml b/app/src/main/res/layout/item_chat_background_image.xml index 619d967c..97375a3b 100644 --- a/app/src/main/res/layout/item_chat_background_image.xml +++ b/app/src/main/res/layout/item_chat_background_image.xml @@ -38,7 +38,7 @@ android:paddingHorizontal="6dp" android:paddingVertical="2dp" android:includeFontPadding="false" - android:text="현재 배경" + android:text="@string/chat_background_current_label" android:textColor="#FFFFFF" android:textSize="12sp" android:visibility="gone" diff --git a/app/src/main/res/layout/item_chat_quota_notice.xml b/app/src/main/res/layout/item_chat_quota_notice.xml index 27220779..ea947c46 100644 --- a/app/src/main/res/layout/item_chat_quota_notice.xml +++ b/app/src/main/res/layout/item_chat_quota_notice.xml @@ -35,7 +35,7 @@ android:layout_height="wrap_content" android:layout_marginTop="8dp" android:fontFamily="@font/pretendard_bold" - android:text="기다리면 무료 이용이 가능합니다." + android:text="@string/chat_quota_notice_message" android:textColor="@color/white" android:textSize="18sp" /> @@ -63,16 +63,17 @@ android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" android:includeFontPadding="false" - android:text="10" + android:text="@string/chat_quota_price" android:textColor="#263238" android:textSize="24sp" /> diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 0690ed6e..a3bfe3d6 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -29,7 +29,35 @@ AI Clone converses based on the creator\'s information, but it may not perfectly reflect all details or match real conversations. VoiceOn AI Character Talk allows a high degree of freedom. You can be anyone in the conversation. Talk as a character in a universe or create your own story with a new persona together with the character.\nNote: AI Character Talk is in open beta; conversations may be awkward or incomplete. + Clone + Character + %1$s profile image Type a message. + Failed to send message. + Hello! Here is a reply to "%1$s". + Failed to purchase. + Failed to unlock the message. + Could not load chat room data. + Could not load previous messages. + Locked message + Unlock this message for %1$s cans? + Unlock + Reset chat + All previous chats will be cleared and a new conversation will start as a new character. + 30 + ⚠️ + Reset for %1$s cans + Resetting chat... + Failed to reset the chat. + Choose background image + Current background + Tap to unlock + You can use chat for free if you wait. + 10 + (12 chats) Start chatting now + Chat settings + Background image + Change background image Send Retry @@ -37,10 +65,12 @@ Profile background image Back Profile image + Close Notice Collapse AI profile image Typing… + Image My message diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 5567ceb1..2741c56e 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -29,7 +29,35 @@ AI Cloneはクリエイターの情報に基づいて会話しますが、すべての情報を完全に反映したり実際の会話と一致するとは限りません。 ボイスオンのAIキャラクタートークでは自由度の高い会話を楽しめます。あなたは誰にでもなれます。\n世界観のキャラクターとして話したり、新しい人物としてキャラクターとあなただけのストーリーを作ってみましょう。\n※ AIキャラクタートークはオープンベータのため、会話が不自然または不完全な場合があります。 + クローン + キャラクター + %1$sのプロフィール画像 メッセージを入力してください。 + メッセージの送信に失敗しました。 + こんにちは。「%1$s」への返信です。 + 購入に失敗しました。 + 購入に失敗しました。 + チャットルームのデータを読み込めませんでした。 + 以前のメッセージを読み込めませんでした。 + ロックされたメッセージ + このメッセージを%1$sキャンで解除しますか? + 解除 + チャットをリセット + これまでの会話がすべて初期化され、新しいキャラクターとして再開します。 + 30 + ⚠️ + %1$sキャンでリセット + チャットをリセット中... + チャットのリセットに失敗しました。 + 背景画像を選択 + 現在の背景 + タップして解除 + 待てば無料で利用できます。 + 10 + (チャット12件) すぐに開始 + チャット設定 + 背景画像 + 背景画像を変更 送信 再送 @@ -37,10 +65,12 @@ プロフィール背景画像 戻る プロフィール画像 + 閉じる お知らせ 折りたたむ AIプロフィール画像 相手が入力中 + 画像 自分のメッセージ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ca2eaf4..e460774e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -29,17 +29,47 @@ AI Clone은 크리에이터의 정보를 기반으로 대화하지만, 모든 정보를 완벽하게 반영하거나 실제 대화와 일치하지 않을 수 있습니다. 보이스온 AI캐릭터톡은 대화의 자유도가 높아 대화에 참여하는 당신은 누구든 될 수 있습니다.\n세계관 속 캐릭터로 대화를 하거나 새로운 인물로 캐릭터와 당신만의 스토리를 만들어보세요.\n※ AI캐릭터톡은 오픈베타 서비스 중이며, 캐릭터의 대화가 어색하거나 불완전할 수 있습니다. + Clone + Character + %1$s 프로필 이미지 메세지를 입력하세요. + 메시지 전송에 실패했습니다. + 안녕하세요! "%1$s"에 대한 답변입니다. + 결제에 실패했습니다. + 구매에 실패했습니다. + 채팅방 데이터를 불러오지 못했습니다. + 이전 메시지를 불러오지 못했습니다. + 잠금된 메시지 + 이 메시지를 %1$s캔으로 잠금해제 하시겠습니까? + 잠금해제 + 대화 초기화 + 지금까지의 대화가 모두 초기화 되고, 이용자가 새로운 캐릭터가 되어 새롭게 대화를 시작합니다. + 30 + ⚠️ + %1$s캔으로 초기화 + 대화 초기화 중... + 대화 초기화에 실패했어요. + 배경 이미지 선택 + 현재 배경 + 눌러서 잠금해제 + 기다리면 무료 이용이 가능합니다. + 10 + (채팅 12개) 바로 대화 시작 + 대화 설정 + 배경 이미지 + 배경 이미지 변경 전송 다시 전송 프로필 배경 이미지 뒤로가기 프로필 이미지 + 닫기 안내 접기 AI 프로필 이미지 상대방이 입력 중 + 이미지 내 메시지