Skip to content

Commit 94c0d1e

Browse files
committed
Merge branch 'main' into tauri - resolve conflicts
2 parents f2b06a7 + 0eda3a1 commit 94c0d1e

File tree

3 files changed

+24
-228
lines changed

3 files changed

+24
-228
lines changed

.github/workflows/build.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ jobs:
3535

3636
- name: Run tests
3737
run: bun run test:jest
38+
39+
- name: Setup tmate session (for debugging)
40+
if: failure() || github.event_name == 'workflow_dispatch'
41+
uses: mxschmitt/action-tmate@v3
42+
timeout-minutes: 3
3843

3944
build:
4045
name: Build - ${{ matrix.platform.target }}

src/components/tabs/quests-tab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,4 +356,4 @@ export function QuestsTab() {
356356
onTranslate={handleTranslate}
357357
/>
358358
);
359-
}
359+
}
Lines changed: 18 additions & 227 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
1-
import {TranslationService, TranslationJob} from "./translation-service";
2-
import {TranslationResult, TranslationTargetType} from "../types/minecraft";
3-
import {invoke} from "@tauri-apps/api/core";
4-
import {ErrorLogger} from "../utils/error-logger";
5-
import { TRANSLATION_DEFAULTS } from "../constants/defaults";
6-
import { backupService, type CreateBackupOptions } from "./backup-service";
1+
import { TranslationService, TranslationJob } from "./translation-service";
2+
import { TranslationResult, TranslationTargetType } from "../types/minecraft";
73

