supervertaler 1.9.153__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.

Potentially problematic release.


This version of supervertaler might be problematic. Click here for more details.

Files changed (85) hide show
  1. Supervertaler.py +47886 -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 +1878 -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 +333 -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 +1172 -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.153.dist-info/METADATA +896 -0
  81. supervertaler-1.9.153.dist-info/RECORD +85 -0
  82. supervertaler-1.9.153.dist-info/WHEEL +5 -0
  83. supervertaler-1.9.153.dist-info/entry_points.txt +2 -0
  84. supervertaler-1.9.153.dist-info/licenses/LICENSE +21 -0
  85. supervertaler-1.9.153.dist-info/top_level.txt +2 -0
@@ -0,0 +1,417 @@
1
+ """
2
+ Database Migration Functions
3
+
4
+ Handles schema updates and data migrations for the Supervertaler database.
5
+ """
6
+
7
+ import sqlite3
8
+ from typing import Optional
9
+
10
+
11
+ def migrate_termbase_fields(db_manager) -> bool:
12
+ """
13
+ Migrate termbase_terms table to add new fields:
14
+ - project (TEXT)
15
+ - client (TEXT)
16
+ - term_uuid (TEXT UNIQUE) - for tracking terms across import/export
17
+
18
+ Note: 'notes' field already exists in schema, 'definition' is legacy (no longer used)
19
+
20
+ Args:
21
+ db_manager: DatabaseManager instance
22
+
23
+ Returns:
24
+ True if migration successful
25
+ """
26
+ try:
27
+ cursor = db_manager.cursor
28
+
29
+ # Check which columns exist
30
+ cursor.execute("PRAGMA table_info(termbase_terms)")
31
+ columns = {row[1] for row in cursor.fetchall()}
32
+
33
+ migrations_needed = []
34
+
35
+ # Add 'project' column if it doesn't exist
36
+ if 'project' not in columns:
37
+ migrations_needed.append(("project", "ALTER TABLE termbase_terms ADD COLUMN project TEXT"))
38
+
39
+ # Add 'client' column if it doesn't exist
40
+ if 'client' not in columns:
41
+ migrations_needed.append(("client", "ALTER TABLE termbase_terms ADD COLUMN client TEXT"))
42
+
43
+ # Add 'term_uuid' column if it doesn't exist
44
+ # Note: SQLite doesn't allow adding UNIQUE constraint via ALTER TABLE,
45
+ # so we add column first, then create unique index separately
46
+ if 'term_uuid' not in columns:
47
+ migrations_needed.append(("term_uuid", "ALTER TABLE termbase_terms ADD COLUMN term_uuid TEXT"))
48
+
49
+ # Add 'note' column if it doesn't exist (legacy, kept for compatibility)
50
+ if 'note' not in columns:
51
+ migrations_needed.append(("note", "ALTER TABLE termbase_terms ADD COLUMN note TEXT"))
52
+
53
+ # Add 'notes' column if it doesn't exist (used by termbase entry editor)
54
+ if 'notes' not in columns:
55
+ migrations_needed.append(("notes", "ALTER TABLE termbase_terms ADD COLUMN notes TEXT"))
56
+
57
+ # Execute migrations
58
+ for column_name, sql in migrations_needed:
59
+ print(f"📊 Adding column '{column_name}' to termbase_terms...")
60
+ cursor.execute(sql)
61
+ print(f" ✓ Column '{column_name}' added successfully")
62
+
63
+ # Create UNIQUE index for term_uuid if column was added
64
+ if 'term_uuid' in [name for name, _ in migrations_needed]:
65
+ print("📊 Creating UNIQUE index for term_uuid...")
66
+ cursor.execute("""
67
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_termbase_term_uuid
68
+ ON termbase_terms(term_uuid)
69
+ """)
70
+ print(" ✓ UNIQUE index created successfully")
71
+
72
+ db_manager.connection.commit()
73
+
74
+ if migrations_needed:
75
+ print(f"✅ Database migration completed: {len(migrations_needed)} column(s) added")
76
+ else:
77
+ print("✅ Database schema is up to date")
78
+
79
+ return True
80
+
81
+ except Exception as e:
82
+ print(f"❌ Database migration failed: {e}")
83
+ import traceback
84
+ traceback.print_exc()
85
+ return False
86
+
87
+
88
+ def create_synonyms_table(db_manager) -> bool:
89
+ """
90
+ Create termbase_synonyms table for storing term synonyms.
91
+
92
+ Schema:
93
+ - id: Primary key
94
+ - term_id: Foreign key to termbase_terms
95
+ - synonym_text: The synonym text
96
+ - language: 'source' or 'target'
97
+ - created_date: Timestamp
98
+
99
+ Args:
100
+ db_manager: DatabaseManager instance
101
+
102
+ Returns:
103
+ True if successful
104
+ """
105
+ try:
106
+ cursor = db_manager.cursor
107
+
108
+ # Check if table already exists
109
+ cursor.execute("""
110
+ SELECT name FROM sqlite_master
111
+ WHERE type='table' AND name='termbase_synonyms'
112
+ """)
113
+
114
+ if cursor.fetchone():
115
+ print("✅ termbase_synonyms table already exists")
116
+ return True
117
+
118
+ print("📊 Creating termbase_synonyms table...")
119
+
120
+ cursor.execute("""
121
+ CREATE TABLE termbase_synonyms (
122
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
123
+ term_id INTEGER NOT NULL,
124
+ synonym_text TEXT NOT NULL,
125
+ language TEXT NOT NULL CHECK(language IN ('source', 'target')),
126
+ display_order INTEGER DEFAULT 0,
127
+ forbidden INTEGER DEFAULT 0,
128
+ created_date TEXT DEFAULT (datetime('now')),
129
+ modified_date TEXT DEFAULT (datetime('now')),
130
+ FOREIGN KEY (term_id) REFERENCES termbase_terms(id) ON DELETE CASCADE
131
+ )
132
+ """)
133
+
134
+ # Create indexes for fast lookups
135
+ cursor.execute("""
136
+ CREATE INDEX IF NOT EXISTS idx_synonyms_term_id
137
+ ON termbase_synonyms(term_id)
138
+ """)
139
+
140
+ cursor.execute("""
141
+ CREATE INDEX IF NOT EXISTS idx_synonyms_text
142
+ ON termbase_synonyms(synonym_text)
143
+ """)
144
+
145
+ cursor.execute("""
146
+ CREATE INDEX IF NOT EXISTS idx_synonyms_language
147
+ ON termbase_synonyms(language)
148
+ """)
149
+
150
+ db_manager.connection.commit()
151
+ print("✅ termbase_synonyms table created successfully")
152
+
153
+ return True
154
+
155
+ except Exception as e:
156
+ print(f"❌ Failed to create termbase_synonyms table: {e}")
157
+ import traceback
158
+ traceback.print_exc()
159
+ return False
160
+
161
+
162
+ def run_all_migrations(db_manager) -> bool:
163
+ """
164
+ Run all pending database migrations.
165
+
166
+ Args:
167
+ db_manager: DatabaseManager instance
168
+
169
+ Returns:
170
+ True if all migrations successful
171
+ """
172
+ print("\n" + "="*60)
173
+ print("DATABASE MIGRATIONS")
174
+ print("="*60)
175
+
176
+ success = True
177
+
178
+ # Migration 1: Add new termbase fields
179
+ if not migrate_termbase_fields(db_manager):
180
+ success = False
181
+
182
+ # Migration 2: Create synonyms table
183
+ if not create_synonyms_table(db_manager):
184
+ success = False
185
+
186
+ # Migration 3: Add display_order and forbidden fields to synonyms
187
+ if not migrate_synonym_fields(db_manager):
188
+ success = False
189
+
190
+ print("="*60)
191
+
192
+ return success
193
+
194
+
195
+ def check_and_migrate(db_manager) -> bool:
196
+ """
197
+ Check if migrations are needed and run them if so.
198
+ This is safe to call on every app startup.
199
+
200
+ Args:
201
+ db_manager: DatabaseManager instance
202
+
203
+ Returns:
204
+ True if migrations successful or not needed
205
+ """
206
+ try:
207
+ print("🔍 Checking database schema for migrations...")
208
+ cursor = db_manager.cursor
209
+
210
+ # Quick check: do we need migrations?
211
+ cursor.execute("PRAGMA table_info(termbase_terms)")
212
+ columns = {row[1] for row in cursor.fetchall()}
213
+ print(f"🔍 Found termbase_terms columns: {sorted(columns)}")
214
+
215
+ needs_migration = (
216
+ 'project' not in columns or
217
+ 'client' not in columns or
218
+ 'term_uuid' not in columns or
219
+ 'note' not in columns
220
+ )
221
+
222
+ # Check if synonyms table exists
223
+ cursor.execute("""
224
+ SELECT name FROM sqlite_master
225
+ WHERE type='table' AND name='termbase_synonyms'
226
+ """)
227
+ needs_synonyms_table = cursor.fetchone() is None
228
+
229
+ if needs_migration:
230
+ print(f"âš ī¸ Migration needed - missing columns: {', '.join([c for c in ['project', 'client', 'term_uuid', 'note'] if c not in columns])}")
231
+
232
+ if needs_synonyms_table:
233
+ print("âš ī¸ Migration needed - termbase_synonyms table missing")
234
+
235
+ if needs_migration or needs_synonyms_table:
236
+ success = run_all_migrations(db_manager)
237
+ if success:
238
+ # Generate UUIDs for terms that don't have them
239
+ generate_missing_uuids(db_manager)
240
+ return success
241
+
242
+ # Even if no schema migration needed, check for missing UUIDs
243
+ print("✅ Database schema is current - checking UUIDs...")
244
+ generate_missing_uuids(db_manager)
245
+
246
+ # Fix project termbase flags if needed
247
+ fix_project_termbase_flags(db_manager)
248
+
249
+ return True
250
+
251
+ except Exception as e:
252
+ print(f"❌ Migration check failed: {e}")
253
+ import traceback
254
+ traceback.print_exc()
255
+ return False
256
+
257
+
258
+ def migrate_synonym_fields(db_manager) -> bool:
259
+ """
260
+ Migrate termbase_synonyms table to add new fields:
261
+ - display_order (INTEGER) - position in synonym list (0 = main term)
262
+ - forbidden (INTEGER) - whether this synonym is forbidden (0/1)
263
+
264
+ Args:
265
+ db_manager: DatabaseManager instance
266
+
267
+ Returns:
268
+ True if migration successful
269
+ """
270
+ try:
271
+ cursor = db_manager.cursor
272
+
273
+ # Check if table exists
274
+ cursor.execute("""
275
+ SELECT name FROM sqlite_master
276
+ WHERE type='table' AND name='termbase_synonyms'
277
+ """)
278
+
279
+ if not cursor.fetchone():
280
+ print("â„šī¸ termbase_synonyms table doesn't exist yet - will be created with new schema")
281
+ return True
282
+
283
+ # Check which columns exist
284
+ cursor.execute("PRAGMA table_info(termbase_synonyms)")
285
+ columns = {row[1] for row in cursor.fetchall()}
286
+
287
+ migrations_needed = []
288
+
289
+ # Add 'display_order' column if it doesn't exist
290
+ if 'display_order' not in columns:
291
+ migrations_needed.append(("display_order", "ALTER TABLE termbase_synonyms ADD COLUMN display_order INTEGER DEFAULT 0"))
292
+
293
+ # Add 'forbidden' column if it doesn't exist
294
+ if 'forbidden' not in columns:
295
+ migrations_needed.append(("forbidden", "ALTER TABLE termbase_synonyms ADD COLUMN forbidden INTEGER DEFAULT 0"))
296
+
297
+ # Execute migrations
298
+ for column_name, sql in migrations_needed:
299
+ print(f"📊 Adding column '{column_name}' to termbase_synonyms...")
300
+ cursor.execute(sql)
301
+ print(f" ✓ Column '{column_name}' added successfully")
302
+
303
+ db_manager.connection.commit()
304
+
305
+ if migrations_needed:
306
+ print(f"✅ Synonym table migration completed: {len(migrations_needed)} column(s) added")
307
+ else:
308
+ print("✅ Synonym table schema is up to date")
309
+
310
+ return True
311
+
312
+ except Exception as e:
313
+ print(f"❌ Synonym table migration failed: {e}")
314
+ import traceback
315
+ traceback.print_exc()
316
+ return False
317
+
318
+
319
+ def generate_missing_uuids(db_manager) -> bool:
320
+ """
321
+ Generate UUIDs for any termbase terms that don't have them.
322
+ This ensures all existing terms get UUIDs after the term_uuid column is added.
323
+
324
+ Args:
325
+ db_manager: DatabaseManager instance
326
+
327
+ Returns:
328
+ True if successful
329
+ """
330
+ try:
331
+ import uuid
332
+ cursor = db_manager.cursor
333
+
334
+ # Find terms without UUIDs
335
+ cursor.execute("""
336
+ SELECT id FROM termbase_terms
337
+ WHERE term_uuid IS NULL OR term_uuid = ''
338
+ """)
339
+ terms_without_uuid = cursor.fetchall()
340
+
341
+ if not terms_without_uuid:
342
+ return True # Nothing to do
343
+
344
+ print(f"📊 Generating UUIDs for {len(terms_without_uuid)} existing terms...")
345
+
346
+ # Generate and assign UUIDs
347
+ for (term_id,) in terms_without_uuid:
348
+ term_uuid = str(uuid.uuid4())
349
+ cursor.execute("""
350
+ UPDATE termbase_terms
351
+ SET term_uuid = ?
352
+ WHERE id = ?
353
+ """, (term_uuid, term_id))
354
+
355
+ db_manager.connection.commit()
356
+ print(f" ✓ Generated {len(terms_without_uuid)} UUIDs successfully")
357
+
358
+ return True
359
+
360
+ except Exception as e:
361
+ print(f"❌ UUID generation failed: {e}")
362
+ import traceback
363
+ traceback.print_exc()
364
+ return False
365
+
366
+
367
+ def fix_project_termbase_flags(db_manager) -> int:
368
+ """
369
+ Fix is_project_termbase flags for termbases that have project_id but is_project_termbase=0.
370
+ This is a data repair function that should be called manually or in migrations.
371
+
372
+ Args:
373
+ db_manager: DatabaseManager instance
374
+
375
+ Returns:
376
+ Number of termbases fixed
377
+ """
378
+ try:
379
+ cursor = db_manager.cursor
380
+
381
+ # Find termbases with project_id but is_project_termbase=0
382
+ cursor.execute("""
383
+ SELECT id, name, project_id
384
+ FROM termbases
385
+ WHERE project_id IS NOT NULL
386
+ AND (is_project_termbase IS NULL OR is_project_termbase = 0)
387
+ """)
388
+ termbases_to_fix = cursor.fetchall()
389
+
390
+ if not termbases_to_fix:
391
+ print("✅ All project termbases are correctly flagged")
392
+ return 0
393
+
394
+ print(f"📊 Found {len(termbases_to_fix)} termbase(s) that need is_project_termbase flag fix:")
395
+ for tb_id, tb_name, project_id in termbases_to_fix:
396
+ print(f" - ID {tb_id}: '{tb_name}' (project_id={project_id})")
397
+
398
+ # Fix the flags
399
+ cursor.execute("""
400
+ UPDATE termbases
401
+ SET is_project_termbase = 1
402
+ WHERE project_id IS NOT NULL
403
+ AND (is_project_termbase IS NULL OR is_project_termbase = 0)
404
+ """)
405
+
406
+ updated_count = cursor.rowcount
407
+ db_manager.connection.commit()
408
+
409
+ print(f"✅ Fixed is_project_termbase flag for {updated_count} termbase(s)")
410
+
411
+ return updated_count
412
+
413
+ except Exception as e:
414
+ print(f"❌ Failed to fix project termbase flags: {e}")
415
+ import traceback
416
+ traceback.print_exc()
417
+ return 0