refactor(i18n): 공급자 식별자를 enum으로 통일한다

This commit is contained in:
2026-11-09 19:14:19 +09:00
parent 6093b37747
commit ec890047a5
21 changed files with 228 additions and 148 deletions
@@ -13,7 +13,7 @@ class LanguageDetectionCacheService(
providers: List<LanguageDetectionProvider>,
properties: LanguageProviderProperties
) {
private val providers = properties.orderedProviders(properties.detectionOrder, providers) { it.providerName }
private val providers = properties.orderedProviders(properties.detectionOrder, providers) { it.providerId }
@Transactional
fun detectWithCache(query: String): DetectedLanguage? {
@@ -24,11 +24,11 @@ class LanguageDetectionCacheService(
providers.forEach { provider ->
val cached = languageDetectionResultRepository.findBySourceHashAndProviderAndNormalizationVersion(
sourceHash = sourceHash,
provider = provider.providerName,
provider = provider.providerId.code,
normalizationVersion = SourceTextNormalizer.NORMALIZATION_VERSION
)
if (cached != null && cached.detectedLanguage.isNotBlank()) {
return DetectedLanguage(cached.detectedLanguage, provider.providerName)
return DetectedLanguage(cached.detectedLanguage, provider.providerId)
}
}
@@ -42,18 +42,18 @@ class LanguageDetectionCacheService(
sourceHash = sourceHash,
sourceTextSample = normalizedQuery.take(MAX_SAMPLE_LENGTH),
detectedLanguage = detectedLanguage,
provider = provider.providerName,
provider = provider.providerId.code,
confidence = null,
normalizationVersion = SourceTextNormalizer.NORMALIZATION_VERSION
)
val winner = requireNotNull(
languageDetectionResultRepository.findDetectedLanguageForUpdate(
sourceHash = sourceHash,
provider = provider.providerName,
provider = provider.providerId.code,
normalizationVersion = SourceTextNormalizer.NORMALIZATION_VERSION
)
)
return DetectedLanguage(winner, provider.providerName)
return DetectedLanguage(winner, provider.providerId)
}
return null
}
@@ -1,3 +1,3 @@
package kr.co.vividnext.sodalive.i18n.translation
data class DetectedLanguage(val detectedLanguage: String, val providerName: String)
data class DetectedLanguage(val detectedLanguage: String, val providerId: LanguageProviderId)
@@ -1,7 +1,7 @@
package kr.co.vividnext.sodalive.i18n.translation
interface LanguageDetectionProvider {
val providerName: String
val providerId: LanguageProviderId
fun detect(query: String): String?
}
@@ -0,0 +1,6 @@
package kr.co.vividnext.sodalive.i18n.translation
enum class LanguageProviderId(val code: String) {
PAPAGO("papago"),
AWS("aws")
}
@@ -1,6 +1,6 @@
package kr.co.vividnext.sodalive.i18n.translation
object LanguageProviderOrder {
val detectionOrder = listOf("papago")
val translationOrder = listOf("papago")
val detectionOrder = listOf(LanguageProviderId.PAPAGO)
val translationOrder = listOf(LanguageProviderId.PAPAGO)
}
@@ -5,18 +5,18 @@ import org.springframework.stereotype.Component
@Component
class LanguageProviderProperties(
val detectionOrder: List<String>,
val translationOrder: List<String>
val detectionOrder: List<LanguageProviderId>,
val translationOrder: List<LanguageProviderId>
) {
@Autowired
constructor() : this(LanguageProviderOrder.detectionOrder, LanguageProviderOrder.translationOrder)
fun <T> orderedProviders(order: List<String>, providers: List<T>, name: (T) -> String): List<T> {
require(order.isNotEmpty() && order.none { it.isBlank() }) { "language provider order must not be empty" }
fun <T> orderedProviders(order: List<LanguageProviderId>, providers: List<T>, id: (T) -> LanguageProviderId): List<T> {
require(order.isNotEmpty()) { "language provider order must not be empty" }
require(order.distinct().size == order.size) { "duplicate language provider order" }
val byName = providers.associateBy(name)
require(byName.size == providers.size) { "duplicate registered language provider name" }
require(order.all { it in byName }) { "unknown language provider in order" }
return order.map { byName.getValue(it) }
val byId = providers.associateBy(id)
require(byId.size == providers.size) { "duplicate registered language provider name" }
require(order.all { it in byId }) { "unknown language provider in order" }
return order.map { byId.getValue(it) }
}
}
@@ -16,7 +16,7 @@ class PapagoLanguageDetectionProvider(
private val papagoClientSecret: String
) : LanguageDetectionProvider {
private val restTemplate = RestTemplate()
override val providerName = "papago"
override val providerId = LanguageProviderId.PAPAGO
override fun detect(query: String): String? {
val headers = HttpHeaders().apply {
@@ -20,7 +20,7 @@ class PapagoTranslationService(
private val papagoTranslateUrl = "https://papago.apigw.ntruss.com/nmt/v1/translation"
override val providerName: String = "papago"
override val providerId: LanguageProviderId = LanguageProviderId.PAPAGO
override val providerVersion: String = "nmt-v1"
@@ -2,6 +2,6 @@ package kr.co.vividnext.sodalive.i18n.translation
data class ProviderTranslationResult(
val result: TranslateResult,
val providerName: String,
val providerId: LanguageProviderId,
val providerVersion: String
)
@@ -8,7 +8,7 @@ class TranslationCoordinator(
properties: LanguageProviderProperties,
private val translationMemoryRepository: TranslationMemoryRepository
) {
private val providers = properties.orderedProviders(properties.translationOrder, providers) { it.providerName }
private val providers = properties.orderedProviders(properties.translationOrder, providers) { it.providerId }
fun findCached(sourceHash: String, sourceLanguage: String, targetLanguage: String): TranslationMemory? {
providers.forEach { provider ->
@@ -17,7 +17,7 @@ class TranslationCoordinator(
sourceHash,
sourceLanguage,
targetLanguage,
provider.providerName,
provider.providerId.code,
SourceTextNormalizer.NORMALIZATION_VERSION
)
if (memory != null && memory.translatedText.isNotBlank()) return memory
@@ -42,7 +42,7 @@ class TranslationCoordinator(
result != null && result.translatedText.size == request.texts.size &&
result.translatedText.none { it.isBlank() }
) {
return ProviderTranslationResult(result, provider.providerName, provider.providerVersion)
return ProviderTranslationResult(result, provider.providerId, provider.providerVersion)
}
}
throw IllegalStateException("all translation providers failed")
@@ -87,7 +87,7 @@ class TranslationJobWorker(
sourceHash = job.sourceHash,
sourceLanguage = job.sourceLanguage,
targetLanguage = job.targetLanguage,
provider = response.providerName,
provider = response.providerId.code,
normalizationVersion = SourceTextNormalizer.NORMALIZATION_VERSION
)
if (memory == null) {
@@ -98,7 +98,7 @@ class TranslationJobWorker(
sourceLanguage = job.sourceLanguage,
targetLanguage = job.targetLanguage,
translatedText = translated,
provider = response.providerName,
provider = response.providerId.code,
providerVersion = response.providerVersion
)
)
@@ -1,7 +1,7 @@
package kr.co.vividnext.sodalive.i18n.translation
interface TranslationProvider {
val providerName: String
val providerId: LanguageProviderId
val providerVersion: String
fun translate(request: TranslateRequest): TranslateResult