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
modules/statuses.py ADDED
@@ -0,0 +1,207 @@
1
+ """Centralized status vocabulary for Supervertaler segments."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Dict, Optional
5
+ import re
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class StatusDefinition:
10
+ key: str
11
+ label: str
12
+ icon: str
13
+ color: str
14
+ memoq_label: str
15
+ memoQ_equivalents: tuple[str, ...]
16
+ match_symbol: str = ""
17
+
18
+
19
+ STATUSES: Dict[str, StatusDefinition] = {
20
+ "not_started": StatusDefinition(
21
+ key="not_started",
22
+ label="Not started",
23
+ icon="❌", # Red X - clear "not done" indicator (matches memoQ style)
24
+ color="#ffe6e6",
25
+ memoq_label="Not started",
26
+ memoQ_equivalents=("not started", "not translated"),
27
+ ),
28
+ "pretranslated": StatusDefinition(
29
+ key="pretranslated",
30
+ label="Pre-translated",
31
+ icon="🤖", # Robot - indicates automatic/machine pre-translation
32
+ color="#e8f2ff",
33
+ memoq_label="Pre-translated",
34
+ memoQ_equivalents=("pre-translated", "pretranslated"),
35
+ match_symbol="⚡",
36
+ ),
37
+ "translated": StatusDefinition(
38
+ key="translated",
39
+ label="Translated",
40
+ icon="✏️", # Pencil - indicates manual translation work (matches Trados style)
41
+ color="#e6ffe6",
42
+ memoq_label="Translated",
43
+ memoQ_equivalents=("translated",),
44
+ match_symbol="✍️",
45
+ ),
46
+ "confirmed": StatusDefinition(
47
+ key="confirmed",
48
+ label="Confirmed",
49
+ icon="✔", # Checkmark - will be styled green via CSS
50
+ color="#d1ffd6",
51
+ memoq_label="Confirmed",
52
+ memoQ_equivalents=("confirmed",),
53
+ match_symbol="🛡️",
54
+ ),
55
+ "tr_confirmed": StatusDefinition(
56
+ key="tr_confirmed",
57
+ label="TR confirmed",
58
+ icon="🌟",
59
+ color="#d9f0ff",
60
+ memoq_label="TR confirmed",
61
+ memoQ_equivalents=("tr confirmed", "translation review confirmed"),
62
+ match_symbol="🌐",
63
+ ),
64
+ "proofread": StatusDefinition(
65
+ key="proofread",
66
+ label="Proofread",
67
+ icon="🟪",
68
+ color="#efe0ff",
69
+ memoq_label="Proofread",
70
+ memoQ_equivalents=("proofread",),
71
+ match_symbol="📘",
72
+ ),
73
+ "rejected": StatusDefinition(
74
+ key="rejected",
75
+ label="Rejected",
76
+ icon="🚫",
77
+ color="#ffe0e0",
78
+ memoq_label="Rejected",
79
+ memoQ_equivalents=("rejected",),
80
+ match_symbol="⛔",
81
+ ),
82
+ "approved": StatusDefinition(
83
+ key="approved",
84
+ label="Approved",
85
+ icon="⭐",
86
+ color="#e6f3ff",
87
+ memoq_label="Approved",
88
+ memoQ_equivalents=("approved", "final", "proofread confirmed"),
89
+ match_symbol="🏁",
90
+ ),
91
+ "pm": StatusDefinition(
92
+ key="pm",
93
+ label="PM (102%)",
94
+ icon="⭐", # Star - perfect/double context match
95
+ color="#b8daff", # Light blue - highest confidence
96
+ memoq_label="Pre-translated (102%)",
97
+ memoQ_equivalents=("pre-translated (102%)", "102%", "xlt", "double context", "perfect match", "pm"),
98
+ match_symbol="⭐",
99
+ ),
100
+ "cm": StatusDefinition(
101
+ key="cm",
102
+ label="CM (101%)",
103
+ icon="💎", # Diamond - context match
104
+ color="#c3e6cb", # Darker green - very high confidence
105
+ memoq_label="Pre-translated (101%)",
106
+ memoQ_equivalents=("pre-translated (101%)", "context match", "cm", "101%"),
107
+ match_symbol="💎",
108
+ ),
109
+ "tm_100": StatusDefinition(
110
+ key="tm_100",
111
+ label="TM 100%",
112
+ icon="✅", # Checkmark - exact match
113
+ color="#d4edda", # Light green - high confidence
114
+ memoq_label="Pre-translated (100%)",
115
+ memoQ_equivalents=("pre-translated (100%)", "100%", "exact match"),
116
+ match_symbol="✅",
117
+ ),
118
+ "tm_fuzzy": StatusDefinition(
119
+ key="tm_fuzzy",
120
+ label="TM Fuzzy",
121
+ icon="🔶", # Orange diamond - partial match
122
+ color="#fff3cd", # Light yellow/orange - needs review
123
+ memoq_label="Pre-translated (fuzzy)",
124
+ memoQ_equivalents=("fuzzy", "fuzzy match"),
125
+ match_symbol="🔶",
126
+ ),
127
+ "repetition": StatusDefinition(
128
+ key="repetition",
129
+ label="Repetition",
130
+ icon="🔁", # Repeat icon - internal repetition
131
+ color="#e2e3e5", # Light gray - auto-propagated
132
+ memoq_label="Repetition",
133
+ memoQ_equivalents=("repetition", "rep", "auto-propagated"),
134
+ match_symbol="🔁",
135
+ ),
136
+ "machine_translated": StatusDefinition(
137
+ key="machine_translated",
138
+ label="MT",
139
+ icon="🤖", # Robot - machine translation
140
+ color="#ffeaa7", # Light orange/yellow - needs review
141
+ memoq_label="Machine Translated",
142
+ memoQ_equivalents=("machine translated", "mt", "nmt", "auto-translated"),
143
+ match_symbol="🤖",
144
+ ),
145
+ }
146
+
147
+ DEFAULT_STATUS = STATUSES["not_started"]
148
+
149
+
150
+ def get_status(key: str) -> StatusDefinition:
151
+ """Return status definition for key, falling back to default."""
152
+ return STATUSES.get(key, DEFAULT_STATUS)
153
+
154
+
155
+ def match_memoq_status(status_text: str) -> tuple[StatusDefinition, Optional[int]]:
156
+ """Map memoQ status string to a StatusDefinition plus optional match percent."""
157
+ status_clean = (status_text or "").strip()
158
+ percent: Optional[int] = None
159
+
160
+ if status_clean:
161
+ match = re.search(r"(\d+)\s*%", status_clean)
162
+ if match:
163
+ try:
164
+ percent = int(match.group(1))
165
+ except ValueError:
166
+ percent = None
167
+
168
+ lower = status_clean.lower()
169
+
170
+ for definition in STATUSES.values():
171
+ if any(eq in lower for eq in definition.memoQ_equivalents):
172
+ return definition, percent
173
+
174
+ if "proofread" in lower and "confirm" in lower:
175
+ return STATUSES["approved"], percent
176
+ if "confirm" in lower and "tr" in lower:
177
+ return STATUSES["tr_confirmed"], percent
178
+ if "confirm" in lower:
179
+ return STATUSES["confirmed"], percent
180
+ if "lock" in lower:
181
+ return STATUSES["not_started"], percent
182
+ if "reject" in lower:
183
+ return STATUSES["rejected"], percent
184
+ if "proof" in lower:
185
+ return STATUSES["proofread"], percent
186
+ if "translate" in lower:
187
+ return STATUSES["translated"], percent
188
+
189
+ return DEFAULT_STATUS, percent
190
+
191
+
192
+ def compose_memoq_status(
193
+ status_key: str,
194
+ match_percent: Optional[int] = None,
195
+ existing: Optional[str] = None,
196
+ ) -> str:
197
+ """Compose a memoQ status string, preserving existing text when provided."""
198
+ if existing and existing.strip():
199
+ return existing.strip()
200
+
201
+ status_def = get_status(status_key)
202
+ base = status_def.memoq_label
203
+ if match_percent is not None:
204
+ return f"{base} ({match_percent}%)"
205
+ return base
206
+
207
+
@@ -0,0 +1,315 @@
1
+ """
2
+ Style Guide Manager Module
3
+
4
+ Manages translation style guides for different languages.
5
+ Supports style guides as Markdown files with optional YAML frontmatter.
6
+
7
+ Extracted for modularity and reusability.
8
+ Supports both individual language-specific guides and optional user additions.
9
+ """
10
+
11
+ import os
12
+ import json
13
+ import shutil
14
+ import re
15
+ from datetime import datetime
16
+ from typing import Dict, List, Optional, Tuple
17
+
18
+
19
+ class StyleGuideLibrary:
20
+ """
21
+ Manages translation style guides for multiple languages.
22
+ Loads style guide files from appropriate folder based on dev mode.
23
+ """
24
+
25
+ # Supported languages for style guides
26
+ SUPPORTED_LANGUAGES = [
27
+ "Dutch",
28
+ "English",
29
+ "Spanish",
30
+ "German",
31
+ "French"
32
+ ]
33
+
34
+ def __init__(self, style_guides_dir=None, log_callback=None):
35
+ """
36
+ Initialize the Style Guide Library.
37
+
38
+ Args:
39
+ style_guides_dir: Path to style guides directory (if None, must be set later)
40
+ log_callback: Function to call for logging messages
41
+ """
42
+ self.style_guides_dir = style_guides_dir
43
+ self.log = log_callback if log_callback else print
44
+
45
+ # Create directory if it doesn't exist and path is provided
46
+ if self.style_guides_dir:
47
+ os.makedirs(self.style_guides_dir, exist_ok=True)
48
+
49
+ # Available style guides: {language: guide_data}
50
+ self.guides = {}
51
+ self.active_guide = None # Currently selected guide
52
+ self.active_guide_language = None
53
+
54
+ def set_directory(self, style_guides_dir):
55
+ """Set the directory after initialization"""
56
+ self.style_guides_dir = style_guides_dir
57
+ os.makedirs(self.style_guides_dir, exist_ok=True)
58
+
59
+ def load_all_guides(self):
60
+ """Load all style guides from the style guides directory"""
61
+ self.guides = {}
62
+
63
+ if not self.style_guides_dir or not os.path.exists(self.style_guides_dir):
64
+ self.log("⚠ Style guides directory not found")
65
+ return 0
66
+
67
+ count = self._load_from_directory(self.style_guides_dir)
68
+ self.log(f"✓ Loaded {count} style guides")
69
+ return count
70
+
71
+ def _load_from_directory(self, directory):
72
+ """Load style guides from directory
73
+
74
+ Expected file naming: <Language>.md or <Language>.txt
75
+ Examples: Dutch.md, English.md, Spanish.txt, etc.
76
+
77
+ Args:
78
+ directory: Path to directory
79
+ """
80
+ count = 0
81
+
82
+ if not directory or not os.path.exists(directory):
83
+ return count
84
+
85
+ for filename in os.listdir(directory):
86
+ filepath = os.path.join(directory, filename)
87
+
88
+ # Skip directories
89
+ if os.path.isdir(filepath):
90
+ continue
91
+
92
+ # Check if file matches supported language format
93
+ if filename.endswith('.md') or filename.endswith('.txt'):
94
+ language = filename.rsplit('.', 1)[0] # Remove extension
95
+
96
+ # Load content
97
+ try:
98
+ with open(filepath, 'r', encoding='utf-8') as f:
99
+ content = f.read()
100
+
101
+ guide_data = {
102
+ 'language': language,
103
+ 'content': content,
104
+ '_filename': filename,
105
+ '_filepath': filepath,
106
+ '_created': datetime.fromtimestamp(os.path.getctime(filepath)).isoformat(),
107
+ '_modified': datetime.fromtimestamp(os.path.getmtime(filepath)).isoformat(),
108
+ }
109
+
110
+ self.guides[language] = guide_data
111
+ count += 1
112
+
113
+ except Exception as e:
114
+ self.log(f"⚠ Failed to load {filename}: {e}")
115
+
116
+ return count
117
+
118
+ def get_guide(self, language: str) -> Optional[Dict]:
119
+ """
120
+ Get a specific style guide by language.
121
+
122
+ Args:
123
+ language: Language name (e.g., 'Dutch', 'English')
124
+
125
+ Returns:
126
+ Dictionary with guide data or None if not found
127
+ """
128
+ return self.guides.get(language)
129
+
130
+ def get_all_languages(self) -> List[str]:
131
+ """Get list of all available style guide languages"""
132
+ return sorted(self.guides.keys())
133
+
134
+ def get_guide_content(self, language: str) -> Optional[str]:
135
+ """Get the content of a specific style guide"""
136
+ guide = self.guides.get(language)
137
+ return guide['content'] if guide else None
138
+
139
+ def update_guide(self, language: str, new_content: str) -> bool:
140
+ """
141
+ Update a style guide with new content.
142
+
143
+ Args:
144
+ language: Language name
145
+ new_content: New content for the guide
146
+
147
+ Returns:
148
+ True if successful, False otherwise
149
+ """
150
+ guide = self.guides.get(language)
151
+ if not guide:
152
+ self.log(f"⚠ Style guide not found: {language}")
153
+ return False
154
+
155
+ try:
156
+ filepath = guide['_filepath']
157
+
158
+ # Write to file
159
+ with open(filepath, 'w', encoding='utf-8') as f:
160
+ f.write(new_content)
161
+
162
+ # Update in memory
163
+ guide['content'] = new_content
164
+ guide['_modified'] = datetime.now().isoformat()
165
+
166
+ self.log(f"✓ Updated style guide: {language}")
167
+ return True
168
+
169
+ except Exception as e:
170
+ self.log(f"⚠ Failed to update {language}: {e}")
171
+ return False
172
+
173
+ def append_to_guide(self, language: str, additional_content: str) -> bool:
174
+ """
175
+ Append content to an existing style guide.
176
+
177
+ Args:
178
+ language: Language name
179
+ additional_content: Content to append
180
+
181
+ Returns:
182
+ True if successful, False otherwise
183
+ """
184
+ guide = self.guides.get(language)
185
+ if not guide:
186
+ self.log(f"⚠ Style guide not found: {language}")
187
+ return False
188
+
189
+ current_content = guide['content']
190
+ new_content = current_content.rstrip() + '\n\n' + additional_content.strip()
191
+
192
+ return self.update_guide(language, new_content)
193
+
194
+ def append_to_all_guides(self, additional_content: str) -> Tuple[int, int]:
195
+ """
196
+ Append content to all style guides.
197
+
198
+ Args:
199
+ additional_content: Content to append to all guides
200
+
201
+ Returns:
202
+ Tuple of (successful_count, failed_count)
203
+ """
204
+ successful = 0
205
+ failed = 0
206
+
207
+ for language in self.guides.keys():
208
+ if self.append_to_guide(language, additional_content):
209
+ successful += 1
210
+ else:
211
+ failed += 1
212
+
213
+ self.log(f"✓ Updated {successful} guides. Failed: {failed}")
214
+ return successful, failed
215
+
216
+ def create_guide(self, language: str, content: str = "") -> bool:
217
+ """
218
+ Create a new style guide file.
219
+
220
+ Args:
221
+ language: Language name
222
+ content: Initial content (optional)
223
+
224
+ Returns:
225
+ True if successful, False otherwise
226
+ """
227
+ if not self.style_guides_dir:
228
+ self.log("⚠ Style guides directory not set")
229
+ return False
230
+
231
+ if language in self.guides:
232
+ self.log(f"⚠ Style guide already exists: {language}")
233
+ return False
234
+
235
+ try:
236
+ filepath = os.path.join(self.style_guides_dir, f"{language}.md")
237
+
238
+ # Create file
239
+ with open(filepath, 'w', encoding='utf-8') as f:
240
+ f.write(content)
241
+
242
+ # Add to guides dictionary
243
+ guide_data = {
244
+ 'language': language,
245
+ 'content': content,
246
+ '_filename': f"{language}.md",
247
+ '_filepath': filepath,
248
+ '_created': datetime.now().isoformat(),
249
+ '_modified': datetime.now().isoformat(),
250
+ }
251
+
252
+ self.guides[language] = guide_data
253
+ self.log(f"✓ Created style guide: {language}")
254
+ return True
255
+
256
+ except Exception as e:
257
+ self.log(f"⚠ Failed to create {language}: {e}")
258
+ return False
259
+
260
+ def export_guide(self, language: str, export_path: str) -> bool:
261
+ """
262
+ Export a style guide to a file.
263
+
264
+ Args:
265
+ language: Language name
266
+ export_path: Path where to save the exported guide
267
+
268
+ Returns:
269
+ True if successful, False otherwise
270
+ """
271
+ guide = self.guides.get(language)
272
+ if not guide:
273
+ self.log(f"⚠ Style guide not found: {language}")
274
+ return False
275
+
276
+ try:
277
+ with open(export_path, 'w', encoding='utf-8') as f:
278
+ f.write(guide['content'])
279
+
280
+ self.log(f"✓ Exported style guide: {language}")
281
+ return True
282
+
283
+ except Exception as e:
284
+ self.log(f"⚠ Failed to export {language}: {e}")
285
+ return False
286
+
287
+ def import_guide(self, language: str, import_path: str, append: bool = False) -> bool:
288
+ """
289
+ Import a style guide from a file.
290
+
291
+ Args:
292
+ language: Language name to import as
293
+ import_path: Path to the file to import
294
+ append: If True, append to existing guide; if False, replace
295
+
296
+ Returns:
297
+ True if successful, False otherwise
298
+ """
299
+ try:
300
+ with open(import_path, 'r', encoding='utf-8') as f:
301
+ content = f.read()
302
+
303
+ if language not in self.guides:
304
+ # Create new guide
305
+ return self.create_guide(language, content)
306
+ elif append:
307
+ # Append to existing guide
308
+ return self.append_to_guide(language, content)
309
+ else:
310
+ # Replace existing guide
311
+ return self.update_guide(language, content)
312
+
313
+ except Exception as e:
314
+ self.log(f"⚠ Failed to import from {import_path}: {e}")
315
+ return False