Giter Site home page Giter Site logo

deeplcom / deepl-node Goto Github PK

View Code? Open in Web Editor NEW
311.0 9.0 18.0 1.44 MB

Official Node.js library for the DeepL language translation API.

License: MIT License

JavaScript 0.76% TypeScript 99.24%
translation nodejs deepl api javascript language official translator i18n

deepl-node's Introduction

deepl-node

Version Minimum node.js version License: MIT

Official Node.js Client Library for the DeepL API.

The DeepL API is a language translation API that allows other computer programs to send texts and documents to DeepL's servers and receive high-quality translations. This opens a whole universe of opportunities for developers: any translation product you can imagine can now be built on top of DeepL's best-in-class translation technology.

The DeepL Node.js library offers a convenient way for applications written for Node.js to interact with the DeepL API. We intend to support all API functions with the library, though support for new features may be added to the library after they’re added to the API.

Getting an authentication key

To use the package, you'll need an API authentication key. To get a key, please create an account here. With a DeepL API Free account you can translate up to 500,000 characters/month for free.

Installation

npm install deepl-node

Requirements

The package officially supports Node.js version 12, 14, 16, 17, and 18.

Starting in 2024, we will drop support for older Node versions that have reached official end-of-life. You can find the Node versions and support timelines here. To continue using this library, you should update to Node 18+.

Usage

Import the package and construct a Translator. The first argument is a string containing your API authentication key as found in your DeepL Pro Account.

Be careful not to expose your key, for example when sharing source code.

An example using async/await and ES Modules:

import * as deepl from 'deepl-node';

const authKey = "f63c02c5-f056-..."; // Replace with your key
const translator = new deepl.Translator(authKey);

(async () => {
    const result = await translator.translateText('Hello, world!', null, 'fr');
    console.log(result.text); // Bonjour, le monde !
})();

This example is for demonstration purposes only. In production code, the authentication key should not be hard-coded, but instead fetched from a configuration file or environment variable.

If you are using CommonJS, you should instead require the package:

const deepl = require('deepl-node');
const translator = new deepl.Translator(authKey);

Translator accepts options as the second argument, see Configuration for more information.

All Translator functions return promises, and for brevity the examples in this file use await and try/catch blocks, however Promise-chaining is also possible:

translator
    .translateText('Hello, world!', null, 'fr')
    .then((result) => {
        console.log(result.text); // Bonjour, le monde !
    })
    .catch((error) => {
        console.error(error);
    });

The package also supports TypeScript:

import * as deepl from 'deepl-node';

(async () => {
    const targetLang: deepl.TargetLanguageCode = 'fr';
    const results = await translator.translateText(
        ['Hello, world!', 'How are you?'],
        null,
        targetLang,
    );
    results.map((result: deepl.TextResult) => {
        console.log(result.text); // Bonjour, le monde !
    });
})();

Translating text

To translate text, call translateText(). The first argument is a string containing the text you want to translate, or an array of strings if you want to translate multiple texts.

The second and third arguments are the source and target language codes. Language codes are case-insensitive strings according to ISO 639-1, for example 'de', 'fr', 'ja''. Some target languages also include the regional variant according to ISO 3166-1, for example 'en-US', or 'pt-BR'. The source language also accepts null, to enable auto-detection of the source language.

The last argument to translateText() is optional, and specifies extra translation options, see Text translation options below.

translateText() returns a Promise that fulfills with a TextResult, or an array of TextResults corresponding to your input text(s). TextResult has two properties: text is the translated text, and detectedSourceLang is the detected source language code.

// Translate text into a target language, in this case, French:
const translationResult = await translator.translateText('Hello, world!', 'en', 'fr');
console.log(translationResult.text); // 'Bonjour, le monde !'

// Translate multiple texts into British English:
const translations = await translator.translateText(
    ['お元気ですか?', '¿Cómo estás?'],
    null,
    'en-GB',
);
console.log(translations[0].text); // 'How are you?'
console.log(translations[0].detectedSourceLang); // 'ja'
console.log(translations[1].text); // 'How are you?'
console.log(translations[1].detectedSourceLang); // 'es'

// Translate into German with less and more Formality:
console.log(await translator.translateText('How are you?', null, 'de', { formality: 'less' })); // 'Wie geht es dir?'
console.log(await translator.translateText('How are you?', null, 'de', { formality: 'more' })); // 'Wie geht es Ihnen?'

Text translation options

  • splitSentences: specify how input text should be split into sentences, default: 'on'.
    • 'on': input text will be split into sentences using both newlines and punctuation.
    • 'off': input text will not be split into sentences. Use this for applications where each input text contains only one sentence.
    • 'nonewlines': input text will be split into sentences using punctuation but not newlines.
  • preserveFormatting: controls automatic-formatting-correction. Set to true to prevent automatic-correction of formatting, default: false.
  • formality: controls whether translations should lean toward informal or formal language. This option is only available for some target languages, see Listing available languages. Use the prefer_* options to apply formality if it is available for the target
    language, or otherwise fallback to the default.
    • 'less': use informal language.
    • 'more': use formal, more polite language.
    • 'default': use default formality.
    • 'prefer_less': use informal language if available, otherwise default.
    • 'prefer_more': use formal, more polite language if available, otherwise default.
  • glossary: specifies a glossary to use with translation, either as a string containing the glossary ID, or a GlossaryInfo as returned by getGlossary().
  • context: specifies additional context to influence translations, that is not translated itself. Note this is an alpha feature: it may be deprecated at any time, or incur charges if it becomes generally available. See the API documentation for more information and example usage.
  • tagHandling: type of tags to parse before translation, options are 'html' and 'xml'.

The following options are only used if tagHandling is 'xml':

  • outlineDetection: specify false to disable automatic tag detection, default is true.
  • splittingTags: list of XML tags that should be used to split text into sentences. Tags may be specified as an array of strings (['tag1', 'tag2']), or a comma-separated list of strings ('tag1,tag2'). The default is an empty list.
  • nonSplittingTags: list of XML tags that should not be used to split text into sentences. Format and default are the same as for splittingTags.
  • ignoreTags: list of XML tags that containing content that should not be translated. Format and default are the same as for splittingTags.
  • extraRequestParameters: Extra body parameters to be passed along with the HTTP request. Only string values are permitted. For example: {'param': 'value', 'param2': 'value2'}

Translating documents

To translate documents, call translateDocument(). The first and second arguments are the input and output files. These arguments accept strings containing file paths, or Streams or FileHandles opened for reading/writing. The input file may also be given as a Buffer containing the file data. Note that if the input file is not given as a file path, then the filename option is required.

The third and fourth arguments are the source and target language codes, and they work exactly the same as when translating text with translateText().

The last argument to translateDocument() is optional, and specifies extra translation options, see Document translation options below.

