Skip to content

Commit 2816ca4

Browse files
feat: Add ability to text translate with a translation memory
1 parent cb043d7 commit 2816ca4

8 files changed

Lines changed: 365 additions & 0 deletions

File tree

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,13 @@ a `TextTranslationOptions`, with the following setters:
167167
- `setStyleRule()`: specifies a style rule to use with translation, as a string
168168
containing the ID of the style rule, or a `StyleRuleInfo` object.
169169
- `setStyleId()` is also available, accepting a string containing the style rule ID.
170+
- `setTranslationMemory()`: specifies a translation memory to use with translation,
171+
as a `TranslationMemoryInfo` object. Sets the translation memory ID.
172+
- `setTranslationMemoryId()` is also available, accepting a string containing
173+
the translation memory ID.
174+
- `setTranslationMemoryThreshold()` is also available, accepting an integer
175+
from 0 to 100 to control the minimum matching percentage for translation
176+
memory matches. We recommend a minimum threshold of 75%.
170177
- `setContext()`: specifies additional context to influence translations, that is not
171178
translated itself. Characters in the `context` parameter are not counted toward billing.
172179
See the [API documentation][api-docs-context-param] for more information and
@@ -797,6 +804,64 @@ class Example { // Continuing class Example from above
797804
}
798805
```
799806

807+
### Translation Memories
808+
809+
Translation memories store and reuse previously created translations, helping to
810+
ensure consistency and reduce effort when translating similar or repeated content.
811+
812+
#### Uploading and managing translation memories
813+
814+
Currently translation memories must be uploaded and managed in the DeepL UI via
815+
https://www.deepl.com/translation-memory. Full CRUD functionality via the APIs will
816+
come shortly.
817+
818+
#### Listing translation memories
819+
820+
Use `listTranslationMemories()` to retrieve translation memories associated
821+
with your account:
822+
823+
```java
824+
class Example { // Continuing class Example from above
825+
public void listTranslationMemoriesExample() throws Exception {
826+
List<TranslationMemoryInfo> translationMemories =
827+
client.listTranslationMemories();
828+
for (TranslationMemoryInfo tm : translationMemories) {
829+
System.out.println(String.format("%s (%s)",
830+
tm.getName(), tm.getTranslationMemoryId()));
831+
}
832+
}
833+
}
834+
```
835+
836+
#### Using a translation memory in translations
837+
838+
You can use a translation memory for text translation by setting the translation
839+
memory options in `TextTranslationOptions`:
840+
841+
```java
842+
class Example { // Continuing class Example from above
843+
public void usingTranslationMemoryExample() throws Exception {
844+
// Using the translation memory ID directly
845+
TextTranslationOptions options = new TextTranslationOptions()
846+
.setTranslationMemoryId("tm-123abc")
847+
.setTranslationMemoryThreshold(80);
848+
TextResult result = client.translateText(
849+
"Hello, world!", null, "de", options);
850+
System.out.println(result.getText());
851+
852+
// Or using a TranslationMemoryInfo object from listTranslationMemories()
853+
List<TranslationMemoryInfo> memories = client.listTranslationMemories();
854+
if (!memories.isEmpty()) {
855+
TextTranslationOptions optionsFromInfo = new TextTranslationOptions()
856+
.setTranslationMemory(memories.get(0));
857+
TextResult resultFromInfo = client.translateText(
858+
"Hello, world!", null, "de", optionsFromInfo);
859+
System.out.println(resultFromInfo.getText());
860+
}
861+
}
862+
}
863+
```
864+
800865
### Checking account usage
801866

802867
To check account usage, use the `getUsage()` function.

deepl-java/src/main/java/com/deepl/api/DeepLClient.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,64 @@ public List<StyleRuleInfo> getAllStyleRules() throws DeepLException, Interrupted
803803
return getAllStyleRules(null, null, null);
804804
}
805805

806+
/**
807+
* Retrieves a list of translation memories available for the account associated with the DeepL
808+
* API auth key. The maximum number of translation memories returned is controlled by pageSize
809+
* (max 25).
810+
*
811+
* @param page Page number to retrieve (starting from 0), or <code>null</code>.
812+
* @param pageSize Number of items per page, or <code>null</code>.
813+
* @return List of {@link TranslationMemoryInfo} objects.
814+
* @throws InterruptedException If the thread is interrupted during execution of this function.
815+
* @throws DeepLException If any error occurs while communicating with the DeepL API.
816+
*/
817+
public List<TranslationMemoryInfo> listTranslationMemories(
818+
@Nullable Integer page, @Nullable Integer pageSize)
819+
throws DeepLException, InterruptedException {
820+
ArrayList<KeyValuePair<String, String>> queryParams = new ArrayList<>();
821+
if (page != null) {
822+
queryParams.add(new KeyValuePair<>("page", page.toString()));
823+
}
824+
if (pageSize != null) {
825+
queryParams.add(new KeyValuePair<>("page_size", pageSize.toString()));
826+
}
827+
828+
String queryString = "";
829+
if (!queryParams.isEmpty()) {
830+
StringBuilder sb = new StringBuilder("?");
831+
for (int i = 0; i < queryParams.size(); i++) {
832+
if (i > 0) {
833+
sb.append("&");
834+
}
835+
KeyValuePair<String, String> param = queryParams.get(i);
836+
try {
837+
sb.append(URLEncoder.encode(param.getKey(), StandardCharsets.UTF_8.name()))
838+
.append("=")
839+
.append(URLEncoder.encode(param.getValue(), StandardCharsets.UTF_8.name()));
840+
} catch (java.io.UnsupportedEncodingException e) {
841+
throw new RuntimeException("UTF-8 encoding not supported", e);
842+
}
843+
}
844+
queryString = sb.toString();
845+
}
846+
847+
String relativeUrl = "/v3/translation_memories" + queryString;
848+
HttpResponse response = httpClientWrapper.sendGetRequestWithBackoff(relativeUrl);
849+
checkResponse(response, false, false);
850+
return jsonParser.parseTranslationMemoryInfoList(response.getBody());
851+
}
852+
853+
/**
854+
* Functions the same as {@link DeepLClient#listTranslationMemories(Integer, Integer, Boolean)}
855+
* but with default parameters (all null).
856+
*
857+
* @see DeepLClient#listTranslationMemories(Integer, Integer)
858+
*/
859+
public List<TranslationMemoryInfo> listTranslationMemories()
860+
throws DeepLException, InterruptedException {
861+
return listTranslationMemories(null, null);
862+
}
863+
806864
/**
807865
* Creates a new style rule with the specified details and returns a {@link StyleRuleInfo} object
808866
* with details about the newly created style rule.

deepl-java/src/main/java/com/deepl/api/TextTranslationOptions.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class TextTranslationOptions extends BaseRequestOptions {
1717
private Formality formality;
1818
private String glossaryId;
1919
private String styleId;
20+
private String translationMemoryId;
21+
private Integer translationMemoryThreshold;
2022
private SentenceSplittingMode sentenceSplittingMode;
2123
private boolean preserveFormatting = false;
2224
private String context;
@@ -85,6 +87,41 @@ public TextTranslationOptions setStyleRule(StyleRuleInfo styleRule) {
8587
return setStyleId(styleRule.getStyleId());
8688
}
8789

90+
/**
91+
* Sets the ID of a translation memory to use with the translation. By default, this value is
92+
* <code>null</code> and no translation memory is used.
93+
*/
94+
public TextTranslationOptions setTranslationMemoryId(String translationMemoryId) {
95+
this.translationMemoryId = translationMemoryId;
96+
return this;
97+
}
98+
99+
/**
100+
* Sets the translation memory to use with the translation. By default, this value is <code>null
101+
* </code> and no translation memory is used.
102+
*/
103+
public TextTranslationOptions setTranslationMemory(TranslationMemoryInfo translationMemory) {
104+
if (translationMemory == null) {
105+
throw new IllegalArgumentException("translationMemory must not be null");
106+
}
107+
return setTranslationMemoryId(translationMemory.getTranslationMemoryId());
108+
}
109+
110+
/**
111+
* Sets the threshold for translation memory matches. By default, this value is <code>null</code>
112+
* and the API default threshold is used. Note: a translation memory ID must also be set via
113+
* {@link #setTranslationMemoryId} or {@link #setTranslationMemory}, otherwise an error will be
114+
* thrown at translation time.
115+
*/
116+
public TextTranslationOptions setTranslationMemoryThreshold(Integer translationMemoryThreshold) {
117+
if (translationMemoryThreshold != null
118+
&& (translationMemoryThreshold < 0 || translationMemoryThreshold > 100)) {
119+
throw new IllegalArgumentException("translationMemoryThreshold must be between 0 and 100");
120+
}
121+
this.translationMemoryThreshold = translationMemoryThreshold;
122+
return this;
123+
}
124+
88125
/**
89126
* Specifies additional context to influence translations, that is not translated itself.
90127
* Characters in the `context` parameter are not counted toward billing. See the API documentation
@@ -210,6 +247,16 @@ public String getStyleId() {
210247
return styleId;
211248
}
212249

250+
/** Gets the current translation memory ID. */
251+
public String getTranslationMemoryId() {
252+
return translationMemoryId;
253+
}
254+
255+
/** Gets the current translation memory threshold. */
256+
public Integer getTranslationMemoryThreshold() {
257+
return translationMemoryThreshold;
258+
}
259+
213260
/** Gets the current sentence splitting mode. */
214261
public SentenceSplittingMode getSentenceSplittingMode() {
215262
return sentenceSplittingMode;
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright 2025 DeepL SE (https://www.deepl.com)
2+
// Use of this source code is governed by an MIT
3+
// license that can be found in the LICENSE file.
4+
package com.deepl.api;
5+
6+
import com.google.gson.annotations.*;
7+
import java.util.*;
8+
9+
/** Information about a translation memory. */
10+
public class TranslationMemoryInfo {
11+
@SerializedName(value = "translation_memory_id")
12+
private final String translationMemoryId;
13+
14+
@SerializedName(value = "name")
15+
private final String name;
16+
17+
@SerializedName(value = "source_language")
18+
private final String sourceLanguage;
19+
20+
@SerializedName(value = "target_languages")
21+
private final List<String> targetLanguages;
22+
23+
@SerializedName(value = "segment_count")
24+
private final int segmentCount;
25+
26+
/**
27+
* Initializes a new {@link TranslationMemoryInfo} containing information about a translation
28+
* memory.
29+
*
30+
* @param translationMemoryId Unique ID assigned to the translation memory.
31+
* @param name User-defined name assigned to the translation memory.
32+
* @param sourceLanguage Source language code for the translation memory.
33+
* @param targetLanguages List of target language codes for the translation memory.
34+
* @param segmentCount Number of segments in the translation memory.
35+
*/
36+
public TranslationMemoryInfo(
37+
String translationMemoryId,
38+
String name,
39+
String sourceLanguage,
40+
List<String> targetLanguages,
41+
int segmentCount) {
42+
this.translationMemoryId = translationMemoryId;
43+
this.name = name;
44+
this.sourceLanguage = sourceLanguage;
45+
this.targetLanguages = targetLanguages;
46+
this.segmentCount = segmentCount;
47+
}
48+
49+
/** @return Unique ID assigned to the translation memory. */
50+
public String getTranslationMemoryId() {
51+
return translationMemoryId;
52+
}
53+
54+
/** @return User-defined name assigned to the translation memory. */
55+
public String getName() {
56+
return name;
57+
}
58+
59+
/** @return Source language code for the translation memory. */
60+
public String getSourceLanguage() {
61+
return sourceLanguage;
62+
}
63+
64+
/** @return List of target language codes for the translation memory. */
65+
public List<String> getTargetLanguages() {
66+
return targetLanguages;
67+
}
68+
69+
/** @return Number of segments in the translation memory. */
70+
public int getSegmentCount() {
71+
return segmentCount;
72+
}
73+
74+
@Override
75+
public String toString() {
76+
return "TranslationMemoryInfo{"
77+
+ "translationMemoryId='"
78+
+ translationMemoryId
79+
+ '\''
80+
+ ", name='"
81+
+ name
82+
+ '\''
83+
+ ", sourceLanguage='"
84+
+ sourceLanguage
85+
+ '\''
86+
+ ", targetLanguages="
87+
+ targetLanguages
88+
+ ", segmentCount="
89+
+ segmentCount
90+
+ '}';
91+
}
92+
}

deepl-java/src/main/java/com/deepl/api/Translator.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,19 @@ private static ArrayList<KeyValuePair<String, String>> createHttpParams(
852852
if (options.getStyleId() != null) {
853853
params.add(new KeyValuePair<>("style_id", options.getStyleId()));
854854
}
855+
if (options.getTranslationMemoryId() != null) {
856+
params.add(new KeyValuePair<>("translation_memory_id", options.getTranslationMemoryId()));
857+
}
858+
if (options.getTranslationMemoryThreshold() != null) {
859+
if (options.getTranslationMemoryId() == null) {
860+
throw new IllegalArgumentException(
861+
"translationMemoryThreshold requires translationMemoryId");
862+
}
863+
params.add(
864+
new KeyValuePair<>(
865+
"translation_memory_threshold",
866+
options.getTranslationMemoryThreshold().toString()));
867+
}
855868
if (options.getCustomInstructions() != null) {
856869
for (String instruction : options.getCustomInstructions()) {
857870
params.add(new KeyValuePair<>("custom_instructions", instruction));

deepl-java/src/main/java/com/deepl/api/parsing/Parser.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ public StyleRuleInfo parseStyleRuleInfo(String json) {
9999
return gson.fromJson(json, StyleRuleInfo.class);
100100
}
101101

102+
public List<TranslationMemoryInfo> parseTranslationMemoryInfoList(String json) {
103+
TranslationMemoryListResponse result = gson.fromJson(json, TranslationMemoryListResponse.class);
104+
return result.getTranslationMemories();
105+
}
106+
107+
public TranslationMemoryInfo parseTranslationMemoryInfo(String json) {
108+
return gson.fromJson(json, TranslationMemoryInfo.class);
109+
}
110+
102111
public CustomInstruction parseCustomInstruction(String json) {
103112
return gson.fromJson(json, CustomInstruction.class);
104113
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2025 DeepL SE (https://www.deepl.com)
2+
// Use of this source code is governed by an MIT
3+
// license that can be found in the LICENSE file.
4+
package com.deepl.api.parsing;
5+
6+
import com.deepl.api.TranslationMemoryInfo;
7+
import java.util.List;
8+
9+
/**
10+
* Class representing v3 translation_memories list response by the DeepL API.
11+
*
12+
* <p>This class is internal; you should not use this class directly.
13+
*/
14+
class TranslationMemoryListResponse {
15+
private List<TranslationMemoryInfo> translation_memories;
16+
17+
public List<TranslationMemoryInfo> getTranslationMemories() {
18+
return translation_memories;
19+
}
20+
}

0 commit comments

Comments
 (0)