Skip to content

Commit

Permalink
fix: allow formality to be set globally (#2698)
Browse files Browse the repository at this point in the history
Closes #1994
  • Loading branch information
stepan662 authored Nov 21, 2024
1 parent b78779f commit 9b87e2f
Show file tree
Hide file tree
Showing 16 changed files with 183 additions and 107 deletions.
1 change: 0 additions & 1 deletion .run/Backend localhost.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<configuration default="false" name="Backend localhost" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true">
<option name="ACTIVE_PROFILES" value="dev" />
<option name="FRAME_DEACTIVATION_UPDATE_POLICY" value="UpdateClassesAndResources" />
<module name="tolgee-platform.server-app.main" />
<option name="SPRING_BOOT_MAIN_CLASS" value="io.tolgee.Application" />
<method v="2">
<option name="Make" enabled="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ class MachineTranslationSettingsController(
return CollectionModel.of(
data.map {
LanguageInfoModel(
it.language.id,
it.language.tag,
it.language?.id,
it.language?.tag,
supportedServices = it.supportedServices,
)
}.sortedBy { it.languageId },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import java.io.Serializable
@Suppress("unused")
@Relation(collectionRelation = "languageInfos", itemRelation = "languageInfo")
class LanguageInfoModel(
val languageId: Long,
val languageTag: String,
val languageId: Long?,
val languageTag: String?,
val supportedServices: List<MtSupportedService>,
) : RepresentationModel<LanguageInfoModel>(), Serializable
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,34 @@ class MachineTranslationSettingsControllerTest : ProjectAuthControllerTest() {
}
}

@Test
@ProjectJWTAuthTestMethod
fun `formality can be set for default`() {
performAuthPut(
"/v2/projects/${project.id}/machine-translation-service-settings",
SetMachineTranslationSettingsDto(
listOf(
MachineTranslationLanguagePropsDto(
targetLanguageId = null,
primaryService = MtServiceType.GOOGLE,
enabledServicesInfo =
setOf(
MtServiceInfo(MtServiceType.GOOGLE, null),
MtServiceInfo(MtServiceType.AWS, Formality.FORMAL),
),
),
),
),
)

executeInNewTransaction {
val germanSetting =
mtServiceConfigService.getProjectSettings(testData.projectBuilder.self)
.find { it.targetLanguage?.id == null }
germanSetting!!.awsFormality.assert.isEqualTo(Formality.FORMAL)
}
}

@Test
@ProjectJWTAuthTestMethod
fun `it sets primary service via info`() {
Expand Down Expand Up @@ -263,7 +291,21 @@ class MachineTranslationSettingsControllerTest : ProjectAuthControllerTest() {
).andPrettyPrint.andAssertThatJson {
node("_embedded.languageInfos") {
isArray
node("[1]") {
node("[0]") {
node("languageTag").isEqualTo(null)
node("supportedServices") {
isArray
node("[0]") {
node("serviceType").isEqualTo("GOOGLE")
node("formalitySupported").isEqualTo(false)
}
node("[1]") {
node("serviceType").isEqualTo("AWS")
node("formalitySupported").isEqualTo(true)
}
}
}
node("[2]") {
node("languageTag").isEqualTo("de")
node("supportedServices") {
isArray
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import io.tolgee.component.machineTranslation.providers.ProviderTranslateParams
import io.tolgee.configuration.tolgee.InternalProperties
import io.tolgee.constants.Caches
import io.tolgee.constants.MtServiceType
import io.tolgee.exceptions.FormalityNotSupportedException
import io.tolgee.exceptions.LanguageNotSupportedException
import io.tolgee.model.mtServiceConfig.Formality
import org.slf4j.LoggerFactory
Expand All @@ -29,13 +28,16 @@ class MtServiceManager(
) {
private val logger = LoggerFactory.getLogger(this::class.java)

private fun findInCache(params: TranslationParams): TranslateResult? {
return params.findInCacheByParams()?.let {
private fun findInCache(
params: ProviderTranslateParams,
serviceType: MtServiceType,
): TranslateResult? {
return params.findInCacheByParams(serviceType)?.let {
TranslateResult(
translatedText = it.translatedText,
contextDescription = it.contextDescription,
actualPrice = 0,
usedService = params.serviceInfo.serviceType,
usedService = serviceType,
params.textRaw.isEmpty(),
)
}
Expand All @@ -45,9 +47,25 @@ class MtServiceManager(
val provider = params.serviceInfo.serviceType.getProvider()
validate(provider, params)

val supportsFormality = provider.isLanguageFormalitySupported(params.targetLanguageTag)

val translateParams =
ProviderTranslateParams(
params.text,
params.textRaw,
params.keyName,
params.sourceLanguageTag,
params.targetLanguageTag,
params.metadata,
if (supportsFormality) params.serviceInfo.formality else null,
params.isBatch,
pluralFormExamples = params.pluralFormExamples,
pluralForms = params.pluralForms,
)

if (internalProperties.fakeMtProviders) {
logger.debug("Fake MT provider is enabled")
return getFaked(params)
return getFaked(translateParams, params.serviceInfo.serviceType)
}

if (params.textRaw.isBlank()) {
Expand All @@ -60,27 +78,14 @@ class MtServiceManager(
)
}

val foundInCache = findInCache(params)
val foundInCache = findInCache(translateParams, params.serviceInfo.serviceType)
if (foundInCache != null) {
return foundInCache
}

return try {
val translated =
provider.translate(
ProviderTranslateParams(
params.text,
params.textRaw,
params.keyName,
params.sourceLanguageTag,
params.targetLanguageTag,
params.metadata,
params.serviceInfo.formality,
params.isBatch,
pluralFormExamples = params.pluralFormExamples,
pluralForms = params.pluralForms,
),
)
provider.translate(translateParams)

val translateResult =
TranslateResult(
Expand All @@ -91,7 +96,7 @@ class MtServiceManager(
params.textRaw.isBlank(),
)

params.cacheResult(translateResult)
translateParams.cacheResult(translateResult, params.serviceInfo.serviceType)

return translateResult
} catch (e: Exception) {
Expand All @@ -114,15 +119,6 @@ class MtServiceManager(
if (!provider.isLanguageSupported(params.targetLanguageTag)) {
throw LanguageNotSupportedException(params.targetLanguageTag, params.serviceInfo.serviceType)
}

val formality = params.serviceInfo.formality
val requiresFormality =
formality != null &&
formality != Formality.DEFAULT

if (!provider.isLanguageFormalitySupported(params.targetLanguageTag) && requiresFormality) {
throw FormalityNotSupportedException(params.targetLanguageTag, params.serviceInfo.serviceType)
}
}

private fun handleSilentFail(
Expand All @@ -145,32 +141,42 @@ class MtServiceManager(
}
}

private fun getFaked(params: TranslationParams): TranslateResult {
var fakedText =
"${params.text} translated with ${params.serviceInfo.serviceType.name} " +
private fun getFaked(
params: ProviderTranslateParams,
serviceType: MtServiceType,
): TranslateResult {
val formalityIndicator =
if ((params.formality ?: Formality.DEFAULT) !== Formality.DEFAULT) {
"${params.formality} "
} else {
""
}
val fakedText =
"${params.text} translated ${formalityIndicator}with ${serviceType.name} " +
"from ${params.sourceLanguageTag} to ${params.targetLanguageTag}"
if ((params.serviceInfo.formality ?: Formality.DEFAULT) !== Formality.DEFAULT) {
fakedText += " ${params.serviceInfo.formality}"
}

return TranslateResult(
translatedText = fakedText,
contextDescription = null,
actualPrice = params.text.length * 100,
usedService = params.serviceInfo.serviceType,
usedService = serviceType,
baseBlank = params.textRaw.isEmpty(),
)
}

private fun TranslationParams.findInCacheByParams(): TranslateResult? {
private fun ProviderTranslateParams.findInCacheByParams(serviceType: MtServiceType): TranslateResult? {
return getCache()?.let { cache ->
val result = cache.get(this.cacheKey)?.get() as? TranslateResult
val result = cache.get(this.cacheKey(serviceType.name))?.get() as? TranslateResult
result?.actualPrice = 0
return result
}
}

private fun TranslationParams.cacheResult(result: TranslateResult) {
getCache()?.put(this.cacheKey, result)
private fun ProviderTranslateParams.cacheResult(
result: TranslateResult,
serviceType: MtServiceType,
) {
getCache()?.put(this.cacheKey(serviceType.name), result)
}

private fun getCache() = cacheManager.getCache(Caches.MACHINE_TRANSLATIONS)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.tolgee.component.machineTranslation

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import io.tolgee.component.machineTranslation.metadata.Metadata
import io.tolgee.service.machineTranslation.MtServiceInfo

Expand All @@ -15,11 +14,4 @@ data class TranslationParams(
val isBatch: Boolean,
var pluralForms: Map<String, String>? = null,
val pluralFormExamples: Map<String, String>? = null,
) {
val cacheKey: String
get() =
jacksonObjectMapper()
.writeValueAsString(
listOf(text, textRaw, pluralForms, sourceLanguageTag, targetLanguageTag, serviceInfo, metadata),
)
}
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.tolgee.component.machineTranslation.providers

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import io.tolgee.component.machineTranslation.metadata.Metadata
import io.tolgee.model.mtServiceConfig.Formality

Expand All @@ -23,4 +24,22 @@ data class ProviderTranslateParams(
* Only for translators supporting plurals
*/
val pluralFormExamples: Map<String, String>? = null,
)
) {
fun cacheKey(provider: String): String {
return jacksonObjectMapper()
.writeValueAsString(
listOf(
text,
textRaw,
keyName,
sourceLanguageTag,
targetLanguageTag,
metadata,
formality,
pluralForms,
pluralFormExamples,
provider,
),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ class TolgeeTranslationProvider(
return metadata
}

override val supportedLanguages = null
override val formalitySupportingLanguages = null
// empty array meaning all is supported
override val supportedLanguages = arrayOf<String>()
override val formalitySupportingLanguages = arrayOf<String>()

override fun isLanguageSupported(tag: String): Boolean = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package io.tolgee.service.machineTranslation
import io.tolgee.dtos.cacheable.LanguageDto

data class MtLanguageInfo(
val language: LanguageDto,
val language: LanguageDto?,
val supportedServices: List<MtSupportedService>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,7 @@ class MtServiceConfigService(
MtServiceType.AWS -> entity.awsFormality = it.formality ?: Formality.DEFAULT
MtServiceType.DEEPL -> entity.deeplFormality = it.formality ?: Formality.DEFAULT
MtServiceType.TOLGEE -> entity.tolgeeFormality = it.formality ?: Formality.DEFAULT
else -> {
if (it.formality == null) {
return@forEach
}
throw BadRequestException(Message.FORMALITY_NOT_SUPPORTED_BY_SERVICE, listOf(it.serviceType))
}
else -> {}
}
}
}
Expand Down Expand Up @@ -330,13 +325,26 @@ class MtServiceConfigService(
}

fun getLanguageInfo(project: ProjectDto): List<MtLanguageInfo> {
return languageService.findAll(project.id).map { language ->
val result: MutableList<MtLanguageInfo> = mutableListOf()
result.add(
MtLanguageInfo(
language = null,
supportedServices =
services.filter {
it.value.second.isEnabled
}.map {
MtSupportedService(it.key, it.value.second.formalitySupportingLanguages !== null)
},
),
)
languageService.findAll(project.id).forEach { language ->
val supportedServices =
services.filter { it.value.second.isLanguageSupported(language.tag) && it.value.second.isEnabled }.map {
MtSupportedService(it.key, it.value.second.isLanguageFormalitySupported(language.tag))
}
MtLanguageInfo(language = language, supportedServices)
result.add(MtLanguageInfo(language = language, supportedServices))
}
return result
}

val services by lazy {
Expand Down
Loading

0 comments on commit 9b87e2f

Please sign in to comment.