// Translate a formal document from English to German:
try {
    await translator.translateDocument(
        'Instruction Manual.docx',
        'Bedienungsanleitung.docx',
        'en',
        'de',
        { formality: 'more' },
    );
} catch (error) {
    // If the error occurs after the document was already uploaded,
    // documentHandle will contain the document ID and key
    if (error.documentHandle) {
        const handle = error.documentHandle;
        console.log(`Document ID: ${handle.documentId}, ` + `Document key: ${handle.documentKey}`);
    } else {
        console.log(`Error occurred during document upload: ${error}`);
    }
}

translateDocument() wraps multiple API calls: uploading, polling status until the translation is complete, and downloading. If your application needs to execute these steps individually, you can instead use the following functions directly:

  • uploadDocument(),
  • getDocumentStatus() (or isDocumentTranslationComplete()), and
  • downloadDocument()

Document translation options

Glossaries

Glossaries allow you to customize your translations using defined terms. Multiple glossaries can be stored with your account, each with a user-specified name and a uniquely-assigned ID.

You can create a glossary with your desired terms and name using createGlossary(). Each glossary applies to a single source-target language pair. Note: glossaries are only supported for some language pairs, check the DeepL API documentation for more information.

// Create an English to German glossary with two terms:
const entries = new deepl.GlossaryEntries({ entries: { artist: 'Maler', prize: 'Gewinn' } });
const glossaryEnToDe = await translator.createGlossary('My glossary', 'en', 'de', entries);

You can also upload a glossary downloaded from the DeepL website using createGlossaryWithCsv(). Instead of supplying the entries as a dictionary, provide the CSV file as a string containing the file path, or a Stream, Buffer, or FileHandle containing the CSV file content:

const csvFilePath = '/path/to/glossary_file.csv';
const glossaryEnToDe = await translator.createGlossaryWithCsv(
    'My glossary',
    'en',
    'de',
    csvFilePath);

The API documentation explains the expected CSV format in detail.

Functions to get, list, and delete stored glossaries are also provided.

// Find details about the glossary named 'My glossary'
const glossaries = await translator.listGlossaries();
const glossary = glossaries.find((glossary) => glossary.name == 'My glossary');
console.log(
    `Glossary ID: ${glossary.glossaryId}, source: ${glossary.sourceLang}, ` +
        `target: ${glossary.targetLang}, contains ${glossary.entryCount} entries.`,
);

To use a glossary when translating text and documents, include the ID (or Glossary object returned by listGlossaries() or createGlossary()) in the function call. The source and target languages must match the glossary.

const resultWithGlossary = await translator.translateText(
    'The artist was awarded a prize.',
    'en',
    'de',
    { glossary },
);
console.log(resultWithGlossary.text); // 'Der Maler wurde mit einem Gewinn ausgezeichnet.'
// Without using a glossary would give:  'Der Künstler wurde mit einem Preis ausgezeichnet.'

Checking account usage

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

The returned Usage object contains up to three usage subtypes, depending on your account type: character, document and teamDocument. For API accounts character will be defined, the others undefined.

Each usage subtypes (if defined) have count and limit properties giving the amount used and maximum amount respectively, and the limitReached() function that checks if the usage has reached the limit. The top level Usage object has the anyLimitReached() function to check all usage subtypes.

const usage = await translator.getUsage();
if (usage.anyLimitReached()) {
    console.log('Translation limit exceeded.');
}
if (usage.character) {
    console.log(`Characters: ${usage.character.count} of ${usage.character.limit}`);
}
if (usage.document) {
    console.log(`Documents: ${usage.document.count} of ${usage.document.limit}`);
}

Listing available languages

You can request the list of languages supported by DeepL Translator for text and documents using the getSourceLanguages() and getTargetLanguages() functions. They both return an array of Language objects.

The name property gives the name of the language in English, and the code property gives the language code. The supportsFormality property only appears for target languages, and is a Boolean indicating whether the target language supports the optional formality parameter.

const sourceLanguages = await translator.getSourceLanguages();
for (let i = 0; i < sourceLanguages.length; i++) {
    const lang = sourceLanguages[i];
    console.log(`${lang.name} (${lang.code})`); // Example: 'English (en)'
}

const targetLanguages = await translator.getTargetLanguages();
for (let i = 0; i < targetLanguages.length; i++) {
    const lang = targetLanguages[i];
    if (lang.supportsFormality) {
        console.log(`${lang.name} (${lang.code}) supports formality`);
        // Example: 'German (DE) supports formality'
    }
}

Glossaries are supported for a subset of language pairs. To retrieve those languages use the getGlossaryLanguagePairs() function, which returns an array of GlossaryLanguagePair objects. Each has sourceLang and targetLang properties indicating that that pair of language codes is supported for glossaries.

const glossaryLanguages = await translator.getGlossaryLanguagePairs();
for (let i = 0; i < glossaryLanguages.length; i++) {
    const languagePair = glossaryLanguages[i];
    console.log(`${languagePair.sourceLang} to ${languagePair.targetLang}`);
    // Example: 'en to de', 'de to en', etc.
}

Writing a Plugin

If you use this library in an application, please identify the application with the appInfo field in the TranslatorOptions, which takes the name and version of the app:

const options = {appInfo: { appName: 'sampleNodeTranslationApp', appVersion: '1.2.3' },};
const deepl = new deepl.Translator('YOUR_AUTH_KEY', options);

This information is passed along when the library makes calls to the DeepL API. Both name and version are required.

Configuration

The Translator constructor accepts configuration options as a second argument, for example:

const options = { maxRetries: 5, minTimeout: 10000 };
const deepl = new deepl.Translator('YOUR_AUTH_KEY', options);

The available options are:

  • maxRetries: the maximum Number of failed HTTP requests to retry, per function call. By default, 5 retries are made. See Request retries.
  • minTimeout: the Number of milliseconds used as connection timeout for each HTTP request retry. The default value is 10000 (10 seconds).
  • serverUrl: string containing the URL of the DeepL API, can be overridden for example for testing purposes. By default, the URL is selected based on the user account type (free or paid).
  • headers: extra HTTP headers attached to every HTTP request. By default, no extra headers are used. Note that Authorization and User-Agent headers are added automatically but may be overridden by this option.
  • proxy: define the hostname, and port of the proxy server, and optionally the protocol, and authorization (as an auth object with username and password fields).

Logging

deepl-node logs debug and info messages for every HTTP request and response using the loglevel module, to the 'deepl' logger. You can reconfigure the log level as follows:

import log from 'loglevel';

log.getLogger('deepl').setLevel('debug'); // Or 'info'

The loglevel package also supports plugins, see the documentation.

Proxy configuration

You can configure a proxy by specifying the proxy argument when constructing a deepl.Translator:

const options = {proxy: {host: 'localhost', port: 3000}};
const deepl = new deepl.Translator('YOUR_AUTH_KEY', options);

The proxy argument is passed to the underlying axios request, see the documentation for axios.

Anonymous platform information

By default, we send some basic information about the platform the client library is running on with each request, see here for an explanation. This data is completely anonymous and only used to improve our product, not track any individual users. If you do not wish to send this data, you can opt-out when creating your Translator object by setting the sendPlatformInfo flag in the TranslatorOptions to false like so:

