supervertaler 1.9.163__py3-none-any.whl

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.
Files changed (85) hide show
  1. Supervertaler.py +48473 -0
  2. modules/__init__.py +10 -0
  3. modules/ai_actions.py +964 -0
  4. modules/ai_attachment_manager.py +343 -0
  5. modules/ai_file_viewer_dialog.py +210 -0
  6. modules/autofingers_engine.py +466 -0
  7. modules/cafetran_docx_handler.py +379 -0
  8. modules/config_manager.py +469 -0
  9. modules/database_manager.py +1911 -0
  10. modules/database_migrations.py +417 -0
  11. modules/dejavurtf_handler.py +779 -0
  12. modules/document_analyzer.py +427 -0
  13. modules/docx_handler.py +689 -0
  14. modules/encoding_repair.py +319 -0
  15. modules/encoding_repair_Qt.py +393 -0
  16. modules/encoding_repair_ui.py +481 -0
  17. modules/feature_manager.py +350 -0
  18. modules/figure_context_manager.py +340 -0
  19. modules/file_dialog_helper.py +148 -0
  20. modules/find_replace.py +164 -0
  21. modules/find_replace_qt.py +457 -0
  22. modules/glossary_manager.py +433 -0
  23. modules/image_extractor.py +188 -0
  24. modules/keyboard_shortcuts_widget.py +571 -0
  25. modules/llm_clients.py +1211 -0
  26. modules/llm_leaderboard.py +737 -0
  27. modules/llm_superbench_ui.py +1401 -0
  28. modules/local_llm_setup.py +1104 -0
  29. modules/model_update_dialog.py +381 -0
  30. modules/model_version_checker.py +373 -0
  31. modules/mqxliff_handler.py +638 -0
  32. modules/non_translatables_manager.py +743 -0
  33. modules/pdf_rescue_Qt.py +1822 -0
  34. modules/pdf_rescue_tkinter.py +909 -0
  35. modules/phrase_docx_handler.py +516 -0
  36. modules/project_home_panel.py +209 -0
  37. modules/prompt_assistant.py +357 -0
  38. modules/prompt_library.py +689 -0
  39. modules/prompt_library_migration.py +447 -0
  40. modules/quick_access_sidebar.py +282 -0
  41. modules/ribbon_widget.py +597 -0
  42. modules/sdlppx_handler.py +874 -0
  43. modules/setup_wizard.py +353 -0
  44. modules/shortcut_manager.py +932 -0
  45. modules/simple_segmenter.py +128 -0
  46. modules/spellcheck_manager.py +727 -0
  47. modules/statuses.py +207 -0
  48. modules/style_guide_manager.py +315 -0
  49. modules/superbench_ui.py +1319 -0
  50. modules/superbrowser.py +329 -0
  51. modules/supercleaner.py +600 -0
  52. modules/supercleaner_ui.py +444 -0
  53. modules/superdocs.py +19 -0
  54. modules/superdocs_viewer_qt.py +382 -0
  55. modules/superlookup.py +252 -0
  56. modules/tag_cleaner.py +260 -0
  57. modules/tag_manager.py +351 -0
  58. modules/term_extractor.py +270 -0
  59. modules/termbase_entry_editor.py +842 -0
  60. modules/termbase_import_export.py +488 -0
  61. modules/termbase_manager.py +1060 -0
  62. modules/termview_widget.py +1176 -0
  63. modules/theme_manager.py +499 -0
  64. modules/tm_editor_dialog.py +99 -0
  65. modules/tm_manager_qt.py +1280 -0
  66. modules/tm_metadata_manager.py +545 -0
  67. modules/tmx_editor.py +1461 -0
  68. modules/tmx_editor_qt.py +2784 -0
  69. modules/tmx_generator.py +284 -0
  70. modules/tracked_changes.py +900 -0
  71. modules/trados_docx_handler.py +430 -0
  72. modules/translation_memory.py +715 -0
  73. modules/translation_results_panel.py +2134 -0
  74. modules/translation_services.py +282 -0
  75. modules/unified_prompt_library.py +659 -0
  76. modules/unified_prompt_manager_qt.py +3951 -0
  77. modules/voice_commands.py +920 -0
  78. modules/voice_dictation.py +477 -0
  79. modules/voice_dictation_lite.py +249 -0
  80. supervertaler-1.9.163.dist-info/METADATA +906 -0
  81. supervertaler-1.9.163.dist-info/RECORD +85 -0
  82. supervertaler-1.9.163.dist-info/WHEEL +5 -0
  83. supervertaler-1.9.163.dist-info/entry_points.txt +2 -0
  84. supervertaler-1.9.163.dist-info/licenses/LICENSE +21 -0
  85. supervertaler-1.9.163.dist-info/top_level.txt +2 -0
