mirror of
https://github.com/aljazceru/ditto.git
synced 2026-02-21 13:05:50 +01:00
97 lines
2.6 KiB
TypeScript
97 lines
2.6 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
import { DittoTranslator, Provider, SourceLanguage, TargetLanguage } from '@/translators/translator.ts';
|
|
import { languageSchema } from '@/schema.ts';
|
|
|
|
interface DeepLTranslatorOpts {
|
|
/** DeepL endpoint to use. Default: 'https://api.deepl.com' */
|
|
endpoint?: string;
|
|
/** DeepL API key. */
|
|
apiKey: string;
|
|
/** Custom fetch implementation. */
|
|
fetch?: typeof fetch;
|
|
}
|
|
|
|
export class DeepLTranslator implements DittoTranslator {
|
|
private readonly endpoint: string;
|
|
private readonly apiKey: string;
|
|
private readonly fetch: typeof fetch;
|
|
private static provider: Provider = 'DeepL.com';
|
|
|
|
constructor(opts: DeepLTranslatorOpts) {
|
|
this.endpoint = opts.endpoint ?? 'https://api.deepl.com';
|
|
this.fetch = opts.fetch ?? globalThis.fetch;
|
|
this.apiKey = opts.apiKey;
|
|
}
|
|
|
|
async translate(
|
|
texts: string[],
|
|
source: SourceLanguage | undefined,
|
|
dest: TargetLanguage,
|
|
opts?: { signal?: AbortSignal },
|
|
) {
|
|
const data = (await this.translateMany(texts, source, dest, opts)).translations;
|
|
|
|
return {
|
|
results: data.map((value) => value.text),
|
|
source_lang: data[0].detected_source_language,
|
|
};
|
|
}
|
|
|
|
/** DeepL translate request. */
|
|
private async translateMany(
|
|
texts: string[],
|
|
source: SourceLanguage | undefined,
|
|
targetLanguage: TargetLanguage,
|
|
opts?: { signal?: AbortSignal },
|
|
) {
|
|
const body: any = {
|
|
text: texts,
|
|
target_lang: targetLanguage.toUpperCase(),
|
|
tag_handling: 'html',
|
|
split_sentences: '1',
|
|
};
|
|
if (source) {
|
|
body.source_lang = source.toUpperCase();
|
|
}
|
|
|
|
const headers = new Headers();
|
|
headers.append('Authorization', 'DeepL-Auth-Key' + ' ' + this.apiKey);
|
|
headers.append('Content-Type', 'application/json');
|
|
|
|
const request = new Request(this.endpoint + '/v2/translate', {
|
|
method: 'POST',
|
|
body: JSON.stringify(body),
|
|
headers,
|
|
signal: opts?.signal,
|
|
});
|
|
|
|
const response = await this.fetch(request);
|
|
const json = await response.json();
|
|
if (!response.ok) {
|
|
throw new Error(json['message']);
|
|
}
|
|
const data = DeepLTranslator.schema().parse(json);
|
|
|
|
return data;
|
|
}
|
|
|
|
/** DeepL response schema.
|
|
* https://developers.deepl.com/docs/api-reference/translate/openapi-spec-for-text-translation */
|
|
private static schema() {
|
|
return z.object({
|
|
translations: z.array(
|
|
z.object({
|
|
detected_source_language: languageSchema,
|
|
text: z.string(),
|
|
}),
|
|
),
|
|
});
|
|
}
|
|
|
|
/** DeepL provider. */
|
|
getProvider(): Provider {
|
|
return DeepLTranslator.provider;
|
|
}
|
|
}
|