@happyvertical/translator 0.80.0 → 0.80.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,211 +0,0 @@
1
- import { isValidText, InvalidTextError, TranslationError, getLanguageName, AuthenticationError, UnsupportedLanguageError } from "../index.js";
2
- class LibreTranslateProvider {
3
- baseUrl;
4
- apiKey;
5
- timeout;
6
- constructor(options) {
7
- this.baseUrl = options.apiUrl || "https://libretranslate.com";
8
- this.apiKey = options.apiKey;
9
- this.timeout = options.timeout || 3e4;
10
- }
11
- /**
12
- * Translates text from source language to target language
13
- */
14
- async translate(text, targetLanguage, sourceLanguage) {
15
- if (!isValidText(text)) {
16
- throw new InvalidTextError("Text cannot be empty", "libretranslate");
17
- }
18
- try {
19
- const body = {
20
- q: text,
21
- target: targetLanguage,
22
- format: "text"
23
- };
24
- if (sourceLanguage) {
25
- body.source = sourceLanguage;
26
- } else {
27
- body.source = "auto";
28
- }
29
- if (this.apiKey) {
30
- body.api_key = this.apiKey;
31
- }
32
- const response = await this.fetchLibreTranslate("/translate", body);
33
- const data = response;
34
- return {
35
- translatedText: data.translatedText,
36
- sourceText: text,
37
- sourceLanguage: data.detectedLanguage?.language || sourceLanguage || "unknown",
38
- targetLanguage,
39
- confidence: data.detectedLanguage?.confidence,
40
- detectedSourceLanguage: !sourceLanguage,
41
- raw: data
42
- };
43
- } catch (error) {
44
- throw this.mapError(error);
45
- }
46
- }
47
- /**
48
- * Detects the language of the provided text
49
- */
50
- async detectLanguage(text) {
51
- if (!isValidText(text)) {
52
- throw new InvalidTextError("Text cannot be empty", "libretranslate");
53
- }
54
- try {
55
- const body = {
56
- q: text
57
- };
58
- if (this.apiKey) {
59
- body.api_key = this.apiKey;
60
- }
61
- const response = await this.fetchLibreTranslate("/detect", body);
62
- if (Array.isArray(response)) {
63
- const detections = response;
64
- if (detections.length === 0) {
65
- throw new TranslationError(
66
- "No language detected",
67
- "NO_DETECTION",
68
- "libretranslate"
69
- );
70
- }
71
- return {
72
- language: detections[0].language,
73
- confidence: detections[0].confidence,
74
- alternatives: detections.slice(1).map((d) => ({
75
- language: d.language,
76
- confidence: d.confidence
77
- })),
78
- raw: response
79
- };
80
- }
81
- throw new TranslationError(
82
- "Invalid detection response",
83
- "INVALID_RESPONSE",
84
- "libretranslate"
85
- );
86
- } catch (error) {
87
- if (error instanceof TranslationError) {
88
- throw error;
89
- }
90
- throw this.mapError(error);
91
- }
92
- }
93
- /**
94
- * Gets the list of languages supported by this provider
95
- */
96
- async getSupportedLanguages() {
97
- try {
98
- const response = await this.fetchLibreTranslate(
99
- "/languages",
100
- void 0,
101
- "GET"
102
- );
103
- if (Array.isArray(response)) {
104
- const languages = response;
105
- return languages.map((lang) => ({
106
- code: lang.code,
107
- name: lang.name || getLanguageName(lang.code)
108
- }));
109
- }
110
- throw new TranslationError(
111
- "Invalid languages response",
112
- "INVALID_RESPONSE",
113
- "libretranslate"
114
- );
115
- } catch (error) {
116
- if (error instanceof TranslationError) {
117
- throw error;
118
- }
119
- throw this.mapError(error);
120
- }
121
- }
122
- /**
123
- * Translates multiple texts in a single batch operation
124
- * Note: LibreTranslate doesn't have native batch support,
125
- * so we translate texts sequentially
126
- */
127
- async translateBatch(texts, targetLanguage, sourceLanguage) {
128
- if (texts.length === 0) {
129
- return [];
130
- }
131
- const results = [];
132
- for (const text of texts) {
133
- const result = await this.translate(text, targetLanguage, sourceLanguage);
134
- results.push(result);
135
- }
136
- return results;
137
- }
138
- /**
139
- * Makes an HTTP request to LibreTranslate API
140
- */
141
- async fetchLibreTranslate(endpoint, body, method = "POST") {
142
- const url = `${this.baseUrl}${endpoint}`;
143
- const controller = new AbortController();
144
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
145
- try {
146
- const options = {
147
- method,
148
- signal: controller.signal
149
- };
150
- if (method === "POST" && body) {
151
- options.headers = {
152
- "Content-Type": "application/json"
153
- };
154
- options.body = JSON.stringify(body);
155
- }
156
- const response = await fetch(url, options);
157
- clearTimeout(timeoutId);
158
- if (!response.ok) {
159
- if (response.status === 401 || response.status === 403) {
160
- throw new AuthenticationError("libretranslate");
161
- }
162
- if (response.status === 400) {
163
- const errorData = await response.json().catch(() => ({}));
164
- if (errorData.error?.includes("language")) {
165
- throw new UnsupportedLanguageError(
166
- body.source || body.target || "unknown",
167
- "libretranslate"
168
- );
169
- }
170
- }
171
- throw new TranslationError(
172
- `HTTP ${response.status}: ${response.statusText}`,
173
- "HTTP_ERROR",
174
- "libretranslate"
175
- );
176
- }
177
- return await response.json();
178
- } catch (error) {
179
- clearTimeout(timeoutId);
180
- if (error instanceof TranslationError) {
181
- throw error;
182
- }
183
- if (error.name === "AbortError") {
184
- throw new TranslationError(
185
- "Request timeout",
186
- "TIMEOUT",
187
- "libretranslate"
188
- );
189
- }
190
- throw error;
191
- }
192
- }
193
- /**
194
- * Maps LibreTranslate errors to standardized error types
195
- */
196
- mapError(error) {
197
- if (error instanceof TranslationError) {
198
- return error;
199
- }
200
- const err = error;
201
- return new TranslationError(
202
- err?.message || "Translation failed",
203
- err?.code || "UNKNOWN_ERROR",
204
- "libretranslate"
205
- );
206
- }
207
- }
208
- export {
209
- LibreTranslateProvider
210
- };
211
- //# sourceMappingURL=libretranslate-BeC38-0r.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"libretranslate-BeC38-0r.js","sources":["../../src/providers/libretranslate.ts"],"sourcesContent":["/**\n * LibreTranslate provider implementation\n */\n\nimport type {\n LanguageDetectionResult,\n LibreTranslateOptions,\n SupportedLanguage,\n TranslationProvider,\n TranslationResult,\n} from '../shared/types';\nimport {\n AuthenticationError,\n InvalidTextError,\n TranslationError,\n UnsupportedLanguageError,\n} from '../shared/types';\nimport { getLanguageName, isValidText } from '../shared/utils';\n\n/**\n * LibreTranslate API response structures\n */\ninterface LibreTranslateTranslateResponse {\n translatedText: string;\n detectedLanguage?: {\n confidence: number;\n language: string;\n };\n}\n\ninterface LibreTranslateDetectResponse {\n confidence: number;\n language: string;\n}\n\ninterface LibreTranslateLanguage {\n code: string;\n name: string;\n}\n\n/**\n * LibreTranslate provider implementation\n */\nexport class LibreTranslateProvider implements TranslationProvider {\n private baseUrl: string;\n private apiKey?: string;\n private timeout: number;\n\n constructor(options: LibreTranslateOptions) {\n this.baseUrl = options.apiUrl || 'https://libretranslate.com';\n this.apiKey = options.apiKey;\n this.timeout = options.timeout || 30000;\n }\n\n /**\n * Translates text from source language to target language\n */\n async translate(\n text: string,\n targetLanguage: string,\n sourceLanguage?: string,\n ): Promise<TranslationResult> {\n if (!isValidText(text)) {\n throw new InvalidTextError('Text cannot be empty', 'libretranslate');\n }\n\n try {\n const body: any = {\n q: text,\n target: targetLanguage,\n format: 'text',\n };\n\n if (sourceLanguage) {\n body.source = sourceLanguage;\n } else {\n body.source = 'auto';\n }\n\n if (this.apiKey) {\n body.api_key = this.apiKey;\n }\n\n const response = await this.fetchLibreTranslate('/translate', body);\n\n const data = response as LibreTranslateTranslateResponse;\n\n return {\n translatedText: data.translatedText,\n sourceText: text,\n sourceLanguage:\n data.detectedLanguage?.language || sourceLanguage || 'unknown',\n targetLanguage,\n confidence: data.detectedLanguage?.confidence,\n detectedSourceLanguage: !sourceLanguage,\n raw: data,\n };\n } catch (error) {\n throw this.mapError(error);\n }\n }\n\n /**\n * Detects the language of the provided text\n */\n async detectLanguage(text: string): Promise<LanguageDetectionResult> {\n if (!isValidText(text)) {\n throw new InvalidTextError('Text cannot be empty', 'libretranslate');\n }\n\n try {\n const body: any = {\n q: text,\n };\n\n if (this.apiKey) {\n body.api_key = this.apiKey;\n }\n\n const response = await this.fetchLibreTranslate('/detect', body);\n\n if (Array.isArray(response)) {\n const detections = response as LibreTranslateDetectResponse[];\n\n if (detections.length === 0) {\n throw new TranslationError(\n 'No language detected',\n 'NO_DETECTION',\n 'libretranslate',\n );\n }\n\n return {\n language: detections[0].language,\n confidence: detections[0].confidence,\n alternatives: detections.slice(1).map((d) => ({\n language: d.language,\n confidence: d.confidence,\n })),\n raw: response,\n };\n }\n\n throw new TranslationError(\n 'Invalid detection response',\n 'INVALID_RESPONSE',\n 'libretranslate',\n );\n } catch (error) {\n if (error instanceof TranslationError) {\n throw error;\n }\n throw this.mapError(error);\n }\n }\n\n /**\n * Gets the list of languages supported by this provider\n */\n async getSupportedLanguages(): Promise<SupportedLanguage[]> {\n try {\n const response = await this.fetchLibreTranslate(\n '/languages',\n undefined,\n 'GET',\n );\n\n if (Array.isArray(response)) {\n const languages = response as LibreTranslateLanguage[];\n return languages.map((lang) => ({\n code: lang.code,\n name: lang.name || getLanguageName(lang.code),\n }));\n }\n\n throw new TranslationError(\n 'Invalid languages response',\n 'INVALID_RESPONSE',\n 'libretranslate',\n );\n } catch (error) {\n if (error instanceof TranslationError) {\n throw error;\n }\n throw this.mapError(error);\n }\n }\n\n /**\n * Translates multiple texts in a single batch operation\n * Note: LibreTranslate doesn't have native batch support,\n * so we translate texts sequentially\n */\n async translateBatch(\n texts: string[],\n targetLanguage: string,\n sourceLanguage?: string,\n ): Promise<TranslationResult[]> {\n if (texts.length === 0) {\n return [];\n }\n\n // Translate each text sequentially\n const results: TranslationResult[] = [];\n for (const text of texts) {\n const result = await this.translate(text, targetLanguage, sourceLanguage);\n results.push(result);\n }\n\n return results;\n }\n\n /**\n * Makes an HTTP request to LibreTranslate API\n */\n private async fetchLibreTranslate(\n endpoint: string,\n body?: any,\n method: 'GET' | 'POST' = 'POST',\n ): Promise<any> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const options: RequestInit = {\n method,\n signal: controller.signal,\n };\n\n if (method === 'POST' && body) {\n options.headers = {\n 'Content-Type': 'application/json',\n };\n options.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, options);\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n throw new AuthenticationError('libretranslate');\n }\n\n if (response.status === 400) {\n const errorData = (await response.json().catch(() => ({}))) as any;\n if (errorData.error?.includes('language')) {\n throw new UnsupportedLanguageError(\n body.source || body.target || 'unknown',\n 'libretranslate',\n );\n }\n }\n\n throw new TranslationError(\n `HTTP ${response.status}: ${response.statusText}`,\n 'HTTP_ERROR',\n 'libretranslate',\n );\n }\n\n return await response.json();\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof TranslationError) {\n throw error;\n }\n\n if ((error as Error).name === 'AbortError') {\n throw new TranslationError(\n 'Request timeout',\n 'TIMEOUT',\n 'libretranslate',\n );\n }\n\n throw error;\n }\n }\n\n /**\n * Maps LibreTranslate errors to standardized error types\n */\n private mapError(error: unknown): TranslationError {\n if (error instanceof TranslationError) {\n return error;\n }\n\n const err = error as any;\n return new TranslationError(\n err?.message || 'Translation failed',\n err?.code || 'UNKNOWN_ERROR',\n 'libretranslate',\n );\n }\n}\n"],"names":[],"mappings":"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"}