const options = {sendPlatformInfo: false};
const deepl = new deepl.Translator('YOUR_AUTH_KEY', options);

Request retries

Requests to the DeepL API that fail due to transient conditions (for example, network timeouts or high server-load) will be retried. The maximum number of retries can be configured when constructing the Translator object using the maxRetries option. The timeout for each request attempt may be controlled using the minTimeout option. An exponential-backoff strategy is used, so requests that fail multiple times will incur delays.

Issues

If you experience problems using the library, or would like to request a new feature, please open an issue.

Development

We welcome Pull Requests, please read the contributing guidelines.

Tests

Execute the tests using npm test. The tests communicate with the DeepL API using the authentication key defined by the DEEPL_AUTH_KEY environment variable.

Be aware that the tests make DeepL API requests that contribute toward your API usage.

The test suite may instead be configured to communicate with the mock-server provided by deepl-mock. Although most test cases work for either, some test cases work only with the DeepL API or the mock-server and will be otherwise skipped. The test cases that require the mock-server trigger server errors and test the client error-handling. To execute the tests using deepl-mock, run it in another terminal while executing the tests. Execute the tests using npm test with the DEEPL_MOCK_SERVER_PORT and DEEPL_SERVER_URL environment variables defined referring to the mock-server.

deepl-node's People

Contributors

daniel-jones-dev avatar deejaytc avatar janebbing avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

deepl-node's Issues

Does this package work with webpack?

I'm trying to implement this package while using webpack, and each time there always seems to be a new problem. Is it just not possible to use deepl-node with webpack?

cause: Error: socket hang up when try to send many requests

I need to translate a lot of data, when i try to do translate in loop i got this error. How i can prevent this?

ConnectionError: Connection failure: socket hang up
at Function.sendAxiosRequest (/Users/matthew/IdeaProjects/backend/node_modules/deepl-node/dist/client.js:163:27)
at runMicrotasks ()
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async HttpClient.sendRequestWithBackoff (/Users/matthew/IdeaProjects/backend/node_modules/deepl-node/dist/client.js:114:28)
at async Translator.translateText (/Users/matthew/IdeaProjects/backend/node_modules/deepl-node/dist/index.js:354:41)
at async /Users/matthew/IdeaProjects/backend/lib/utils/formatDocsJSON.js:156:17
at async Promise.all (index 45)
at async /Users/matthew/IdeaProjects/backend/lib/utils/formatDocsJSON.js:140:16
at async Promise.all (index 3)
at async formatJsonFile (/Users/matthew/IdeaProjects/backend/lib/utils/formatDocsJSON.js:139:18)
at async main (/Users/matthew/IdeaProjects/backend/lib/utils/formatDocsJSON.js:34:5) {
error: AxiosError: socket hang up
at Function.AxiosError.from (/Users/matthew/IdeaProjects/backend/node_modules/axios/dist/node/axios.cjs:789:14)
at RedirectableRequest.handleRequestError (/Users/matthew/IdeaProjects/backend/node_modules/axios/dist/node/axios.cjs:2744:25)
at RedirectableRequest.emit (node:events:525:35)
at ClientRequest.eventHandlers. (/Users/matthew/IdeaProjects/backend/node_modules/follow-redirects/index.js:14:24)
at ClientRequest.emit (node:events:513:28)
at TLSSocket.socketOnEnd (node:_http_client:518:9)
at TLSSocket.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1358:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
code: 'ECONNRESET',
config: {
transitional: [Object],
adapter: [Array],
transformRequest: [Array],
transformResponse: [Array],
timeout: 20000,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: [Object],
validateStatus: null,
headers: [AxiosHeaders],
url: '/v2/translate',
method: 'post',
baseURL: 'https://api.deepl.com',
responseType: 'text',
data: 'target_lang=en-US&source_lang=de&text=Apikoaortales%2C+klappentragendes+Konduit'
},
request: Writable {
_writableState: [WritableState],
_events: [Object: null prototype],
_eventsCount: 3,
_maxListeners: undefined,
_options: [Object],
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 79,
_requestBodyBuffers: [Array],
_onNativeResponse: [Function (anonymous)],
_currentRequest: [ClientRequest],
_currentUrl: 'https://api.deepl.com/v2/translate',
_timeout: null,
[Symbol(kCapture)]: false
},
cause: Error: socket hang up
at connResetException (node:internal/errors:705:14)
at TLSSocket.socketOnEnd (node:_http_client:518:23)
at TLSSocket.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1358:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
code: 'ECONNRESET'
}
},
shouldRetry: false
}

This is my configutration deepl.Translator(config.deeplApiKey, { maxRetries: 50, minTimeout: 20000 });

SSL error using node 17+

Describe the bug
All requests result in the following error:

C:\Projects\ext\translate-doc\node_modules\deepl-node\dist\client.js:163
            const error = new errors_1.ConnectionError(`Connection failure: ${message}`);
                          ^

ConnectionError: Connection failure: write EPROTO 98720000:error:0A000152:SSL routines:final_renegotiate:unsafe legacy renegotiation disabled:c:\ws\de
ps\openssl\openssl\ssl\statem\extensions.c:922:

    at HttpClient.sendAxiosRequest (C:\Projects\ext\translate-doc\node_modules\deepl-node\dist\client.js:163:27)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async HttpClient.sendRequestWithBackoff (C:\Projects\ext\translate-doc\node_modules\deepl-node\dist\client.js:114:28)
    at async Translator.translateText (C:\Projects\ext\translate-doc\node_modules\deepl-node\dist\index.js:355:41)
    at async file:///C:/Projects/ext/translate-doc/index.js:7:20 {
  error: AxiosError: write EPROTO 98720000:error:0A000152:SSL routines:final_renegotiate:unsafe legacy renegotiation disabled:c:\ws\deps\openssl\opens
sl\ssl\statem\extensions.c:922:

      at AxiosError.from (C:\Projects\ext\translate-doc\node_modules\axios\dist\node\axios.cjs:836:14)
      at RedirectableRequest.handleRequestError (C:\Projects\ext\translate-doc\node_modules\axios\dist\node\axios.cjs:3010:25)
      at RedirectableRequest.emit (node:events:525:35)
      at eventHandlers.<computed> (C:\Projects\ext\translate-doc\node_modules\follow-redirects\index.js:14:24)
      at ClientRequest.emit (node:events:513:28)
      at TLSSocket.socketErrorListener (node:_http_client:502:9)
      at TLSSocket.emit (node:events:513:28)
      at emitErrorNT (node:internal/streams/destroy:151:8)
      at emitErrorCloseNT (node:internal/streams/destroy:116:3)
      at process.processTicksAndRejections (node:internal/process/task_queues:82:21)

The underlying issue is probably the following: https://stackoverflow.com/questions/74324019/allow-legacy-renegotiation-for-nodejs

This only occurs on Node 17+.

To Reproduce

  1. Install node 18 (possibly using nvm)
  2. Create a new basic npm project npm init with index.js
  3. npm install deepl-node
  4. Copy/paste the contents of the 'hello world' example
  5. Enter authKey
  6. node index.js
  7. Generates the above error.

