Skip to content

Commit

Permalink
fix: Import optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
JanCizmar committed Dec 15, 2023
1 parent afacd4f commit dea59b9
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 45 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.tolgee.component
package io.tolgee.component.autoTranslation

import com.google.cloud.translate.Translation
import io.tolgee.activity.data.ActivityType
Expand All @@ -9,42 +9,30 @@ import io.tolgee.model.activity.ActivityModifiedEntity
import io.tolgee.model.key.Key
import io.tolgee.service.project.ProjectService
import io.tolgee.service.translation.AutoTranslationService
import io.tolgee.util.Logging
import jakarta.persistence.EntityManager
import org.springframework.context.event.EventListener
import org.springframework.core.annotation.Order
import org.springframework.stereotype.Component

@Component
class AutoTranslationListener(
private val autoTranslationService: AutoTranslationService,
private val projectService: ProjectService,
private val entityManager: EntityManager,
) : Logging {

companion object {
/**
* import activities start visible batch job
*/
private val IMPORT_ACTIVITIES = listOf(ActivityType.IMPORT)

/**
* Low volume activities start hidden batch job
*/
private val LOW_VOLUME_ACTIVITIES =
listOf(ActivityType.SET_TRANSLATIONS, ActivityType.CREATE_KEY, ActivityType.COMPLEX_EDIT)
}

@Order(2)
@EventListener
fun onApplicationEvent(event: OnProjectActivityStoredEvent) {
val projectId = event.activityRevision.projectId ?: return

if (!shouldRunTheOperation(event, projectId)) {
import org.springframework.context.ApplicationContext
import kotlin.properties.Delegates

/**
* Utility class which handles auto translation.
*
* Separated from [AutoTranslationListener] to be able to cache some data in local
* variables without need to pass the params to so many methods.
*/
class AutoTranslationEventHandler(
private val event: OnProjectActivityStoredEvent,
private val applicationContext: ApplicationContext
) {
var projectId by Delegates.notNull<Long>()

fun handle() {
projectId = event.activityRevision.projectId ?: return

if (!shouldRunTheOperation()) {
return
}

val keyIds = getKeyIdsToAutoTranslate(projectId, event.activityRevision.modifiedEntities)
val keyIds = getKeyIdsToAutoTranslate()

if (keyIds.isEmpty()) {
return
Expand All @@ -55,12 +43,13 @@ class AutoTranslationListener(
projectId = projectId,
keyIds = keyIds,
isBatch = true,
baseLanguageId = baseLanguageId ?: return,
isHiddenJob = event.isLowVolumeActivity()
)
}
}

private fun shouldRunTheOperation(event: OnProjectActivityStoredEvent, projectId: Long): Boolean {
private fun shouldRunTheOperation(): Boolean {
val configs = autoTranslationService.getConfigs(
entityManager.getReference(Project::class.java, projectId)
)
Expand All @@ -84,17 +73,17 @@ class AutoTranslationListener(
private fun OnProjectActivityStoredEvent.isLowVolumeActivity() =
activityRevision.type in LOW_VOLUME_ACTIVITIES

fun getKeyIdsToAutoTranslate(projectId: Long, modifiedEntities: MutableList<ActivityModifiedEntity>): List<Long> {
return modifiedEntities.mapNotNull { modifiedEntity ->
if (!modifiedEntity.isBaseTranslationTextChanged(projectId)) {
private fun getKeyIdsToAutoTranslate(): List<Long> {
return event.activityRevision.modifiedEntities.mapNotNull { modifiedEntity ->
if (!modifiedEntity.isBaseTranslationTextChanged()) {
return@mapNotNull null
}
getKeyId(modifiedEntity)
}
}

private fun ActivityModifiedEntity.isBaseTranslationTextChanged(projectId: Long): Boolean {
return this.isTranslation() && this.isBaseTranslation(projectId) && this.isTextChanged()
private fun ActivityModifiedEntity.isBaseTranslationTextChanged(): Boolean {
return this.isTranslation() && this.isBaseTranslation() && this.isTextChanged()
}

private fun getKeyId(modifiedEntity: ActivityModifiedEntity) =
Expand All @@ -110,11 +99,38 @@ class AutoTranslationListener(
private fun ActivityModifiedEntity.isTranslation() =
entityClass == Translation::class.simpleName

private fun ActivityModifiedEntity.isBaseTranslation(projectId: Long): Boolean {
val baseLanguageId = projectService.get(projectId).baseLanguage?.id ?: return false

private fun ActivityModifiedEntity.isBaseTranslation(): Boolean {
return describingRelations?.values
?.any { it.entityClass == Language::class.simpleName && it.entityId == baseLanguageId }
?: false
}

private val baseLanguageId: Long? by lazy {
projectService.get(projectId).baseLanguage?.id
}

private val autoTranslationService: AutoTranslationService by lazy {
applicationContext.getBean(AutoTranslationService::class.java)
}

private val projectService: ProjectService by lazy {
applicationContext.getBean(ProjectService::class.java)
}

private val entityManager: EntityManager by lazy {
applicationContext.getBean(EntityManager::class.java)
}

companion object {
/**
* import activities start visible batch job
*/
private val IMPORT_ACTIVITIES = listOf(ActivityType.IMPORT)

/**
* Low volume activities start hidden batch job
*/
private val LOW_VOLUME_ACTIVITIES =
listOf(ActivityType.SET_TRANSLATIONS, ActivityType.CREATE_KEY, ActivityType.COMPLEX_EDIT)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.tolgee.component.autoTranslation

import com.google.cloud.translate.Translation
import io.tolgee.activity.data.ActivityType
import io.tolgee.events.OnProjectActivityStoredEvent
import io.tolgee.model.Language
import io.tolgee.model.Project
import io.tolgee.model.activity.ActivityModifiedEntity
import io.tolgee.model.key.Key
import io.tolgee.service.project.ProjectService
import io.tolgee.service.translation.AutoTranslationService
import io.tolgee.util.Logging
import jakarta.persistence.EntityManager
import org.springframework.context.ApplicationContext
import org.springframework.context.event.EventListener
import org.springframework.core.annotation.Order
import org.springframework.stereotype.Component

@Component
class AutoTranslationListener(
private val applicationContext: ApplicationContext
) : Logging {

@Order(2)
@EventListener
fun onApplicationEvent(event: OnProjectActivityStoredEvent) {
AutoTranslationEventHandler(event, applicationContext).handle()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.springframework.stereotype.Repository
@Repository
interface AutoTranslationConfigRepository : JpaRepository<AutoTranslationConfig, Long> {
fun findOneByProjectAndTargetLanguageId(project: Project, languageId: Long?): AutoTranslationConfig?
fun findByProjectAndTargetLanguageIdIn(project: Project, languageIds: List<Long>): List<AutoTranslationConfig>

@Query(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,20 @@ class AutoTranslationService(
fun autoTranslateViaBatchJob(
projectId: Long,
keyIds: List<Long>,
baseLanguageId: Long,
useTranslationMemory: Boolean? = null,
useMachineTranslation: Boolean? = null,
isBatch: Boolean,
isHiddenJob: Boolean,
) {
val project = entityManager.getReference(Project::class.java, projectId)
val languageIds = languageService.findAll(projectId).map { it.id }
val languageIds = languageService.findAll(projectId).map { it.id }.filter { it != baseLanguageId }
val configs = this.getConfigs(project, languageIds)
val request = AutoTranslationRequest().apply {
target = languageIds.flatMap { languageId ->
if(configs[languageId]?.usingTm == false && configs[languageId]?.usingPrimaryMtService == false) {
return@flatMap listOf()
}
keyIds.map { keyId ->
BatchTranslationTargetItem(
keyId = keyId,
Expand Down Expand Up @@ -288,11 +293,24 @@ class AutoTranslationService(
return list!!
}


fun getConfigs(project: Project, targetLanguageIds: List<Long>): Map<Long, AutoTranslationConfig> {
val configs = autoTranslationConfigRepository.findByProjectAndTargetLanguageIdIn(project, targetLanguageIds)
val default = autoTranslationConfigRepository.findDefaultForProject(project)
?: autoTranslationConfigRepository.findDefaultForProject(project) ?: AutoTranslationConfig().also {
it.project = project
}

return targetLanguageIds.associateWith { languageId ->
(configs.find { it.targetLanguage?.id == languageId } ?: default)
}
}

fun getConfig(project: Project, targetLanguageId: Long) =
autoTranslationConfigRepository.findOneByProjectAndTargetLanguageId(project, targetLanguageId)
?: autoTranslationConfigRepository.findDefaultForProject(project) ?: AutoTranslationConfig().also {
it.project = project
}
it.project = project
}

fun getDefaultConfig(project: Project) =
autoTranslationConfigRepository.findOneByProjectAndTargetLanguageId(project, null) ?: AutoTranslationConfig()
Expand Down

0 comments on commit dea59b9

Please sign in to comment.