8-
/**
9-
* Shared translation runner for all tabs.
10-
* Processes jobs chunk-by-chunk, checks for cancellation, and reports progress/results.
11-
*/
124
export interface RunTranslationJobsOptions<T extends TranslationJob = TranslationJob> {
135
jobs: T[];
146
translationService: TranslationService;
@@ -57,32 +49,13 @@ export async function runTranslationJobs<T extends TranslationJob = TranslationJ
5749

5850
for (let i = 0; i < jobs.length; i++) {
5951
const job = jobs[i];
60-
61-
// Set session information for comprehensive logging
62-
job.totalFiles = jobs.length;
63-
job.currentFileIndex = i + 1;
64-
6552
if (onJobStart) onJobStart(job, i);
6653
if (setCurrentJobId) setCurrentJobId(job.id);
6754

6855
// Start the translation job chunk-by-chunk, checking for interruption
6956
job.status = "processing";
7057
job.startTime = Date.now();
7158

72-
// Log initial file progress
73-
await logFileProgress(
74-
job.currentFileName || `File ${i + 1}`,
75-
i + 1,
76-
jobs.length,
77-
0,
78-
job.chunks.length,
79-
0,
80-
getTotalKeysInJob(job)
81-
);
82-
83-
let failedChunksCount = 0;
84-
const maxFailedChunks = Math.ceil(job.chunks.length * TRANSLATION_DEFAULTS.maxFailedChunksRatio);
85-
8659
for (let chunkIndex = 0; chunkIndex < job.chunks.length; chunkIndex++) {
8760
// Check for cancellation
8861
if (translationService.isJobInterrupted(job.id)) {
@@ -92,91 +65,23 @@ export async function runTranslationJobs<T extends TranslationJob = TranslationJ
9265
break;
9366
}
9467
const chunk = job.chunks[chunkIndex];
95-
96-
// Skip already failed chunks
97-
if (chunk.status === "failed") {
98-
continue;
99-
}
100-
10168
chunk.status = "processing";
10269
try {
10370
const translatedContent = await translationService.translateChunk(
10471
chunk.content,
10572
job.targetLanguage,
10673
job.id
10774
);
108-
109-
// Check if translation actually produced content
110-
if (!translatedContent || Object.keys(translatedContent).length === 0) {
111-
// Handle empty content as a failure without throwing
112-
console.log(`[TranslationRunner] Translation returned empty content for chunk ${chunkIndex} - possible API key issue`);
113-
chunk.status = "failed";
114-
chunk.error = "Translation returned empty content - possible API key issue";
115-
chunk.translatedContent = {};
116-
failedChunksCount++;
117-
118-
// Log the failure
119-
const errorMessage = "API key is not configured or translation failed";
120-
if (errorMessage.includes("API key")) {
121-
console.log(`[TranslationRunner] API key error detected, stopping job immediately`);
122-
job.status = "failed";
123-
job.error = errorMessage;
124-
break;
125-
}
126-
} else {
127-
chunk.translatedContent = translatedContent;
128-
chunk.status = "completed";
129-
}
75+
chunk.translatedContent = translatedContent;
76+
chunk.status = "completed";
13077
} catch (error) {
13178
chunk.status = "failed";
13279
chunk.error = error instanceof Error ? error.message : String(error);
133-
failedChunksCount++;
134-
135-
// Log the failure
136-
console.log(`[TranslationRunner] Chunk ${chunkIndex} failed:`, error);
137-
138-
// If it's an API key error, stop the entire job immediately
139-
const errorMessage = error instanceof Error ? error.message : String(error);
140-
if (errorMessage.includes("API key is not configured") ||
141-
errorMessage.includes("API key is not set") ||
142-
errorMessage.includes("Incorrect API key provided")) {
143-
console.log(`[TranslationRunner] API key error detected, stopping job immediately`);
144-
job.status = "failed";
145-
job.error = errorMessage;
146-
break;
147-
}
148-
149-
// If too many chunks fail, stop processing this job
150-
if (failedChunksCount > maxFailedChunks && maxFailedChunks > 0) {
151-
console.log(`[TranslationRunner] Too many failed chunks (${failedChunksCount}/${job.chunks.length}), stopping job`);
152-
job.status = "failed";
153-
job.error = `Too many chunks failed (${failedChunksCount}/${job.chunks.length})`;
154-
break;
155-
}
15680
}
157-
81+
15882
// Increment chunk-level progress once per chunk (only if chunk tracking is used)
159-
if (incrementCompletedChunks) {
160-
console.log(`[TranslationRunner] Incrementing completed chunks for job ${job.id}, chunk ${chunkIndex + 1}/${job.chunks.length}`);
161-
incrementCompletedChunks();
162-
}
83+
if (incrementCompletedChunks) incrementCompletedChunks();
16384
if (onJobChunkComplete) onJobChunkComplete(job, chunkIndex);
164-
165-
// Log updated file progress after chunk completion
166-
const completedChunks = job.chunks.filter(c => c.status === "completed").length;
167-
const completedKeys = job.chunks
168-
.filter(c => c.status === "completed")
169-
.reduce((sum, c) => sum + Object.keys(c.content).length, 0);
170-
171-
await logFileProgress(
172-
job.currentFileName || `File ${i + 1}`,
173-
i + 1,
174-
jobs.length,
175-
completedChunks,
176-
job.chunks.length,
177-
completedKeys,
178-
getTotalKeysInJob(job)
179-
);
18085
}
18186

18287
// If interrupted, stop processing further jobs
@@ -188,154 +93,40 @@ export async function runTranslationJobs<T extends TranslationJob = TranslationJ
18893
// Mark job as complete
18994
job.status = job.chunks.every((c: import("./translation-service").TranslationChunk) => c.status === "completed") ? "completed" : "failed";
19095
job.endTime = Date.now();
191-
192-
// Log performance metrics for this job
193-
const jobDuration = job.endTime - job.startTime;
194-
const jobTotalKeys = getTotalKeysInJob(job);
195-
const keysPerSecond = jobTotalKeys / (jobDuration / 1000);
196-
197-
await logPerformanceMetrics(
198-
`Job Translation`,
199-
jobDuration,
200-
undefined,
201-
`${jobTotalKeys} keys, ${keysPerSecond.toFixed(2)} keys/sec, ${job.chunks.length} chunks`
202-
);
203-
20496
if (onJobComplete) onJobComplete(job, i);
20597

20698
// Write output and report result
20799
const outputPath = getOutputPath(job);
208100
const content = getResultContent(job);
209101
let writeSuccess = true;
210-
102+
211103
try {
212-
// Create backup before writing output (if enabled and session ID provided)
213-
if (enableBackup && sessionId) {
214-
try {
215-
// Determine source name for backup
216-
const sourceName = job.currentFileName || job.id || `${type}_${i + 1}`;
217-
218-
// Calculate file size estimate
219-
const contentSize = JSON.stringify(content).length;
220-
221-
// Create backup options
222-
const backupOptions: CreateBackupOptions = {
223-
type,
224-
sourceName,
225-
targetLanguage,
226-
sessionId,
227-
filePaths: [outputPath], // Path where the output will be written
228-
statistics: {
229-
totalKeys: getTotalKeysInJob(job),
230-
successfulTranslations: job.chunks.filter(c => c.status === "completed").length,
231-
fileSize: contentSize
232-
}
233-
};
234-
235-
// Create the backup
236-
const backupInfo = await backupService.createBackup(backupOptions);
237-
console.log(`[TranslationRunner] Backup created for ${sourceName}: ${backupInfo.metadata.id}`);
238-
} catch (backupError) {
239-
// Log backup error but don't fail the translation
240-
console.warn(`[TranslationRunner] Failed to create backup for job ${job.id}:`, backupError);
241-
await ErrorLogger.logError(`Backup creation failed for job ${job.id}`, backupError, type);
242-
}
243-
}
244-
245104
await writeOutput(job, outputPath, content);
246105
} catch (error) {
247-
await ErrorLogger.logError(`Failed to write output for job ${job.id}`, error, type);
106+
console.error(`Failed to write output for job ${job.id}:`, error);
248107
writeSuccess = false;
249108
}
250109

251110
if (onResult) {
252-
// Check if content is actually valid (not empty)
253-
const hasValidContent = content && Object.keys(content).length > 0;
254-
255111
onResult({
256112
type,
257113
id: type === "mod" ? (job.currentFileName || job.id) : job.id,
258114
displayName: job.currentFileName || job.id,
259115
targetLanguage,
260116
content,
261117
outputPath,
262-
success: job.status === "completed" && writeSuccess && hasValidContent
118+
success: writeSuccess && job.status === "completed",
119+
sessionId,
120+
enableBackup
263121
});
264122
}
265123

266-
// Increment mod-level progress when entire job is complete (only if mod tracking is used)
267-
if (incrementCompletedMods) {
268-
console.log(`[TranslationRunner] Incrementing completed mods for job ${job.id}`);
269-
incrementCompletedMods();
270-
}
271-
}
272-
if (setCurrentJobId) setCurrentJobId(null);
273-
}
274-
275-
/**
276-
* Log file progress with detailed status
277-
* @param fileName Name of the file
278-
* @param fileIndex Current file index (1-based)
279-
* @param totalFiles Total number of files
280-
* @param chunksCompleted Chunks completed for this file
281-
* @param totalChunks Total chunks for this file
282-
* @param keysCompleted Keys completed for this file
283-
* @param totalKeys Total keys for this file
284-
*/
285-
async function logFileProgress(
286-
fileName: string,
287-
fileIndex: number,
288-
totalFiles: number,
289-
chunksCompleted: number,
290-
totalChunks: number,
291-
keysCompleted: number,
292-
totalKeys: number
293-
): Promise<void> {
294-
try {
295-
await invoke('log_file_progress', {
296-
fileName: fileName,
297-
fileIndex: fileIndex,
298-
totalFiles: totalFiles,
299-
chunksCompleted: chunksCompleted,
300-
totalChunks: totalChunks,
301-
keysCompleted: keysCompleted,
302-
totalKeys: totalKeys
303-
});
304-
} catch (error) {
305-
await ErrorLogger.logError('logFileProgress', error, 'TRANSLATION_PROGRESS');
124+
// Increment mod-level progress if applicable
125+
if (incrementCompletedMods) incrementCompletedMods();
126+
127+
// Increment whole progress
128+
if (incrementWholeProgress) incrementWholeProgress();
306129
}
307-
}
308-
309-
/**
310-
* Get total number of keys in a translation job
311-
* @param job Translation job
312-
* @returns Total number of keys
313-
*/
314-
function getTotalKeysInJob(job: TranslationJob): number {
315-
return job.chunks.reduce((sum, chunk) => sum + Object.keys(chunk.content).length, 0);
316-
}
317130

318-
/**
319-
* Log performance metrics for debugging
320-
* @param operation Operation name
321-
* @param durationMs Duration in milliseconds
322-
* @param memoryUsageMb Optional memory usage in MB
323-
* @param additionalInfo Optional additional information
324-
*/
325-
async function logPerformanceMetrics(
326-
operation: string,
327-
durationMs: number,
328-
memoryUsageMb?: number,
329-
additionalInfo?: string
330-
): Promise<void> {
331-
try {
332-
await invoke('log_performance_metrics', {
333-
operation,
334-
durationMs: durationMs,
335-
memoryUsageMb: memoryUsageMb,
336-
additionalInfo: additionalInfo
337-
});
338-
} catch (error) {
339-
await ErrorLogger.logError('logPerformanceMetrics', error, 'PERFORMANCE');
340-
}
341-
}
131+
if (setCurrentJobId) setCurrentJobId(null);
132+
}

0 commit comments

Comments
 (0)