Expected behavior
The translation is logged to the console

Desktop

  • OS: Windows
  • Node 18.16.1

Feature Idea: Translate webpage from url

The contributors file said that would-be contributors should open an issue for suggested features instead of just jumping straight into making a pull request. I'm using the bug template because there is no feature template.

Describe the Feature

Generate a translated HTML document based off of the URL for a webpage. The following code snippet would translate the page for DeepL's English Wikipedia article into German and save it in the file DeepLWiki.html:

await translator.translateWebpageToDocument(
        'https://en.wikipedia.org/wiki/DeepL_Translator',
        'DeepLWiki.html',
        'en',
        'de',
        { formality: 'more' },
    );

In line with the other document related functions, there can be an uploadWebpageToDocument function that takes a URL as the first argument with the rest of its arguments being the same as uploadDocument. getDocumentStatus and downloadDocument would not need their own versions as uploadWebpageToDocument would return a DocumentHandle like uploadDocument does.

Implementation

Without writing the exact code, I think uploadWebpageToDocument would first make a request to the URL that's passed in as an argument. If the request is successful and the response has it's Content-Type header set text/html, the response HTML gets put into a buffer and passed to uploadDocument along with the rest of the parameters. If the request to the website fails or the response is not the expected mime type, the function throws an error.

Translation w/ glossary entries are only partially translated and include sourceLang string

Describe the bug
After creating a glossary and running a test translation, the glossary entry provided was partially translated and the source entry is sometimes included in the translation.

To Reproduce
Steps to reproduce the behavior:

  1. I have created a glossary from EN to DE
  2. I have added some entries to test the functionality
  3. Results as seen in the screenshot below are not sticking to the terms set in the glossary.

image

This is the code I'm calling the translations with:

  const testTranslation3 = await translator.translateText('test1', 'en', 'de', {
    glossary: glossaryId,
  })

Expected behavior
I'm uncertain if I misunderstood how glossaries work, but I thought they would always take precedence over default translations. Also, the source language string should never show up in the translation.

getting overcharged 9 times more

Describe the bug
A clear and concise description of what the bug is.

Since DeepL API does not understand text in multiple lines, I query just like below. encodeURIComponent() is a solution that I was actually suggested by DeepL support.

const inputText = encodeURIComponent(translateText);
const responseDeepL = await axios.post(
      deeplURL,
      `text=${inputText}&target_lang=${targetLang}`,
      {
        headers: {
          Authorization: `DeepL-Auth-Key ${DEEPL_KEY}`,
          "Content-Type": "application/x-www-form-urlencoded",
          "User-Agent": "axios 1.2.0-alpha.1",
        },
      }
    );

The problem is the volume of string becomes way larger than the original input.
For example,

const inputText = "こんにちは";
console.log( encodeURIComponent(inputText).length ) // this is 45 characters
console.log( inputText.length ) // this is 5 characters

I am currently receiving 9x overcharges on this issue.

Unable to resolve module fs | React native deepl-node integration

Hi, i am trying to integrate deepl-node with my react native app but i keep getting this error after following the installation steps
error message:
iOS Bundling failed 232ms
Unable to resolve module fs from C:\Users\oem\Desktop\Reway\Reway-App-Dev\node_modules\deepl-node\dist\index.js: fs could not be found within the project or in these directories:
node_modules
39 | const parsing_1 = require("./parsing");
40 | const utils_1 = require("./utils");

41 | const fs = __importStar(require("fs"));
| ^
42 | const http_1 = require("http");
43 | const path_1 = __importDefault(require("path"));
44 | const url_1 = require("url");

`.translateText` function overload is not exhaustively typed

Summary

Your definition of .translateText runs into this canonically known typescript issue. It expects the language compiler to exhaustively perform a combinatorically expensive type casting which is not supported.

Code

type TranslationText = string | string[];
const firstTextToTranslate: TranslationText = 'hello world';
const secondTextToTranslate: TranslationText = ['hello world'];

deepl.translateText(firstTextToTranslate, ...);
/* yields compiler error:
No overload matches this call.
  Overload 1 of 2, '(texts: string, sourceLang: SourceLanguageCode | null, targetLang: TargetLanguageCode, options?: TranslateTextOptions | undefined): Promise<...>', gave the following error.
    Argument of type 'string | string[]' is not assignable to parameter of type 'string'.
      Type 'string[]' is not assignable to type 'string'.
  Overload 2 of 2, '(texts: string[], sourceLang: SourceLanguageCode | null, targetLang: TargetLanguageCode, options?: TranslateTextOptions | undefined): Promise<...>', gave the following error.
    Argument of type 'string | string[]' is not assignable to parameter of type 'string[]'.
      Type 'string' is not assignable to type 'string[]'.ts(2769)
*/

// on the other hand...
deepl.translateText(secondTextToTranslate, ...);
/* yields the same compiler error: */

Expected Behaviour

Typescript/your type definitions should be able to deduce that your function supports both types of inputs

Solution Proposition

As the Typescript team already made very clear that they are not planning to implement a combinatorically expensive feature, we have to work around this.

The typescript docs on conditional types state that overloading is unnecessary and your function definition could be done in a single, stable go with some generics and conditional types.

  async translateText<T extends string | string[]>(
      texts: T,
      sourceLang: SourceLanguageCode | null,
      targetLang: TargetLanguageCode,
      options?: TranslateTextOptions,
  ): Promise<T extends string ? TextResult : TextResult[]>

Cloudflare workers support?

This library cannot be used in cloudflare workers because it depends on XMLHttpRequest.
Moreover, if I send requests manually they fail with status code 525.

Code to reproduce

const deepLUrl = 'https://api-free.deepl.com/v2/translate'
const text = 'I like my cat'
const to = 'de'
const from = 'en'

const resp = await fetch(deepLUrl, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    Authorization: `DeepL-Auth-Key ${env.DEEPL}`,
  },
  body: `text=${encodeURIComponent(text)}&target_lang=${to.toUpperCase()}&source_lang=${from.toUpperCase()}`,
})
if (!resp.ok) throw new Error(`DeepL error (${resp.status}) ` + resp.statusText) // throws in workers
const response = await resp.json()
response.translations[0].text // works in node

This problem is often mentioned in cloudflare community (example). According to cloudflare "This is typically caused by a configuration issue in the origin web server".

Is there any hope for a fix? Cloudflare workers become more and more popular nowadays.

XML tags with attributes change the order of the translation when tagHandling is XML but are OK when tagHandling is off

Describe the bug
I am translating a text using Deepl API that contains XML tags and some of these tags include custom attributes; ex.

That’s the <fontcolor="#007af2">timer</fontcolor>! It measures the time you spend in a module OR the time you have left to complete a challenge!

However, the format of the XML tag is not conserved when the text is translated to Slovenian and Italian (I have not tested in other languages but could be the case for others as well). The result is like this:

Slovenian: To je časovnik <fontcolor="#007af2"></fontcolor> ! Meri čas, ki ga porabite v modulu, ALI čas, ki vam je ostal do konca izziva!

