Skip to content

Commit 2a13037

Browse files
feat: Add support for multilingual glossary endpoints
1 parent abf1010 commit 2a13037

19 files changed

+2497
-46
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
87
## [Unreleased]
98
### Added
9+
* Added support for the /v3 Multilingual Glossary APIs in the client library
10+
while providing backwards compatability for the previous /v2 Glossary
11+
endpoints. Please refer to the README or
12+
[upgrading_to_multilingual_glossaries.md](upgrading_to_multilingual_glossaries.md)
13+
for usage instructions.
1014
* Added Ukrainian language code
1115

1216

README.md

Lines changed: 206 additions & 40 deletions
Large diffs are not rendered by default.

deepl-java/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ dependencies {
2727
implementation("org.jetbrains:annotations:20.1.0")
2828
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
2929
testImplementation("org.mockito:mockito-inline:4.11.0")
30+
implementation("org.apache.httpcomponents:httpclient:4.5.2") { because("java.net.HttpURLConnection does not support PATCH") }
3031

3132
// implementation("com.google.guava:guava:30.1.1-jre")
3233
implementation("com.google.code.gson:gson:2.10.1")

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

Lines changed: 779 additions & 1 deletion
Large diffs are not rendered by default.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public DocumentTranslationOptions setGlossaryId(String glossaryId) {
4343
* Sets the glossary to use with the translation. By default, this value is <code>null</code> and
4444
* no glossary is used.
4545
*/
46-
public DocumentTranslationOptions setGlossary(GlossaryInfo glossary) {
46+
public DocumentTranslationOptions setGlossary(IGlossary glossary) {
4747
return setGlossary(glossary.getGlossaryId());
4848
}
4949

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import org.jetbrains.annotations.*;
99

1010
/** Information about a glossary, excluding the entry list. */
11-
public class GlossaryInfo {
11+
public class GlossaryInfo implements IGlossary {
1212

1313
@SerializedName(value = "glossary_id")
1414
private final String glossaryId;

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

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
import java.net.*;
1010
import java.time.*;
1111
import java.util.*;
12+
import org.apache.http.client.config.RequestConfig;
13+
import org.apache.http.client.methods.HttpPatch;
14+
import org.apache.http.entity.ByteArrayEntity;
15+
import org.apache.http.impl.client.CloseableHttpClient;
16+
import org.apache.http.impl.client.HttpClients;
17+
import org.apache.http.util.EntityUtils;
1218
import org.jetbrains.annotations.*;
1319

1420
/**
@@ -21,6 +27,7 @@ class HttpClientWrapper {
2127
private static final String GET = "GET";
2228
private static final String POST = "POST";
2329
private static final String DELETE = "DELETE";
30+
private static final String PUT = "PUT";
2431
private final String serverUrl;
2532
private final Map<String, String> headers;
2633
private final Duration minTimeout;
@@ -45,9 +52,16 @@ public HttpResponse sendGetRequestWithBackoff(String relativeUrl)
4552
return sendRequestWithBackoff(GET, relativeUrl, null).toStringResponse();
4653
}
4754

55+
public HttpResponse sendDeleteRequestWithBackoff(
56+
String relativeUrl, @Nullable Iterable<KeyValuePair<String, String>> params)
57+
throws InterruptedException, DeepLException {
58+
HttpContent content = HttpContent.buildFormURLEncodedContent(params);
59+
return sendRequestWithBackoff(DELETE, relativeUrl, content).toStringResponse();
60+
}
61+
4862
public HttpResponse sendDeleteRequestWithBackoff(String relativeUrl)
4963
throws InterruptedException, DeepLException {
50-
return sendRequestWithBackoff(DELETE, relativeUrl, null).toStringResponse();
64+
return sendDeleteRequestWithBackoff(relativeUrl, null);
5165
}
5266

5367
public HttpResponse sendRequestWithBackoff(String relativeUrl)
@@ -62,6 +76,56 @@ public HttpResponse sendRequestWithBackoff(
6276
return sendRequestWithBackoff(POST, relativeUrl, content).toStringResponse();
6377
}
6478

79+
public HttpResponse sendPutRequestWithBackoff(
80+
String relativeUrl, @Nullable Iterable<KeyValuePair<String, String>> params)
81+
throws InterruptedException, DeepLException {
82+
HttpContent content = HttpContent.buildFormURLEncodedContent(params);
83+
return sendRequestWithBackoff(PUT, relativeUrl, content).toStringResponse();
84+
}
85+
86+
public HttpResponse sendPatchRequestWithBackoff(
87+
String relativeUrl, @Nullable Iterable<KeyValuePair<String, String>> params)
88+
throws DeepLException {
89+
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
90+
HttpContent content = HttpContent.buildFormURLEncodedContent(params);
91+
HttpPatch request = new HttpPatch(serverUrl + relativeUrl);
92+
93+
// Set timeouts
94+
BackoffTimer backoffTimer = new BackoffTimer(this.minTimeout);
95+
RequestConfig requestConfig =
96+
RequestConfig.custom()
97+
.setConnectTimeout((int) backoffTimer.getTimeoutMillis())
98+
.setSocketTimeout((int) backoffTimer.getTimeoutMillis())
99+
.build();
100+
request.setConfig(requestConfig);
101+
102+
// Set headers
103+
for (Map.Entry<String, String> entry : this.headers.entrySet()) {
104+
request.setHeader(entry.getKey(), entry.getValue());
105+
}
106+
107+
request.setHeader("Content-Type", content.getContentType());
108+
request.setEntity(new ByteArrayEntity(content.getContent()));
109+
110+
// Execute the request
111+
org.apache.http.HttpResponse response = httpClient.execute(request);
112+
113+
// Get the response stream
114+
InputStream responseStream =
115+
(response.getStatusLine().getStatusCode() >= 200
116+
&& response.getStatusLine().getStatusCode() < 400)
117+
? response.getEntity().getContent()
118+
: new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
119+
120+
return new HttpResponseStream(response.getStatusLine().getStatusCode(), responseStream)
121+
.toStringResponse();
122+
} catch (SocketTimeoutException e) {
123+
throw new ConnectionException(e.getMessage(), true, e);
124+
} catch (RuntimeException | IOException e) {
125+
throw new ConnectionException(e.getMessage(), false, e);
126+
}
127+
}
128+
65129
public HttpResponseStream downloadWithBackoff(
66130
String relativeUrl, @Nullable Iterable<KeyValuePair<String, String>> params)
67131
throws InterruptedException, DeepLException {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
/** Interface representing a glossary. */
7+
public interface IGlossary {
8+
/** @return Unique ID assigned to the glossary. */
9+
String getGlossaryId();
10+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
/** Stores the entries of a glossary. */
7+
public class MultilingualGlossaryDictionaryEntries {
8+
private final String sourceLanguageCode;
9+
private final String targetLanguageCode;
10+
private final GlossaryEntries entries;
11+
12+
/**
13+
* Initializes a new {@link MultilingualGlossaryDictionaryInfo} containing information about a
14+
* glossary dictionary.
15+
*
16+
* @param sourceLanguageCode the source language for this dictionary
17+
* @param targetLanguageCode the target language for this dictionary
18+
* @param entries the entries in this dictionary
19+
*/
20+
public MultilingualGlossaryDictionaryEntries(
21+
String sourceLanguageCode, String targetLanguageCode, GlossaryEntries entries) {
22+
this.sourceLanguageCode = sourceLanguageCode;
23+
this.targetLanguageCode = targetLanguageCode;
24+
this.entries = entries;
25+
}
26+
27+
/** @return the source language code */
28+
public String getSourceLanguageCode() {
29+
return this.sourceLanguageCode;
30+
}
31+
32+
/** @return the target language code */
33+
public String getTargetLanguageCode() {
34+
return this.targetLanguageCode;
35+
}
36+
37+
/** @return the entry count */
38+
public GlossaryEntries getEntries() {
39+
return this.entries;
40+
}
41+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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.SerializedName;
7+
8+
/** Stores the entries of a glossary. */
9+
public class MultilingualGlossaryDictionaryInfo {
10+
@SerializedName(value = "source_lang")
11+
private final String sourceLanguageCode;
12+
13+
@SerializedName(value = "target_lang")
14+
private final String targetLanguageCode;
15+
16+
@SerializedName(value = "entry_count")
17+
private final long entryCount;
18+
19+
/**
20+
* Initializes a new {@link MultilingualGlossaryDictionaryInfo} containing information about a
21+
* glossary dictionary.
22+
*
23+
* @param sourceLanguageCode the source language for this dictionary
24+
* @param targetLanguageCode the target language for this dictionary
25+
* @param entryCount the number of entries in this dictionary
26+
*/
27+
public MultilingualGlossaryDictionaryInfo(
28+
String sourceLanguageCode, String targetLanguageCode, long entryCount) {
29+
this.sourceLanguageCode = sourceLanguageCode;
30+
this.targetLanguageCode = targetLanguageCode;
31+
this.entryCount = entryCount;
32+
}
33+
34+
/** @return the source language code */
35+
public String getSourceLanguageCode() {
36+
return this.sourceLanguageCode;
37+
}
38+
39+
/** @return the target language code */
40+
public String getTargetLanguageCode() {
41+
return this.targetLanguageCode;
42+
}
43+
44+
/** @return the entry count */
45+
public long getEntryCount() {
46+
return this.entryCount;
47+
}
48+
}

0 commit comments

Comments
 (0)