오디오 콘텐츠 전체 화면 문자열 리소스화

This commit is contained in:
2025-12-03 12:12:08 +09:00
parent 5a4b833516
commit a3fb090593
16 changed files with 161 additions and 54 deletions

View File

@@ -38,6 +38,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
private var userId: Long = 0
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
private val allCategoryLabel by lazy { getString(R.string.audio_content_label_all) }
override fun onCreate(savedInstanceState: Bundle?) {
userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
@@ -53,7 +54,11 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
super.onCreate(savedInstanceState)
if (userId <= 0) {
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
Toast.makeText(
applicationContext,
getString(R.string.screen_audio_content_error_invalid_request),
Toast.LENGTH_LONG
).show()
finish()
}
@@ -64,7 +69,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = "콘텐츠 전체보기"
binding.toolbar.tvBack.text = getString(R.string.screen_audio_content_title)
binding.toolbar.tvBack.setOnClickListener { finish() }
audioContentAdapter = AudioContentAdapter {
@@ -75,7 +80,9 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
activityResultLauncher.launch(intent)
}
categoryAdapter = AudioContentCategoryAdapter {
categoryAdapter = AudioContentCategoryAdapter(
allCategoryLabel = allCategoryLabel
) {
viewModel.selectCategory(it, userId = userId)
}
@@ -259,7 +266,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
if (it.isNotEmpty()) {
binding.rvCategory.visibility = View.VISIBLE
val items = it as MutableList<GetCategoryListResponse>
items.add(0, GetCategoryListResponse(0, "전체"))
items.add(0, GetCategoryListResponse(0, allCategoryLabel))
categoryAdapter.addItems(items = items)
} else {
binding.rvCategory.visibility = View.GONE

View File

@@ -66,7 +66,8 @@ class AudioContentAdapter(
} else {
binding.tvPrice.visibility = View.VISIBLE
if (item.price < 1) {
binding.tvPrice.text = "무료"
binding.tvPrice.text =
binding.root.context.getString(R.string.audio_content_price_free)
binding.tvPrice.setCompoundDrawables(null, null, null, null)
} else {
binding.tvPrice.text = item.price.moneyFormat()

View File

@@ -6,9 +6,11 @@ import com.google.gson.annotations.SerializedName
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.audio_content.category.GetCategoryListResponse
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
import kr.co.vividnext.sodalive.explorer.profile.GetAudioContentListResponse
class AudioContentViewModel(private val repository: AudioContentRepository) : BaseViewModel() {
@@ -80,7 +82,8 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
@@ -94,7 +97,10 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
_toastLiveData.postValue(
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
if (onFailure != null) {
onFailure()
}
@@ -134,7 +140,8 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
}
@@ -144,7 +151,10 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
_toastLiveData.postValue(
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
)
)

View File

@@ -57,9 +57,9 @@ class AudioContentAllActivity : BaseActivity<ActivityAudioContentAllBinding>(
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = when {
isPointOnly -> "포인트 대여 전체"
isFree -> "무료 콘텐츠 전체"
else -> "콘텐츠 전체보기"
isPointOnly -> getString(R.string.screen_audio_content_all_title_point_only)
isFree -> getString(R.string.screen_audio_content_all_title_free)
else -> getString(R.string.screen_audio_content_title)
}
binding.toolbar.tvBack.setOnClickListener { finish() }

View File

@@ -5,9 +5,11 @@ 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.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.home.AudioContentMainItem
@@ -46,6 +48,7 @@ class AudioContentAllViewModel(
isFree: Boolean? = null,
isPointAvailableOnly: Boolean? = null
) {
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
compositeDisposable.add(
repository.getAudioContentActiveThemeList(
isFree = isFree,
@@ -60,22 +63,20 @@ class AudioContentAllViewModel(
_themeListLiveData.postValue(it.data)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(unknownError)
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(unknownError)
}
)
)
}
@@ -85,6 +86,7 @@ class AudioContentAllViewModel(
) {
if (_isLoading.value == true || isLast) return
_isLoading.value = true
val unknownError = SodaLiveApplicationHolder.get().getString(R.string.common_error_unknown)
compositeDisposable.add(
repository.getAllAudioContents(
@@ -110,7 +112,7 @@ class AudioContentAllViewModel(
_isLoading.value = false
}, { t ->
_isLoading.value = false
_toastLiveData.postValue(t.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
_toastLiveData.postValue(t.message ?: unknownError)
})
)
}

View File

@@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemContentCategoryBinding
class AudioContentCategoryAdapter(
private val allCategoryLabel: String,
private val onClick: (Long) -> Unit
) : RecyclerView.Adapter<AudioContentCategoryAdapter.ViewHolder>() {
@@ -24,7 +25,7 @@ class AudioContentCategoryAdapter(
fun bind(item: GetCategoryListResponse) {
if (
item.category == selectedCategory ||
(selectedCategory == "" && item.category == "전체")
(selectedCategory.isEmpty() && item.category == allCategoryLabel)
) {
binding.tvCategory.setBackgroundResource(
R.drawable.bg_round_corner_16_7_transparent_3bb9f1

View File

@@ -7,9 +7,9 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemPlaylistListBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.R
class AudioContentPlaylistListAdapter(
private val onClickItem: (Long) -> Unit
@@ -20,7 +20,6 @@ class AudioContentPlaylistListAdapter(
inner class ViewHolder(
private val binding: ItemPlaylistListBinding
) : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bind(item: GetPlaylistsItem) {
binding.ivCover.load(item.coverImageUrl) {
crossfade(true)
@@ -29,7 +28,10 @@ class AudioContentPlaylistListAdapter(
}
binding.tvTitle.text = item.title
binding.tvContentCount.text = "${item.contentCount}"
binding.tvContentCount.text = binding.root.context.getString(
R.string.audio_content_playlist_content_count,
item.contentCount
)
if (item.desc.isNotBlank()) {
binding.tvDesc.text = item.desc

View File

@@ -1,14 +1,16 @@
package kr.co.vividnext.sodalive.audio_content.playlist
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.playlist.create.AudioContentPlaylistCreateActivity
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistDetailActivity
import kr.co.vividnext.sodalive.base.BaseFragment
@@ -43,6 +45,7 @@ class AudioContentPlaylistListFragment : BaseFragment<FragmentAudioContentPlayli
viewModel.getPlaylistList()
}
@OptIn(UnstableApi::class)
private fun setupView() {
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
adapter = AudioContentPlaylistListAdapter { playlistId ->
@@ -107,7 +110,6 @@ class AudioContentPlaylistListFragment : BaseFragment<FragmentAudioContentPlayli
}
}
@SuppressLint("SetTextI18n")
private fun bindData() {
viewModel.isLoading.observe(viewLifecycleOwner) {
if (it) {
@@ -122,7 +124,8 @@ class AudioContentPlaylistListFragment : BaseFragment<FragmentAudioContentPlayli
}
viewModel.totalCountLiveData.observe(viewLifecycleOwner) {
binding.tvTotalCount.text = "${it}"
binding.tvTotalCount.text =
getString(R.string.audio_content_playlist_total_count, it)
}
viewModel.playlistLiveData.observe(viewLifecycleOwner) {

View File

@@ -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.SodaLiveApplicationHolder
class AudioContentPlaylistListViewModel(
private val repository: AudioContentPlaylistRepository
@@ -44,7 +46,8 @@ class AudioContentPlaylistListViewModel(
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
}
@@ -52,7 +55,10 @@ class AudioContentPlaylistListViewModel(
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
_toastLiveData.postValue(
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
)
)

View File

@@ -28,7 +28,7 @@
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="17dp"
android:text="새로운 콘텐츠 등록하기"
android:text="@string/screen_audio_content_new_content"
android:textColor="@color/white"
android:textSize="14.7sp"
android:visibility="gone" />
@@ -49,7 +49,7 @@
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="최신순"
android:text="@string/screen_audio_content_sort_newest"
android:textColor="@color/color_88e2e2e2"
android:textSize="13.3sp" />
@@ -60,7 +60,7 @@
android:layout_marginHorizontal="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="높은 가격순"
android:text="@string/screen_audio_content_sort_price_high"
android:textColor="@color/color_88e2e2e2"
android:textSize="13.3sp" />
@@ -70,7 +70,7 @@
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="낮은 가격순"
android:text="@string/screen_audio_content_sort_price_low"
android:textColor="@color/color_88e2e2e2"
android:textSize="13.3sp" />
</LinearLayout>
@@ -88,7 +88,7 @@
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="전체"
android:text="@string/audio_content_label_all"
android:textColor="@color/color_e2e2e2"
android:textSize="13.3sp" />
@@ -109,7 +109,7 @@
android:layout_marginStart="2dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text=""
android:text="@string/audio_content_total_unit"
android:textColor="@color/color_e2e2e2"
android:textSize="13.3sp" />
</LinearLayout>

View File

@@ -32,7 +32,7 @@
android:layout_height="wrap_content"
android:fontFamily="@font/pretendard_medium"
android:gravity="center"
android:text="최신순"
android:text="@string/screen_audio_content_sort_newest"
android:textColor="@color/color_88e2e2e2"
android:textSize="16sp" />
@@ -43,7 +43,7 @@
android:layout_marginStart="12dp"
android:fontFamily="@font/pretendard_medium"
android:gravity="center"
android:text="인기순"
android:text="@string/screen_audio_content_sort_popularity"
android:textColor="@color/color_88e2e2e2"
android:textSize="16sp" />
</LinearLayout>
@@ -67,7 +67,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="표시할 콘텐츠가 없습니다."
android:text="@string/screen_audio_content_empty"
android:textColor="@color/color_d2d2d2"
android:textSize="14sp" />
</LinearLayout>

View File

@@ -16,7 +16,7 @@
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="13.3dp"
android:text="+ 새 재생목록 만들기"
android:text="@string/audio_content_playlist_create"
android:textColor="@color/white"
android:textSize="14.7sp"
app:layout_constraintEnd_toEndOf="parent"
@@ -38,7 +38,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="전체"
android:text="@string/audio_content_label_all"
android:textColor="@color/white"
android:textSize="14.7sp" />
@@ -82,7 +82,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="재생목록이 비어있습니다."
android:text="@string/audio_content_playlist_empty_title"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
@@ -92,7 +92,7 @@
android:layout_marginTop="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="자주 듣는 콘텐츠를\n재생목록으로 만들어 보세요."
android:text="@string/audio_content_playlist_empty_desc"
android:textColor="@color/color_bbbbbb"
android:textSize="11sp" />
</LinearLayout>

View File

@@ -36,7 +36,7 @@
android:background="@drawable/bg_round_corner_2_6_003851"
android:fontFamily="@font/gmarket_sans_medium"
android:padding="2.6dp"
android:text="오픈예정"
android:text="@string/audio_content_badge_scheduled"
android:textColor="@color/color_3bb9f1"
android:textSize="8sp"
android:visibility="gone"
@@ -78,7 +78,7 @@
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:padding="2.6dp"
android:text="포인트"
android:text="@string/audio_content_badge_point"
android:textColor="@color/white"
android:textSize="8sp"
android:visibility="gone"
@@ -196,7 +196,7 @@
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="5.3dp"
android:paddingVertical="2.7dp"
android:text="소장중"
android:text="@string/audio_content_badge_owned"
android:textColor="@color/color_111111"
android:textSize="13.3sp"
android:visibility="gone" />
@@ -209,7 +209,7 @@
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="5.3dp"
android:paddingVertical="2.7dp"
android:text="대여중"
android:text="@string/audio_content_badge_rented"
android:textColor="@color/white"
android:textSize="13.3sp"
android:visibility="gone" />
@@ -222,7 +222,7 @@
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="5.3dp"
android:paddingVertical="3.3dp"
android:text="Sold Out"
android:text="@string/audio_content_badge_sold_out"
android:textColor="@color/color_d2d2d2"
android:textSize="12sp"
android:visibility="gone" />

View File

@@ -831,6 +831,31 @@
<string name="screen_sign_out_submit">Delete account</string>
<string name="screen_sign_out_reason_required">Please select a reason for deleting your account.</string>
<!-- Audio Content -->
<string name="screen_audio_content_title">View all content</string>
<string name="screen_audio_content_all_title_free">All free content</string>
<string name="screen_audio_content_all_title_point_only">All point rentals</string>
<string name="screen_audio_content_error_invalid_request">Invalid request.</string>
<string name="screen_audio_content_new_content">Add new content</string>
<string name="screen_audio_content_sort_newest">Newest</string>
<string name="screen_audio_content_sort_price_high">Price: High to Low</string>
<string name="screen_audio_content_sort_price_low">Price: Low to High</string>
<string name="screen_audio_content_sort_popularity">Popularity</string>
<string name="screen_audio_content_empty">No content to display.</string>
<string name="audio_content_label_all">All</string>
<string name="audio_content_total_unit">items</string>
<string name="audio_content_price_free">Free</string>
<string name="audio_content_badge_scheduled">Coming soon</string>
<string name="audio_content_badge_point">Points</string>
<string name="audio_content_badge_owned">Owned</string>
<string name="audio_content_badge_rented">Rented</string>
<string name="audio_content_badge_sold_out">Sold Out</string>
<string name="audio_content_playlist_create">+ Create new playlist</string>
<string name="audio_content_playlist_total_count">%1$d items</string>
<string name="audio_content_playlist_content_count">Total %1$d items</string>
<string name="audio_content_playlist_empty_title">No playlists yet.</string>
<string name="audio_content_playlist_empty_desc">Create a playlist with your favorite content.</string>
<!-- Alarm -->
<string name="alarm_time_format">hh:mm</string>
<string name="alarm_date_format">MMM d</string>

View File

@@ -831,6 +831,31 @@
<string name="screen_sign_out_submit">退会する</string>
<string name="screen_sign_out_reason_required">退会理由を選択してください。</string>
<!-- Audio Content -->
<string name="screen_audio_content_title">コンテンツをすべて見る</string>
<string name="screen_audio_content_all_title_free">すべての無料コンテンツ</string>
<string name="screen_audio_content_all_title_point_only">ポイントレンタル一覧</string>
<string name="screen_audio_content_error_invalid_request">無効なリクエストです。</string>
<string name="screen_audio_content_new_content">新しいコンテンツを登録</string>
<string name="screen_audio_content_sort_newest">最新順</string>
<string name="screen_audio_content_sort_price_high">価格が高い順</string>
<string name="screen_audio_content_sort_price_low">価格が低い順</string>
<string name="screen_audio_content_sort_popularity">人気順</string>
<string name="screen_audio_content_empty">表示できるコンテンツがありません。</string>
<string name="audio_content_label_all">すべて</string>
<string name="audio_content_total_unit"></string>
<string name="audio_content_price_free">無料</string>
<string name="audio_content_badge_scheduled">オープン予定</string>
<string name="audio_content_badge_point">ポイント</string>
<string name="audio_content_badge_owned">所持中</string>
<string name="audio_content_badge_rented">レンタル中</string>
<string name="audio_content_badge_sold_out">売り切れ</string>
<string name="audio_content_playlist_create">+ 新しいプレイリストを作成</string>
<string name="audio_content_playlist_total_count">%1$d件</string>
<string name="audio_content_playlist_content_count">合計 %1$d件</string>
<string name="audio_content_playlist_empty_title">プレイリストが空です。</string>
<string name="audio_content_playlist_empty_desc">よく聴くコンテンツで\nプレイリストを作成してください。</string>
<!-- Alarm -->
<string name="alarm_time_format">hh:mm</string>
<string name="alarm_date_format">M月 d日</string>

View File

@@ -830,6 +830,31 @@
<string name="screen_sign_out_submit">탈퇴하기</string>
<string name="screen_sign_out_reason_required">계정을 삭제하려는 이유를 선택해 주세요.</string>
<!-- Audio Content -->
<string name="screen_audio_content_title">콘텐츠 전체보기</string>
<string name="screen_audio_content_all_title_free">무료 콘텐츠 전체</string>
<string name="screen_audio_content_all_title_point_only">포인트 대여 전체</string>
<string name="screen_audio_content_error_invalid_request">잘못된 요청입니다.</string>
<string name="screen_audio_content_new_content">새로운 콘텐츠 등록하기</string>
<string name="screen_audio_content_sort_newest">최신순</string>
<string name="screen_audio_content_sort_price_high">높은 가격순</string>
<string name="screen_audio_content_sort_price_low">낮은 가격순</string>
<string name="screen_audio_content_sort_popularity">인기순</string>
<string name="screen_audio_content_empty">표시할 콘텐츠가 없습니다.</string>
<string name="audio_content_label_all">전체</string>
<string name="audio_content_total_unit"></string>
<string name="audio_content_price_free">무료</string>
<string name="audio_content_badge_scheduled">오픈예정</string>
<string name="audio_content_badge_point">포인트</string>
<string name="audio_content_badge_owned">소장중</string>
<string name="audio_content_badge_rented">대여중</string>
<string name="audio_content_badge_sold_out">Sold Out</string>
<string name="audio_content_playlist_create">+ 새 재생목록 만들기</string>
<string name="audio_content_playlist_total_count">%1$d개</string>
<string name="audio_content_playlist_content_count">총 %1$d개</string>
<string name="audio_content_playlist_empty_title">재생목록이 비어있습니다.</string>
<string name="audio_content_playlist_empty_desc">자주 듣는 콘텐츠를\n재생목록으로 만들어 보세요.</string>
<!-- Alarm -->
<string name="alarm_time_format">hh:mm</string>
<string name="alarm_date_format">MM월 dd일</string>