Italian: Questo è il timer <fontcolor="#007af2"></fontcolor> ! Misura il tempo trascorso in un modulo O il tempo rimasto per completare una sfida!

Meaning that instead of putting the word timer inside the tag, it gets out and leaves the tag empty. This happens when the tagHandling option is set to either XML or HTML, however if I set the tagHandling to off, the result is OK but other problems occur for my text because the tagHandling is set to off.

To Reproduce
Steps to reproduce the behavior:
Can be reproduced in the Deepl API Simulator: https://www.deepl.com/en/docs-api/simulator/

  1. Go to Deepl API Simulator
  2. Copy the text That’s the <fontcolor="#007af2">timer</fontcolor>! It measures the time you spend in a module OR the time you have left to complete a challenge! in the Text field.
  3. Set the target language to Slovenian or Italian
  4. Set tagHandling to XML
  5. Click on Send and compare the results with when the tagHandling is set to off

Expected behavior
The correct text should be:

Slovenian: To je <fontcolor="#007af2">časomer</fontcolor>! Meri čas, ki ga porabite v modulu, ALI čas, ki vam je ostal za dokončanje izziva!

Italian: È il <fontcolor="#007af2">timer</fontcolor>! Misura il tempo trascorso in un modulo O il tempo rimanente per completare una sfida!

Which is the case when the tagHandling is set to off but that should not be the case.

What has been tested

I tried combining different options together to see if I can make it work but none of them gave me the intended result. These are the parameters that I changed:

SentenceSplitting=on,off,noNewLines
preserveFormatting=on,off
nonSplittingTags=fontcolor,null

UPDATE 07/10/2023 11:47 AM
The problem seems to be the fact that the API takes into account the ="#007af2" part of the tag as the name of the tag and it doesn't see the closing tag for the same thing. So if we add a space: <fontcolor "=#007af2"> , it will work as expected. I don't know if a fix for that would be necessary but maybe a support for custom attributes like this would be nice.

Bad request on unsupported formality

Currently, a request that specifies a formality setting not yet supported by DeepL returns an error without a translation.
DeepLError: Bad request, message: 'formality' is not supported for given 'target_lang'.

Maybe a more user friendly alternative would be to just ignore any unsupported options in the request, possibly attaching a warning message to the response informing the user of their mistake. This way, applications that call the DeepL api won't break when supplied an invalid configuration.

Translating HTML with English text to French adds HTML Tags and full sentence that is not in the input text

Describe the bug
When translating a English text with HTML elements to French, the response contains unexpected additional HTML Tags and often a full sentence that was not in the input.

To Reproduce
Minimal JS Script to reproduce the Error (last tested on March 9th 2024 6PM CET)

const deepl = require('deepl-node')
const authKey = "<authkey>"
const translator = new deepl.Translator(authKey)

async function translate(targetLang) {
	const result = await translator.translateText('<p><strong>Testing the system</strong></p>', 'en', targetLang, tag_handling = 'html')
	console.log(result)
}

translate('de')
translate('fr')

This results in the following responses:

{
  text: '<p><strong>Test des Systems</strong></p>',
  detectedSourceLang: 'en'
}
{
  text: "</p><strong>Tester le système</strong></p><strong></p><strong>La mise en place d'un système de gestion de l'information est une priorité.",
  detectedSourceLang: 'en'
}

The German translation is correct but the French translation has <strong></p><strong>La mise en place d'un système de gestion de l'information est une priorité. appended to a seemingly correct result.

I've noticed that without the <strong> Tag it does not happen but I have not tested that exhaustively.

Thank you very much.

remove supportsFormaility from getSourceLanguages call

Describe the bug
For all languages in the getSourceLanguages call an empty 'supportyFormality' field is returned, this should be omitted.

 { name: 'Bulgarian', code: 'bg', supportsFormality: undefined },
 { name: 'Czech', code: 'cs', supportsFormality: undefined },
 { name: 'Danish', code: 'da', supportsFormality: undefined },
 { name: 'German', code: 'de', supportsFormality: undefined },

To Reproduce
use translator.getSourceLanguages()

Expected behavior
undefined fields should be omited

Feature Request: Markdown Handling

Hi there, thanks for the great library to use the DeepL API!

I made a github action for using deepl-node to translate text documents, however there's quite a lot of limitations in trying to parse markdown elements.

You can refer to some limitations that's mentioned in this demo or this PR.

The formatting errors that were raised in both examples may be due to the use of markdown checkboxes, bolded text etc, since most other HTML elements were able to be translated accurately, and only break on certain languages.

Issue with axios 1.2.0: "DeepLError: Error parsing response JSON: SyntaxError"

If axios v1.2.0 is used, the following error can occur when calling many library functions (e.g. getUsage()):
DeepLError: Error parsing response JSON: SyntaxError: Unexpected token in JSON at position 0

We have released v1.7.2 as a workaround: this updates the dependency requirement to disallow version axios v1.2.0, and are working on a fix.

TypeError

We are found when we test to use deepl-node packages in our mobile app.
Package download link..
deepl-node - npm (npmjs.com)

Our app is based on react-native language.
We just use sample code and connection tests with deepl server.

Found err info:
[TypeError: Cannot read property 'prototype' of undefined]

Wrong detection of source language

I need to detect source language of word "Insomnia". When i use deepl-node package, i got source language Slovak(sk). When i use Deepl on site translator i got, when i typed "Insomnia", English language detection.

tag handling

I'm using deepl-node with node v16.14.0

I am having issue in very specific translations from fr to en-gb when there is only one sentence, markup and ponctuations

🔴<p>C'est bien d'avoir fait ça !</p>-> <It's good that you did that!
<p>C'est bien d'avoir fait ça !</p><p>Non ?</p><p>Si bien sûr</p> -> <p>It's good that you did that!</p><p>Didn't you?</p><p>Yes of course</p>
<p>C'est bien d'avoir fait ça</p> -> <p>It's good to have done this</p>

I have tried these options without success tag_handling: 'xml' tag_handling: 'html' splitSentences : 'off' preserveFormatting: true

Thanks for your help

Uncaught TypeError: os.type is not a function

I become this error when i initialise the repository

Uncaught TypeError: os.type is not a function
at Translator.constructUserAgentString (deepl-node.js?v=e2e7fb1a:3446:33)
at new Translator (deepl-node.js?v=e2e7fb1a:3116:30)
at main.js:8:20
constructUserAgentString @ deepl-node.js?v=e2e7fb1a:3446
Translator @ deepl-node.js?v=e2e7fb1a:3116
(anonym) @ main.js:8

Type 'string' is not assignable to type 'TargetLanguageCode'

Describe the bug
A clear and concise description of what the bug is.
[Type error]: I input the target language (string) but deepl.TargetLanguageCode does not allow it.

const defaultLang = "ja";
let typedTargetLang: deepl.TargetLanguageCode = defaultLang;

Type 'string' is not assignable to type 'TargetLanguageCode'.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

url_1.URLSearchParams is not a constructor

Hi,

