@ollang-dev/sdk 0.3.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/bin/tms.js +47 -0
- package/dist/browser/index.d.ts +143 -0
- package/dist/browser/index.js +2336 -0
- package/dist/browser/ollang-browser.min.js +1 -0
- package/dist/browser/script-loader.d.ts +1 -0
- package/dist/browser/script-loader.js +53 -0
- package/dist/client.d.ts +13 -0
- package/dist/client.js +60 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +74 -0
- package/dist/resources/cms.d.ts +29 -0
- package/dist/resources/cms.js +34 -0
- package/dist/resources/customInstructions.d.ts +11 -0
- package/dist/resources/customInstructions.js +24 -0
- package/dist/resources/orders.d.ts +13 -0
- package/dist/resources/orders.js +65 -0
- package/dist/resources/projects.d.ts +8 -0
- package/dist/resources/projects.js +29 -0
- package/dist/resources/revisions.d.ts +9 -0
- package/dist/resources/revisions.js +18 -0
- package/dist/resources/scans.d.ts +38 -0
- package/dist/resources/scans.js +52 -0
- package/dist/resources/uploads.d.ts +8 -0
- package/dist/resources/uploads.js +25 -0
- package/dist/tms/config.d.ts +16 -0
- package/dist/tms/config.js +172 -0
- package/dist/tms/detector/audio-detector.d.ts +27 -0
- package/dist/tms/detector/audio-detector.js +168 -0
- package/dist/tms/detector/auto-detect.d.ts +1 -0
- package/dist/tms/detector/auto-detect.js +152 -0
- package/dist/tms/detector/cms-detector.d.ts +17 -0
- package/dist/tms/detector/cms-detector.js +94 -0
- package/dist/tms/detector/content-type-detector.d.ts +79 -0
- package/dist/tms/detector/content-type-detector.js +2 -0
- package/dist/tms/detector/hardcoded-detector.d.ts +11 -0
- package/dist/tms/detector/hardcoded-detector.js +154 -0
- package/dist/tms/detector/i18n-detector.d.ts +16 -0
- package/dist/tms/detector/i18n-detector.js +311 -0
- package/dist/tms/detector/image-detector.d.ts +11 -0
- package/dist/tms/detector/image-detector.js +170 -0
- package/dist/tms/detector/text-detector.d.ts +9 -0
- package/dist/tms/detector/text-detector.js +35 -0
- package/dist/tms/detector/video-detector.d.ts +12 -0
- package/dist/tms/detector/video-detector.js +188 -0
- package/dist/tms/index.d.ts +12 -0
- package/dist/tms/index.js +38 -0
- package/dist/tms/multi-content-tms.d.ts +42 -0
- package/dist/tms/multi-content-tms.js +230 -0
- package/dist/tms/server/index.d.ts +1 -0
- package/dist/tms/server/index.js +1473 -0
- package/dist/tms/server/strapi-pusher.d.ts +31 -0
- package/dist/tms/server/strapi-pusher.js +296 -0
- package/dist/tms/server/strapi-schema.d.ts +47 -0
- package/dist/tms/server/strapi-schema.js +93 -0
- package/dist/tms/tms.d.ts +48 -0
- package/dist/tms/tms.js +875 -0
- package/dist/tms/types.d.ts +189 -0
- package/dist/tms/types.js +2 -0
- package/dist/tms/ui-dist/assets/index-5U1Hw3uo.css +1 -0
- package/dist/tms/ui-dist/assets/index-HvrqZV5Z.js +149 -0
- package/dist/tms/ui-dist/index.html +14 -0
- package/dist/types/index.d.ts +174 -0
- package/dist/types/index.js +2 -0
- package/package.json +98 -0
package/dist/tms/tms.js
ADDED
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TranslationManagementSystem = void 0;
|
|
4
|
+
const index_js_1 = require("../index.js");
|
|
5
|
+
const text_detector_js_1 = require("./detector/text-detector.js");
|
|
6
|
+
const video_detector_js_1 = require("./detector/video-detector.js");
|
|
7
|
+
const image_detector_js_1 = require("./detector/image-detector.js");
|
|
8
|
+
const audio_detector_js_1 = require("./detector/audio-detector.js");
|
|
9
|
+
const config_js_1 = require("./config.js");
|
|
10
|
+
class TranslationManagementSystem {
|
|
11
|
+
constructor(customConfig = {}) {
|
|
12
|
+
this.configManager = new config_js_1.ConfigManager();
|
|
13
|
+
this.config = this.configManager.load(customConfig);
|
|
14
|
+
this.ollangClient = new index_js_1.Ollang({
|
|
15
|
+
apiKey: this.config.ollang.apiKey,
|
|
16
|
+
baseUrl: this.config.ollang.baseUrl,
|
|
17
|
+
});
|
|
18
|
+
this.textDetector = new text_detector_js_1.TextDetector();
|
|
19
|
+
this.videoDetector = new video_detector_js_1.VideoDetector();
|
|
20
|
+
this.imageDetector = new image_detector_js_1.ImageDetector();
|
|
21
|
+
this.audioDetector = new audio_detector_js_1.AudioDetector();
|
|
22
|
+
this.state = this.createInitialState();
|
|
23
|
+
}
|
|
24
|
+
async scan() {
|
|
25
|
+
this.state.isScanning = true;
|
|
26
|
+
this.state.lastError = null;
|
|
27
|
+
try {
|
|
28
|
+
const scanConfig = {
|
|
29
|
+
includePaths: this.config.detection.includePaths.map((p) => `${this.config.projectRoot}/${p}`),
|
|
30
|
+
excludePaths: this.config.detection.excludePaths,
|
|
31
|
+
includePatterns: this.config.detection.includePatterns,
|
|
32
|
+
detectI18n: this.config.detection.detectI18n,
|
|
33
|
+
detectHardcoded: this.config.detection.detectHardcoded,
|
|
34
|
+
detectCMS: this.config.detection.detectCMS,
|
|
35
|
+
sourceLanguage: this.config.sourceLanguage,
|
|
36
|
+
};
|
|
37
|
+
const texts = await this.textDetector.scan(scanConfig);
|
|
38
|
+
const i18nSetup = await this.textDetector.detectI18nSetup(this.config.projectRoot);
|
|
39
|
+
const filteredTexts = await this.checkExistingTranslations(texts);
|
|
40
|
+
this.state.texts = filteredTexts;
|
|
41
|
+
this.state.i18nSetup = i18nSetup;
|
|
42
|
+
return filteredTexts;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
this.state.lastError = error;
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
this.state.isScanning = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async checkExistingTranslations(texts) {
|
|
53
|
+
const fs = require('fs').promises;
|
|
54
|
+
const path = require('path');
|
|
55
|
+
const processedTexts = [];
|
|
56
|
+
let submittedCount = 0;
|
|
57
|
+
for (const text of texts) {
|
|
58
|
+
if (!text.id.startsWith('i18n-')) {
|
|
59
|
+
processedTexts.push(text);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
let hasExistingTranslation = false;
|
|
63
|
+
try {
|
|
64
|
+
const withoutPrefix = text.id.substring(5);
|
|
65
|
+
const jsonIndex = withoutPrefix.indexOf('.json');
|
|
66
|
+
if (jsonIndex > 0) {
|
|
67
|
+
const afterJson = withoutPrefix.substring(jsonIndex + 5);
|
|
68
|
+
if (afterJson.startsWith('-')) {
|
|
69
|
+
const sourceFilePath = withoutPrefix.substring(0, jsonIndex + 5);
|
|
70
|
+
const key = afterJson.substring(1);
|
|
71
|
+
for (const targetLanguage of this.config.targetLanguages) {
|
|
72
|
+
const targetFilePath = sourceFilePath.replace(`/${this.config.sourceLanguage}.json`, `/${targetLanguage}.json`);
|
|
73
|
+
try {
|
|
74
|
+
const content = await fs.readFile(targetFilePath, 'utf-8');
|
|
75
|
+
const targetData = JSON.parse(content);
|
|
76
|
+
const keys = key.split('.');
|
|
77
|
+
let current = targetData;
|
|
78
|
+
let exists = true;
|
|
79
|
+
for (const k of keys) {
|
|
80
|
+
if (current && typeof current === 'object' && k in current) {
|
|
81
|
+
current = current[k];
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
exists = false;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (exists && current && typeof current === 'string') {
|
|
89
|
+
hasExistingTranslation = true;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) { }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error(` ❌ Error checking translation for ${text.id}:`, error);
|
|
100
|
+
}
|
|
101
|
+
if (hasExistingTranslation) {
|
|
102
|
+
processedTexts.push({
|
|
103
|
+
...text,
|
|
104
|
+
status: 'submitted',
|
|
105
|
+
});
|
|
106
|
+
submittedCount++;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
processedTexts.push(text);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return processedTexts;
|
|
113
|
+
}
|
|
114
|
+
async syncWithCodebase(targetLanguage) {
|
|
115
|
+
const fs = require('fs').promises;
|
|
116
|
+
const path = require('path');
|
|
117
|
+
let changedCount = 0;
|
|
118
|
+
let submittedCount = 0;
|
|
119
|
+
for (const text of this.state.texts) {
|
|
120
|
+
if (!text.id.startsWith('i18n-'))
|
|
121
|
+
continue;
|
|
122
|
+
const statusByLanguage = text.statusByLanguage || {};
|
|
123
|
+
const langStatus = statusByLanguage[targetLanguage];
|
|
124
|
+
const isSubmittedGlobal = text.status === 'submitted';
|
|
125
|
+
const isSubmittedLang = langStatus === 'submitted';
|
|
126
|
+
if (!isSubmittedGlobal && !isSubmittedLang)
|
|
127
|
+
continue;
|
|
128
|
+
const hasTranslationForThisLanguage = text.translations && text.translations[targetLanguage];
|
|
129
|
+
if (!hasTranslationForThisLanguage) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
submittedCount++;
|
|
133
|
+
try {
|
|
134
|
+
const withoutPrefix = text.id.substring(5);
|
|
135
|
+
const jsonIndex = withoutPrefix.indexOf('.json');
|
|
136
|
+
if (jsonIndex > 0) {
|
|
137
|
+
const afterJson = withoutPrefix.substring(jsonIndex + 5);
|
|
138
|
+
if (afterJson.startsWith('-')) {
|
|
139
|
+
const sourceFilePath = withoutPrefix.substring(0, jsonIndex + 5);
|
|
140
|
+
const key = afterJson.substring(1);
|
|
141
|
+
const targetFilePath = sourceFilePath.replace(`/${this.config.sourceLanguage}.json`, `/${targetLanguage}.json`);
|
|
142
|
+
let existsInCodebase = false;
|
|
143
|
+
try {
|
|
144
|
+
const content = await fs.readFile(targetFilePath, 'utf-8');
|
|
145
|
+
const targetData = JSON.parse(content);
|
|
146
|
+
const keys = key.split('.');
|
|
147
|
+
let current = targetData;
|
|
148
|
+
for (const k of keys) {
|
|
149
|
+
if (current && typeof current === 'object' && k in current) {
|
|
150
|
+
current = current[k];
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
current = null;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (current && typeof current === 'string') {
|
|
158
|
+
existsInCodebase = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
// File doesn't exist or can't be read
|
|
163
|
+
}
|
|
164
|
+
const hasTranslation = this.state.translations.has(text.id) ||
|
|
165
|
+
(text.translations && text.translations[targetLanguage]);
|
|
166
|
+
if (!existsInCodebase && hasTranslation) {
|
|
167
|
+
text.status = 'translated';
|
|
168
|
+
if (!text.statusByLanguage) {
|
|
169
|
+
text.statusByLanguage = {};
|
|
170
|
+
}
|
|
171
|
+
text.statusByLanguage[targetLanguage] = 'translated';
|
|
172
|
+
changedCount++;
|
|
173
|
+
}
|
|
174
|
+
else if (existsInCodebase && hasTranslation) {
|
|
175
|
+
if (text.status !== 'submitted') {
|
|
176
|
+
text.status = 'submitted';
|
|
177
|
+
changedCount++;
|
|
178
|
+
}
|
|
179
|
+
if (!text.statusByLanguage) {
|
|
180
|
+
text.statusByLanguage = {};
|
|
181
|
+
}
|
|
182
|
+
if (text.statusByLanguage[targetLanguage] !== 'submitted') {
|
|
183
|
+
text.statusByLanguage[targetLanguage] = 'submitted';
|
|
184
|
+
changedCount++;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
console.error(` ❌ Error syncing ${text.id}:`, error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async translate(texts, targetLanguage, level = this.config.ollang.defaultLevel, folderName, folderId) {
|
|
196
|
+
this.state.isTranslating = true;
|
|
197
|
+
this.state.lastError = null;
|
|
198
|
+
try {
|
|
199
|
+
if (this.config.ollang.mockMode) {
|
|
200
|
+
return this.translateMock(texts, targetLanguage, level);
|
|
201
|
+
}
|
|
202
|
+
const params = {
|
|
203
|
+
texts,
|
|
204
|
+
sourceLanguage: this.config.sourceLanguage,
|
|
205
|
+
targetLanguage,
|
|
206
|
+
level,
|
|
207
|
+
projectId: this.config.ollang.projectId,
|
|
208
|
+
folderName,
|
|
209
|
+
};
|
|
210
|
+
const order = await this.createOrder(params);
|
|
211
|
+
this.state.currentOrder = order;
|
|
212
|
+
await this.pollOrderStatus(order.id);
|
|
213
|
+
return order;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error('❌ Translation Error Details:');
|
|
217
|
+
console.error(' Error:', error);
|
|
218
|
+
if (error instanceof Error) {
|
|
219
|
+
console.error(' Message:', error.message);
|
|
220
|
+
console.error(' Stack:', error.stack);
|
|
221
|
+
}
|
|
222
|
+
this.state.lastError = error;
|
|
223
|
+
throw error;
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
this.state.isTranslating = false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async translateMock(texts, targetLanguage, level) {
|
|
230
|
+
const order = {
|
|
231
|
+
id: `mock-${Date.now()}`,
|
|
232
|
+
status: 'pending',
|
|
233
|
+
texts,
|
|
234
|
+
sourceLanguage: this.config.sourceLanguage,
|
|
235
|
+
targetLanguage,
|
|
236
|
+
createdAt: new Date(),
|
|
237
|
+
};
|
|
238
|
+
this.state.currentOrder = order;
|
|
239
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
240
|
+
for (const text of texts) {
|
|
241
|
+
if (text.cmsFields && Object.keys(text.cmsFields).length > 0) {
|
|
242
|
+
for (const [field, value] of Object.entries(text.cmsFields)) {
|
|
243
|
+
const subId = `${text.id}__${field}`;
|
|
244
|
+
const translation = {
|
|
245
|
+
textId: subId,
|
|
246
|
+
originalText: value,
|
|
247
|
+
translatedText: `[${targetLanguage.toUpperCase()}] ${value}`,
|
|
248
|
+
confidence: 0.95,
|
|
249
|
+
};
|
|
250
|
+
this.state.translations.set(subId, translation);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
const translation = {
|
|
255
|
+
textId: text.id,
|
|
256
|
+
originalText: text.text,
|
|
257
|
+
translatedText: `[${targetLanguage.toUpperCase()}] ${text.text}`,
|
|
258
|
+
confidence: 0.95,
|
|
259
|
+
};
|
|
260
|
+
this.state.translations.set(translation.textId, translation);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
order.status = 'completed';
|
|
264
|
+
order.completedAt = new Date();
|
|
265
|
+
return order;
|
|
266
|
+
}
|
|
267
|
+
async createOrder(params) {
|
|
268
|
+
const documentData = {
|
|
269
|
+
metadata: {
|
|
270
|
+
filename: `tms-document-${Date.now()}.json`,
|
|
271
|
+
sourceLanguage: params.sourceLanguage,
|
|
272
|
+
targetLanguage: params.targetLanguage,
|
|
273
|
+
},
|
|
274
|
+
slides: [
|
|
275
|
+
{
|
|
276
|
+
id: 'tms_document',
|
|
277
|
+
textElements: params.texts.flatMap((text) => {
|
|
278
|
+
if (text.cmsFields && Object.keys(text.cmsFields).length > 0) {
|
|
279
|
+
return Object.entries(text.cmsFields).map(([field, value]) => ({
|
|
280
|
+
id: `${text.id}__${field}`,
|
|
281
|
+
text: value,
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
return [{ id: text.id, text: text.text }];
|
|
285
|
+
}),
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
const FormData = require('form-data');
|
|
290
|
+
const formData = new FormData();
|
|
291
|
+
const jsonContent = JSON.stringify(documentData, null, 2);
|
|
292
|
+
const jsonBlob = Buffer.from(jsonContent, 'utf-8');
|
|
293
|
+
formData.append('file', jsonBlob, {
|
|
294
|
+
filename: `tms-document-${Date.now()}.json`,
|
|
295
|
+
contentType: 'application/json',
|
|
296
|
+
});
|
|
297
|
+
formData.append('name', `TMS-Document-${Date.now()}`);
|
|
298
|
+
formData.append('sourceLanguage', params.sourceLanguage);
|
|
299
|
+
if (params.folderId) {
|
|
300
|
+
console.log(`📁 Using provided folderId: ${params.folderId}`);
|
|
301
|
+
formData.append('folderId', params.folderId);
|
|
302
|
+
}
|
|
303
|
+
else if (params.folderName) {
|
|
304
|
+
console.log(`📁 Getting folderId for folder: ${params.folderName}`);
|
|
305
|
+
try {
|
|
306
|
+
const axios = require('axios');
|
|
307
|
+
const response = await axios.get('http://localhost:5972/api/folders');
|
|
308
|
+
const folders = response.data.folders || [];
|
|
309
|
+
const targetFolder = folders.find((f) => f.name === params.folderName);
|
|
310
|
+
if (targetFolder && targetFolder.id) {
|
|
311
|
+
console.log(`📁 Found folderId: ${targetFolder.id}`);
|
|
312
|
+
formData.append('folderId', targetFolder.id);
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
console.warn(`⚠️ Folder "${params.folderName}" not found in folders list`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
console.warn('⚠️ Could not get folder list:', error);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
else if (params.projectId) {
|
|
323
|
+
console.log(`📌 Getting folder from project: ${params.projectId}`);
|
|
324
|
+
try {
|
|
325
|
+
const project = await this.ollangClient.projects.get(params.projectId);
|
|
326
|
+
if (project.folderId) {
|
|
327
|
+
console.log(`📁 Found folderId: ${project.folderId}`);
|
|
328
|
+
formData.append('folderId', project.folderId);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
console.warn('⚠️ Could not get project folder:', error);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
console.log('📤 Uploading document...');
|
|
336
|
+
const uploadResponse = await this.ollangClient
|
|
337
|
+
.getClient()
|
|
338
|
+
.uploadFile('/integration/upload/direct', formData);
|
|
339
|
+
const projectId = uploadResponse.projectId;
|
|
340
|
+
console.log(`✅ Document uploaded, project: ${projectId}`);
|
|
341
|
+
const orderParams = {
|
|
342
|
+
orderType: 'document',
|
|
343
|
+
level: params.level,
|
|
344
|
+
projectId,
|
|
345
|
+
targetLanguageConfigs: [
|
|
346
|
+
{
|
|
347
|
+
language: params.targetLanguage,
|
|
348
|
+
isRush: false,
|
|
349
|
+
},
|
|
350
|
+
],
|
|
351
|
+
};
|
|
352
|
+
console.log('📤 Creating order with params:');
|
|
353
|
+
console.log(JSON.stringify(orderParams, null, 2));
|
|
354
|
+
const orderResponse = await this.ollangClient.orders.create(orderParams);
|
|
355
|
+
const order = {
|
|
356
|
+
id: orderResponse.id,
|
|
357
|
+
status: 'pending',
|
|
358
|
+
texts: params.texts,
|
|
359
|
+
sourceLanguage: params.sourceLanguage,
|
|
360
|
+
targetLanguage: params.targetLanguage,
|
|
361
|
+
createdAt: new Date(),
|
|
362
|
+
};
|
|
363
|
+
return order;
|
|
364
|
+
}
|
|
365
|
+
async pollOrderStatus(orderId) {
|
|
366
|
+
const maxAttempts = 120;
|
|
367
|
+
let attempts = 0;
|
|
368
|
+
while (attempts < maxAttempts) {
|
|
369
|
+
const order = await this.ollangClient.orders.get(orderId);
|
|
370
|
+
if (order.status === 'completed') {
|
|
371
|
+
await this.extractTranslations(order);
|
|
372
|
+
if (this.state.currentOrder) {
|
|
373
|
+
this.state.currentOrder.status = 'completed';
|
|
374
|
+
this.state.currentOrder.completedAt = new Date();
|
|
375
|
+
}
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (order.status === 'failed' || order.status === 'cancelled') {
|
|
379
|
+
if (this.state.currentOrder) {
|
|
380
|
+
this.state.currentOrder.status = order.status;
|
|
381
|
+
}
|
|
382
|
+
throw new Error(`Order ${orderId} ${order.status}`);
|
|
383
|
+
}
|
|
384
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
385
|
+
attempts++;
|
|
386
|
+
}
|
|
387
|
+
throw new Error(`Order ${orderId} timed out after ${maxAttempts * 5} seconds`);
|
|
388
|
+
}
|
|
389
|
+
async extractTranslations(order) {
|
|
390
|
+
try {
|
|
391
|
+
let documents = order.documents || order.targetDocuments || order.orderDocs || [];
|
|
392
|
+
if (!Array.isArray(documents) && order.document) {
|
|
393
|
+
documents = [order.document];
|
|
394
|
+
}
|
|
395
|
+
if (documents.length > 0) {
|
|
396
|
+
console.log(`Found ${documents.length} documents`);
|
|
397
|
+
for (const doc of documents) {
|
|
398
|
+
const documentUrl = doc.targetDocumentUrl || doc.url || doc.documentUrl;
|
|
399
|
+
if (documentUrl) {
|
|
400
|
+
console.log(`📥 Downloading translated document: ${documentUrl}`);
|
|
401
|
+
const axios = require('axios');
|
|
402
|
+
const response = await axios.get(documentUrl, {
|
|
403
|
+
responseType: 'json',
|
|
404
|
+
});
|
|
405
|
+
const translatedData = response.data;
|
|
406
|
+
console.log('📄 Translated document:', JSON.stringify(translatedData, null, 2));
|
|
407
|
+
if (translatedData.slides && Array.isArray(translatedData.slides)) {
|
|
408
|
+
for (const slide of translatedData.slides) {
|
|
409
|
+
if (slide.textElements && Array.isArray(slide.textElements)) {
|
|
410
|
+
for (const element of slide.textElements) {
|
|
411
|
+
if (!element || !element.id || !element.text)
|
|
412
|
+
continue;
|
|
413
|
+
const id = element.id;
|
|
414
|
+
const isCmsField = id.startsWith('cms-entry-') || id.includes('__');
|
|
415
|
+
const isKnownText = this.state.texts.some((t) => t.id === id);
|
|
416
|
+
if (!isCmsField && !isKnownText) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
const translation = {
|
|
420
|
+
textId: id,
|
|
421
|
+
originalText: '',
|
|
422
|
+
translatedText: element.text,
|
|
423
|
+
confidence: 1.0,
|
|
424
|
+
};
|
|
425
|
+
this.state.translations.set(translation.textId, translation);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
console.warn('⚠️ Document URL not found in document:', doc);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
console.log(`✅ Extracted ${this.state.translations.size} translations`);
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
console.log('⚠️ No documents found in order, trying alternative methods...');
|
|
439
|
+
if (order.projectId) {
|
|
440
|
+
console.log(`📥 Fetching documents from project: ${order.projectId}`);
|
|
441
|
+
try {
|
|
442
|
+
const project = await this.ollangClient.projects.get(order.projectId);
|
|
443
|
+
console.log('📋 Project structure:', JSON.stringify(project, null, 2));
|
|
444
|
+
if (project.targetDocuments && project.targetDocuments.length > 0) {
|
|
445
|
+
const targetDoc = project.targetDocuments[0];
|
|
446
|
+
const documentUrl = targetDoc.url || targetDoc.documentUrl;
|
|
447
|
+
if (documentUrl) {
|
|
448
|
+
console.log(`📥 Downloading from project: ${documentUrl}`);
|
|
449
|
+
const axios = require('axios');
|
|
450
|
+
const response = await axios.get(documentUrl, {
|
|
451
|
+
responseType: 'json',
|
|
452
|
+
});
|
|
453
|
+
const translatedData = response.data;
|
|
454
|
+
if (translatedData.slides && Array.isArray(translatedData.slides)) {
|
|
455
|
+
for (const slide of translatedData.slides) {
|
|
456
|
+
if (slide.textElements && Array.isArray(slide.textElements)) {
|
|
457
|
+
for (const element of slide.textElements) {
|
|
458
|
+
if (element.id && element.text) {
|
|
459
|
+
const translation = {
|
|
460
|
+
textId: element.id,
|
|
461
|
+
originalText: '',
|
|
462
|
+
translatedText: element.text,
|
|
463
|
+
confidence: 1.0,
|
|
464
|
+
};
|
|
465
|
+
this.state.translations.set(translation.textId, translation);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
console.error('❌ Error fetching from project:', error);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (this.state.translations.size === 0) {
|
|
479
|
+
const segments = order.segments || [];
|
|
480
|
+
for (const segment of segments) {
|
|
481
|
+
const translation = {
|
|
482
|
+
textId: segment.metadata?.textId || segment.id,
|
|
483
|
+
originalText: segment.sourceText,
|
|
484
|
+
translatedText: segment.targetText,
|
|
485
|
+
confidence: segment.confidence,
|
|
486
|
+
};
|
|
487
|
+
this.state.translations.set(translation.textId, translation);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
console.error('❌ Error extracting translations:', error);
|
|
494
|
+
throw error;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
async createProjectWithVtt(params) {
|
|
498
|
+
const fs = require('fs');
|
|
499
|
+
const path = require('path');
|
|
500
|
+
const FormData = require('form-data');
|
|
501
|
+
const vttContent = this.generateVttContent(params.texts, params.sourceLanguage);
|
|
502
|
+
const tmpDir = require('os').tmpdir();
|
|
503
|
+
const tmpFile = path.join(tmpDir, `tms-${Date.now()}.vtt`);
|
|
504
|
+
fs.writeFileSync(tmpFile, vttContent, 'utf-8');
|
|
505
|
+
try {
|
|
506
|
+
const formData = new FormData();
|
|
507
|
+
formData.append('file', fs.createReadStream(tmpFile), {
|
|
508
|
+
filename: 'tms-texts.vtt',
|
|
509
|
+
contentType: 'text/vtt',
|
|
510
|
+
});
|
|
511
|
+
formData.append('name', `TMS-${Date.now()}`);
|
|
512
|
+
formData.append('sourceLanguage', params.sourceLanguage);
|
|
513
|
+
const response = await this.ollangClient
|
|
514
|
+
.getClient()
|
|
515
|
+
.uploadFile('/integration/upload/direct', formData);
|
|
516
|
+
return response.projectId;
|
|
517
|
+
}
|
|
518
|
+
finally {
|
|
519
|
+
try {
|
|
520
|
+
fs.unlinkSync(tmpFile);
|
|
521
|
+
}
|
|
522
|
+
catch (e) { }
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
generateVttContent(texts, sourceLanguage) {
|
|
526
|
+
let vtt = 'WEBVTT\n\n';
|
|
527
|
+
texts.forEach((text, index) => {
|
|
528
|
+
const startTime = this.formatVttTime(index * 5);
|
|
529
|
+
const endTime = this.formatVttTime(index * 5 + 4);
|
|
530
|
+
vtt += `${index + 1}\n`;
|
|
531
|
+
vtt += `${startTime} --> ${endTime}\n`;
|
|
532
|
+
vtt += `${text.text}\n\n`;
|
|
533
|
+
});
|
|
534
|
+
return vtt;
|
|
535
|
+
}
|
|
536
|
+
formatVttTime(seconds) {
|
|
537
|
+
const hours = Math.floor(seconds / 3600);
|
|
538
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
539
|
+
const secs = Math.floor(seconds % 60);
|
|
540
|
+
const ms = Math.floor((seconds % 1) * 1000);
|
|
541
|
+
return `${hours.toString().padStart(2, '0')}:${minutes
|
|
542
|
+
.toString()
|
|
543
|
+
.padStart(2, '0')}:${secs.toString().padStart(2, '0')}.${ms.toString().padStart(3, '0')}`;
|
|
544
|
+
}
|
|
545
|
+
getState() {
|
|
546
|
+
return { ...this.state };
|
|
547
|
+
}
|
|
548
|
+
getConfig() {
|
|
549
|
+
return { ...this.config };
|
|
550
|
+
}
|
|
551
|
+
getI18nSetup() {
|
|
552
|
+
return this.state.i18nSetup;
|
|
553
|
+
}
|
|
554
|
+
getSDK() {
|
|
555
|
+
return this.ollangClient;
|
|
556
|
+
}
|
|
557
|
+
getTexts() {
|
|
558
|
+
return [...this.state.texts];
|
|
559
|
+
}
|
|
560
|
+
getTranslations() {
|
|
561
|
+
return new Map(this.state.translations);
|
|
562
|
+
}
|
|
563
|
+
async applyTranslations(targetLanguage, textIds) {
|
|
564
|
+
this.state.isApplying = true;
|
|
565
|
+
this.state.lastError = null;
|
|
566
|
+
try {
|
|
567
|
+
const translationsToApply = textIds && textIds.length > 0
|
|
568
|
+
? new Map(Array.from(this.state.translations.entries()).filter(([id]) => textIds.includes(id)))
|
|
569
|
+
: this.state.translations;
|
|
570
|
+
const fs = require('fs').promises;
|
|
571
|
+
const path = require('path');
|
|
572
|
+
const fileGroups = new Map();
|
|
573
|
+
for (const [textId, translation] of translationsToApply) {
|
|
574
|
+
if (textId.startsWith('i18n-')) {
|
|
575
|
+
const withoutPrefix = textId.substring(5);
|
|
576
|
+
const jsonIndex = withoutPrefix.indexOf('.json');
|
|
577
|
+
if (jsonIndex > 0) {
|
|
578
|
+
const afterJson = withoutPrefix.substring(jsonIndex + 5);
|
|
579
|
+
if (afterJson.startsWith('-')) {
|
|
580
|
+
const filePath = withoutPrefix.substring(0, jsonIndex + 5);
|
|
581
|
+
// Path traversal protection
|
|
582
|
+
const absoluteFilePath = path.resolve(this.config.projectRoot, filePath);
|
|
583
|
+
if (!absoluteFilePath.startsWith(path.resolve(this.config.projectRoot) + path.sep) &&
|
|
584
|
+
absoluteFilePath !== path.resolve(this.config.projectRoot)) {
|
|
585
|
+
console.warn(` ⚠️ Skipping path outside project root: ${filePath}`);
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
const key = afterJson.substring(1);
|
|
589
|
+
if (!fileGroups.has(filePath)) {
|
|
590
|
+
fileGroups.set(filePath, new Map());
|
|
591
|
+
}
|
|
592
|
+
fileGroups.get(filePath).set(key, translation.translatedText);
|
|
593
|
+
console.log(` Mapped: ${key} -> ${filePath}`);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
console.log(` Found ${fileGroups.size} files to update`);
|
|
599
|
+
let updatedFiles = 0;
|
|
600
|
+
for (const [originalFilePath, translations] of fileGroups) {
|
|
601
|
+
try {
|
|
602
|
+
const targetFilePath = originalFilePath.replace(`/${this.config.sourceLanguage}.json`, `/${targetLanguage}.json`);
|
|
603
|
+
const absoluteTargetPath = path.resolve(this.config.projectRoot, targetFilePath);
|
|
604
|
+
if (!absoluteTargetPath.startsWith(path.resolve(this.config.projectRoot) + path.sep) &&
|
|
605
|
+
absoluteTargetPath !== path.resolve(this.config.projectRoot)) {
|
|
606
|
+
console.warn(` ⚠️ Skipping target path outside project root: ${targetFilePath}`);
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
console.log(` Processing: ${targetFilePath}`);
|
|
610
|
+
const targetDir = path.dirname(absoluteTargetPath);
|
|
611
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
612
|
+
let existingContent = {};
|
|
613
|
+
try {
|
|
614
|
+
const content = await fs.readFile(absoluteTargetPath, 'utf-8');
|
|
615
|
+
existingContent = JSON.parse(content);
|
|
616
|
+
}
|
|
617
|
+
catch (error) {
|
|
618
|
+
console.log(` Creating new file: ${targetFilePath}`);
|
|
619
|
+
}
|
|
620
|
+
for (const [key, value] of translations) {
|
|
621
|
+
const keys = key.split('.');
|
|
622
|
+
let current = existingContent;
|
|
623
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
624
|
+
if (!current[keys[i]]) {
|
|
625
|
+
current[keys[i]] = {};
|
|
626
|
+
}
|
|
627
|
+
current = current[keys[i]];
|
|
628
|
+
}
|
|
629
|
+
current[keys[keys.length - 1]] = value;
|
|
630
|
+
}
|
|
631
|
+
await fs.writeFile(absoluteTargetPath, JSON.stringify(existingContent, null, 2) + '\n', 'utf-8');
|
|
632
|
+
console.log(` ✅ Updated: ${targetFilePath} (${translations.size} keys)`);
|
|
633
|
+
updatedFiles++;
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
console.error(` ❌ Error updating ${originalFilePath}:`, error);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
console.log(`✅ Applied translations to ${updatedFiles} files`);
|
|
640
|
+
if (this.state.imageTranslations && this.state.imageTranslations.size > 0) {
|
|
641
|
+
console.log(`\n🖼️ Applying ${this.state.imageTranslations.size} image translations...`);
|
|
642
|
+
for (const [imageId, translation] of this.state.imageTranslations) {
|
|
643
|
+
if (translation.targetLanguage !== targetLanguage) {
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
if (translation.isUrl) {
|
|
647
|
+
const sourceFile = this.findSourceFileForUrl(imageId);
|
|
648
|
+
if (sourceFile) {
|
|
649
|
+
await this.replaceUrlInFile(sourceFile, translation.originalPath, translation.translatedPath);
|
|
650
|
+
updatedFiles++;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
const sourceExists = await fs
|
|
655
|
+
.access(translation.originalPath)
|
|
656
|
+
.then(() => true)
|
|
657
|
+
.catch(() => false);
|
|
658
|
+
if (sourceExists) {
|
|
659
|
+
await fs.copyFile(translation.originalPath, translation.translatedPath);
|
|
660
|
+
updatedFiles++;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return updatedFiles;
|
|
666
|
+
}
|
|
667
|
+
catch (error) {
|
|
668
|
+
this.state.lastError = error;
|
|
669
|
+
throw error;
|
|
670
|
+
}
|
|
671
|
+
finally {
|
|
672
|
+
this.state.isApplying = false;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
findSourceFileForUrl(imageId) {
|
|
676
|
+
const imageItem = this.state.texts.find((t) => t.id === imageId);
|
|
677
|
+
if (!imageItem) {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
if (imageItem._imageData) {
|
|
681
|
+
const imageData = imageItem._imageData;
|
|
682
|
+
if (imageData.metadata?.sourceFile) {
|
|
683
|
+
return imageData.metadata.sourceFile;
|
|
684
|
+
}
|
|
685
|
+
if (imageData.metadata?.isUrl) {
|
|
686
|
+
return imageData.path;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
async replaceUrlInFile(filePath, oldUrl, newUrl) {
|
|
692
|
+
const fs = require('fs').promises;
|
|
693
|
+
try {
|
|
694
|
+
let content = await fs.readFile(filePath, 'utf-8');
|
|
695
|
+
const escapedOldUrl = oldUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
696
|
+
const regex = new RegExp(`"${escapedOldUrl}"`, 'g');
|
|
697
|
+
content = content.replace(regex, `"${oldUrl}","${newUrl}"`);
|
|
698
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
699
|
+
}
|
|
700
|
+
catch (error) {
|
|
701
|
+
console.error(` ❌ Error replacing URL in ${filePath}:`, error);
|
|
702
|
+
throw error;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
async scanVideos() {
|
|
706
|
+
const detectionConfig = {
|
|
707
|
+
includePaths: ['.'],
|
|
708
|
+
excludePaths: this.config.detection.excludePaths,
|
|
709
|
+
includePatterns: this.config.detection.includePatterns,
|
|
710
|
+
};
|
|
711
|
+
return this.videoDetector.detect(this.config.projectRoot, detectionConfig);
|
|
712
|
+
}
|
|
713
|
+
async scanImages() {
|
|
714
|
+
const detectionConfig = {
|
|
715
|
+
includePaths: ['.'],
|
|
716
|
+
excludePaths: this.config.detection.excludePaths,
|
|
717
|
+
includePatterns: this.config.detection.includePatterns,
|
|
718
|
+
};
|
|
719
|
+
return this.imageDetector.detect(this.config.projectRoot, detectionConfig);
|
|
720
|
+
}
|
|
721
|
+
async scanAudios() {
|
|
722
|
+
const detectionConfig = {
|
|
723
|
+
includePaths: ['.'],
|
|
724
|
+
excludePaths: this.config.detection.excludePaths,
|
|
725
|
+
includePatterns: this.config.detection.includePatterns,
|
|
726
|
+
};
|
|
727
|
+
return this.audioDetector.detect(this.config.projectRoot, detectionConfig);
|
|
728
|
+
}
|
|
729
|
+
async scanAll() {
|
|
730
|
+
const [texts, videos, images, audios] = await Promise.all([
|
|
731
|
+
this.scan(),
|
|
732
|
+
this.scanVideos(),
|
|
733
|
+
this.scanImages(),
|
|
734
|
+
this.scanAudios(),
|
|
735
|
+
]);
|
|
736
|
+
return {
|
|
737
|
+
texts,
|
|
738
|
+
videos,
|
|
739
|
+
images,
|
|
740
|
+
audios,
|
|
741
|
+
total: texts.length + videos.length + images.length + audios.length,
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
async translateVideo(video, targetLanguage, level = this.config.ollang.defaultLevel) {
|
|
745
|
+
const isUrl = video.metadata?.isUrl || (video.url && !video.path);
|
|
746
|
+
if (isUrl && video.url) {
|
|
747
|
+
const getFilenameFromUrl = (url) => {
|
|
748
|
+
const urlWithoutQuery = url.split('?')[0];
|
|
749
|
+
const parts = urlWithoutQuery.split('/');
|
|
750
|
+
return parts[parts.length - 1] || 'video.mp4';
|
|
751
|
+
};
|
|
752
|
+
const filename = getFilenameFromUrl(video.url);
|
|
753
|
+
const uploadParams = {
|
|
754
|
+
url: video.url,
|
|
755
|
+
originalname: filename,
|
|
756
|
+
size: video.metadata?.size || 0,
|
|
757
|
+
sourceLanguage: this.config.sourceLanguage,
|
|
758
|
+
};
|
|
759
|
+
const uploadResponse = await this.ollangClient
|
|
760
|
+
.getClient()
|
|
761
|
+
.post('/integration/upload/direct-url', uploadParams);
|
|
762
|
+
const projectId = uploadResponse.projectId;
|
|
763
|
+
const orderParams = {
|
|
764
|
+
orderType: 'aiDubbing',
|
|
765
|
+
level,
|
|
766
|
+
projectId,
|
|
767
|
+
targetLanguageConfigs: [
|
|
768
|
+
{
|
|
769
|
+
language: targetLanguage,
|
|
770
|
+
isRush: false,
|
|
771
|
+
},
|
|
772
|
+
],
|
|
773
|
+
};
|
|
774
|
+
const order = await this.ollangClient.orders.create(orderParams);
|
|
775
|
+
return order.id;
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
const FormData = require('form-data');
|
|
779
|
+
const fs = require('fs');
|
|
780
|
+
const formData = new FormData();
|
|
781
|
+
formData.append('file', fs.createReadStream(video.path));
|
|
782
|
+
formData.append('name', `Video-Dubbing-${Date.now()}`);
|
|
783
|
+
formData.append('sourceLanguage', this.config.sourceLanguage);
|
|
784
|
+
const uploadResponse = await this.ollangClient
|
|
785
|
+
.getClient()
|
|
786
|
+
.uploadFile('/integration/upload/direct', formData);
|
|
787
|
+
const projectId = uploadResponse.projectId;
|
|
788
|
+
const orderParams = {
|
|
789
|
+
orderType: 'aiDubbing',
|
|
790
|
+
level,
|
|
791
|
+
projectId,
|
|
792
|
+
targetLanguageConfigs: [
|
|
793
|
+
{
|
|
794
|
+
language: targetLanguage,
|
|
795
|
+
isRush: false,
|
|
796
|
+
},
|
|
797
|
+
],
|
|
798
|
+
};
|
|
799
|
+
const order = await this.ollangClient.orders.create(orderParams);
|
|
800
|
+
return order.id;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
async translateImage(image, targetLanguage, level = this.config.ollang.defaultLevel) {
|
|
804
|
+
const path = require('path');
|
|
805
|
+
let translatedPath;
|
|
806
|
+
const isUrl = image.metadata.isUrl || false;
|
|
807
|
+
if (isUrl && image.url) {
|
|
808
|
+
translatedPath = `${image.url}-${targetLanguage}`;
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
const ext = path.extname(image.path);
|
|
812
|
+
const basePath = image.path.slice(0, -ext.length);
|
|
813
|
+
translatedPath = `${basePath}-${targetLanguage}${ext}`;
|
|
814
|
+
}
|
|
815
|
+
const mockOrderId = `mock-image-${Date.now()}`;
|
|
816
|
+
if (!this.state.imageTranslations) {
|
|
817
|
+
this.state.imageTranslations = new Map();
|
|
818
|
+
}
|
|
819
|
+
const mapKey = image.textItemId || image.id;
|
|
820
|
+
this.state.imageTranslations.set(mapKey, {
|
|
821
|
+
originalPath: isUrl ? image.url : image.path,
|
|
822
|
+
translatedPath,
|
|
823
|
+
targetLanguage,
|
|
824
|
+
isUrl,
|
|
825
|
+
orderId: mockOrderId,
|
|
826
|
+
});
|
|
827
|
+
return mockOrderId;
|
|
828
|
+
}
|
|
829
|
+
async translateAudio(audio, targetLanguage, level = this.config.ollang.defaultLevel) {
|
|
830
|
+
const FormData = require('form-data');
|
|
831
|
+
const fs = require('fs');
|
|
832
|
+
const formData = new FormData();
|
|
833
|
+
formData.append('file', fs.createReadStream(audio.path));
|
|
834
|
+
formData.append('name', `Audio-Dubbing-${Date.now()}`);
|
|
835
|
+
formData.append('sourceLanguage', this.config.sourceLanguage);
|
|
836
|
+
const uploadResponse = await this.ollangClient
|
|
837
|
+
.getClient()
|
|
838
|
+
.uploadFile('/integration/upload/direct', formData);
|
|
839
|
+
const projectId = uploadResponse.projectId;
|
|
840
|
+
const orderParams = {
|
|
841
|
+
orderType: 'aiDubbing',
|
|
842
|
+
level,
|
|
843
|
+
projectId,
|
|
844
|
+
targetLanguageConfigs: [
|
|
845
|
+
{
|
|
846
|
+
language: targetLanguage,
|
|
847
|
+
isRush: false,
|
|
848
|
+
},
|
|
849
|
+
],
|
|
850
|
+
};
|
|
851
|
+
const order = await this.ollangClient.orders.create(orderParams);
|
|
852
|
+
return order.id;
|
|
853
|
+
}
|
|
854
|
+
createInitialState() {
|
|
855
|
+
return {
|
|
856
|
+
config: this.config,
|
|
857
|
+
texts: [],
|
|
858
|
+
i18nSetup: null,
|
|
859
|
+
selectedTextIds: new Set(),
|
|
860
|
+
currentOrder: null,
|
|
861
|
+
translations: new Map(),
|
|
862
|
+
editedTranslations: new Map(),
|
|
863
|
+
panelVisible: false,
|
|
864
|
+
panelMinimized: false,
|
|
865
|
+
previewActive: false,
|
|
866
|
+
searchQuery: '',
|
|
867
|
+
activeFilters: [],
|
|
868
|
+
isScanning: false,
|
|
869
|
+
isTranslating: false,
|
|
870
|
+
isApplying: false,
|
|
871
|
+
lastError: null,
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
exports.TranslationManagementSystem = TranslationManagementSystem;
|