deepl-node
Version:
deepl-node is the official DeepL Node.js client library
283 lines (282 loc) • 11.1 kB
JavaScript
;
// 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.
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractGlossaryId = exports.appendCsvDictionaryEntries = exports.appendDictionaryEntries = exports.validateAndAppendTextOptions = exports.appendTextsAndReturnIsSingular = exports.buildURLSearchParams = exports.nonRegionalLanguageCode = exports.standardizeLanguageCode = exports.isFreeAccountAuthKey = exports.toBoolString = exports.isString = exports.timeout = exports.streamToString = exports.streamToBuffer = exports.logInfo = exports.logDebug = void 0;
const loglevel_1 = __importDefault(require("loglevel"));
const errors_1 = require("./errors");
const logger = loglevel_1.default.getLogger('deepl');
function concatLoggingArgs(args) {
let detail = '';
if (args) {
for (const [key, value] of Object.entries(args)) {
detail += `, ${key} = ${value}`;
}
}
return detail;
}
function logDebug(message, args) {
logger.debug(message + concatLoggingArgs(args));
}
exports.logDebug = logDebug;
function logInfo(message, args) {
logger.info(message + concatLoggingArgs(args));
}
exports.logInfo = logInfo;
/**
* Converts contents of given stream to a Buffer.
* @private
*/
async function streamToBuffer(stream) {
const chunks = [];
return new Promise((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('error', (err) => reject(err));
stream.on('end', () => resolve(Buffer.concat(chunks)));
});
}
exports.streamToBuffer = streamToBuffer;
/**
* Converts contents of given stream to a string using UTF-8 encoding.
* @private
*/
async function streamToString(stream) {
return (await streamToBuffer(stream)).toString('utf8');
}
exports.streamToString = streamToString;
// Wrap setTimeout() with Promise
const timeout = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
exports.timeout = timeout;
/**
* Returns true if the given argument is a string.
* @param arg Argument to check.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
/**
* Returns '1' if the given arg is truthy, '0' otherwise.
* @param arg Argument to check.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function toBoolString(arg) {
return arg ? '1' : '0';
}
exports.toBoolString = toBoolString;
/**
* Returns true if the specified DeepL Authentication Key is associated with a free account,
* otherwise false.
* @param authKey The authentication key to check.
* @return True if the key is associated with a free account, otherwise false.
*/
function isFreeAccountAuthKey(authKey) {
return authKey.endsWith(':fx');
}
exports.isFreeAccountAuthKey = isFreeAccountAuthKey;
/**
* Changes the upper- and lower-casing of the given language code to match ISO 639-1 with an
* optional regional code from ISO 3166-1.
* For example, input 'EN-US' returns 'en-US'.
* @param langCode String containing language code to standardize.
* @return Standardized language code.
*/
function standardizeLanguageCode(langCode) {
if (!isString(langCode) || langCode.length === 0) {
throw new errors_1.DeepLError('langCode must be a non-empty string');
}
const [lang, region] = langCode.split('-', 2);
return (region === undefined ? lang.toLowerCase() : `${lang.toLowerCase()}-${region.toUpperCase()}`);
}
exports.standardizeLanguageCode = standardizeLanguageCode;
/**
* Removes the regional variant from a language, for example inputs 'en' and 'en-US' both return
* 'en'.
* @param langCode String containing language code to convert.
* @return Language code with regional variant removed.
*/
function nonRegionalLanguageCode(langCode) {
if (!isString(langCode) || langCode.length === 0) {
throw new errors_1.DeepLError('langCode must be a non-empty string');
}
return langCode.split('-', 2)[0].toLowerCase();
}
exports.nonRegionalLanguageCode = nonRegionalLanguageCode;
/**
* Joins given TagList with commas to form a single comma-delimited string.
* @private
*/
function joinTagList(tagList) {
if (isString(tagList)) {
return tagList;
}
else {
return tagList.join(',');
}
}
/**
* Validates and prepares URLSearchParams for arguments common to text and document translation.
* @private
*/
function buildURLSearchParams(sourceLang, targetLang, formality, glossary, extraRequestParameters) {
targetLang = standardizeLanguageCode(targetLang);
if (sourceLang !== null) {
sourceLang = standardizeLanguageCode(sourceLang);
}
if (glossary !== undefined && sourceLang === null) {
throw new errors_1.DeepLError('sourceLang is required if using a glossary');
}
if (targetLang === 'en') {
throw new errors_1.DeepLError("targetLang='en' is deprecated, please use 'en-GB' or 'en-US' instead.");
}
else if (targetLang === 'pt') {
throw new errors_1.DeepLError("targetLang='pt' is deprecated, please use 'pt-PT' or 'pt-BR' instead.");
}
const searchParams = new URLSearchParams({
target_lang: targetLang,
});
if (sourceLang !== null) {
searchParams.append('source_lang', sourceLang);
}
if (formality !== undefined) {
const formalityStr = String(formality).toLowerCase();
searchParams.append('formality', formalityStr);
}
if (glossary !== undefined) {
if (!isString(glossary)) {
if (glossary.glossaryId === undefined) {
throw new errors_1.DeepLError('glossary option should be a string containing the Glossary ID or a GlossaryInfo object.');
}
glossary = glossary.glossaryId;
}
searchParams.append('glossary_id', glossary);
}
if (extraRequestParameters !== undefined) {
for (const paramName in extraRequestParameters) {
searchParams.append(paramName, extraRequestParameters[paramName]);
}
}
return searchParams;
}
exports.buildURLSearchParams = buildURLSearchParams;
/**
* Validates and appends texts to HTTP request parameters, and returns whether a single text
* argument was provided.
* @param data Parameters for HTTP request.
* @param texts User-supplied texts to be checked.
* @return True if only a single text was provided.
* @private
*/
function appendTextsAndReturnIsSingular(data, texts) {
const singular = !Array.isArray(texts);
if (singular) {
if (!isString(texts) || texts.length === 0) {
throw new errors_1.DeepLError('texts parameter must be a non-empty string or array of non-empty strings');
}
data.append('text', texts);
}
else {
for (const text of texts) {
if (!isString(text) || text.length === 0) {
throw new errors_1.DeepLError('texts parameter must be a non-empty string or array of non-empty strings');
}
data.append('text', text);
}
}
return singular;
}
exports.appendTextsAndReturnIsSingular = appendTextsAndReturnIsSingular;
/**
* Validates and appends text options to HTTP request parameters.
* @param data Parameters for HTTP request.
* @param options Options for translate text request.
* Note the formality and glossaryId options are handled separately, because these options
* overlap with the translateDocument function.
* @private
*/
function validateAndAppendTextOptions(data, options) {
if (!options) {
return;
}
if (options.splitSentences !== undefined) {
options.splitSentences = options.splitSentences.toLowerCase();
if (options.splitSentences === 'on' || options.splitSentences === 'default') {
data.append('split_sentences', '1');
}
else if (options.splitSentences === 'off') {
data.append('split_sentences', '0');
}
else {
data.append('split_sentences', options.splitSentences);
}
}
if (options.preserveFormatting !== undefined) {
data.append('preserve_formatting', toBoolString(options.preserveFormatting));
}
if (options.tagHandling !== undefined) {
data.append('tag_handling', options.tagHandling);
}
if (options.outlineDetection !== undefined) {
data.append('outline_detection', toBoolString(options.outlineDetection));
}
if (options.context !== undefined) {
data.append('context', options.context);
}
if (options.modelType !== undefined) {
data.append('model_type', options.modelType);
}
if (options.nonSplittingTags !== undefined) {
data.append('non_splitting_tags', joinTagList(options.nonSplittingTags));
}
if (options.splittingTags !== undefined) {
data.append('splitting_tags', joinTagList(options.splittingTags));
}
if (options.ignoreTags !== undefined) {
data.append('ignore_tags', joinTagList(options.ignoreTags));
}
}
exports.validateAndAppendTextOptions = validateAndAppendTextOptions;
/**
* Appends glossary dictionaries to HTTP request parameters.
* @param data URL-encoded parameters for a HTTP request.
* @param dictionaries Glossary dictionaries to append.
* @private
*/
function appendDictionaryEntries(data, dictionaries) {
dictionaries.forEach((dict, index) => {
data.append(`dictionaries[${index}].source_lang`, dict.sourceLangCode);
data.append(`dictionaries[${index}].target_lang`, dict.targetLangCode);
data.append(`dictionaries[${index}].entries`, dict.entries.toTsv());
data.append(`dictionaries[${index}].entries_format`, 'tsv');
});
}
exports.appendDictionaryEntries = appendDictionaryEntries;
/**
* Appends a glossary dictionary with CSV entries to HTTP request parameters.
* @param data URL-encoded parameters for a HTTP request.
* @param sourceLanguageCode Source language code of the dictionary.
* @param targetLanguageCode Target language code of the dictionary.
* @param csvContent CSV-formatted string containing the dictionary entries.
* @private
*/
function appendCsvDictionaryEntries(data, sourceLanguageCode, targetLanguageCode, csvContent) {
data.append('dictionaries[0].source_lang', sourceLanguageCode);
data.append('dictionaries[0].target_lang', targetLanguageCode);
data.append('dictionaries[0].entries', csvContent);
data.append('dictionaries[0].entries_format', 'csv');
}
exports.appendCsvDictionaryEntries = appendCsvDictionaryEntries;
/**
* Extract the glossary ID from the argument.
* @param glossary The glossary as a string, GlossaryInfo, or MultilingualGlossaryInfo.
* @private
*/
function extractGlossaryId(glossary) {
return typeof glossary === 'string' ? glossary : glossary.glossaryId;
}
exports.extractGlossaryId = extractGlossaryId;