I'm trying to build a node app with vite using : npm create vite@latest

when using your code example after installing npm install deepl-node:

import './style.css'
import * as deepl from 'deepl-node';

const authKey = "...-...-...-...-...:fx"; // Replace with your key
const translator = new deepl.Translator(authKey);

(async () => {
    const result = await translator.translateText('Hello, world!', null, 'fr');
    console.log(result.text); // Bonjour, le monde !
})();

I get the following error:

Uncaught (in promise) TypeError: url_1.URLSearchParams is not a constructor
    at buildURLSearchParams (index.js:123:26)
    at Translator.translateText (index.js:354:22)
    at main.js?t=1656189862004:12:37
    at main.js?t=1656189862004:14:3

I have a free account with DeepL

Thanks! (I'm pretty new to this ;-)

oe.URLSearchParams is not a constructor Error

I have tried to use this library but when I run my code I get the following error in the browser console:

index.3240d547.js:10 Uncaught (in promise) TypeError: oe.URLSearchParams is not a constructor
    at je (index.3240d547.js:10:69597)
    at a.Translator.translateText (index.3240d547.js:10:73014)
    at Le (index.3240d547.js:10:71558)

Desktop (please complete the following information):

  • OS: Windows 10
  • Browser Electron/19.1.8
  • Version [e.g. 22]
  • Node 16.15.0

Additional context
I'm using typescript and have no errors when I build my app - only when I run it. However, I'm not a professional programmer so it's possible I've installed the wrong version of something. My tsconfig.json file is below:

{
  "compilerOptions": {
    "lib": [
      "es2021",
      "dom"
    ],
    "module": "commonjs",
    "target": "es2021",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node"
  }
}

and my package.json

{
  "name": "logseq-deepl-integration",
  "version": "0.0.1",
  "description": "Translate selected blocks via deepl",
  "main": "dist/index.html",
  "targets": {
    "main": false
  },
  "scripts": {
    "build": "parcel build --no-source-maps index.html --public-url ./",
    "dev": "parcel build --no-optimize index.html --public-url ./"
  },
  "author": "dcoales",
  "license": "MIT",
  "dependencies": {
    "@logseq/libs": "^0.0.10",
    "deepl-node": "^1.7.3"
  },
  "logseq": {
    "id": "logseq-deepl",
    "title": "Logseq Deepl Integration",
    "author": "dcoales",
    "description": "Translate selected blocks via deepl"
  },
  "devDependencies": {
    "@types/jest": "^29.0.3",
    "@types/node": "^18.11.9",
    "buffer": "^5.5.0",
    "events": "^3.3.0",
    "parcel": "^2.8.0",
    "path-browserify": "^1.0.1",
    "punycode": "^1.4.1",
    "querystring-es3": "^0.2.1",
    "stream-http": "^3.2.0",
    "ts-node": "^10.9.1",
    "typescript": "^4.8.3",
    "url": "^0.11.0",
    "util": "^0.12.5"
  }
}

I'm running this as a plugin to a tool called LogSeq. The plugin code is below. Any help would be much appreciated. Thanks.

import '@logseq/libs';
import {BlockEntity} from "@logseq/libs/dist/LSPlugin";
import { SettingSchemaDesc } from '@logseq/libs/dist/LSPlugin.user';
import * as deepl from 'deepl-node';
import {TextResult} from "deepl-node";

/**
 * entry
 */

function main() {

    logseq.useSettingsSchema(settings);

    logseq.Editor.registerSlashCommand('Get Jira Details for Selection', (_) => {
        return translate();
    })

    logseq.App.registerCommand('deeplTranslate', {
        key: 'deeplTranslate',
        label: 'Translate the selected lines',
        desc: 'Get translations for each of the currently selected lines',
        keybinding: {binding: 'mod+alt+t'}
    }, (e) => {
        return translate();
    })
}

async function translate() {
    let selection: BlockEntity[] | null = await logseq.Editor.getSelectedBlocks();
   //console.log(selection);
    if (!selection || selection.length === 0) {
        const block: BlockEntity | null = await logseq.Editor.getCurrentBlock();
        if (block){
            selection = [block];
        }
    }
    const lines:string[] = [];
    if (selection){
        for (let b of selection){
            lines.push(b.content);
        }
    }

    const authKey = logseq.settings?.APIToken;
    const translator = new deepl.Translator(authKey);
    const results:TextResult[] = await translator.translateText(lines,null,logseq.settings?.language);
    results.map((result: deepl.TextResult) => {
        console.log(result.text);
    });
}

const settings: SettingSchemaDesc[] = [
    {
        key: "language",
        description: "The language for the translated text",
        type: "string",
        default: "pl",
        title: "Translated text language",
    },
    {
        key: "APIToken",
        description: "Deepl API token",
        type: "string",
        default: "",
        title: "Deepl API token",
    }
];

logseq.ready(main).catch(console.error);

[QUESTION] Temporary glosseries

This is not really an issue, but rather a question, and possibly feature request.
Would it be possible to have some kind of temporary glossaries, that you could pass as an argument in a translate request, without having to create a glossary?

To give a more precise example, here is my use case:

I am building a translation tool that would allow automatically translating strings from one language to a bunch of other languages.
Those strings may contain parameters (something like The count is [count].).
Sometimes, the translation result will rightly place the parameter like a word in a sentence, keeping its original form.
Sometimes it will also translate the parameter's name.
I would like to keep the original parameter name, without creating a glossary that would hold values on your side, when I only need them once.

This is admittedly much more complex than just a stipped-down glossary feature, but that would already be a start.

I hope you were able to understand my thoughts and hope this is somewhat usable feedback, but I am completly aware of its complexity and would not be surprised if it never finds its way onto future updates.

Also I apologize for my english if you didn't understand everything, I'm not a native speaker and I try not to use Deepl but to talk by myself as much as I can (ironically haha).

Ionic & Angular ReferenceError when initializing deepl.Translator

Describe the bug
ReferenceError when initializing deepl.Translator

To Reproduce
Steps to reproduce the behavior:

  1. Running a project with Ionic 6 and Angular 15 (typescript)
  2. Adding the starter code from the README

Expected behavior
Expected no issues and a console log that it was successful

Screenshots
image
image

Desktop (please complete the following information):

  • OS: Windows
  • Browser Chrome
  • Version 111.0.5563.66

Additional context
I am not sure what is going on. At first I thought it was a circular import issue but I have made sure I am not calling this anywhere else. I have deleted and generated a new page and I still get these issues at all times. I really need some help in understanding the approach I am doing wrong here. I appreciate all your help and please let me know if there is anything else I would need to provide.

If I remove the line const translator = new deepl.Translator(authkey);, everything runs fine.

Deepl Limitations - Timeout Errors during concurrent calls

Hello,

I am utilizing the PRO Deepl API and have encountered some challenges related to concurrent requests while using the Deepl-Node client.

Here's the scenario: I have a service hosted on Azure, leveraging Azure Functions. Within this setup, there are 15 concurrent functions that attempt to translate a total of 72 KiB of text. The translateText<string[]> function takes an array of strings as input. The interesting aspect is that when these 15 functions are triggered, I encounter 'timeout' errors for all the requests. It's important to note that all these functions run on the same Virtual Machine, which implies that a single Deepl Client is employed to handle these 15 concurrent requests.

My questions are as follows:

  • Are there any limitations on the number of concurrent calls per Deepl Client or per API Key?
  • Would it be advisable to reduce the number of concurrent calls? If so, what would be an appropriate threshold in your opinion?
  • The current timeout configuration is set to 30000ms.

Your insights and guidance on optimizing these concurrent translation calls would be greatly appreciated. The service aim to translate ~1 000 000 000 characters.

Please be aware that the translation process functions correctly when a single request is made. This singular request encompasses the following elements:

An array input containing 600 texts (It is noteworthy to mention that the documentation indicates a limit of 50 texts per request.)
A maximum of 72 KiB of text, equating to a request payload of approximately 76 KiB (It is important to acknowledge that the documentation specifies a payload size allowance of up to 128 KiB. However, I have observed that if the payload size exceeds 85 KiB, it results in a '413 - Payload Too Large' error).

Could you provide more information regarding the limits documented?

Circular dependency index.js ➜ parsing.js ➜ index.js

Describe the bug

When building my Svelte app that uses deepl-node, I get a warning about circular dependencies:

Circular dependency: node_modules/.pnpm/[email protected]/node_modules/deepl-node/dist/index.js -> node_modules/.pnpm/[email protected]/node_modules/deepl-node/dist/parsing.js -> node_modules/.pnpm/[email protected]/node_modules/deepl-node/dist/index.js

To Reproduce
Steps to reproduce the behavior:

  1. Create a (Svelte) app
  2. Install, import (and use?) deepl-node in your code
  3. Build it

Expected behavior
The warning not to appear by refactoring your code

Desktop (please complete the following information):

  • OS: macOS
  • Browser: Arc
  • Version: 1.39.0

autotranslate does not work

today autotranslate does not work, until yesterday it worked fine, today the language detected is the same as the target language

translation using arrays does not work

Good day, i am trying to translate a big array with deepl. Somehow when i put even a small array in the translateText function i am getting an error:

DeepLError: texts parameter must not be a non-empty string or array of non-empty strings at appendTextsAndReturnIsSingular projectpath/node_modules/deepl-node/dist/index.js:166:23

It seems that arrays are not supported

translator.translateText(
['hallo', 'test'],
req.body.sourceLanguageCode, //this is nl
req.body.targetLanguageCode, // this is en-GB
)

[tests] Jest may incorrectly detect open handles when running the tests

Describe the bug
See fix in jest: jestjs/jest#13414
Unfortunately, this version of Jest (29.2+) requires Node 14.

To Reproduce
In the console, running tests may give a warning similar to the following

$ node_modules/.bin/jest --detectOpenHandles --no-cache tests/
 PASS  tests/general.test.ts
 PASS  tests/glossary.test.ts (24.288 s)
 PASS  tests/translateDocument.test.ts (31.975 s)
 PASS  tests/translateText.test.ts (6.858 s)

Test Suites: 4 passed, 4 total
Tests:       11 skipped, 50 passed, 61 total
Snapshots:   0 total
Time:        66.442 s
Ran all test suites matching /tests\//i.

Jest has detected the following 2 open handles potentially keeping Jest from exiting:

  ●  TLSWRAP

      220 |     ): Promise<{ statusCode: number; content: TContent }> {
      221 |         try {
    > 222 |             const response = await axios.request(axiosRequestConfig);
          |                                          ^
      223 |
      224 |             if (axiosRequestConfig.responseType === 'text') {
      225 |                 // Workaround for axios-bug: https://github.com/axios/axios/issues/907

      at node_modules/nock/lib/intercept.js:427:16
      at Object.module.request (node_modules/nock/lib/common.js:96:14)
      at RedirectableRequest.Object.<anonymous>.RedirectableRequest._performRequest (node_modules/follow-redirects/index.js:284:24)
      at new RedirectableRequest (node_modules/follow-redirects/index.js:66:8)
      at Object.request (node_modules/follow-redirects/index.js:523:14)
      at dispatchHttpRequest (node_modules/axios/lib/adapters/http.js:436:21)
      at node_modules/axios/lib/adapters/http.js:143:5
      at wrapAsync (node_modules/axios/lib/adapters/http.js:123:10)
      at http (node_modules/axios/lib/adapters/http.js:149:10)
      at Axios.dispatchRequest (node_modules/axios/lib/core/dispatchRequest.js:51:10)
      at Axios.request (node_modules/axios/lib/core/Axios.js:148:33)
      at Function.wrap [as request] (node_modules/axios/lib/helpers/bind.js:5:15)
      at Function.sendAxiosRequest (src/client.ts:222:42)
      at HttpClient.sendRequestWithBackoff (src/client.ts:176:45)
      at Translator.translateText (src/index.ts:571:63)
      at Object.<anonymous> (tests/translateText.test.ts:19:41)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:404:19)
      at _run10000 (node_modules/@jest/core/build/cli/index.js:320:7)
      at runCLI (node_modules/@jest/core/build/cli/index.js:173:3)


  ●  TLSWRAP

      220 |     ): Promise<{ statusCode: number; content: TContent }> {
      221 |         try {
    > 222 |             const response = await axios.request(axiosRequestConfig);
          |                                          ^
      223 |
      224 |             if (axiosRequestConfig.responseType === 'text') {
      225 |                 // Workaround for axios-bug: https://github.com/axios/axios/issues/907

      at node_modules/nock/lib/intercept.js:427:16
      at Object.module.request (node_modules/nock/lib/common.js:96:14)
      at RedirectableRequest.Object.<anonymous>.RedirectableRequest._performRequest (node_modules/follow-redirects/index.js:284:24)
      at new RedirectableRequest (node_modules/follow-redirects/index.js:66:8)
      at Object.request (node_modules/follow-redirects/index.js:523:14)
      at dispatchHttpRequest (node_modules/axios/lib/adapters/http.js:436:21)
      at node_modules/axios/lib/adapters/http.js:143:5
      at wrapAsync (node_modules/axios/lib/adapters/http.js:123:10)
      at http (node_modules/axios/lib/adapters/http.js:149:10)
      at Axios.dispatchRequest (node_modules/axios/lib/core/dispatchRequest.js:51:10)
      at Axios.request (node_modules/axios/lib/core/Axios.js:148:33)
      at Function.wrap [as request] (node_modules/axios/lib/helpers/bind.js:5:15)
      at Function.sendAxiosRequest (src/client.ts:222:42)
      at HttpClient.sendRequestWithBackoff (src/client.ts:176:45)
      at Translator.translateText (src/index.ts:571:63)
      at Object.<anonymous> (tests/translateText.test.ts:221:41)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:404:19)
      at _run10000 (node_modules/@jest/core/build/cli/index.js:320:7)
      at runCLI (node_modules/@jest/core/build/cli/index.js:173:3)

Expected behavior
Tests should run without throwing warnings.

Is it possible to get the alternatives of the phrase as well ?

When using the translator in the website we are able to get alternatives along with the translated phrase. For example I'm translating the word friend into Czech language and I'm getting the following result:

image

When using deepl-node API I'm only getting a single string in return which seems to be the original translation. Is it possible to get a translation response including these alternatives ? If not, why not ?

Thanks

Update axios to latest version

Version used by deepl-node has vulnerabilities and should be updated

  • moderate | Follow Redirects improperly handles URLs in the url.parse() function
  • Package | follow-redirects
  • Patched in | >=1.15.4
  • Dependency of | deepl-node
  • Path | deepl-node > axios > follow-redirects
  • More info | https://www.npmjs.com/advisories/1095374

Bug while using deepl-node

Hi , I have recently subscribed on Deepl Pro Advanced plan. I am trying to use deepl-node package: https://github.com/DeepLcom/deepl-node
However i get the following error : AuthorizationError: Authorization failure, check auth_key, message: Wrong endpoint. Use https://api.deepl.com
at checkStatusCode
I tried creating a new authentication key and I tried with it but no chance.I was wondering if you could help me, please?

Axios proxy as URL

The options parameter of the Translator constructor only takes one type of proxy as ProxyConfig (looks same as AxiosProxyConfig).
It would be useful to be able to use a proxy URL string as proxy parameter. An axios instance creation in the client should look like this:

import { HttpProxyAgent, HttpProxyAgent } from 'hpagent';
axios.create({
   proxy: true,
   httpsAgent: new HttpsProxyAgent({ proxy: 'http://user:[email protected]:4567' })
   httpAgent: new HttpProxyAgent({ proxy: 'http://user:[email protected]:4567' })
})

Would it be an improvement in flexibility?
I always use one secret for the whole proxy URL, so it would help a lot.

The most flexible approach would be to have an axiosInstanace parameter for the Translator constructor, but this would cause a lot of code rewrites :(

downloadDocument() response is empty for PDFs

Describe the bug
When downloading PDFs via translator.downloadDocument(), the resulting file is always empty and the file size is always 2KB. It seems that only the file's metadata is downloaded (see below), but the content itself is wiped out.

This is running inside a Lambda on AWS.

Note: .txt files work as expected.

To Reproduce
Steps to reproduce the behavior:

Upload code

const myBuffer = fs.readFileSync(files["deepl-file-to-upload"].path);
console.log(`my buffer length: ${myBuffer.length}`); // <-- Buffer length is 143KB 
translator.uploadDocument(
        myBuffer,
        `EN`,
        `DE`,
        { filename: `${files["deepl-file-to-upload"].name}` }
      ).then((uploadResult) => {
        console.log(uploadResult); // Returns documentId + documentKey as expected
      }).catch((err) => {
        console.log(err);
        reject(err);
});

Download code

let builtDocumentHandle = {
          'documentId': documentId,
          'documentKey': documentKey
};

let myFileName = `translate-result-${builtDocumentHandle.documentId}.${fileType}`; // Define file name
let attachmentPath = `/tmp/${myFileName}`; // Build path where we will temporarily store file after it's been downloaded
let myWS = fs.createWriteStream(`/tmp/${myFileName}`); // Create write stream to hold the downloaded file
            
// Download newly translated document from DeepL
translator.downloadDocument(
    builtDocumentHandle,
    myWS
).then(() => {

   // Check download file size for debug purposes
    try {
        let myFileSize = getFilesizeInBytes(attachmentPath);
        console.log(`deepl file size after download: ${myFileSize} bytes`); // <-- Always returns around 2KB for PDFs
    } catch (error) {
        console.log('filesize error');
        console.log(error);
    }

}).catch((err) => {
    console.log(err);
});

function getFilesizeInBytes(filename) {
  var stats = fs.statSync(filename);
  var fileSizeInBytes = stats.size;
  return fileSizeInBytes;
}

Expected behavior
The downloaded PDF document should include all translated content.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):
Chrome Version 113.0.5672.126

Additional context

Example PDF content that I'm getting back from the DeepL API

%PDF-1.7
5 0 obj
<</Type /Page/Parent 3 0 R/Contents 6 0 R/MediaBox [0 0 612 792]/Resources<<>>/Group <</Type/Group/S/Transparency/CS/DeviceRGB>>>>
endobj
6 0 obj
<</Length 7 0 R>>stream
1 0 0 -1 0 792 cm q 1 0 0 1 86 91 cm q 1 0 0 1 3.852 0 cm Q Q 1 0 0 -1 -0 792 cm 
endstream
endobj
7 0 obj
81 
endobj
8 0 obj
<</Type /Page/Parent 3 0 R/Contents 9 0 R/MediaBox [0 0 612 792]/Resources<<>>/Group <</Type/Group/S/Transparency/CS/DeviceRGB>>>>
endobj
9 0 obj
<</Length 10 0 R>>stream
1 0 0 -1 0 792 cm q 1 0 0 1 86 91 cm Q 1 0 0 -1 -0 792 cm 
endstream
endobj
10 0 obj
58 
endobj
1 0 obj
<</Keywords(���,� �d�o�c�I�d�:�C�E�C�6�4�8�3�6�7�9�5�B�F�E�C�8�B�1�2�9�E�0�E�F�2�0�8�A�C�7�E�E)/Creator(���M�i�c�r�o�s�o�f�t� �O�f�f�i�c�e� �W�o�r�d)/Producer(���A�s�p�o�s�e�.�W�o�r�d�s� �f�o�r� �.�N�E�T� �2�3�.�1�.�0)/CreationDate(D:20230608155704Z)/ModDate(D:20230608155704Z)>>
endobj
2 0 obj
<</Type /Catalog/Pages 3 0 R/Lang(en-US)/Metadata 4 0 R>>
endobj
3 0 obj
<</Type /Pages/Count 2/Kids[5 0 R 8 0 R ]>>
endobj
4 0 obj
<</Type /Metadata/Subtype /XML/Length 11 0 R>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="PDFNet">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">
<xmp:CreateDate>2023-06-08T15:57:04Z</xmp:CreateDate>
<xmp:ModifyDate>2023-06-08T15:57:04Z</xmp:ModifyDate>
<xmp:CreatorTool>Microsoft Office Word</xmp:CreatorTool>
</rdf:Description>
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:format>application/pdf</dc:format>
</rdf:Description>
<rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<pdf:Keywords>, docId:CEC64836795BFEC8B129E0EF208AC7EE</pdf:Keywords>
<pdf:Producer>Aspose.Words for .NET 23.1.0</pdf:Producer>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>

endstream
endobj
11 0 obj
826 
endobj
12 0 obj
<</Type /XRef/W [1 4 2]/Size 13/Info 1 0 R/Root 2 0 R/ID [<395C0EA322A4574B9446E6B21AB973A7><395C0EA322A4574B9446E6B21AB973A7>]/Length 91>>stream
�����������[���������������������������
�������������'������=�������������D����������������
endstream
endobj
startxref
1973
%%EOF

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.