@@ -0,0 +1,481 @@
1
+ """
2
+ Encoding Repair Tool UI - Menu-based interface for the encoding repair module
3
+
4
+ Provides a user-friendly GUI for detecting and fixing text encoding corruption.
5
+ """
6
+
7
+ import tkinter as tk
8
+ from tkinter import ttk, filedialog, messagebox, scrolledtext
9
+ from pathlib import Path
10
+ import threading
11
+ from modules.encoding_repair import EncodingRepair
12
+
13
+
14
+ class EncodingRepairWindow:
15
+ """GUI window for encoding repair operations."""
16
+
17
+ def __init__(self, parent, theme_colors=None):
18
+ """
19
+ Initialize the encoding repair window.
20
+
21
+ Args:
22
+ parent: Parent tkinter widget
23
+ theme_colors: Optional dict with color scheme
24
+ """
25
+ self.parent = parent
26
+ self.colors = theme_colors or {
27
+ 'bg': '#f0f0f0',
28
+ 'fg': '#333333',
29
+ 'accent': '#0066cc',
30
+ 'success': '#4CAF50',
31
+ 'error': '#f44336',
32
+ 'warning': '#ff9800',
33
+ }
34
+
35
+ self.window = tk.Toplevel(parent)
36
+ self.window.title("Text Encoding Repair Tool")
37
+ self.window.geometry("700x600")
38
+ self.window.resizable(True, True)
39
+
40
+ self._create_ui()
41
+
42
+ def _create_ui(self):
43
+ """Create the user interface."""
44
+ # Main frame
45
+ main_frame = ttk.Frame(self.window)
46
+ main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
47
+
48
+ # Title
49
+ title_label = ttk.Label(
50
+ main_frame,
51
+ text="Text Encoding Corruption Repair",
52
+ font=("Arial", 14, "bold")
53
+ )
54
+ title_label.pack(pady=(0, 10))
55
+
56
+ # Description
57
+ desc = ttk.Label(
58
+ main_frame,
59
+ text="Detects and fixes text encoding issues (mojibake) caused by UTF-8\n"
60
+ "being incorrectly decoded as Latin-1 or Windows-1252.",
61
+ font=("Arial", 9),
62
+ justify=tk.LEFT,
63
+ )
64
+ desc.pack(pady=(0, 15), fill=tk.X)
65
+
66
+ # File selection frame
67
+ file_frame = ttk.LabelFrame(main_frame, text="File Selection", padding=10)
68
+ file_frame.pack(fill=tk.X, pady=(0, 10))
69
+
70
+ button_frame = ttk.Frame(file_frame)
71
+ button_frame.pack(fill=tk.X)
72
+
73
+ self.file_path_var = tk.StringVar()
74
+ ttk.Button(
75
+ button_frame,
76
+ text="📂 Select File",
77
+ command=self._select_file
78
+ ).pack(side=tk.LEFT, padx=(0, 10))
79
+
80
+ ttk.Button(
81
+ button_frame,
82
+ text="📁 Select Folder",
83
+ command=self._select_folder
84
+ ).pack(side=tk.LEFT, padx=(0, 10))
85
+
86
+ # File path display
87
+ self.path_label = ttk.Label(
88
+ file_frame,
89
+ text="No file selected",
90
+ font=("Arial", 9),
91
+ foreground="#666666"
92
+ )
93
+ self.path_label.pack(pady=(10, 0), fill=tk.X)
94
+
95
+ # Action buttons frame
96
+ action_frame = ttk.LabelFrame(main_frame, text="Actions", padding=10)
97
+ action_frame.pack(fill=tk.X, pady=(0, 10))
98
+
99
+ button_row1 = ttk.Frame(action_frame)
100
+ button_row1.pack(fill=tk.X, pady=(0, 10))
101
+
102
+ ttk.Button(
103
+ button_row1,
104
+ text="🔍 Scan File",
105
+ command=self._scan_file,
106
+ width=20
107
+ ).pack(side=tk.LEFT, padx=(0, 10))
108
+
109
+ ttk.Button(
110
+ button_row1,
111
+ text="🔧 Repair File",
112
+ command=self._repair_file,
113
+ width=20
114
+ ).pack(side=tk.LEFT, padx=(0, 10))
115
+
116
+ button_row2 = ttk.Frame(action_frame)
117
+ button_row2.pack(fill=tk.X)
118
+
119
+ ttk.Button(
120
+ button_row2,
121
+ text="📂 Scan Folder",
122
+ command=self._scan_folder,
123
+ width=20
124
+ ).pack(side=tk.LEFT, padx=(0, 10))
125
+
126
+ ttk.Button(
127
+ button_row2,
128
+ text="🔧 Repair Folder",
129
+ command=self._repair_folder,
130
+ width=20
131
+ ).pack(side=tk.LEFT, padx=(0, 10))
132
+
133
+ # Results frame
134
+ results_frame = ttk.LabelFrame(main_frame, text="Results", padding=10)
135
+ results_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
136
+
137
+ self.results_text = scrolledtext.ScrolledText(
138
+ results_frame,
139
+ height=12,
140
+ font=("Courier New", 9),
141
+ bg="white",
142
+ fg="#333333",
143
+ )
144
+ self.results_text.pack(fill=tk.BOTH, expand=True)
145
+
146
+ # Add tags for colorization
147
+ self.results_text.tag_config("success", foreground="#4CAF50", font=("Courier New", 9, "bold"))
148
+ self.results_text.tag_config("error", foreground="#f44336", font=("Courier New", 9, "bold"))
149
+ self.results_text.tag_config("warning", foreground="#ff9800", font=("Courier New", 9, "bold"))
150
+ self.results_text.tag_config("info", foreground="#0066cc")
151
+
152
+ # Status bar
153
+ self.status_var = tk.StringVar(value="Ready")
154
+ status_bar = ttk.Label(
155
+ main_frame,
156
+ textvariable=self.status_var,
157
+ font=("Arial", 8),
158
+ foreground="#666666"
159
+ )
160
+ status_bar.pack(fill=tk.X)
161
+
162
+ def _select_file(self):
163
+ """Open file selection dialog."""
164
+ file_path = filedialog.askopenfilename(
165
+ title="Select a text file",
166
+ filetypes=[
167
+ ("Text files", "*.txt"),
168
+ ("CSV files", "*.csv"),
169
+ ("TSV files", "*.tsv"),
170
+ ("Markdown files", "*.md"),
171
+ ("All files", "*.*"),
172
+ ]
173
+ )
174
+
175
+ if file_path:
176
+ self.file_path_var.set(file_path)
177
+ self.path_label.config(text=f"📄 {Path(file_path).name}")
178
+ self._update_status(f"Selected: {Path(file_path).name}")
179
+
180
+ def _select_folder(self):
181
+ """Open folder selection dialog."""
182
+ folder_path = filedialog.askdirectory(title="Select a folder")
183
+
184
+ if folder_path:
185
+ self.file_path_var.set(folder_path)
186
+ self.path_label.config(text=f"📁 {Path(folder_path).name}")
187
+ self._update_status(f"Selected: {Path(folder_path).name}")
188
+
189
+ def _scan_file(self):
190
+ """Scan a single file for encoding issues."""
191
+ file_path = self.file_path_var.get()
192
+
193
+ if not file_path:
194
+ messagebox.showwarning("No file selected", "Please select a file first.")
195
+ return
196
+
197
+ self._clear_results()
198
+ self._update_status("Scanning file...")
199
+
200
+ def scan():
201
+ try:
202
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
203
+ content = f.read()
204
+
205
+ has_corruption, count, patterns = EncodingRepair.detect_corruption(content)
206
+
207
+ # Display results
208
+ self.results_text.insert(tk.END, f"File: {Path(file_path).name}\n", "info")
209
+ self.results_text.insert(tk.END, f"Path: {file_path}\n", "info")
210
+ self.results_text.insert(tk.END, f"Size: {len(content):,} characters\n\n", "info")
211
+
212
+ if has_corruption:
213
+ self.results_text.insert(
214
+ tk.END,
215
+ f"⚠️ ENCODING CORRUPTION DETECTED\n",
216
+ "warning"
217
+ )
218
+ self.results_text.insert(tk.END, f"Total corruptions: {count}\n\n", "warning")
219
+ self.results_text.insert(tk.END, "Patterns found:\n", "warning")
220
+
221
+ for i, pattern in enumerate(patterns, 1):
222
+ self.results_text.insert(tk.END, f" {i}. {pattern}\n")
223
+
224
+ self.results_text.insert(
225
+ tk.END,
226
+ "\n✅ You can repair this file using the 'Repair File' button.\n",
227
+ "success"
228
+ )
229
+ else:
230
+ self.results_text.insert(
231
+ tk.END,
232
+ "✅ NO ENCODING CORRUPTION DETECTED\n",
233
+ "success"
234
+ )
235
+ self.results_text.insert(
236
+ tk.END,
237
+ "This file appears to be properly encoded.\n",
238
+ "success"
239
+ )
240
+
241
+ self._update_status("Scan complete")
242
+
243
+ except Exception as e:
244
+ self.results_text.insert(tk.END, f"❌ Error: {str(e)}\n", "error")
245
+ self._update_status("Scan failed")
246
+
247
+ # Run in background thread
248
+ thread = threading.Thread(target=scan, daemon=True)
249
+ thread.start()
250
+
251
+ def _repair_file(self):
252
+ """Repair encoding issues in a single file."""
253
+ file_path = self.file_path_var.get()
254
+
255
+ if not file_path:
256
+ messagebox.showwarning("No file selected", "Please select a file first.")
257
+ return
258
+
259
+ if not Path(file_path).is_file():
260
+ messagebox.showerror("Invalid file", "The selected path is not a file.")
261
+ return
262
+
263
+ # Confirm before repair
264
+ if not messagebox.askyesno("Confirm Repair", f"Repair {Path(file_path).name}?\n\nA backup will be created."):
265
+ return
266
+
267
+ self._clear_results()
268
+ self._update_status("Repairing file...")
269
+
270
+ def repair():
271
+ try:
272
+ # Create backup
273
+ backup_path = f"{file_path}.backup"
274
+ Path(file_path).read_text(encoding='utf-8', errors='ignore')
275
+ with open(file_path, 'rb') as f_src:
276
+ with open(backup_path, 'wb') as f_dst:
277
+ f_dst.write(f_src.read())
278
+
279
+ # Repair
280
+ success, message, info = EncodingRepair.repair_with_encoding_fallback(file_path)
281
+
282
+ if success:
283
+ self.results_text.insert(tk.END, message + "\n\n", "success")
284
+ self.results_text.insert(tk.END, f"Backup created: {backup_path}\n", "info")
285
+ messagebox.showinfo("Success", f"File repaired successfully!\n\n{message}")
286
+ self._update_status("File repaired successfully")
287
+ else:
288
+ self.results_text.insert(tk.END, message + "\n", "error")
289
+ self._update_status("Repair failed")
290
+
291
+ except Exception as e:
292
+ error_msg = f"❌ Error during repair: {str(e)}\n"
293
+ self.results_text.insert(tk.END, error_msg, "error")
294
+ messagebox.showerror("Repair Failed", error_msg)
295
+ self._update_status("Repair failed")
296
+
297
+ # Run in background thread
298
+ thread = threading.Thread(target=repair, daemon=True)
299
+ thread.start()
300
+
301
+ def _scan_folder(self):
302
+ """Scan a folder for files with encoding issues."""
303
+ folder_path = self.file_path_var.get()
304
+
305
+ if not folder_path:
306
+ messagebox.showwarning("No folder selected", "Please select a folder first.")
307
+ return
308
+
309
+ if not Path(folder_path).is_dir():
310
+ messagebox.showerror("Invalid folder", "The selected path is not a folder.")
311
+ return
312
+
313
+ self._clear_results()
314
+ self._update_status("Scanning folder...")
315
+
316
+ def scan():
317
+ try:
318
+ results = EncodingRepair.scan_directory(folder_path)
319
+
320
+ self.results_text.insert(tk.END, f"Folder: {Path(folder_path).name}\n", "info")
321
+ self.results_text.insert(tk.END, f"Path: {folder_path}\n\n", "info")
322
+ self.results_text.insert(tk.END, f"Files scanned: {results['files_scanned']}\n", "info")
323
+
324
+ if results['files_with_corruption']:
325
+ self.results_text.insert(
326
+ tk.END,
327
+ f"⚠️ Files with corruption: {len(results['files_with_corruption'])}\n",
328
+ "warning"
329
+ )
330
+ self.results_text.insert(
331
+ tk.END,
332
+ f"Total corruptions found: {results['total_corruptions']}\n\n",
333
+ "warning"
334
+ )
335
+
336
+ for file_info in results['files_with_corruption']:
337
+ self.results_text.insert(
338
+ tk.END,
339
+ f"📄 {Path(file_info['file']).name}\n",
340
+ "warning"
341
+ )
342
+ self.results_text.insert(
343
+ tk.END,
344
+ f" Corruptions: {file_info['corruptions']}\n",
345
+ "info"
346
+ )
347
+ for pattern in file_info['patterns']:
348
+ self.results_text.insert(tk.END, f" • {pattern}\n", "info")
349
+ self.results_text.insert(tk.END, "\n")
350
+ else:
351
+ self.results_text.insert(
352
+ tk.END,
353
+ "✅ NO ENCODING CORRUPTION DETECTED\n",
354
+ "success"
355
+ )
356
+ self.results_text.insert(
357
+ tk.END,
358
+ "All files in this folder are properly encoded.\n",
359
+ "success"
360
+ )
361
+
362
+ self._update_status("Folder scan complete")
363
+
364
+ except Exception as e:
365
+ self.results_text.insert(tk.END, f"❌ Error: {str(e)}\n", "error")
366
+ self._update_status("Scan failed")
367
+
368
+ # Run in background thread
369
+ thread = threading.Thread(target=scan, daemon=True)
370
+ thread.start()
371
+
372
+ def _repair_folder(self):
373
+ """Repair encoding issues in all files in a folder."""
374
+ folder_path = self.file_path_var.get()
375
+
376
+ if not folder_path:
377
+ messagebox.showwarning("No folder selected", "Please select a folder first.")
378
+ return
379
+
380
+ if not Path(folder_path).is_dir():
381
+ messagebox.showerror("Invalid folder", "The selected path is not a folder.")
382
+ return
383
+
384
+ # First scan to show what will be repaired
385
+ results = EncodingRepair.scan_directory(folder_path)
386
+
387
+ if not results['files_with_corruption']:
388
+ messagebox.showinfo("No issues found", "No encoding corruption detected in this folder.")
389
+ return
390
+
391
+ files_to_repair = len(results['files_with_corruption'])
392
+ if not messagebox.askyesno(
393
+ "Confirm Repair",
394
+ f"Repair {files_to_repair} file(s) with encoding issues?\n\nBackups will be created."
395
+ ):
396
+ return
397
+
398
+ self._clear_results()
399
+ self._update_status("Repairing folder...")
400
+
401
+ def repair():
402
+ repaired_count = 0
403
+ failed_count = 0
404
+
405
+ self.results_text.insert(tk.END, f"Repairing {files_to_repair} file(s)...\n\n", "info")
406
+
407
+ for file_info in results['files_with_corruption']:
408
+ file_path = file_info['file']
409
+ try:
410
+ # Create backup
411
+ backup_path = f"{file_path}.backup"
412
+ with open(file_path, 'rb') as f_src:
413
+ with open(backup_path, 'wb') as f_dst:
414
+ f_dst.write(f_src.read())
415
+
416
+ # Repair
417
+ success, message, _ = EncodingRepair.repair_with_encoding_fallback(file_path)
418
+
419
+ if success:
420
+ self.results_text.insert(
421
+ tk.END,
422
+ f"✅ {Path(file_path).name}\n",
423
+ "success"
424
+ )
425
+ repaired_count += 1
426
+ else:
427
+ self.results_text.insert(
428
+ tk.END,
429
+ f"❌ {Path(file_path).name}: {message}\n",
430
+ "error"
431
+ )
432
+ failed_count += 1
433
+
434
+ except Exception as e:
435
+ self.results_text.insert(
436
+ tk.END,
437
+ f"❌ {Path(file_path).name}: {str(e)}\n",
438
+ "error"
439
+ )
440
+ failed_count += 1
441
+
442
+ # Summary
443
+ self.results_text.insert(tk.END, f"\n{'='*50}\n", "info")
444
+ self.results_text.insert(
445
+ tk.END,
446
+ f"Repair complete: {repaired_count} succeeded, {failed_count} failed\n",
447
+ "success" if failed_count == 0 else "warning"
448
+ )
449
+
450
+ self._update_status("Folder repair complete")
451
+ messagebox.showinfo(
452
+ "Repair Complete",
453
+ f"Repaired {repaired_count} file(s)\n"
454
+ f"Failed: {failed_count} file(s)"
455
+ )
456
+
457
+ # Run in background thread
458
+ thread = threading.Thread(target=repair, daemon=True)
459
+ thread.start()
460
+
461
+ def _clear_results(self):
462
+ """Clear the results text area."""
463
+ self.results_text.config(state=tk.NORMAL)
464
+ self.results_text.delete(1.0, tk.END)
465
+
466
+ def _update_status(self, message: str):
467
+ """Update the status bar."""
468
+ self.status_var.set(message)
469
+ self.window.update()
470
+
471
+
472
+ def open_encoding_repair_tool(parent, theme_colors=None):
473
+ """
474
+ Open the encoding repair tool window.
475
+
476
+ Args:
477
+ parent: Parent tkinter widget
478
+ theme_colors: Optional dict with color scheme
479
+ """
480
+ window = EncodingRepairWindow(parent, theme_colors)
481
+ return window