From 3cf24c2ab6829ca6f0be72f1e2e191b328f2779e Mon Sep 17 00:00:00 2001 From: klaus Date: Mon, 1 Dec 2025 17:00:26 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BA=90=EB=A6=AD=ED=84=B0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=A6=AC=EC=86=8C?= =?UTF-8?q?=EC=8A=A4=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CharacterDetail/갤러리 탭 다국어 리소스 추가 UiText로 오류 메시지 지역화 처리 --- .../detail/CharacterDetailActivity.kt | 12 ++++-- .../detail/detail/CharacterDetailFragment.kt | 37 ++++++++++--------- .../detail/detail/CharacterDetailViewModel.kt | 16 +++++--- .../gallery/CharacterGalleryFragment.kt | 26 +++++++++---- .../gallery/CharacterGalleryViewModel.kt | 16 +++++--- .../kr/co/vividnext/sodalive/common/UiText.kt | 16 ++++++++ .../res/layout/fragment_character_detail.xml | 26 ++++++------- .../res/layout/fragment_character_gallery.xml | 2 +- .../fragment_character_gallery_viewer.xml | 2 +- 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 +++++++++++++++ 12 files changed, 189 insertions(+), 54 deletions(-) create mode 100644 app/src/main/java/kr/co/vividnext/sodalive/common/UiText.kt diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt index a875d987..150f367f 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/CharacterDetailActivity.kt @@ -17,7 +17,7 @@ class CharacterDetailActivity : BaseActivity( val characterId = intent.getLongExtra(EXTRA_CHARACTER_ID, 0) if (characterId <= 0) { - showToast("잘못된 접근 입니다.") + showToast(getString(R.string.character_detail_error_invalid_access)) finish() return } @@ -28,11 +28,15 @@ class CharacterDetailActivity : BaseActivity( override fun setupView() { // 뒤로 가기 binding.detailToolbar.tvBack.setOnClickListener { finish() } - binding.detailToolbar.tvBack.text = "캐릭터 정보" + binding.detailToolbar.tvBack.text = getString(R.string.screen_character_detail_title) // 탭 구성: 상세, 갤러리 - binding.tabLayout.addTab(binding.tabLayout.newTab().setText("상세")) - binding.tabLayout.addTab(binding.tabLayout.newTab().setText("갤러리")) + binding.tabLayout.addTab( + binding.tabLayout.newTab().setText(R.string.screen_character_detail_tab_info) + ) + binding.tabLayout.addTab( + binding.tabLayout.newTab().setText(R.string.screen_character_detail_tab_gallery) + ) val characterId = intent.getLongExtra(EXTRA_CHARACTER_ID, 0) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt index 4aacb370..34dfba7b 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailFragment.kt @@ -92,10 +92,9 @@ class CharacterDetailFragment : BaseFragment( } // 2) 에러 토스트 처리 - state.error?.let { errorMsg -> - if (errorMsg.isNotBlank()) { - showToast(errorMsg) - } + state.error?.let { error -> + val message = error.asString(requireContext()) + if (message.isNotBlank()) showToast(message) } // 2-1) 채팅방 생성 성공 처리 (이벤트) @@ -143,7 +142,7 @@ class CharacterDetailFragment : BaseFragment( if (detail.age != null) { binding.tvAge.visibility = View.VISIBLE - binding.tvAge.text = "${detail.age}세" + binding.tvAge.text = getString(R.string.character_detail_age, detail.age) } else { binding.tvAge.visibility = View.GONE } @@ -167,8 +166,8 @@ class CharacterDetailFragment : BaseFragment( binding.tvCharacterName.text = detail.name binding.tvCharacterStatus.text = when (detail.characterType) { - CharacterType.CLONE -> "Clone" - CharacterType.CHARACTER -> "Character" + CharacterType.CLONE -> getString(R.string.chat_character_type_clone) + CharacterType.CHARACTER -> getString(R.string.chat_character_type_character) } // 캐릭터 타입에 따른 배경 설정 binding.tvCharacterStatus.setBackgroundResource( @@ -192,7 +191,7 @@ class CharacterDetailFragment : BaseFragment( // 표시 상태는 항상 접힘 상태로 시작 applyWorldviewCollapsedLayout() isWorldviewExpanded = false - binding.tvWorldviewExpand.text = "더보기" + binding.tvWorldviewExpand.text = getString(R.string.read_more) binding.ivWorldviewExpand.setImageResource(R.drawable.ic_chevron_down) } @@ -207,7 +206,7 @@ class CharacterDetailFragment : BaseFragment( binding.llPersonalityExpand.visibility = if (needExpand) View.VISIBLE else View.GONE applyPersonalityCollapsedLayout() isPersonalityExpanded = false - binding.tvPersonalityExpand.text = "더보기" + binding.tvPersonalityExpand.text = getString(R.string.read_more) binding.ivPersonalityExpand.setImageResource(R.drawable.ic_chevron_down) } @@ -300,7 +299,7 @@ class CharacterDetailFragment : BaseFragment( val idFromState = viewModel.uiState.value?.detail?.characterId ?: 0L val targetCharacterId = if (idFromState > 0) idFromState else characterId if (targetCharacterId <= 0) { - showToast("잘못된 접근 입니다.") + showToast(getString(R.string.character_detail_error_invalid_access)) return@setOnClickListener } @@ -313,13 +312,15 @@ class CharacterDetailFragment : BaseFragment( .subscribe({ resp -> if (resp.success) { binding.etCommentInput.setText("") - showToast("등록되었습니다.") + showToast(getString(R.string.character_detail_comment_register_success)) viewModel.load(targetCharacterId) } else { - showToast(resp.message ?: "요청 중 오류가 발생했습니다") + showToast( + resp.message ?: getString(R.string.common_error_request) + ) } }, { e -> - showToast(e.message ?: "요청 중 오류가 발생했습니다") + showToast(e.message ?: getString(R.string.common_error_request)) }) compositeDisposable.add(d) } @@ -384,7 +385,7 @@ class CharacterDetailFragment : BaseFragment( if (targetId > 0) { viewModel.createChatRoom(targetId) } else { - showToast("잘못된 접근 입니다.") + showToast(getString(R.string.character_detail_error_invalid_access)) } } } @@ -395,12 +396,12 @@ class CharacterDetailFragment : BaseFragment( // 확장 상태 binding.tvWorldviewContent.maxLines = Integer.MAX_VALUE binding.tvWorldviewContent.ellipsize = null - binding.tvWorldviewExpand.text = "간략히" + binding.tvWorldviewExpand.text = getString(R.string.read_less) binding.ivWorldviewExpand.setImageResource(R.drawable.ic_chevron_up) } else { // 접힘 상태 (3줄) applyWorldviewCollapsedLayout() - binding.tvWorldviewExpand.text = "더보기" + binding.tvWorldviewExpand.text = getString(R.string.read_more) binding.ivWorldviewExpand.setImageResource(R.drawable.ic_chevron_down) } } @@ -415,11 +416,11 @@ class CharacterDetailFragment : BaseFragment( if (isPersonalityExpanded) { binding.tvPersonalityContent.maxLines = Integer.MAX_VALUE binding.tvPersonalityContent.ellipsize = null - binding.tvPersonalityExpand.text = "간략히" + binding.tvPersonalityExpand.text = getString(R.string.read_less) binding.ivPersonalityExpand.setImageResource(R.drawable.ic_chevron_up) } else { applyPersonalityCollapsedLayout() - binding.tvPersonalityExpand.text = "더보기" + binding.tvPersonalityExpand.text = getString(R.string.read_more) binding.ivPersonalityExpand.setImageResource(R.drawable.ic_chevron_down) } } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt index fe119714..9cfef23a 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/detail/CharacterDetailViewModel.kt @@ -5,8 +5,10 @@ import androidx.lifecycle.MutableLiveData import com.orhanobut.logger.Logger import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.schedulers.Schedulers +import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.chat.talk.room.CreateChatRoomRequest +import kr.co.vividnext.sodalive.common.UiText import kr.co.vividnext.sodalive.common.SharedPreferenceManager /** @@ -24,7 +26,7 @@ class CharacterDetailViewModel( data class UiState( val detail: CharacterDetailResponse? = null, val isLoading: Boolean = false, - val error: String? = null, + val error: UiText? = null, val chatRoomId: Long? = null ) @@ -49,7 +51,9 @@ class CharacterDetailViewModel( _uiState.value = UiState( detail = null, isLoading = false, - error = response.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + error = response.message?.takeIf { it.isNotBlank() } + ?.let { UiText.DynamicString(it) } + ?: UiText.StringResource(R.string.common_error_unknown) ) } }, @@ -58,7 +62,7 @@ class CharacterDetailViewModel( _uiState.value = UiState( detail = null, isLoading = false, - error = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요." + error = UiText.StringResource(R.string.common_error_unknown) ) } ) @@ -89,7 +93,9 @@ class CharacterDetailViewModel( } else { _uiState.value = _uiState.value?.copy( isLoading = false, - error = response.message ?: "채팅방 생성에 실패했습니다. 다시 시도해 주세요." + error = response.message?.takeIf { it.isNotBlank() } + ?.let { UiText.DynamicString(it) } + ?: UiText.StringResource(R.string.character_detail_chat_room_create_failed) ) } }, @@ -97,7 +103,7 @@ class CharacterDetailViewModel( Logger.e(throwable, throwable.message ?: "") _uiState.value = _uiState.value?.copy( isLoading = false, - error = "채팅방 생성 중 오류가 발생했습니다. 다시 시도해 주세요." + error = UiText.StringResource(R.string.character_detail_chat_room_create_failed) ) } ) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryFragment.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryFragment.kt index 5673df23..d4bbadac 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryFragment.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryFragment.kt @@ -7,6 +7,7 @@ import android.view.View import androidx.core.graphics.toColorInt import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView +import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.base.BaseFragment import kr.co.vividnext.sodalive.base.SodaDialog import kr.co.vividnext.sodalive.chat.character.detail.CharacterDetailActivity.Companion.EXTRA_CHARACTER_ID @@ -106,11 +107,16 @@ class CharacterGalleryFragment : BaseFragment( binding.clRatio.visibility = View.VISIBLE val percent = (state.ratio * 100).toInt() - binding.tvRatioLeft.text = "$percent% 보유중" + binding.tvRatioLeft.text = + getString(R.string.character_gallery_ratio_owned, percent) val ownedStr = state.ownedCount.toString() val totalStr = state.totalCount.toString() - val fullText = "$ownedStr / ${totalStr}개" + val fullText = getString( + R.string.character_gallery_ratio_count, + state.ownedCount, + state.totalCount + ) val spannable = android.text.SpannableString(fullText) val ownedColor = "#FDD453".toColorInt() spannable.setSpan( @@ -132,7 +138,10 @@ class CharacterGalleryFragment : BaseFragment( binding.clRatio.visibility = View.GONE } - state.error?.let { showToast(it) } + state.error?.let { error -> + val message = error.asString(requireContext()) + if (message.isNotBlank()) showToast(message) + } } } @@ -140,13 +149,16 @@ class CharacterGalleryFragment : BaseFragment( SodaDialog( activity = requireActivity(), layoutInflater = this.layoutInflater, - title = "구매 확인", - desc = "선택한 이미지를 구매하시겠습니까?", - confirmButtonTitle = "${item.imagePriceCan}캔으로 구매", + title = getString(R.string.character_gallery_purchase_title), + desc = getString(R.string.character_gallery_purchase_desc), + confirmButtonTitle = getString( + R.string.character_gallery_purchase_confirm, + item.imagePriceCan + ), confirmButtonClick = { viewModel.purchaseImage(item.id, position) }, - cancelButtonTitle = "취소" + cancelButtonTitle = getString(R.string.cancel) ).show(screenWidth) } diff --git a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryViewModel.kt b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryViewModel.kt index 168b0b23..b4b0d75d 100644 --- a/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryViewModel.kt +++ b/app/src/main/java/kr/co/vividnext/sodalive/chat/character/detail/gallery/CharacterGalleryViewModel.kt @@ -5,8 +5,10 @@ import androidx.lifecycle.MutableLiveData import com.orhanobut.logger.Logger import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.schedulers.Schedulers +import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.common.SharedPreferenceManager +import kr.co.vividnext.sodalive.common.UiText class CharacterGalleryViewModel( private val repository: CharacterGalleryRepository @@ -18,7 +20,7 @@ class CharacterGalleryViewModel( val ratio: Float = 0f, // 0.0 ~ 1.0 val items: List = emptyList(), val isLoading: Boolean = false, - val error: String? = null + val error: UiText? = null ) private val _uiState = MutableLiveData(UiState()) @@ -92,7 +94,9 @@ class CharacterGalleryViewModel( } else { _uiState.value = _uiState.value?.copy( isLoading = isRequesting || isPurchasing, - error = response.message ?: "갤러리 정보를 불러오지 못했습니다." + error = response.message?.takeIf { it.isNotBlank() } + ?.let { UiText.DynamicString(it) } + ?: UiText.StringResource(R.string.character_gallery_load_error) ) } }, { throwable -> @@ -100,7 +104,7 @@ class CharacterGalleryViewModel( Logger.e(throwable, throwable.message ?: "") _uiState.value = _uiState.value?.copy( isLoading = isRequesting || isPurchasing, - error = "네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요." + error = UiText.StringResource(R.string.common_error_network_retry) ) }) ) @@ -153,7 +157,9 @@ class CharacterGalleryViewModel( ) } else { _uiState.value = _uiState.value?.copy( - error = response.message ?: "구매에 실패했습니다." + error = response.message?.takeIf { it.isNotBlank() } + ?.let { UiText.DynamicString(it) } + ?: UiText.StringResource(R.string.character_gallery_purchase_failed) ) } }, @@ -162,7 +168,7 @@ class CharacterGalleryViewModel( Logger.e(throwable, throwable.message ?: "") _uiState.value = _uiState.value?.copy( isLoading = isRequesting || isPurchasing, - error = "네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요." + error = UiText.StringResource(R.string.common_error_network_retry) ) } ) diff --git a/app/src/main/java/kr/co/vividnext/sodalive/common/UiText.kt b/app/src/main/java/kr/co/vividnext/sodalive/common/UiText.kt new file mode 100644 index 00000000..f837f107 --- /dev/null +++ b/app/src/main/java/kr/co/vividnext/sodalive/common/UiText.kt @@ -0,0 +1,16 @@ +package kr.co.vividnext.sodalive.common + +import android.content.Context +import androidx.annotation.StringRes + +sealed class UiText { + data class DynamicString(val value: String) : UiText() + class StringResource(@StringRes val resId: Int, vararg val args: Any) : UiText() { + val formatArgs: Array = args + } + + fun asString(context: Context): String = when (this) { + is DynamicString -> value + is StringResource -> context.getString(resId, *formatArgs) + } +} diff --git a/app/src/main/res/layout/fragment_character_detail.xml b/app/src/main/res/layout/fragment_character_detail.xml index 029ce1ff..ce7ce0e9 100644 --- a/app/src/main/res/layout/fragment_character_detail.xml +++ b/app/src/main/res/layout/fragment_character_detail.xml @@ -170,7 +170,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="[세계관 및 작품 소개]" + android:text="@string/character_detail_worldview_title" android:textColor="@color/white" android:textSize="16sp" /> @@ -209,7 +209,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_regular" - android:text="더보기" + android:text="@string/read_more" android:textColor="@color/color_607d8b" android:textSize="14sp" /> @@ -230,7 +230,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="[원작]" + android:text="@string/character_detail_original_title" android:textColor="@color/white" android:textSize="16sp" /> @@ -256,7 +256,7 @@ android:background="@drawable/bg_round_corner_16_stroke_3bb9f1" android:fontFamily="@font/pretendard_bold" android:gravity="center" - android:text="원작 보러가기" + android:text="@string/character_detail_original_link" android:textColor="@color/color_3bb9f1" android:textSize="16sp" /> @@ -276,7 +276,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="[성격 및 특징]" + android:text="@string/character_detail_personality_title" android:textColor="@color/white" android:textSize="16sp" /> @@ -315,7 +315,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_regular" - android:text="더보기" + android:text="@string/read_more" android:textColor="@color/color_607d8b" android:textSize="14sp" /> @@ -339,7 +339,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_bold" - android:text="⚠️ 캐릭터톡 대화 가이드" + android:text="@string/character_detail_chat_guide_title" android:textColor="@color/color_b0bec5" android:textSize="16sp" /> @@ -351,7 +351,7 @@ android:layout_marginTop="8dp" android:fontFamily="@font/pretendard_regular" android:lineSpacingExtra="4dp" - android:text="보이스온 AI캐릭터톡은 대화의 자유도가 높아 대화에 참여하는 당신은 누구든 될 수 있습니다.\n세계관 속 캐릭터로 대화를 하거나 새로운 인물로 캐릭터와 당신만의 스토리를 만들어보세요." + android:text="@string/character_detail_chat_guide_desc" android:textColor="@color/color_7c7c80" android:textSize="16sp" /> @@ -363,7 +363,7 @@ android:layout_marginTop="8dp" android:fontFamily="@font/pretendard_regular" android:lineSpacingExtra="4dp" - android:text="※ AI캐릭터톡은 오픈베타 서비스 중이며, 캐릭터의 대화가 어색하거나 불완전할 수 있습니다. 대화 초반에 캐릭터 붕괴가 느껴진다면 대화를 리셋하고 다시 시도해보세요." + android:text="@string/character_detail_chat_guide_notice" android:textColor="@color/color_7c7c80" android:textSize="14sp" /> @@ -393,7 +393,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:fontFamily="@font/pretendard_regular" - android:text="댓글" + android:text="@string/character_detail_comments_label" android:textColor="@color/color_b0bec5" android:textSize="16sp" /> @@ -479,7 +479,7 @@ android:layout_weight="1" android:background="@android:color/transparent" android:fontFamily="@font/pretendard_regular" - android:hint="댓글을 입력해보세요" + android:hint="@string/character_detail_comment_input_hint" android:imeOptions="actionSend" android:importantForAutofill="no" android:inputType="textCapSentences|textMultiLine" @@ -523,7 +523,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:fontFamily="@font/pretendard_bold" - android:text="장르의 다른 캐릭터" + android:text="@string/character_detail_other_characters_title" android:textColor="@color/white" android:textSize="26sp" /> @@ -550,7 +550,7 @@ android:background="@drawable/bg_round_corner_16_solid_3bb9f1" android:fontFamily="@font/pretendard_bold" android:gravity="center" - android:text="대화하기" + android:text="@string/character_detail_chat_button" android:textColor="@color/white" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/layout/fragment_character_gallery.xml b/app/src/main/res/layout/fragment_character_gallery.xml index 3d716c94..e57bb33d 100644 --- a/app/src/main/res/layout/fragment_character_gallery.xml +++ b/app/src/main/res/layout/fragment_character_gallery.xml @@ -79,7 +79,7 @@ android:layout_weight="1" android:fontFamily="@font/pretendard_bold" android:gravity="center" - android:text="갤러리가 비어있습니다" + android:text="@string/character_gallery_empty" android:textColor="@color/white" android:textSize="20sp" android:visibility="gone" /> diff --git a/app/src/main/res/layout/fragment_character_gallery_viewer.xml b/app/src/main/res/layout/fragment_character_gallery_viewer.xml index f2cfd046..96437d06 100644 --- a/app/src/main/res/layout/fragment_character_gallery_viewer.xml +++ b/app/src/main/res/layout/fragment_character_gallery_viewer.xml @@ -20,7 +20,7 @@ android:layout_height="40dp" android:layout_margin="16dp" android:background="@android:color/transparent" - android:contentDescription="close" + android:contentDescription="@string/a11y_close" android:scaleType="center" android:src="@android:drawable/ic_menu_close_clear_cancel" app:layout_constraintTop_toTopOf="parent" diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 43cc88a4..eac276f0 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -164,6 +164,36 @@ Complete Contents An unknown error occurred. Please try again. + An error occurred while processing the request. + A network error occurred. Please try again later. + + Character info + Details + Gallery + Invalid access. + %1$d years old + [World & Story Intro] + [Original work] + View original work + [Personality & Traits] + ⚠️ Character Talk Guide + VoiceOn AI Character Talk lets you become anyone in the conversation.\nChat as a story character or create your own role and build a story with the character. + ※ AI Character Talk is in open beta, so replies may be awkward or incomplete. If the character breaks early in the conversation, reset and try again. + Comments + Write a comment + Other characters in this genre + Start chat + Saved. + Failed to create a chat room. Please try again. + + No images in the gallery. + %1$d%% owned + %1$d / %2$d items + Purchase confirmation + Do you want to buy the selected image? + Buy with %1$d cans + Failed to load gallery info. + Failed to complete the purchase. Recent characters Popular characters New characters diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index cc9657f6..1e6c8c7a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -164,6 +164,36 @@ 完結 コンテンツ 不明なエラーが発生しました。もう一度お試しください。 + リクエスト処理中にエラーが発生しました。 + ネットワークエラーが発生しました。しばらくしてから再試行してください。 + + キャラクター情報 + 詳細 + ギャラリー + 不正なアクセスです。 + %1$d歳 + [世界観・作品紹介] + [原作] + 原作を見に行く + [性格・特徴] + ⚠️ キャラクタートークガイド + VoiceOn AIキャラクタートークは会話の自由度が高く、あなたは誰にでもなれます。\n世界観のキャラクターとして話すことも、新しい人物になってキャラクターと物語を作ることもできます。 + ※ AIキャラクタートークはオープンベータ中のため、会話が不自然または不完全な場合があります。会話の序盤でキャラクター崩壊を感じたら、リセットして再試行してください。 + コメント + コメントを入力してください + 同ジャンルの他のキャラクター + チャットする + 登録しました。 + チャットルームの作成に失敗しました。もう一度お試しください。 + + ギャラリーが空です + %1$d%% 保有中 + %1$d / %2$d件 + 購入確認 + 選択した画像を購入しますか? + %1$dキャンで購入 + ギャラリー情報を読み込めませんでした。 + 購入に失敗しました。 最近話したキャラクター 人気キャラクター 新着キャラクター diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2f364020..fb7671f9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -163,6 +163,36 @@ 완결 콘텐츠 알 수 없는 오류가 발생했습니다. 다시 시도해 주세요. + 요청 중 오류가 발생했습니다. + 네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요. + + 캐릭터 정보 + 상세 + 갤러리 + 잘못된 접근입니다. + %1$d세 + [세계관 및 작품 소개] + [원작] + 원작 보러가기 + [성격 및 특징] + ⚠️ 캐릭터톡 대화 가이드 + 보이스온 AI캐릭터톡은 대화의 자유도가 높아 대화에 참여하는 당신은 누구든 될 수 있습니다.\n세계관 속 캐릭터로 대화를 하거나 새로운 인물로 캐릭터와 당신만의 스토리를 만들어보세요. + ※ AI캐릭터톡은 오픈베타 서비스 중이며, 캐릭터의 대화가 어색하거나 불완전할 수 있습니다. 대화 초반에 캐릭터 붕괴가 느껴진다면 대화를 리셋하고 다시 시도해보세요. + 댓글 + 댓글을 입력해보세요 + 장르의 다른 캐릭터 + 대화하기 + 등록되었습니다. + 채팅방 생성에 실패했습니다. 다시 시도해 주세요. + + 갤러리가 비어있습니다 + %1$d%% 보유중 + %1$d / %2$d개 + 구매 확인 + 선택한 이미지를 구매하시겠습니까? + %1$d캔으로 구매 + 갤러리 정보를 불러오지 못했습니다. + 구매에 실패했습니다. 최근 대화한 캐릭터 인기 캐릭터 신규 캐릭터