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,499 @@
1
+ """
2
+ Theme Manager
3
+ =============
4
+ Manages UI themes and color schemes for Supervertaler Qt.
5
+ Allows users to customize the appearance of the entire application.
6
+
7
+ Features:
8
+ - Predefined themes (Light, Dark, Sepia, High Contrast)
9
+ - Custom theme creation and editing
10
+ - Save/load user themes
11
+ - Apply themes to all UI elements
12
+ """
13
+
14
+ from PyQt6.QtGui import QColor, QPalette
15
+ from PyQt6.QtWidgets import QApplication
16
+ from dataclasses import dataclass, asdict
17
+ import json
18
+ from pathlib import Path
19
+ from typing import Dict, Optional
20
+
21
+
22
+ @dataclass
23
+ class Theme:
24
+ """Theme definition with all UI colors"""
25
+ name: str
26
+
27
+ # Main window colors
28
+ window_bg: str = "#F5F5F5" # Main background
29
+ alternate_bg: str = "#EBEBEB" # Alternate row color
30
+
31
+ # Text colors
32
+ text: str = "#212121" # Primary text
33
+ text_disabled: str = "#9E9E9E" # Disabled text
34
+ text_placeholder: str = "#BDBDBD" # Placeholder text
35
+
36
+ # Control colors
37
+ base: str = "#FFFFFF" # Input fields, text areas
38
+ button: str = "#E0E0E0" # Button background
39
+ button_hover: str = "#D5D5D5" # Button hover
40
+
41
+ # Highlight colors
42
+ highlight: str = "#2196F3" # Selection highlight
43
+ highlight_text: str = "#FFFFFF" # Selected text
44
+
45
+ # Border and separator colors
46
+ border: str = "#CCCCCC" # Borders
47
+ separator: str = "#E0E0E0" # Separators
48
+
49
+ # Status colors
50
+ success: str = "#4CAF50" # Green for success
51
+ warning: str = "#FF9800" # Orange for warnings
52
+ error: str = "#F44336" # Red for errors
53
+ info: str = "#2196F3" # Blue for info
54
+
55
+ # Grid colors
56
+ grid_header: str = "#E8E8E8" # Table headers
57
+ grid_line: str = "#E0E0E0" # Grid lines
58
+
59
+ # Tab colors
60
+ tab_bg: str = "#F5F5F5" # Tab background
61
+ tab_selected: str = "#FFFFFF" # Selected tab
62
+
63
+ # TM match colors (for colored match percentages)
64
+ tm_exact: str = "#C8E6C9" # 100% match (light green)
65
+ tm_high: str = "#FFF9C4" # 95-99% (light yellow)
66
+ tm_medium: str = "#FFE0B2" # 85-94% (light orange)
67
+ tm_low: str = "#F5F5F5" # <85% (default)
68
+
69
+ # Action button colors (for buttons that need specific semantic colors)
70
+ button_success: str = "#4CAF50" # Green for success actions (save, apply, etc.)
71
+ button_info: str = "#2196F3" # Blue for info actions
72
+ button_warning: str = "#FF9800" # Orange for warning actions
73
+ button_danger: str = "#F44336" # Red for danger actions (delete, etc.)
74
+ button_neutral: str = "#607D8B" # Blue-gray for neutral actions
75
+ button_purple: str = "#9C27B0" # Purple for special actions
76
+
77
+ # Panel/info box backgrounds
78
+ panel_info: str = "#F0F7FF" # Light blue info panels
79
+ panel_warning: str = "#FFF3CD" # Light yellow warning panels
80
+ panel_neutral: str = "#F3F4F6" # Gray neutral panels
81
+ panel_preview: str = "#F9F9F9" # Preview areas
82
+ panel_accent: str = "#FFF3E0" # Accent panels
83
+
84
+ # TM results display colors
85
+ tm_source_label: str = "#1976D2" # Blue for source language label
86
+ tm_target_label: str = "#388E3C" # Green for target language label
87
+ tm_highlight_bg: str = "#FFFF00" # Yellow background for search term highlight
88
+ tm_highlight_text: str = "#000000" # Black text for highlighted terms
89
+
90
+ def to_dict(self) -> Dict:
91
+ """Convert theme to dictionary"""
92
+ return asdict(self)
93
+
94
+ @classmethod
95
+ def from_dict(cls, data: Dict) -> 'Theme':
96
+ """Create theme from dictionary"""
97
+ return cls(**data)
98
+
99
+
100
+ class ThemeManager:
101
+ """Manages application themes"""
102
+
103
+ # Predefined themes
104
+ PREDEFINED_THEMES = {
105
+ "Light (Default)": Theme(
106
+ name="Light (Default)",
107
+ window_bg="#F5F5F5",
108
+ alternate_bg="#EBEBEB",
109
+ text="#212121",
110
+ base="#FFFFFF",
111
+ button="#E0E0E0",
112
+ highlight="#e3f2fd",
113
+ highlight_text="#000000",
114
+ ),
115
+
116
+ "Soft Gray": Theme(
117
+ name="Soft Gray",
118
+ window_bg="#E8E8E8",
119
+ alternate_bg="#DEDEDE",
120
+ text="#1A1A1A",
121
+ base="#F8F8F8",
122
+ button="#D5D5D5",
123
+ highlight="#1976D2",
124
+ ),
125
+
126
+ "Warm Cream": Theme(
127
+ name="Warm Cream",
128
+ window_bg="#F5F0E8",
129
+ alternate_bg="#EBE6DE",
130
+ text="#3E2723",
131
+ base="#FFFEF8",
132
+ button="#E8DED0",
133
+ highlight="#6D4C41",
134
+ grid_header="#EBE6DE",
135
+ ),
136
+
137
+ "Dark": Theme(
138
+ name="Dark",
139
+ window_bg="#2B2B2B",
140
+ alternate_bg="#353535",
141
+ text="#E0E0E0",
142
+ text_disabled="#757575",
143
+ text_placeholder="#616161",
144
+ base="#1E1E1E",
145
+ button="#404040",
146
+ button_hover="#4A4A4A",
147
+ highlight="#0D47A1",
148
+ highlight_text="#FFFFFF",
149
+ border="#505050",
150
+ separator="#404040",
151
+ grid_header="#353535",
152
+ grid_line="#404040",
153
+ tab_bg="#2B2B2B",
154
+ tab_selected="#1E1E1E",
155
+ # TM match colors (darker versions for dark mode)
156
+ tm_exact="#2E5C35", # Dark green
157
+ tm_high="#5C5424", # Dark yellow
158
+ tm_medium="#5C4224", # Dark orange
159
+ tm_low="#2B2B2B", # Match window background
160
+ # Action button colors (keep vibrant for visibility in dark mode)
161
+ button_success="#388E3C", # Darker green
162
+ button_info="#1976D2", # Darker blue
163
+ button_warning="#F57C00", # Darker orange
164
+ button_danger="#D32F2F", # Darker red
165
+ button_neutral="#455A64", # Darker blue-gray
166
+ button_purple="#7B1FA2", # Darker purple
167
+ # Panel/info box backgrounds (dark versions)
168
+ panel_info="#1A2F3A", # Dark blue
169
+ panel_warning="#3A3020", # Dark yellow
170
+ panel_neutral="#323232", # Dark gray
171
+ panel_preview="#252525", # Dark preview
172
+ panel_accent="#3A2F1A", # Dark accent
173
+ # TM results display colors (brighter for visibility in dark mode)
174
+ tm_source_label="#64B5F6", # Brighter blue for source language label
175
+ tm_target_label="#81C784", # Brighter green for target language label
176
+ tm_highlight_bg="#FFD54F", # Softer yellow for dark mode
177
+ tm_highlight_text="#000000", # Black text for highlighted terms
178
+ ),
179
+
180
+ "Sepia": Theme(
181
+ name="Sepia",
182
+ window_bg="#F4ECD8",
183
+ alternate_bg="#E8E0CE",
184
+ text="#3E2723",
185
+ base="#FFFEF5",
186
+ button="#E0D8C8",
187
+ highlight="#8D6E63",
188
+ grid_header="#E8E0CE",
189
+ ),
190
+
191
+ "High Contrast": Theme(
192
+ name="High Contrast",
193
+ window_bg="#FFFFFF",
194
+ alternate_bg="#F0F0F0",
195
+ text="#000000",
196
+ base="#FFFFFF",
197
+ button="#E0E0E0",
198
+ highlight="#0000FF",
199
+ highlight_text="#FFFFFF",
200
+ border="#000000",
201
+ ),
202
+ }
203
+
204
+ def __init__(self, user_data_path: Path):
205
+ """
206
+ Initialize theme manager
207
+
208
+ Args:
209
+ user_data_path: Path to user_data folder for saving custom themes
210
+ """
211
+ self.user_data_path = user_data_path
212
+ self.themes_file = user_data_path / "themes.json"
213
+ self.current_theme: Theme = self.PREDEFINED_THEMES["Light (Default)"]
214
+ self.custom_themes: Dict[str, Theme] = {}
215
+
216
+ # Load custom themes
217
+ self.load_custom_themes()
218
+
219
+ def get_all_themes(self) -> Dict[str, Theme]:
220
+ """Get all available themes (predefined + custom)"""
221
+ all_themes = self.PREDEFINED_THEMES.copy()
222
+ all_themes.update(self.custom_themes)
223
+ return all_themes
224
+
225
+ def get_theme(self, name: str) -> Optional[Theme]:
226
+ """Get theme by name"""
227
+ all_themes = self.get_all_themes()
228
+ return all_themes.get(name)
229
+
230
+ def set_theme(self, name: str) -> bool:
231
+ """
232
+ Set current theme
233
+
234
+ Args:
235
+ name: Theme name
236
+
237
+ Returns:
238
+ True if theme was found and applied
239
+ """
240
+ theme = self.get_theme(name)
241
+ if theme:
242
+ self.current_theme = theme
243
+ return True
244
+ return False
245
+
246
+ def save_custom_theme(self, theme: Theme):
247
+ """Save a custom theme"""
248
+ self.custom_themes[theme.name] = theme
249
+ self._save_themes()
250
+
251
+ def delete_custom_theme(self, name: str) -> bool:
252
+ """Delete a custom theme"""
253
+ if name in self.custom_themes:
254
+ del self.custom_themes[name]
255
+ self._save_themes()
256
+ return True
257
+ return False
258
+
259
+ def load_custom_themes(self):
260
+ """Load custom themes from file"""
261
+ if self.themes_file.exists():
262
+ try:
263
+ with open(self.themes_file, 'r', encoding='utf-8') as f:
264
+ data = json.load(f)
265
+ for theme_data in data.get('themes', []):
266
+ theme = Theme.from_dict(theme_data)
267
+ self.custom_themes[theme.name] = theme
268
+
269
+ # Load last used theme
270
+ current_theme_name = data.get('current_theme')
271
+ if current_theme_name:
272
+ self.set_theme(current_theme_name)
273
+ except Exception as e:
274
+ print(f"Error loading themes: {e}")
275
+
276
+ def _save_themes(self):
277
+ """Save custom themes to file"""
278
+ try:
279
+ data = {
280
+ 'current_theme': self.current_theme.name,
281
+ 'themes': [theme.to_dict() for theme in self.custom_themes.values()]
282
+ }
283
+
284
+ with open(self.themes_file, 'w', encoding='utf-8') as f:
285
+ json.dump(data, f, indent=2)
286
+ except Exception as e:
287
+ print(f"Error saving themes: {e}")
288
+
289
+ def apply_theme(self, app: QApplication):
290
+ """
291
+ Apply current theme to application
292
+
293
+ Args:
294
+ app: QApplication instance
295
+ """
296
+ theme = self.current_theme
297
+
298
+ # Create and apply stylesheet - COLORS ONLY, preserves native sizes/spacing
299
+ stylesheet = f"""
300
+ /* Main window background */
301
+ QMainWindow, QWidget {{
302
+ background-color: {theme.window_bg};
303
+ color: {theme.text};
304
+ }}
305
+
306
+ /* Input fields and text areas */
307
+ QLineEdit, QTextEdit, QPlainTextEdit, QSpinBox, QDoubleSpinBox {{
308
+ background-color: {theme.base};
309
+ color: {theme.text};
310
+ border: 1px solid {theme.border};
311
+ }}
312
+
313
+ QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus {{
314
+ border: 1px solid {theme.highlight};
315
+ }}
316
+
317
+ /* Buttons */
318
+ QPushButton {{
319
+ background-color: {theme.button};
320
+ color: {theme.text};
321
+ border: 1px solid {theme.border};
322
+ }}
323
+
324
+ QPushButton:hover {{
325
+ background-color: {theme.button_hover};
326
+ }}
327
+
328
+ QPushButton:pressed {{
329
+ background-color: {theme.highlight};
330
+ color: {theme.highlight_text};
331
+ }}
332
+
333
+ QPushButton:disabled {{
334
+ color: {theme.text_disabled};
335
+ }}
336
+
337
+ /* Combo boxes */
338
+ QComboBox {{
339
+ background-color: {theme.base};
340
+ color: {theme.text};
341
+ border: 1px solid {theme.border};
342
+ }}
343
+
344
+ QComboBox:hover {{
345
+ border: 1px solid {theme.highlight};
346
+ }}
347
+
348
+ /* Tables */
349
+ QTableWidget {{
350
+ background-color: {theme.base};
351
+ alternate-background-color: {theme.alternate_bg};
352
+ color: {theme.text};
353
+ gridline-color: {theme.grid_line};
354
+ border: 1px solid {theme.border};
355
+ }}
356
+
357
+ QTableWidget::item:selected {{
358
+ background-color: {theme.highlight};
359
+ color: {theme.highlight_text};
360
+ }}
361
+
362
+ QHeaderView::section {{
363
+ background-color: {theme.grid_header};
364
+ color: {theme.text};
365
+ border: 1px solid {theme.border};
366
+ }}
367
+
368
+ /* Tabs */
369
+ QTabWidget::pane {{
370
+ border: 1px solid {theme.border};
371
+ background-color: {theme.base};
372
+ }}
373
+
374
+ QTabBar::tab {{
375
+ background-color: {theme.tab_bg};
376
+ color: {theme.text};
377
+ border: 1px solid {theme.border};
378
+ padding: 6px 12px;
379
+ }}
380
+
381
+ QTabBar::tab:selected {{
382
+ background-color: {theme.tab_selected};
383
+ border-bottom: 1px solid {theme.highlight};
384
+ }}
385
+
386
+ QTabBar::tab:hover {{
387
+ background-color: {theme.button_hover};
388
+ }}
389
+
390
+ /* Splitter */
391
+ QSplitter::handle {{
392
+ background-color: {theme.separator};
393
+ }}
394
+
395
+ /* Scrollbars */
396
+ QScrollBar:vertical {{
397
+ background-color: {theme.window_bg};
398
+ }}
399
+
400
+ QScrollBar::handle:vertical {{
401
+ background-color: {theme.button};
402
+ }}
403
+
404
+ QScrollBar::handle:vertical:hover {{
405
+ background-color: {theme.button_hover};
406
+ }}
407
+
408
+ QScrollBar:horizontal {{
409
+ background-color: {theme.window_bg};
410
+ }}
411
+
412
+ QScrollBar::handle:horizontal {{
413
+ background-color: {theme.button};
414
+ }}
415
+
416
+ QScrollBar::handle:horizontal:hover {{
417
+ background-color: {theme.button_hover};
418
+ }}
419
+
420
+ /* Checkboxes and Radio buttons */
421
+ QCheckBox, QRadioButton {{
422
+ color: {theme.text};
423
+ }}
424
+
425
+ QCheckBox::indicator, QRadioButton::indicator {{
426
+ border: 1px solid {theme.border};
427
+ background-color: {theme.base};
428
+ }}
429
+
430
+ QCheckBox::indicator:checked {{
431
+ background-color: {theme.highlight};
432
+ }}
433
+
434
+ /* Menu bar */
435
+ QMenuBar {{
436
+ background-color: {theme.window_bg};
437
+ color: {theme.text};
438
+ }}
439
+
440
+ QMenuBar::item:selected {{
441
+ background-color: {theme.highlight};
442
+ color: {theme.highlight_text};
443
+ }}
444
+
445
+ QMenu {{
446
+ background-color: {theme.base};
447
+ color: {theme.text};
448
+ border: 1px solid {theme.border};
449
+ }}
450
+
451
+ QMenu::item:selected {{
452
+ background-color: {theme.highlight};
453
+ color: {theme.highlight_text};
454
+ }}
455
+
456
+ /* Status bar */
457
+ QStatusBar {{
458
+ background-color: {theme.window_bg};
459
+ color: {theme.text};
460
+ }}
461
+
462
+ /* Group boxes - minimal styling to avoid title rendering issues */
463
+ QGroupBox {{
464
+ color: {theme.text};
465
+ border: 1px solid {theme.border};
466
+ padding: 18px 10px 10px 10px;
467
+ margin-top: 12px;
468
+ }}
469
+
470
+ QGroupBox::title {{
471
+ color: {theme.text};
472
+ subcontrol-origin: margin;
473
+ subcontrol-position: top left;
474
+ padding: 2px 5px;
475
+ background-color: {theme.window_bg};
476
+ }}
477
+
478
+ /* Dialogs */
479
+ QDialog {{
480
+ background-color: {theme.window_bg};
481
+ color: {theme.text};
482
+ }}
483
+
484
+ /* Labels */
485
+ QLabel {{
486
+ color: {theme.text};
487
+ padding: 3px 2px;
488
+ }}
489
+
490
+ /* Form layouts need extra spacing */
491
+ QFormLayout {{
492
+ vertical-spacing: 8px;
493
+ }}
494
+ """
495
+
496
+ app.setStyleSheet(stylesheet)
497
+
498
+ # Save current theme
499
+ self._save_themes()
@@ -0,0 +1,99 @@
1
+ """
2
+ TM Editor Dialog - Edit a specific Translation Memory
3
+
4
+ This dialog provides comprehensive editing for a single TM:
5
+ - Browse entries
6
+ - Concordance search
7
+ - Statistics
8
+ - Import/Export (scoped to this TM)
9
+ - Maintenance
10
+
11
+ Similar to TMManagerDialog but scoped to a specific tm_id.
12
+ """
13
+
14
+ from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QLabel, QTabWidget, QWidget, QPushButton)
15
+ from PyQt6.QtCore import Qt
16
+
17
+ # Import the existing TM Manager tabs
18
+ from modules.tm_manager_qt import TMManagerDialog
19
+
20
+
21
+ class TMEditorDialog(QDialog):
22
+ """TM Editor for a specific translation memory"""
23
+
24
+ def __init__(self, parent, db_manager, log_callback, tm_id: str, tm_name: str):
25
+ """
26
+ Initialize TM Editor
27
+
28
+ Args:
29
+ parent: Parent widget
30
+ db_manager: DatabaseManager instance
31
+ log_callback: Logging function
32
+ tm_id: The tm_id to edit
33
+ tm_name: Display name of the TM
34
+ """
35
+ super().__init__(parent)
36
+ self.db_manager = db_manager
37
+ self.log = log_callback
38
+ self.tm_id = tm_id
39
+ self.tm_name = tm_name
40
+
41
+ self.setWindowTitle(f"TM Editor - {tm_name}")
42
+ self.setMinimumSize(1000, 700)
43
+
44
+ self.init_ui()
45
+
46
+ def init_ui(self):
47
+ """Initialize UI - tabs for editing a specific TM"""
48
+ layout = QVBoxLayout(self)
49
+
50
+ # Header showing which TM is being edited
51
+ header = QLabel(f"๐Ÿ“ Editing: {self.tm_name}")
52
+ header.setStyleSheet("""
53
+ font-size: 16px;
54
+ font-weight: bold;
55
+ padding: 10px;
56
+ background-color: #e3f2fd;
57
+ border-radius: 4px;
58
+ margin-bottom: 10px;
59
+ """)
60
+ layout.addWidget(header)
61
+
62
+ # Info about TM
63
+ from modules.tm_metadata_manager import TMMetadataManager
64
+ tm_metadata_mgr = TMMetadataManager(self.db_manager, self.log)
65
+ tm_info = tm_metadata_mgr.get_tm_by_tm_id(self.tm_id)
66
+
67
+ if tm_info:
68
+ info_text = f"TM ID: {self.tm_id} | Languages: {tm_info['source_lang'] or '?'} โ†’ {tm_info['target_lang'] or '?'} | Entries: {tm_info['entry_count']}"
69
+ info_label = QLabel(info_text)
70
+ info_label.setStyleSheet("color: #666; font-size: 11px; padding: 5px; margin-bottom: 10px;")
71
+ layout.addWidget(info_label)
72
+
73
+ # Create nested TM Manager for this specific TM
74
+ tm_manager = TMManagerDialog(self, self.db_manager, self.log, tm_ids=[self.tm_id])
75
+
76
+ # Create tab widget with only relevant tabs for editing a specific TM
77
+ tabs = QTabWidget()
78
+
79
+ # Tab 1: Browse (this TM only)
80
+ tabs.addTab(tm_manager.browser_tab, "๐Ÿ“– Browse Entries")
81
+
82
+ # Tab 2: Import/Export (this TM only)
83
+ tabs.addTab(tm_manager.import_export_tab, "๐Ÿ“ฅ Import/Export")
84
+
85
+ # Tab 3: Statistics (this TM only)
86
+ tabs.addTab(tm_manager.stats_tab, "๐Ÿ“Š Statistics")
87
+
88
+ # Tab 4: Maintenance (this TM only)
89
+ tabs.addTab(tm_manager.maintenance_tab, "๐Ÿงน Maintenance")
90
+
91
+ # Store reference to prevent garbage collection
92
+ self._tm_manager = tm_manager
93
+
94
+ layout.addWidget(tabs)
95
+
96
+ # Close button
97
+ close_btn = QPushButton("Close")
98
+ close_btn.clicked.connect(self.accept)
99
+ layout.addWidget(close_btn)