Skip to content

Commit 8a06474

Browse files
zefixllujaJanCizmar
authored andcommitted
DeepL machine translation
This adds support for DeepL machine translation. Both key types (commercial/free) are supported. This also adds a `jenv` compatible `.java-version` file (using J14).
1 parent 435e645 commit 8a06474

File tree

9 files changed

+151
-2
lines changed

9 files changed

+151
-2
lines changed

.java-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
14.0

backend/app/src/main/kotlin/io/tolgee/api/v2/hateoas/machineTranslation/SuggestResultModel.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class SuggestResultModel(
1313
example = """
1414
{
1515
"GOOGLE": "This was translated by Google",
16-
"AWS": "This was translated by AWS"
16+
"AWS": "This was translated by AWS",
17+
"DEEPL": "This was translated by DeepL"
1718
}
1819
"""
1920
)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package io.tolgee.component.machineTranslation.providers
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty
4+
import io.tolgee.configuration.tolgee.machineTranslation.DeeplMachineTranslationProperties
5+
import org.springframework.beans.factory.config.ConfigurableBeanFactory
6+
import org.springframework.context.annotation.Scope
7+
import org.springframework.http.HttpHeaders
8+
import org.springframework.http.MediaType
9+
import org.springframework.stereotype.Component
10+
import org.springframework.util.LinkedMultiValueMap
11+
import org.springframework.util.MultiValueMap
12+
import org.springframework.web.client.RestTemplate
13+
import org.springframework.web.client.postForEntity
14+
15+
@Component
16+
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
17+
class DeeplTranslationProvider(
18+
private val deeplMachineTranslationProperties: DeeplMachineTranslationProperties,
19+
private val restTemplate: RestTemplate,
20+
) : AbstractMtValueProvider() {
21+
22+
override val isEnabled: Boolean
23+
get() = !deeplMachineTranslationProperties.authKey.isNullOrEmpty()
24+
25+
override fun translateViaProvider(text: String, sourceTag: String, targetTag: String): String? {
26+
val headers = HttpHeaders()
27+
headers.contentType = MediaType.APPLICATION_FORM_URLENCODED
28+
29+
val requestBody: MultiValueMap<String, String> = LinkedMultiValueMap()
30+
// Mandatory parameters
31+
requestBody.add("auth_key", deeplMachineTranslationProperties.authKey)
32+
requestBody.add("text", text)
33+
requestBody.add("source_lang", sourceTag.uppercase())
34+
requestBody.add("target_lang", targetTag.uppercase())
35+
// Optional parameters
36+
requestBody.add("formality", deeplMachineTranslationProperties.formality)
37+
38+
val response = restTemplate.postForEntity<DeeplResponse>(
39+
apiEndpointFromKey(),
40+
requestBody
41+
)
42+
43+
return response.body?.translations?.first()?.text
44+
?: throw RuntimeException(response.toString())
45+
}
46+
47+
/**
48+
* Free API keys are identified by the ':fx' suffix, they also require a different endpoint.
49+
*/
50+
private fun apiEndpointFromKey(): String {
51+
if (deeplMachineTranslationProperties.authKey!!.endsWith(":fx")) {
52+
return "https://api-free.deepl.com/v2/translate"
53+
}
54+
return "https://api.deepl.com/v2/translate"
55+
}
56+
57+
/**
58+
* Data structure for mapping the DeepL JSON response objects.
59+
*/
60+
companion object {
61+
class DeeplResponse {
62+
@JsonProperty("translations")
63+
var translations: List<DeeplTranslation>? = null
64+
}
65+
66+
class DeeplTranslation {
67+
@JsonProperty("detected_source_language")
68+
var detectedSourceLanguage: String? = null
69+
70+
@JsonProperty("text")
71+
var text: String? = null
72+
}
73+
}
74+
75+
override fun calculateProviderPrice(text: String): Int {
76+
return text.length * 100
77+
}
78+
79+
override val supportedLanguages = arrayOf(
80+
"bg",
81+
"cs",
82+
"da",
83+
"de",
84+
"el",
85+
"en",
86+
"en-gb",
87+
"en-us",
88+
"es",
89+
"et",
90+
"fi",
91+
"fr",
92+
"hu",
93+
"it",
94+
"ja",
95+
"lt",
96+
"lv",
97+
"nl",
98+
"pl",
99+
"pt",
100+
"pt-pt",
101+
"pt-br",
102+
"ro",
103+
"ru",
104+
"sk",
105+
"sl",
106+
"sv",
107+
"zh"
108+
)
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.tolgee.configuration.tolgee.machineTranslation
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties
4+
5+
@ConfigurationProperties(prefix = "tolgee.machine-translation.deepl")
6+
open class DeeplMachineTranslationProperties(
7+
override var defaultEnabled: Boolean = true,
8+
override var defaultPrimary: Boolean = false,
9+
var authKey: String? = null,
10+
var formality: String = "default"
11+
) : MachineTranslationServiceProperties

backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/machineTranslation/MachineTranslationProperties.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties
66
open class MachineTranslationProperties(
77
var google: GoogleMachineTranslationProperties = GoogleMachineTranslationProperties(),
88
var aws: AwsMachineTranslationProperties = AwsMachineTranslationProperties(),
9+
var deepl: DeeplMachineTranslationProperties = DeeplMachineTranslationProperties(),
910
var freeCreditsAmount: Long = -1,
1011
)

backend/data/src/main/kotlin/io/tolgee/constants/MtServiceType.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package io.tolgee.constants
22

33
import io.tolgee.component.machineTranslation.MtValueProvider
44
import io.tolgee.component.machineTranslation.providers.AwsMtValueProvider
5+
import io.tolgee.component.machineTranslation.providers.DeeplTranslationProvider
56
import io.tolgee.component.machineTranslation.providers.GoogleTranslationProvider
67
import io.tolgee.configuration.tolgee.machineTranslation.AwsMachineTranslationProperties
8+
import io.tolgee.configuration.tolgee.machineTranslation.DeeplMachineTranslationProperties
79
import io.tolgee.configuration.tolgee.machineTranslation.GoogleMachineTranslationProperties
810
import io.tolgee.configuration.tolgee.machineTranslation.MachineTranslationServiceProperties
911

@@ -12,5 +14,6 @@ enum class MtServiceType(
1214
val providerClass: Class<out MtValueProvider>
1315
) {
1416
GOOGLE(GoogleMachineTranslationProperties::class.java, GoogleTranslationProvider::class.java),
15-
AWS(AwsMachineTranslationProperties::class.java, AwsMtValueProvider::class.java);
17+
AWS(AwsMachineTranslationProperties::class.java, AwsMtValueProvider::class.java),
18+
DEEPL(DeeplMachineTranslationProperties::class.java, DeeplTranslationProvider::class.java);
1619
}
Lines changed: 19 additions & 0 deletions
Loading

webapp/src/views/projects/languages/MachineTranslation/LanguageRow.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export const LanguageRow: React.FC<Props> = ({ lang, providers, disabled }) => {
4242
return t('project_languages_primary_none', 'None');
4343
case 'GOOGLE':
4444
return 'Google';
45+
case 'DEEPL':
46+
return 'DeepL';
4547
default:
4648
return provider;
4749
}

webapp/src/views/projects/translations/TranslationTools/useProviderImg.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export const useProviderImg = () => {
99
return '/images/providers/google-translate.svg';
1010
case 'AWS':
1111
return `/images/providers/aws-logo-${palette.mode}.svg`;
12+
case 'DEEPL':
13+
return `/images/providers/deepl-logo.svg`;
1214
default:
1315
return null;
1416
}

0 commit comments

Comments
 (0)