diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt index eb8cbfb..6efc678 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/controller/OriginalWorkController.kt @@ -7,8 +7,10 @@ import kr.co.vividnext.sodalive.chat.original.dto.OriginalWorkDetailResponse import kr.co.vividnext.sodalive.chat.original.dto.OriginalWorkListItemResponse import kr.co.vividnext.sodalive.chat.original.dto.OriginalWorkListResponse import kr.co.vividnext.sodalive.chat.original.service.OriginalWorkQueryService +import kr.co.vividnext.sodalive.chat.original.translation.OriginalWorkTranslationRepository import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.i18n.LangContext import kr.co.vividnext.sodalive.member.Member import org.springframework.beans.factory.annotation.Value import org.springframework.security.core.annotation.AuthenticationPrincipal @@ -30,6 +32,10 @@ class OriginalWorkController( private val queryService: OriginalWorkQueryService, private val characterImageRepository: CharacterImageRepository, + private val langContext: LangContext, + + private val originalWorkTranslationRepository: OriginalWorkTranslationRepository, + @Value("\${cloud.aws.cloud-front.host}") private val imageHost: String ) { @@ -51,7 +57,57 @@ class OriginalWorkController( val includeAdult = member?.auth != null val pageRes = queryService.listForAppPage(includeAdult, page, size) val content = pageRes.content.map { OriginalWorkListItemResponse.from(it, imageHost) } - ApiResponse.ok(OriginalWorkListResponse(totalCount = pageRes.totalElements, content = content)) + + /** + * 원작 목록의 제목과 콘텐츠 타입을 현재 언어(locale)에 맞춰 일괄 번역한다. + * + * 처리 절차: + * - 입력된 원작들의 originalWorkId 집합을 만들고, 요청 언어 코드(langContext.lang.code)로 + * originalWorkTranslationRepository 번역 데이터를 한 번에 조회한다. + * - 각 항목에 대해 번역된 제목과 콘텐츠 타입이 존재하고 비어있지 않으면 title과 contentType을 번역 값으로 교체한다. + * - 번역이 없거나 공백이면 원본 항목을 그대로 반환한다. + * + * 성능: + * - N건의 항목을 1회의 조회로 해결하기 위해 IN 쿼리를 사용한다. + */ + val translatedContent = run { + if (content.isEmpty()) { + content + } else { + val ids = content.map { it.id }.toSet() + val locale = langContext.lang.code + val translations = originalWorkTranslationRepository + .findByOriginalWorkIdInAndLocale(ids, locale) + .associateBy { it.originalWorkId } + + content.map { item -> + val payload = translations[item.id]?.renderedPayload + if (payload != null) { + val newTitle = payload.title.trim() + val newContentType = payload.contentType.trim() + val hasTitle = newTitle.isNotEmpty() + val hasContentType = newContentType.isNotEmpty() + if (hasTitle || hasContentType) { + item.copy( + title = if (hasTitle) newTitle else item.title, + contentType = if (hasContentType) newContentType else item.contentType + ) + } else { + item + } + } else { + item + } + } + } + } + + ApiResponse.ok( + OriginalWorkListResponse( + totalCount = pageRes.totalElements, + content = translatedContent + ) + ) } /** diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/translation/OriginalWorkTranslationRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/translation/OriginalWorkTranslationRepository.kt index e63fbeb..0e88a4a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/translation/OriginalWorkTranslationRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/chat/original/translation/OriginalWorkTranslationRepository.kt @@ -4,4 +4,6 @@ import org.springframework.data.jpa.repository.JpaRepository interface OriginalWorkTranslationRepository : JpaRepository { fun findByOriginalWorkIdAndLocale(originalWorkId: Long, locale: String): OriginalWorkTranslation? + + fun findByOriginalWorkIdInAndLocale(originalWorkIds: Set, locale: String): List }