캐릭터 상세 문자열 리소스화
CharacterDetail/갤러리 탭 다국어 리소스 추가 UiText로 오류 메시지 지역화 처리
This commit is contained in:
@@ -17,7 +17,7 @@ class CharacterDetailActivity : BaseActivity<ActivityCharacterDetailBinding>(
|
||||
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<ActivityCharacterDetailBinding>(
|
||||
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)
|
||||
|
||||
|
||||
@@ -92,10 +92,9 @@ class CharacterDetailFragment : BaseFragment<FragmentCharacterDetailBinding>(
|
||||
}
|
||||
|
||||
// 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<FragmentCharacterDetailBinding>(
|
||||
|
||||
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<FragmentCharacterDetailBinding>(
|
||||
|
||||
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<FragmentCharacterDetailBinding>(
|
||||
// 표시 상태는 항상 접힘 상태로 시작
|
||||
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<FragmentCharacterDetailBinding>(
|
||||
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<FragmentCharacterDetailBinding>(
|
||||
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<FragmentCharacterDetailBinding>(
|
||||
.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<FragmentCharacterDetailBinding>(
|
||||
if (targetId > 0) {
|
||||
viewModel.createChatRoom(targetId)
|
||||
} else {
|
||||
showToast("잘못된 접근 입니다.")
|
||||
showToast(getString(R.string.character_detail_error_invalid_access))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,12 +396,12 @@ class CharacterDetailFragment : BaseFragment<FragmentCharacterDetailBinding>(
|
||||
// 확장 상태
|
||||
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<FragmentCharacterDetailBinding>(
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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<FragmentCharacterGalleryBinding>(
|
||||
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<FragmentCharacterGalleryBinding>(
|
||||
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<FragmentCharacterGalleryBinding>(
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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<CharacterImageListItemResponse> = 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)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
16
app/src/main/java/kr/co/vividnext/sodalive/common/UiText.kt
Normal file
16
app/src/main/java/kr/co/vividnext/sodalive/common/UiText.kt
Normal file
@@ -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<out Any> = args
|
||||
}
|
||||
|
||||
fun asString(context: Context): String = when (this) {
|
||||
is DynamicString -> value
|
||||
is StringResource -> context.getString(resId, *formatArgs)
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
</LinearLayout>
|
||||
@@ -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" />
|
||||
</LinearLayout>
|
||||
@@ -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" />
|
||||
</LinearLayout>
|
||||
@@ -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" />
|
||||
</LinearLayout>
|
||||
@@ -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" />
|
||||
</LinearLayout>
|
||||
@@ -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"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -164,6 +164,36 @@
|
||||
<string name="screen_home_series_complete">Complete</string>
|
||||
<string name="screen_home_recommend_channel_content_label">Contents</string>
|
||||
<string name="common_error_unknown">An unknown error occurred. Please try again.</string>
|
||||
<string name="common_error_request">An error occurred while processing the request.</string>
|
||||
<string name="common_error_network_retry">A network error occurred. Please try again later.</string>
|
||||
<!-- Character detail -->
|
||||
<string name="screen_character_detail_title">Character info</string>
|
||||
<string name="screen_character_detail_tab_info">Details</string>
|
||||
<string name="screen_character_detail_tab_gallery">Gallery</string>
|
||||
<string name="character_detail_error_invalid_access">Invalid access.</string>
|
||||
<string name="character_detail_age">%1$d years old</string>
|
||||
<string name="character_detail_worldview_title">[World & Story Intro]</string>
|
||||
<string name="character_detail_original_title">[Original work]</string>
|
||||
<string name="character_detail_original_link">View original work</string>
|
||||
<string name="character_detail_personality_title">[Personality & Traits]</string>
|
||||
<string name="character_detail_chat_guide_title">⚠️ Character Talk Guide</string>
|
||||
<string name="character_detail_chat_guide_desc">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.</string>
|
||||
<string name="character_detail_chat_guide_notice">※ 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.</string>
|
||||
<string name="character_detail_comments_label">Comments</string>
|
||||
<string name="character_detail_comment_input_hint">Write a comment</string>
|
||||
<string name="character_detail_other_characters_title">Other characters in this genre</string>
|
||||
<string name="character_detail_chat_button">Start chat</string>
|
||||
<string name="character_detail_comment_register_success">Saved.</string>
|
||||
<string name="character_detail_chat_room_create_failed">Failed to create a chat room. Please try again.</string>
|
||||
<!-- Character gallery -->
|
||||
<string name="character_gallery_empty">No images in the gallery.</string>
|
||||
<string name="character_gallery_ratio_owned">%1$d%% owned</string>
|
||||
<string name="character_gallery_ratio_count">%1$d / %2$d items</string>
|
||||
<string name="character_gallery_purchase_title">Purchase confirmation</string>
|
||||
<string name="character_gallery_purchase_desc">Do you want to buy the selected image?</string>
|
||||
<string name="character_gallery_purchase_confirm">Buy with %1$d cans</string>
|
||||
<string name="character_gallery_load_error">Failed to load gallery info.</string>
|
||||
<string name="character_gallery_purchase_failed">Failed to complete the purchase.</string>
|
||||
<string name="screen_character_tab_recent_title">Recent characters</string>
|
||||
<string name="screen_character_tab_popular_title">Popular characters</string>
|
||||
<string name="screen_character_tab_new_title">New characters</string>
|
||||
|
||||
@@ -164,6 +164,36 @@
|
||||
<string name="screen_home_series_complete">完結</string>
|
||||
<string name="screen_home_recommend_channel_content_label">コンテンツ</string>
|
||||
<string name="common_error_unknown">不明なエラーが発生しました。もう一度お試しください。</string>
|
||||
<string name="common_error_request">リクエスト処理中にエラーが発生しました。</string>
|
||||
<string name="common_error_network_retry">ネットワークエラーが発生しました。しばらくしてから再試行してください。</string>
|
||||
<!-- Character detail -->
|
||||
<string name="screen_character_detail_title">キャラクター情報</string>
|
||||
<string name="screen_character_detail_tab_info">詳細</string>
|
||||
<string name="screen_character_detail_tab_gallery">ギャラリー</string>
|
||||
<string name="character_detail_error_invalid_access">不正なアクセスです。</string>
|
||||
<string name="character_detail_age">%1$d歳</string>
|
||||
<string name="character_detail_worldview_title">[世界観・作品紹介]</string>
|
||||
<string name="character_detail_original_title">[原作]</string>
|
||||
<string name="character_detail_original_link">原作を見に行く</string>
|
||||
<string name="character_detail_personality_title">[性格・特徴]</string>
|
||||
<string name="character_detail_chat_guide_title">⚠️ キャラクタートークガイド</string>
|
||||
<string name="character_detail_chat_guide_desc">VoiceOn AIキャラクタートークは会話の自由度が高く、あなたは誰にでもなれます。\n世界観のキャラクターとして話すことも、新しい人物になってキャラクターと物語を作ることもできます。</string>
|
||||
<string name="character_detail_chat_guide_notice">※ AIキャラクタートークはオープンベータ中のため、会話が不自然または不完全な場合があります。会話の序盤でキャラクター崩壊を感じたら、リセットして再試行してください。</string>
|
||||
<string name="character_detail_comments_label">コメント</string>
|
||||
<string name="character_detail_comment_input_hint">コメントを入力してください</string>
|
||||
<string name="character_detail_other_characters_title">同ジャンルの他のキャラクター</string>
|
||||
<string name="character_detail_chat_button">チャットする</string>
|
||||
<string name="character_detail_comment_register_success">登録しました。</string>
|
||||
<string name="character_detail_chat_room_create_failed">チャットルームの作成に失敗しました。もう一度お試しください。</string>
|
||||
<!-- Character gallery -->
|
||||
<string name="character_gallery_empty">ギャラリーが空です</string>
|
||||
<string name="character_gallery_ratio_owned">%1$d%% 保有中</string>
|
||||
<string name="character_gallery_ratio_count">%1$d / %2$d件</string>
|
||||
<string name="character_gallery_purchase_title">購入確認</string>
|
||||
<string name="character_gallery_purchase_desc">選択した画像を購入しますか?</string>
|
||||
<string name="character_gallery_purchase_confirm">%1$dキャンで購入</string>
|
||||
<string name="character_gallery_load_error">ギャラリー情報を読み込めませんでした。</string>
|
||||
<string name="character_gallery_purchase_failed">購入に失敗しました。</string>
|
||||
<string name="screen_character_tab_recent_title">最近話したキャラクター</string>
|
||||
<string name="screen_character_tab_popular_title">人気キャラクター</string>
|
||||
<string name="screen_character_tab_new_title">新着キャラクター</string>
|
||||
|
||||
@@ -163,6 +163,36 @@
|
||||
<string name="screen_home_series_complete">완결</string>
|
||||
<string name="screen_home_recommend_channel_content_label">콘텐츠</string>
|
||||
<string name="common_error_unknown">알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.</string>
|
||||
<string name="common_error_request">요청 중 오류가 발생했습니다.</string>
|
||||
<string name="common_error_network_retry">네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.</string>
|
||||
<!-- Character detail -->
|
||||
<string name="screen_character_detail_title">캐릭터 정보</string>
|
||||
<string name="screen_character_detail_tab_info">상세</string>
|
||||
<string name="screen_character_detail_tab_gallery">갤러리</string>
|
||||
<string name="character_detail_error_invalid_access">잘못된 접근입니다.</string>
|
||||
<string name="character_detail_age">%1$d세</string>
|
||||
<string name="character_detail_worldview_title">[세계관 및 작품 소개]</string>
|
||||
<string name="character_detail_original_title">[원작]</string>
|
||||
<string name="character_detail_original_link">원작 보러가기</string>
|
||||
<string name="character_detail_personality_title">[성격 및 특징]</string>
|
||||
<string name="character_detail_chat_guide_title">⚠️ 캐릭터톡 대화 가이드</string>
|
||||
<string name="character_detail_chat_guide_desc">보이스온 AI캐릭터톡은 대화의 자유도가 높아 대화에 참여하는 당신은 누구든 될 수 있습니다.\n세계관 속 캐릭터로 대화를 하거나 새로운 인물로 캐릭터와 당신만의 스토리를 만들어보세요.</string>
|
||||
<string name="character_detail_chat_guide_notice">※ AI캐릭터톡은 오픈베타 서비스 중이며, 캐릭터의 대화가 어색하거나 불완전할 수 있습니다. 대화 초반에 캐릭터 붕괴가 느껴진다면 대화를 리셋하고 다시 시도해보세요.</string>
|
||||
<string name="character_detail_comments_label">댓글</string>
|
||||
<string name="character_detail_comment_input_hint">댓글을 입력해보세요</string>
|
||||
<string name="character_detail_other_characters_title">장르의 다른 캐릭터</string>
|
||||
<string name="character_detail_chat_button">대화하기</string>
|
||||
<string name="character_detail_comment_register_success">등록되었습니다.</string>
|
||||
<string name="character_detail_chat_room_create_failed">채팅방 생성에 실패했습니다. 다시 시도해 주세요.</string>
|
||||
<!-- Character gallery -->
|
||||
<string name="character_gallery_empty">갤러리가 비어있습니다</string>
|
||||
<string name="character_gallery_ratio_owned">%1$d%% 보유중</string>
|
||||
<string name="character_gallery_ratio_count">%1$d / %2$d개</string>
|
||||
<string name="character_gallery_purchase_title">구매 확인</string>
|
||||
<string name="character_gallery_purchase_desc">선택한 이미지를 구매하시겠습니까?</string>
|
||||
<string name="character_gallery_purchase_confirm">%1$d캔으로 구매</string>
|
||||
<string name="character_gallery_load_error">갤러리 정보를 불러오지 못했습니다.</string>
|
||||
<string name="character_gallery_purchase_failed">구매에 실패했습니다.</string>
|
||||
<string name="screen_character_tab_recent_title">최근 대화한 캐릭터</string>
|
||||
<string name="screen_character_tab_popular_title">인기 캐릭터</string>
|
||||
<string name="screen_character_tab_new_title">신규 캐릭터</string>
|
||||
|
||||
Reference in New Issue
Block a user