feat(i18n): 번역 작업 큐와 언어 감지 캐시를 도입한다

조회 중 외부 번역 호출을 줄이고 누락 번역을 비동기 job으로 처리한다.
This commit is contained in:
2026-05-06 18:02:36 +09:00
parent dfb97fba80
commit 3a0c30e340
30 changed files with 1561 additions and 848 deletions

View File

@@ -22,8 +22,6 @@ import kr.co.vividnext.sodalive.content.pin.PinContent
import kr.co.vividnext.sodalive.content.pin.PinContentRepository
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository
import kr.co.vividnext.sodalive.content.theme.translation.ContentThemeTranslationRepository
import kr.co.vividnext.sodalive.content.translation.ContentTranslation
import kr.co.vividnext.sodalive.content.translation.ContentTranslationPayload
import kr.co.vividnext.sodalive.content.translation.ContentTranslationRepository
import kr.co.vividnext.sodalive.content.translation.TranslatedContent
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
@@ -36,8 +34,7 @@ import kr.co.vividnext.sodalive.i18n.LangContext
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
import kr.co.vividnext.sodalive.i18n.translation.LanguageTranslationEvent
import kr.co.vividnext.sodalive.i18n.translation.LanguageTranslationTargetType
import kr.co.vividnext.sodalive.i18n.translation.PapagoTranslationService
import kr.co.vividnext.sodalive.i18n.translation.TranslateRequest
import kr.co.vividnext.sodalive.i18n.translation.ResourceTranslationJobScheduler
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import kr.co.vividnext.sodalive.member.contentpreference.isAdultVisibleByPolicy
@@ -70,7 +67,7 @@ class AudioContentService(
private val audioContentLikeRepository: AudioContentLikeRepository,
private val pinContentRepository: PinContentRepository,
private val translationService: PapagoTranslationService,
private val resourceTranslationJobScheduler: ResourceTranslationJobScheduler,
private val contentTranslationRepository: ContentTranslationRepository,
private val s3Uploader: S3Uploader,
@@ -770,7 +767,7 @@ class AudioContentService(
* TranslatedContent로 가공한다
*
* 번역 콘텐츠가 없으면
* 파파고 API를 통해 번역한 후 저장한다.
* 누락 번역 job을 예약하고 원문 응답을 유지한다.
*
* 번역 대상: title, detail, tags
*
@@ -792,49 +789,11 @@ class AudioContentService(
tags = payload.tags
)
} else {
val texts = mutableListOf<String>()
texts.add(audioContent.title)
texts.add(audioContent.detail)
texts.add(tag)
val sourceLanguage = audioContent.languageCode ?: "ko"
val response = translationService.translate(
request = TranslateRequest(
texts = texts,
sourceLanguage = sourceLanguage,
targetLanguage = langContext.lang.code
)
resourceTranslationJobScheduler.scheduleResourceTranslation(
resourceType = LanguageTranslationTargetType.CONTENT,
resourceId = audioContent.id!!,
targetLanguage = langContext.lang.code
)
val translatedTexts = response.translatedText
if (translatedTexts.size == texts.size) {
var index = 0
val translatedTitle = translatedTexts[index++]
val translatedDetail = translatedTexts[index++]
val translatedTags = translatedTexts[index]
val payload = ContentTranslationPayload(
title = translatedTitle,
detail = translatedDetail,
tags = translatedTags
)
contentTranslationRepository.save(
ContentTranslation(
contentId = audioContent.id!!,
locale = langContext.lang.code,
renderedPayload = payload
)
)
translated = TranslatedContent(
title = translatedTitle,
detail = translatedDetail,
tags = translatedTags
)
}
}
}