@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.
- package/dist/chunks/deepl-C9iR9zJ1.js +164 -0
- package/dist/chunks/deepl-C9iR9zJ1.js.map +1 -0
- package/dist/chunks/google-jZMDn2Ru.js +180 -0
- package/dist/chunks/google-jZMDn2Ru.js.map +1 -0
- package/dist/chunks/libretranslate-oJr-l5MM.js +146 -0
- package/dist/chunks/libretranslate-oJr-l5MM.js.map +1 -0
- package/dist/cli/claude-context.js +17 -17
- package/dist/cli/claude-context.js.map +1 -1
- package/dist/index.js +319 -238
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/dist/chunks/deepl-CWEP0MSh.js +0 -216
- package/dist/chunks/deepl-CWEP0MSh.js.map +0 -1
- package/dist/chunks/google-KGGP9X0w.js +0 -215
- package/dist/chunks/google-KGGP9X0w.js.map +0 -1
- package/dist/chunks/libretranslate-BeC38-0r.js +0 -211
- package/dist/chunks/libretranslate-BeC38-0r.js.map +0 -1
|
@@ -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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"}
|