diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt index 5c91b2a..1fc1586 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt @@ -4,8 +4,11 @@ import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.content.AudioContentRepository import kr.co.vividnext.sodalive.content.LanguageDetectEvent import kr.co.vividnext.sodalive.content.LanguageDetectTargetType +import kr.co.vividnext.sodalive.i18n.LangContext 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.member.Member import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import org.springframework.context.ApplicationEventPublisher @@ -18,8 +21,11 @@ class CategoryService( private val contentRepository: AudioContentRepository, private val blockMemberRepository: BlockMemberRepository, private val categoryContentRepository: CategoryContentRepository, + private val categoryTranslationRepository: CategoryTranslationRepository, - private val applicationEventPublisher: ApplicationEventPublisher + private val langContext: LangContext, + private val applicationEventPublisher: ApplicationEventPublisher, + private val translationService: PapagoTranslationService ) { @Transactional fun createCategory(request: CreateCategoryRequest, member: Member) { @@ -119,11 +125,83 @@ class CategoryService( } } + @Transactional fun getCategoryList(creatorId: Long, memberId: Long): List { val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = creatorId) if (isBlocked) throw SodaException("잘못된 접근입니다.") - return repository.findByCreatorId(creatorId = creatorId) + // 기본 카테고리 목록 조회 (원본 언어 기준) + val baseList = repository.findByCreatorId(creatorId = creatorId) + if (baseList.isEmpty()) return baseList + + val locale = langContext.lang.code + + // 원본 엔티티를 조회하여 languageCode 파악 + val categoryIds = baseList.map { it.categoryId } + val entities = repository.findAllById(categoryIds) + val entityMap = entities.associateBy { it.id!! } + + // 요청 로케일로 이미 저장된 번역 일괄 조회 + val translations = categoryTranslationRepository + .findByCategoryIdInAndLocale(categoryIds, locale) + .associateBy { it.categoryId } + + // 각 항목에 대해 번역 적용. 없으면 Papago로 번역 저장 후 적용 + val result = mutableListOf() + for (item in baseList) { + val entity = entityMap[item.categoryId] + if (entity == null) { + result.add(item) + continue + } + + val sourceLang = entity.languageCode + if (!sourceLang.isNullOrBlank() && sourceLang != locale) { + val existing = translations[item.categoryId] + if (existing != null && !existing.category.isNullOrBlank()) { + result.add(GetCategoryListResponse(categoryId = item.categoryId, category = existing.category)) + continue + } + + // 번역본이 없으면 Papago 번역 후 저장 + val texts = listOf(entity.title) + val response = translationService.translate( + request = TranslateRequest( + texts = texts, + sourceLanguage = sourceLang, + targetLanguage = locale + ) + ) + + val translatedTexts = response.translatedText + if (translatedTexts.size == texts.size) { + val translatedCategory = translatedTexts[0] + + val existingOne = categoryTranslationRepository + .findByCategoryIdAndLocale(entity.id!!, locale) + if (existingOne == null) { + categoryTranslationRepository.save( + CategoryTranslation( + categoryId = entity.id!!, + locale = locale, + category = translatedCategory + ) + ) + } else { + existingOne.category = translatedCategory + categoryTranslationRepository.save(existingOne) + } + + result.add(GetCategoryListResponse(categoryId = item.categoryId, category = translatedCategory)) + continue + } + } + + // 번역이 필요 없거나 실패한 경우 원본 사용 + result.add(item) + } + + return result } private fun validateTitle(title: String) { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryTranslationRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryTranslationRepository.kt index 92b8839..a99f61d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryTranslationRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryTranslationRepository.kt @@ -4,4 +4,6 @@ import org.springframework.data.jpa.repository.JpaRepository interface CategoryTranslationRepository : JpaRepository { fun findByCategoryIdAndLocale(categoryId: Long, locale: String): CategoryTranslation? + + fun findByCategoryIdInAndLocale(categoryIds: Collection, locale: String): List }