diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/LanguageTranslationEvent.kt b/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/LanguageTranslationEvent.kt index 75763590..b266e4c7 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/LanguageTranslationEvent.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/LanguageTranslationEvent.kt @@ -18,7 +18,8 @@ enum class LanguageTranslationTargetType { ORIGINAL_WORK, - CREATOR_CONTENT_CATEGORY + CREATOR_CONTENT_CATEGORY, + CREATOR_COMMUNITY } class LanguageTranslationEvent( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationSourceExtractor.kt b/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationSourceExtractor.kt index a7f84596..9175c79c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationSourceExtractor.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationSourceExtractor.kt @@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.chat.original.OriginalWorkRepository import kr.co.vividnext.sodalive.content.AudioContentRepository import kr.co.vividnext.sodalive.content.category.CategoryRepository import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityRepository import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Component @@ -19,7 +20,8 @@ data class TranslationSource( val resourceType: LanguageTranslationTargetType, val resourceId: Long, val sourceLanguage: String, - val fields: List + val fields: List, + val sourceRevision: Long? = null ) @Component @@ -30,7 +32,8 @@ class TranslationSourceExtractor( private val seriesRepository: AdminContentSeriesRepository, private val seriesGenreRepository: AdminContentSeriesGenreRepository, private val originalWorkRepository: OriginalWorkRepository, - private val categoryRepository: CategoryRepository + private val categoryRepository: CategoryRepository, + private val creatorCommunityRepository: CreatorCommunityRepository ) { fun extract(resourceType: LanguageTranslationTargetType, resourceId: Long): TranslationSource? { return when (resourceType) { @@ -41,6 +44,7 @@ class TranslationSourceExtractor( LanguageTranslationTargetType.SERIES_GENRE -> extractSeriesGenre(resourceId) LanguageTranslationTargetType.ORIGINAL_WORK -> extractOriginalWork(resourceId) LanguageTranslationTargetType.CREATOR_CONTENT_CATEGORY -> extractCategory(resourceId) + LanguageTranslationTargetType.CREATOR_COMMUNITY -> extractCreatorCommunity(resourceId) } } @@ -152,4 +156,16 @@ class TranslationSourceExtractor( fields = listOf(TranslationSourceField("category", category.title)) ) } + + private fun extractCreatorCommunity(resourceId: Long): TranslationSource? { + val creatorCommunity = creatorCommunityRepository.findByIdAndIsActiveTrue(resourceId) ?: return null + val sourceLanguage = creatorCommunity.languageCode?.takeIf { it.isNotBlank() } ?: return null + return TranslationSource( + resourceType = LanguageTranslationTargetType.CREATOR_COMMUNITY, + resourceId = resourceId, + sourceLanguage = sourceLanguage, + fields = listOf(TranslationSourceField("content", creatorCommunity.content)), + sourceRevision = creatorCommunity.contentRevision + ) + } } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationJobWorkerTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationJobWorkerTest.kt index 6c2ea3f0..1bf48ef7 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationJobWorkerTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/i18n/translation/TranslationJobWorkerTest.kt @@ -75,6 +75,51 @@ class TranslationJobWorkerTest { Mockito.verify(materializer, Mockito.times(1)).materialize(LanguageTranslationTargetType.CONTENT, 10L, "en") } + @Test + fun shouldUseExistingMemoryBeforeMaterializingCreatorCommunity() { + val jobRepository = Mockito.mock(TranslationJobRepository::class.java) + val memoryRepository = Mockito.mock(TranslationMemoryRepository::class.java) + val provider = failingProvider() + val materializer = Mockito.mock(TranslationReadModelMaterializer::class.java) + val worker = TranslationJobWorker( + translationJobRepository = jobRepository, + translationMemoryRepository = memoryRepository, + translationProvider = provider, + materializer = materializer, + transactionManager = TestTransactionManager() + ) + val job = translationJob( + resourceType = LanguageTranslationTargetType.CREATOR_COMMUNITY, + fieldKey = "content", + sourceText = "본문" + ).also { it.id = 100L } + Mockito.`when`(jobRepository.findNextPendingGroupJobIdsForUpdate(anyLocalDateTime())).thenReturn(listOf(100L)) + Mockito.`when`(jobRepository.findById(100L)).thenReturn(Optional.of(job)) + Mockito.`when`( + memoryRepository.findBySourceHashAndSourceLanguageAndTargetLanguageAndProviderAndNormalizationVersion( + job.sourceHash, + "ko", + "en", + "papago", + SourceTextNormalizer.NORMALIZATION_VERSION + ) + ).thenReturn( + TranslationMemory( + sourceHash = job.sourceHash, + sourceText = job.sourceText, + sourceLanguage = "ko", + targetLanguage = "en", + translatedText = "translated", + provider = "papago", + providerVersion = "nmt-v1" + ) + ) + + worker.processNextGroup() + + Mockito.verify(materializer).materialize(LanguageTranslationTargetType.CREATOR_COMMUNITY, 10L, "en") + } + @Test fun shouldRetryGroupWhenMaterializationFails() { val jobRepository = Mockito.mock(TranslationJobRepository::class.java) @@ -174,11 +219,12 @@ class TranslationJobWorkerTest { private fun translationJob( resourceId: Long = 10L, + resourceType: LanguageTranslationTargetType = LanguageTranslationTargetType.CONTENT, fieldKey: String = "title", sourceText: String = "제목" ): TranslationJob { return TranslationJob( - resourceType = LanguageTranslationTargetType.CONTENT, + resourceType = resourceType, resourceId = resourceId, fieldKey = fieldKey, sourceHash = SourceTextNormalizer.hash(sourceText),