All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.deepl.api.Translator Maven / Gradle / Ivy

The newest version!
// Copyright 2022 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api;

import com.deepl.api.http.HttpResponse;
import com.deepl.api.http.HttpResponseStream;
import com.deepl.api.parsing.Parser;
import com.deepl.api.utils.*;
import com.google.gson.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.util.*;
import org.jetbrains.annotations.Nullable;

/**
 * Client for the DeepL API. To use the DeepL API, initialize an instance of this class using your
 * DeepL Authentication Key as found in your DeepL
 * account.
 */
public class Translator {
  /** Base URL for DeepL API Free accounts. */
  private static final String DEEPL_SERVER_URL_FREE = "https://api-free.deepl.com";
  /** Base URL for DeepL API Pro accounts */
  private static final String DEEPL_SERVER_URL_PRO = "https://api.deepl.com";

  private final Parser jsonParser = new Parser();
  private final HttpClientWrapper httpClientWrapper;

  /**
   * Initializes a new Translator object using your Authentication Key.
   *
   * 

Note: This function does not establish a connection to the DeepL API. To check connectivity, * use {@link Translator#getUsage()}. * * @param authKey DeepL Authentication Key as found in your DeepL account. * @param options Additional options controlling Translator behaviour. * @throws IllegalArgumentException If authKey is invalid. */ public Translator(String authKey, TranslatorOptions options) throws IllegalArgumentException { if (authKey == null || authKey.length() == 0) { throw new IllegalArgumentException("authKey must be a non-empty string"); } String serverUrl = (options.getServerUrl() != null) ? options.getServerUrl() : (isFreeAccountAuthKey(authKey) ? DEEPL_SERVER_URL_FREE : DEEPL_SERVER_URL_PRO); Map headers = new HashMap<>(); if (options.getHeaders() != null) { headers.putAll(options.getHeaders()); } headers.putIfAbsent("Authorization", "DeepL-Auth-Key " + authKey); headers.putIfAbsent( "User-Agent", constructUserAgentString(options.getSendPlatformInfo(), options.getAppInfo())); this.httpClientWrapper = new HttpClientWrapper( serverUrl, headers, options.getTimeout(), options.getProxy(), options.getMaxRetries()); } /** * Initializes a new Translator object using your Authentication Key. * *

Note: This function does not establish a connection to the DeepL API. To check connectivity, * use {@link Translator#getUsage()}. * * @param authKey DeepL Authentication Key as found in your DeepL account. * @throws IllegalArgumentException If authKey is invalid. */ public Translator(String authKey) throws IllegalArgumentException { this(authKey, new TranslatorOptions()); } /** * Builds the user-agent String which contains platform information. * * @return A string containing the client library version, java version and operating system. */ private String constructUserAgentString(boolean sendPlatformInfo, AppInfo appInfo) { StringBuilder sb = new StringBuilder(); sb.append("deepl-java/1.7.0"); if (sendPlatformInfo) { sb.append(" ("); Properties props = System.getProperties(); sb.append(props.get("os.name") + "-" + props.get("os.version") + "-" + props.get("os.arch")); sb.append(") java/"); sb.append(props.get("java.version")); } if (appInfo != null) { sb.append(" " + appInfo.getAppName() + "/" + appInfo.getAppVersion()); } return sb.toString(); } /** * Determines if the given DeepL Authentication Key belongs to an API Free account. * * @param authKey DeepL Authentication Key as found in your DeepL account. * @return true if the Authentication Key belongs to an API Free account, otherwise * false. */ public static boolean isFreeAccountAuthKey(String authKey) { return authKey != null && authKey.endsWith(":fx"); } /** * Translate specified text from source language into target language. * * @param text Text to translate; must not be empty. * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return Text translated into specified target language, and detected source language. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public TextResult translateText( String text, @Nullable String sourceLang, String targetLang, @Nullable TextTranslationOptions options) throws InterruptedException, DeepLException { ArrayList texts = new ArrayList<>(); texts.add(text); return translateText(texts, sourceLang, targetLang, options).get(0); } /** * Functions the same as {@link Translator#translateText(String, String, String, * TextTranslationOptions)} but with default options. * * @see Translator#translateText(String, String, String, TextTranslationOptions) */ public TextResult translateText(String text, @Nullable String sourceLang, String targetLang) throws DeepLException, InterruptedException { return translateText(text, sourceLang, targetLang, null); } /** * Functions the same as {@link Translator#translateText(String, String, String, * TextTranslationOptions)} but accepts {@link Language} objects for source and target languages, * and uses default options. * * @see Translator#translateText(String, String, String, TextTranslationOptions) */ public TextResult translateText(String text, @Nullable Language sourceLang, Language targetLang) throws DeepLException, InterruptedException { return translateText( text, (sourceLang != null) ? sourceLang.getCode() : null, targetLang.getCode(), null); } /** * Functions the same as {@link Translator#translateText(String, String, String, * TextTranslationOptions)} but accepts {@link Language} objects for source and target languages. * * @see Translator#translateText(String, String, String, TextTranslationOptions) */ public TextResult translateText( String text, @Nullable Language sourceLang, Language targetLang, @Nullable TextTranslationOptions options) throws DeepLException, InterruptedException { return translateText( text, (sourceLang != null) ? sourceLang.getCode() : null, targetLang.getCode(), options); } /** * Translate specified texts from source language into target language. * * @param texts List of texts to translate; each text must not be empty. * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return List of texts translated into specified target language, and detected source language. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public List translateText( List texts, @Nullable String sourceLang, String targetLang, @Nullable TextTranslationOptions options) throws DeepLException, InterruptedException { Iterable> params = createHttpParams(texts, sourceLang, targetLang, options); HttpResponse response = httpClientWrapper.sendRequestWithBackoff("/v2/translate", params); checkResponse(response, false, false); return jsonParser.parseTextResult(response.getBody()); } /** * Functions the same as {@link Translator#translateText(List, String, String, * TextTranslationOptions)} but accepts {@link Language} objects for source and target languages, * and uses default options. * * @see Translator#translateText(List, String, String, TextTranslationOptions) */ public List translateText( List texts, @Nullable Language sourceLang, Language targetLang) throws DeepLException, InterruptedException { return translateText( texts, (sourceLang != null) ? sourceLang.getCode() : null, targetLang.getCode(), null); } /** * Functions the same as {@link Translator#translateText(List, String, String, * TextTranslationOptions)} but accepts {@link Language} objects for source and target languages. * * @see Translator#translateText(List, String, String, TextTranslationOptions) */ public List translateText( List texts, @Nullable Language sourceLang, Language targetLang, @Nullable TextTranslationOptions options) throws DeepLException, InterruptedException { return translateText( texts, (sourceLang != null) ? sourceLang.getCode() : null, targetLang.getCode(), options); } /** * Functions the same as {@link Translator#translateText(List, String, String, * TextTranslationOptions)} but uses default options. * * @see Translator#translateText(List, String, String, TextTranslationOptions) */ public List translateText( List texts, @Nullable String sourceLang, String targetLang) throws DeepLException, InterruptedException { return translateText(texts, sourceLang, targetLang, null); } /** * Retrieves the usage in the current billing period for this DeepL account. This function can * also be used to check connectivity with the DeepL API and that the account has access. * * @return {@link Usage} object containing account usage information. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public Usage getUsage() throws DeepLException, InterruptedException { HttpResponse response = httpClientWrapper.sendGetRequestWithBackoff("/v2/usage"); checkResponse(response, false, false); return jsonParser.parseUsage(response.getBody()); } /** * Retrieves the list of supported translation source languages. * * @return List of {@link Language} objects representing the available translation source * languages. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public List getSourceLanguages() throws DeepLException, InterruptedException { return getLanguages(LanguageType.Source); } /** * Retrieves the list of supported translation target languages. * * @return List of {@link Language} objects representing the available translation target * languages. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public List getTargetLanguages() throws DeepLException, InterruptedException { return getLanguages(LanguageType.Target); } /** * Retrieves the list of supported translation source or target languages. * * @param languageType The type of languages to retrieve, source or target. * @return List of {@link Language} objects representing the available translation source or * target languages. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public List getLanguages(LanguageType languageType) throws DeepLException, InterruptedException { ArrayList> params = new ArrayList<>(); if (languageType == LanguageType.Target) { params.add(new KeyValuePair<>("type", "target")); } HttpResponse response = httpClientWrapper.sendRequestWithBackoff("/v2/languages", params); checkResponse(response, false, false); return jsonParser.parseLanguages(response.getBody()); } /** * Retrieves the list of supported glossary language pairs. When creating glossaries, the source * and target language pair must match one of the available language pairs. * * @return List of {@link GlossaryLanguagePair} objects representing the available glossary * language pairs. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public List getGlossaryLanguages() throws DeepLException, InterruptedException { HttpResponse response = httpClientWrapper.sendGetRequestWithBackoff("/v2/glossary-language-pairs"); checkResponse(response, false, false); return jsonParser.parseGlossaryLanguageList(response.getBody()); } /** * Translate specified document content from source language to target language and store the * translated document content to specified stream. * * @param inputFile File to upload to be translated. * @param outputFile File to download translated document to. * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return Status when document translation completed, this allows the number of billed characters * to be queried. * @throws IOException If the output path is occupied or the input file does not exist. * @throws DocumentTranslationException If any error occurs while communicating with the DeepL * API, or if the thread is interrupted during execution of this function. The exception * includes the document handle that may be used to retrieve the document. */ public DocumentStatus translateDocument( File inputFile, File outputFile, @Nullable String sourceLang, String targetLang, @Nullable DocumentTranslationOptions options) throws DocumentTranslationException, IOException { try { if (outputFile.exists()) { throw new IOException("File already exists at output path"); } try (InputStream inputStream = new FileInputStream(inputFile); OutputStream outputStream = new FileOutputStream(outputFile)) { return translateDocument( inputStream, inputFile.getName(), outputStream, sourceLang, targetLang, options); } } catch (Exception exception) { outputFile.delete(); throw exception; } } /** * Functions the same as {@link Translator#translateDocument(File, File, String, String, * DocumentTranslationOptions)} but uses default options. * * @see Translator#translateDocument(File, File, String, String, DocumentTranslationOptions) */ public DocumentStatus translateDocument( File inputFile, File outputFile, @Nullable String sourceLang, String targetLang) throws DocumentTranslationException, IOException { return translateDocument(inputFile, outputFile, sourceLang, targetLang, null); } /** * Translate specified document content from source language to target language and store the * translated document content to specified stream. On return, input stream will be at end of * stream and neither stream will be closed. * * @param inputStream Stream containing file to upload to be translated. * @param fileName Name of the input file. The file extension is used to determine file type. * @param outputStream Stream to download translated document to. * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return Status when document translation completed, this allows the number of billed characters * to be queried. * @throws DocumentTranslationException If any error occurs while communicating with the DeepL * API, or if the thread is interrupted during execution of this function. The exception * includes the document handle that may be used to retrieve the document. */ public DocumentStatus translateDocument( InputStream inputStream, String fileName, OutputStream outputStream, @Nullable String sourceLang, String targetLang, @Nullable DocumentTranslationOptions options) throws DocumentTranslationException { DocumentHandle handle = null; try { handle = translateDocumentUpload(inputStream, fileName, sourceLang, targetLang, options); DocumentStatus status = translateDocumentWaitUntilDone(handle); translateDocumentDownload(handle, outputStream); return status; } catch (Exception exception) { throw new DocumentTranslationException( "Error occurred during document translation: " + exception.getMessage(), exception, handle); } } /** * Functions the same as {@link Translator#translateDocument(InputStream, String, OutputStream, * String, String, DocumentTranslationOptions)} but uses default options. * * @see Translator#translateDocument(InputStream, String, OutputStream, String, String, * DocumentTranslationOptions) */ public DocumentStatus translateDocument( InputStream inputFile, String fileName, OutputStream outputFile, @Nullable String sourceLang, String targetLang) throws DocumentTranslationException { return translateDocument(inputFile, fileName, outputFile, sourceLang, targetLang, null); } /** * Upload document at specified input path for translation from source language to target * language. See the DeepL API * documentation for the currently supported document types. * * @param inputFile File containing document to be translated. * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return Handle associated with the in-progress document translation. * @throws IOException If the input file does not exist. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public DocumentHandle translateDocumentUpload( File inputFile, @Nullable String sourceLang, String targetLang, @Nullable DocumentTranslationOptions options) throws DeepLException, IOException, InterruptedException { Iterable> params = createHttpParams(sourceLang, targetLang, options); try (FileInputStream inputStream = new FileInputStream(inputFile)) { HttpResponse response = httpClientWrapper.uploadWithBackoff( "/v2/document", params, inputFile.getName(), inputStream); checkResponse(response, false, false); return jsonParser.parseDocumentHandle(response.getBody()); } } /** * Functions the same as {@link Translator#translateDocumentUpload(File, String, String, * DocumentTranslationOptions)} but uses default options. * * @see Translator#translateDocumentUpload(File, String, String, DocumentTranslationOptions) */ public DocumentHandle translateDocumentUpload( File inputFile, @Nullable String sourceLang, String targetLang) throws DeepLException, IOException, InterruptedException { return translateDocumentUpload(inputFile, sourceLang, targetLang, null); } /** * Upload document at specified input path for translation from source language to target * language. See the DeepL API * documentation for the currently supported document types. * * @param inputStream Stream containing document to be translated. On return, input stream will be * at end of stream and will not be closed. * @param fileName Name of the input file. The file extension is used to determine file type. * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return Handle associated with the in-progress document translation. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public DocumentHandle translateDocumentUpload( InputStream inputStream, String fileName, @Nullable String sourceLang, String targetLang, @Nullable DocumentTranslationOptions options) throws DeepLException, InterruptedException { Iterable> params = createHttpParams(sourceLang, targetLang, options); HttpResponse response = httpClientWrapper.uploadWithBackoff("/v2/document/", params, fileName, inputStream); checkResponse(response, false, false); return jsonParser.parseDocumentHandle(response.getBody()); } /** * Functions the same as {@link Translator#translateDocumentUpload(InputStream, String, String, * String, DocumentTranslationOptions)} but uses default options. * * @see Translator#translateDocumentUpload(InputStream, String, String, String, * DocumentTranslationOptions) */ public DocumentHandle translateDocumentUpload( InputStream inputStream, String fileName, @Nullable String sourceLang, String targetLang) throws DeepLException, InterruptedException { return translateDocumentUpload(inputStream, fileName, sourceLang, targetLang, null); } /** * Retrieve the status of in-progress document translation associated with specified handle. * * @param handle Handle associated with document translation to check. * @return Status of the document translation. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public DocumentStatus translateDocumentStatus(DocumentHandle handle) throws DeepLException, InterruptedException { ArrayList> params = new ArrayList<>(); params.add(new KeyValuePair<>("document_key", handle.getDocumentKey())); String relativeUrl = String.format("/v2/document/%s", handle.getDocumentId()); HttpResponse response = httpClientWrapper.sendRequestWithBackoff(relativeUrl, params); checkResponse(response, false, false); return jsonParser.parseDocumentStatus(response.getBody()); } /** * Checks document translation status and waits until document translation is complete or fails * due to an error. * * @param handle Handle associated with document translation to wait for. * @return Status when document translation completed, this allows the number of billed characters * to be queried. * @throws InterruptedException If the thread is interrupted while waiting for the document * translation to complete. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public DocumentStatus translateDocumentWaitUntilDone(DocumentHandle handle) throws InterruptedException, DeepLException { DocumentStatus status = translateDocumentStatus(handle); while (status.ok() && !status.done()) { Thread.sleep(calculateDocumentWaitTimeMillis(status.getSecondsRemaining())); status = translateDocumentStatus(handle); } if (!status.ok()) { String message = (status.getErrorMessage() != null) ? status.getErrorMessage() : "Unknown error"; throw new DeepLException(message); } return status; } /** * Downloads the resulting translated document associated with specified handle to the specified * output file. The document translation must be complete i.e. {@link DocumentStatus#done()} for * the document status must be true. * * @param handle Handle associated with document translation to download. * @param outputFile File to download translated document to. * @throws IOException If the output path is occupied. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public void translateDocumentDownload(DocumentHandle handle, File outputFile) throws DeepLException, IOException, InterruptedException { try { if (outputFile.exists()) { throw new IOException("File already exists at output path"); } try (FileOutputStream outputStream = new FileOutputStream(outputFile)) { translateDocumentDownload(handle, outputStream); } } catch (Exception exception) { outputFile.delete(); throw exception; } } /** * Downloads the resulting translated document associated with specified handle to the specified * output stream. The document translation must be complete i.e. {@link DocumentStatus#done()} for * the document status must be true. The output stream is not closed. * * @param handle Handle associated with document translation to download. * @param outputStream Stream to download translated document to. * @throws IOException If an I/O error occurs. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public void translateDocumentDownload(DocumentHandle handle, OutputStream outputStream) throws DeepLException, IOException, InterruptedException { ArrayList> params = new ArrayList<>(); params.add(new KeyValuePair<>("document_key", handle.getDocumentKey())); String relativeUrl = String.format("/v2/document/%s/result", handle.getDocumentId()); try (HttpResponseStream response = httpClientWrapper.downloadWithBackoff(relativeUrl, params)) { checkResponse(response); assert response.getBody() != null; StreamUtil.transferTo(response.getBody(), outputStream); } } /** * Creates a glossary in your DeepL account with the specified details and returns a {@link * GlossaryInfo} object with details about the newly created glossary. The glossary can be used in * translations to override translations for specific terms (words). The glossary source and * target languages must match the languages of translations for which it will be used. * * @param name User-defined name to assign to the glossary; must not be empty. * @param sourceLang Language code of the source terms language. * @param targetLang Language code of the target terms language. * @param entries Glossary entries to add to the glossary. * @return {@link GlossaryInfo} object with details about the newly created glossary. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public GlossaryInfo createGlossary( String name, String sourceLang, String targetLang, GlossaryEntries entries) throws DeepLException, InterruptedException { return createGlossaryInternal(name, sourceLang, targetLang, "tsv", entries.toTsv()); } /** * Creates a glossary in your DeepL account with the specified details and returns a {@link * GlossaryInfo} object with details about the newly created glossary. The glossary can be used in * translations to override translations for specific terms (words). The glossary source and * target languages must match the languages of translations for which it will be used. * * @param name User-defined name to assign to the glossary; must not be empty. * @param sourceLang Language code of the source terms language. * @param targetLang Language code of the target terms language. * @param csvFile File containing CSV content for glossary. * @return {@link GlossaryInfo} object with details about the newly created glossary. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. * @throws IOException If an I/O error occurs. */ public GlossaryInfo createGlossaryFromCsv( String name, String sourceLang, String targetLang, File csvFile) throws DeepLException, InterruptedException, IOException { try (FileInputStream stream = new FileInputStream(csvFile)) { String csvContent = StreamUtil.readStream(stream); return createGlossaryFromCsv(name, sourceLang, targetLang, csvContent); } } /** * Creates a glossary in your DeepL account with the specified details and returns a {@link * GlossaryInfo} object with details about the newly created glossary. The glossary can be used in * translations to override translations for specific terms (words). The glossary source and * target languages must match the languages of translations for which it will be used. * * @param name User-defined name to assign to the glossary; must not be empty. * @param sourceLang Language code of the source terms language. * @param targetLang Language code of the target terms language. * @param csvContent String containing CSV content. * @return {@link GlossaryInfo} object with details about the newly created glossary. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public GlossaryInfo createGlossaryFromCsv( String name, String sourceLang, String targetLang, String csvContent) throws DeepLException, InterruptedException { return createGlossaryInternal(name, sourceLang, targetLang, "csv", csvContent); } /** * Retrieves information about the glossary with the specified ID and returns a {@link * GlossaryInfo} object containing details. This does not retrieve the glossary entries; to * retrieve entries use {@link Translator#getGlossaryEntries(String)} * * @param glossaryId ID of glossary to retrieve. * @return {@link GlossaryInfo} object with details about the specified glossary. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public GlossaryInfo getGlossary(String glossaryId) throws DeepLException, InterruptedException { String relativeUrl = String.format("/v2/glossaries/%s", glossaryId); HttpResponse response = httpClientWrapper.sendGetRequestWithBackoff(relativeUrl); checkResponse(response, false, true); return jsonParser.parseGlossaryInfo(response.getBody()); } /** * Retrieves information about all glossaries and returns an array of {@link GlossaryInfo} objects * containing details. This does not retrieve the glossary entries; to retrieve entries use {@link * Translator#getGlossaryEntries(String)} * * @return Array of {@link GlossaryInfo} objects with details about each glossary. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public List listGlossaries() throws DeepLException, InterruptedException { HttpResponse response = httpClientWrapper.sendGetRequestWithBackoff("/v2/glossaries"); checkResponse(response, false, false); return jsonParser.parseGlossaryInfoList(response.getBody()); } /** * Retrieves the entries containing within the glossary and returns them as a {@link * GlossaryEntries}. * * @param glossary {@link GlossaryInfo} object corresponding to glossary for which to retrieve * entries. * @return {@link GlossaryEntries} containing entry pairs of the glossary. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public GlossaryEntries getGlossaryEntries(GlossaryInfo glossary) throws DeepLException, InterruptedException { return getGlossaryEntries(glossary.getGlossaryId()); } /** * Retrieves the entries containing within the glossary with the specified ID and returns them as * a {@link GlossaryEntries}. * * @param glossaryId ID of glossary for which to retrieve entries. * @return {@link GlossaryEntries} containing entry pairs of the glossary. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public GlossaryEntries getGlossaryEntries(String glossaryId) throws DeepLException, InterruptedException { String relativeUrl = String.format("/v2/glossaries/%s/entries", glossaryId); HttpResponse response = httpClientWrapper.sendGetRequestWithBackoff(relativeUrl); checkResponse(response, false, true); return GlossaryEntries.fromTsv(response.getBody()); } /** * Deletes the specified glossary. * * @param glossary {@link GlossaryInfo} object corresponding to glossary to delete. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public void deleteGlossary(GlossaryInfo glossary) throws DeepLException, InterruptedException { deleteGlossary(glossary.getGlossaryId()); } /** * Deletes the glossary with the specified ID. * * @param glossaryId ID of glossary to delete. * @throws InterruptedException If the thread is interrupted during execution of this function. * @throws DeepLException If any error occurs while communicating with the DeepL API. */ public void deleteGlossary(String glossaryId) throws DeepLException, InterruptedException { String relativeUrl = String.format("/v2/glossaries/%s", glossaryId); HttpResponse response = httpClientWrapper.sendDeleteRequestWithBackoff(relativeUrl); checkResponse(response, false, true); } /** * Checks the specified texts, languages and options are valid, and returns an iterable of * containing the parameters to include in HTTP request. * * @param texts Iterable of texts to translate. * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return Iterable of parameters for HTTP request. */ private static ArrayList> createHttpParams( List texts, @Nullable String sourceLang, String targetLang, @Nullable TextTranslationOptions options) { ArrayList> params = createHttpParamsCommon( sourceLang, targetLang, options != null ? options.getFormality() : null, options != null ? options.getGlossaryId() : null); texts.forEach( (text) -> { if (text.isEmpty()) throw new IllegalArgumentException("text must not be empty"); params.add(new KeyValuePair<>("text", text)); }); // Always send show_billed_characters=1, remove when the API default is changed to true params.add(new KeyValuePair<>("show_billed_characters", "1")); if (options != null) { // Note: formality and glossaryId are added above if (options.getSentenceSplittingMode() != null) { switch (options.getSentenceSplittingMode()) { case Off: params.add(new KeyValuePair<>("split_sentences", "0")); break; case NoNewlines: params.add(new KeyValuePair<>("split_sentences", "nonewlines")); break; case All: params.add(new KeyValuePair<>("split_sentences", "1")); break; default: break; } } if (options.isPreserveFormatting()) { params.add(new KeyValuePair<>("preserve_formatting", "1")); } if (options.getContext() != null) { params.add(new KeyValuePair<>("context", options.getContext())); } if (options.getModelType() != null) { params.add(new KeyValuePair<>("model_type", options.getModelType())); } if (options.getTagHandling() != null) { params.add(new KeyValuePair<>("tag_handling", options.getTagHandling())); } if (!options.isOutlineDetection()) { params.add(new KeyValuePair<>("outline_detection", "0")); } if (options.getSplittingTags() != null) { params.add(new KeyValuePair<>("splitting_tags", joinTags(options.getSplittingTags()))); } if (options.getNonSplittingTags() != null) { params.add( new KeyValuePair<>("non_splitting_tags", joinTags(options.getNonSplittingTags()))); } if (options.getIgnoreTags() != null) { params.add(new KeyValuePair<>("ignore_tags", joinTags(options.getIgnoreTags()))); } } return params; } /** * Checks the specified languages and document translation options are valid, and returns an * iterable of containing the parameters to include in HTTP request. * * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param options Options influencing translation. * @return Iterable of parameters for HTTP request. */ private static ArrayList> createHttpParams( String sourceLang, String targetLang, DocumentTranslationOptions options) { return createHttpParamsCommon( sourceLang, targetLang, options != null ? options.getFormality() : null, options != null ? options.getGlossaryId() : null); } /** * Checks the specified parameters common to both text and document translation are valid, and * returns an iterable of containing the parameters to include in HTTP request. * * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @param formality Formality option for translation. * @param glossaryId ID of glossary to use for translation. * @return Iterable of parameters for HTTP request. */ private static ArrayList> createHttpParamsCommon( @Nullable String sourceLang, String targetLang, @Nullable Formality formality, @Nullable String glossaryId) { targetLang = LanguageCode.standardize(targetLang); sourceLang = sourceLang == null ? null : LanguageCode.standardize(sourceLang); checkValidLanguages(sourceLang, targetLang); ArrayList> params = new ArrayList<>(); if (sourceLang != null) { params.add(new KeyValuePair<>("source_lang", sourceLang)); } params.add(new KeyValuePair<>("target_lang", targetLang)); if (formality != null) { switch (formality) { case More: params.add(new KeyValuePair<>("formality", "more")); break; case Less: params.add(new KeyValuePair<>("formality", "less")); break; case PreferMore: params.add(new KeyValuePair<>("formality", "prefer_more")); break; case PreferLess: params.add(new KeyValuePair<>("formality", "prefer_less")); break; case Default: default: params.add(new KeyValuePair<>("formality", "default")); break; } } if (glossaryId != null) { if (sourceLang == null) { throw new IllegalArgumentException("sourceLang is required if using a glossary"); } params.add(new KeyValuePair<>("glossary_id", glossaryId)); } return params; } /** Combine XML tags with comma-delimiter to be included in HTTP request parameters. */ private static String joinTags(Iterable tags) { return String.join(",", tags); } /** * Checks the specified source and target language are valid. * * @param sourceLang Language code of the input language, or null to use * auto-detection. * @param targetLang Language code of the desired output language. * @throws IllegalArgumentException If either language code is invalid. */ private static void checkValidLanguages(@Nullable String sourceLang, String targetLang) throws IllegalArgumentException { if (sourceLang != null && sourceLang.isEmpty()) { throw new IllegalArgumentException("sourceLang must be null or non-empty"); } if (targetLang.isEmpty()) { throw new IllegalArgumentException("targetLang must not be empty"); } switch (targetLang) { case "en": throw new IllegalArgumentException( "targetLang=\"en\" is not allowed, please use \"en-GB\" or \"en-US\" instead"); case "pt": throw new IllegalArgumentException( "targetLang=\"pt\" is not allowed, please use \"pt-PT\" or \"pt-BR\" instead"); default: break; } } /** Creates a glossary with given details. */ private GlossaryInfo createGlossaryInternal( String name, String sourceLang, String targetLang, String entriesFormat, String entries) throws DeepLException, InterruptedException { ArrayList> params = new ArrayList<>(); params.add(new KeyValuePair<>("name", name)); params.add(new KeyValuePair<>("source_lang", sourceLang)); params.add(new KeyValuePair<>("target_lang", targetLang)); params.add(new KeyValuePair<>("entries_format", entriesFormat)); params.add(new KeyValuePair<>("entries", entries)); HttpResponse response = httpClientWrapper.sendRequestWithBackoff("/v2/glossaries", params); checkResponse(response, false, false); return jsonParser.parseGlossaryInfo(response.getBody()); } /** * Functions the same as {@link Translator#checkResponse(HttpResponse, boolean, boolean)} but * accepts response stream for document downloads. If the HTTP status code represents failure, the * response stream is converted to a String response to throw the appropriate exception. * * @see Translator#checkResponse(HttpResponse, boolean, boolean) */ private void checkResponse(HttpResponseStream response) throws DeepLException { if (response.getCode() >= HttpURLConnection.HTTP_OK && response.getCode() < HttpURLConnection.HTTP_BAD_REQUEST) { return; } if (response.getBody() == null) { throw new DeepLException("response stream is empty"); } checkResponse(response.toStringResponse(), true, false); } /** * Checks the response HTTP status is OK, otherwise throws corresponding exception. * * @param response Response received from DeepL API. * @param inDocumentDownload True if document download function is used, otherwise false. * @param usingGlossary True if a glossary function is used, otherwise false. * @throws DeepLException Throws {@link DeepLException} or a derived exception depending on the * type of error. */ private void checkResponse( HttpResponse response, boolean inDocumentDownload, boolean usingGlossary) throws DeepLException { if (response.getCode() >= 200 && response.getCode() < 300) { return; } String messageSuffix = ""; String body = response.getBody(); if (body != null && !body.isEmpty()) { try { messageSuffix = ", error message: " + jsonParser.parseErrorMessage(body); } catch (JsonSyntaxException ignored) { messageSuffix = ", response: " + body; } } switch (response.getCode()) { case HttpURLConnection.HTTP_BAD_REQUEST: throw new DeepLException("Bad request" + messageSuffix); case HttpURLConnection.HTTP_FORBIDDEN: throw new AuthorizationException("Authorization failure, check auth_key" + messageSuffix); case HttpURLConnection.HTTP_NOT_FOUND: if (usingGlossary) { throw new GlossaryNotFoundException("Glossary not found" + messageSuffix); } else { throw new NotFoundException("Not found, check serverUrl" + messageSuffix); } case 429: throw new TooManyRequestsException( "Too many requests, DeepL servers are currently experiencing high load" + messageSuffix); case 456: throw new QuotaExceededException( "Quota for this billing period has been exceeded" + messageSuffix); case HttpURLConnection.HTTP_UNAVAILABLE: { if (inDocumentDownload) { throw new DocumentNotReadyException("Document not ready" + messageSuffix); } else { throw new DeepLException("Service unavailable" + messageSuffix); } } default: throw new DeepLException("Unknown error" + messageSuffix); } } private int calculateDocumentWaitTimeMillis(Long secondsRemaining) { // secondsRemaining is currently unreliable, so just poll equidistantly return 5000; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy