supervertaler 1.9.128__py3-none-any.whl → 1.9.130__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.
- Supervertaler.py +102 -33
- modules/shortcut_manager.py +8 -0
- modules/unified_prompt_manager_qt.py +12 -2
- {supervertaler-1.9.128.dist-info → supervertaler-1.9.130.dist-info}/METADATA +7 -3
- {supervertaler-1.9.128.dist-info → supervertaler-1.9.130.dist-info}/RECORD +9 -9
- {supervertaler-1.9.128.dist-info → supervertaler-1.9.130.dist-info}/WHEEL +0 -0
- {supervertaler-1.9.128.dist-info → supervertaler-1.9.130.dist-info}/entry_points.txt +0 -0
- {supervertaler-1.9.128.dist-info → supervertaler-1.9.130.dist-info}/licenses/LICENSE +0 -0
- {supervertaler-1.9.128.dist-info → supervertaler-1.9.130.dist-info}/top_level.txt +0 -0
Supervertaler.py
CHANGED
|
@@ -34,7 +34,7 @@ License: MIT
|
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
36
|
# Version Information.
|
|
37
|
-
__version__ = "1.9.
|
|
37
|
+
__version__ = "1.9.130"
|
|
38
38
|
__phase__ = "0.9"
|
|
39
39
|
__release_date__ = "2026-01-19"
|
|
40
40
|
__edition__ = "Qt"
|
|
@@ -123,7 +123,7 @@ try:
|
|
|
123
123
|
QButtonGroup, QDialogButtonBox, QTabWidget, QGroupBox, QGridLayout, QCheckBox,
|
|
124
124
|
QProgressBar, QProgressDialog, QFormLayout, QTabBar, QPlainTextEdit, QAbstractItemDelegate,
|
|
125
125
|
QFrame, QListWidget, QListWidgetItem, QStackedWidget, QTreeWidget, QTreeWidgetItem,
|
|
126
|
-
QScrollArea, QSizePolicy, QSlider, QToolButton
|
|
126
|
+
QScrollArea, QSizePolicy, QSlider, QToolButton, QAbstractItemView
|
|
127
127
|
)
|
|
128
128
|
from PyQt6.QtCore import Qt, QSize, QTimer, pyqtSignal, QObject, QUrl
|
|
129
129
|
from PyQt6.QtGui import QFont, QAction, QKeySequence, QIcon, QTextOption, QColor, QDesktopServices, QTextCharFormat, QTextCursor, QBrush, QSyntaxHighlighter, QPalette, QTextBlockFormat
|
|
@@ -170,11 +170,11 @@ def cleanup_ahk_process():
|
|
|
170
170
|
try:
|
|
171
171
|
_ahk_process.terminate()
|
|
172
172
|
_ahk_process.wait(timeout=1)
|
|
173
|
-
print("[
|
|
173
|
+
print("[Hotkeys] AHK process terminated on exit")
|
|
174
174
|
except:
|
|
175
175
|
try:
|
|
176
176
|
_ahk_process.kill()
|
|
177
|
-
print("[
|
|
177
|
+
print("[Hotkeys] AHK process killed on exit")
|
|
178
178
|
except:
|
|
179
179
|
pass
|
|
180
180
|
|
|
@@ -910,6 +910,7 @@ class _CtrlReturnEventFilter(QObject):
|
|
|
910
910
|
|
|
911
911
|
return False
|
|
912
912
|
|
|
913
|
+
|
|
913
914
|
class GridTableEventFilter:
|
|
914
915
|
"""Mixin to pass keyboard shortcuts from editor to table"""
|
|
915
916
|
pass
|
|
@@ -5592,6 +5593,11 @@ class SupervertalerQt(QMainWindow):
|
|
|
5592
5593
|
self.termview_shortcuts = []
|
|
5593
5594
|
self._termview_last_key = None # Track last key for double-tap detection
|
|
5594
5595
|
self._termview_last_time = 0 # Track timing for double-tap
|
|
5596
|
+
|
|
5597
|
+
# Double-tap Shift detection for context menu
|
|
5598
|
+
self._shift_last_press_time = 0
|
|
5599
|
+
self._shift_double_tap_threshold = 0.35 # 350ms window
|
|
5600
|
+
|
|
5595
5601
|
for i in range(0, 10): # 0-9
|
|
5596
5602
|
shortcut_id = f"termview_insert_{i}"
|
|
5597
5603
|
default_key = f"Alt+{i}"
|
|
@@ -5635,6 +5641,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
5635
5641
|
self._ctrl_return_event_filter = _CtrlReturnEventFilter(self)
|
|
5636
5642
|
QApplication.instance().installEventFilter(self._ctrl_return_event_filter)
|
|
5637
5643
|
|
|
5644
|
+
# Note: Double-tap Shift for context menu is handled by AutoHotkey (double_shift_menu.ahk)
|
|
5645
|
+
# Qt's event system makes reliable double-tap detection difficult in Python
|
|
5646
|
+
|
|
5638
5647
|
# Ctrl+Shift+Enter - Always confirm all selected segments
|
|
5639
5648
|
create_shortcut("editor_confirm_selected", "Ctrl+Shift+Return", self.confirm_selected_segments)
|
|
5640
5649
|
|
|
@@ -14029,7 +14038,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
14029
14038
|
prefs_layout.addLayout(quickmenu_context_layout)
|
|
14030
14039
|
|
|
14031
14040
|
quickmenu_context_info = QLabel(
|
|
14032
|
-
" ⓘ When using {{
|
|
14041
|
+
" ⓘ When using {{SOURCE+TARGET_CONTEXT}} or {{SOURCE_CONTEXT}} placeholders in QuickMenu prompts.\n"
|
|
14033
14042
|
" 0% = disabled, 50% = half the document (default), 100% = entire document.\n"
|
|
14034
14043
|
" Limit: maximum 100 segments for performance."
|
|
14035
14044
|
)
|
|
@@ -28298,6 +28307,20 @@ class SupervertalerQt(QMainWindow):
|
|
|
28298
28307
|
# Full processing for non-arrow-key navigation (click, etc.)
|
|
28299
28308
|
self._on_cell_selected_full(current_row, current_col, previous_row, previous_col)
|
|
28300
28309
|
|
|
28310
|
+
def _center_row_in_viewport(self, row: int):
|
|
28311
|
+
"""Center the given row vertically in the visible table viewport.
|
|
28312
|
+
|
|
28313
|
+
Uses Qt's built-in scrollTo() with PositionAtCenter hint.
|
|
28314
|
+
"""
|
|
28315
|
+
if row < 0 or row >= self.table.rowCount():
|
|
28316
|
+
return
|
|
28317
|
+
|
|
28318
|
+
# Get the model index for any cell in this row (use column 0)
|
|
28319
|
+
index = self.table.model().index(row, 0)
|
|
28320
|
+
if index.isValid():
|
|
28321
|
+
# Use Qt's built-in centering - PositionAtCenter puts the item in the center of the viewport
|
|
28322
|
+
self.table.scrollTo(index, QAbstractItemView.ScrollHint.PositionAtCenter)
|
|
28323
|
+
|
|
28301
28324
|
def _on_cell_selected_minimal(self, current_row, previous_row):
|
|
28302
28325
|
"""Minimal UI update for fast arrow key navigation - just highlight and scroll"""
|
|
28303
28326
|
try:
|
|
@@ -28319,7 +28342,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
28319
28342
|
|
|
28320
28343
|
# Auto-center if enabled
|
|
28321
28344
|
if getattr(self, 'auto_center_active_segment', False) and not getattr(self, 'filtering_active', False):
|
|
28322
|
-
self.
|
|
28345
|
+
self._center_row_in_viewport(current_row)
|
|
28323
28346
|
except Exception as e:
|
|
28324
28347
|
if self.debug_mode_enabled:
|
|
28325
28348
|
self.log(f"Error in minimal cell selection: {e}")
|
|
@@ -28364,7 +28387,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
28364
28387
|
current_id_item.setForeground(QColor("white"))
|
|
28365
28388
|
|
|
28366
28389
|
if getattr(self, 'auto_center_active_segment', False) and not getattr(self, 'filtering_active', False):
|
|
28367
|
-
self.
|
|
28390
|
+
self._center_row_in_viewport(current_row)
|
|
28368
28391
|
|
|
28369
28392
|
if not self.current_project or current_row < 0:
|
|
28370
28393
|
return
|
|
@@ -37720,7 +37743,9 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37720
37743
|
- {{SELECTION}} or {{SOURCE_TEXT}} - The selected text
|
|
37721
37744
|
- {{SOURCE_LANGUAGE}} - Source language name
|
|
37722
37745
|
- {{TARGET_LANGUAGE}} - Target language name
|
|
37723
|
-
- {{
|
|
37746
|
+
- {{SOURCE+TARGET_CONTEXT}} - Project segments with both source and target (for proofreading)
|
|
37747
|
+
- {{SOURCE_CONTEXT}} - Project segments with source only (for translation questions)
|
|
37748
|
+
- {{TARGET_CONTEXT}} - Project segments with target only (for consistency/style analysis)
|
|
37724
37749
|
"""
|
|
37725
37750
|
if not hasattr(self, 'prompt_manager_qt') or not self.prompt_manager_qt:
|
|
37726
37751
|
raise RuntimeError("Prompt manager not available")
|
|
@@ -37738,17 +37763,47 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37738
37763
|
if not prompt_content:
|
|
37739
37764
|
raise RuntimeError("Prompt content is empty")
|
|
37740
37765
|
|
|
37741
|
-
# Build document context if requested
|
|
37742
|
-
|
|
37743
|
-
|
|
37744
|
-
|
|
37766
|
+
# Build document context if requested (three variants)
|
|
37767
|
+
source_target_context = ""
|
|
37768
|
+
source_only_context = ""
|
|
37769
|
+
target_only_context = ""
|
|
37770
|
+
|
|
37771
|
+
has_source_target = "{{SOURCE+TARGET_CONTEXT}}" in prompt_content
|
|
37772
|
+
has_source_only = "{{SOURCE_CONTEXT}}" in prompt_content
|
|
37773
|
+
has_target_only = "{{TARGET_CONTEXT}}" in prompt_content
|
|
37774
|
+
|
|
37775
|
+
if (has_source_target or has_source_only or has_target_only) and hasattr(self, 'current_project') and self.current_project:
|
|
37776
|
+
if has_source_target:
|
|
37777
|
+
source_target_context = self._build_quickmenu_document_context(mode="both")
|
|
37778
|
+
self.log(f"🔍 QuickMenu: Built SOURCE+TARGET context ({len(source_target_context)} chars)")
|
|
37779
|
+
if has_source_only:
|
|
37780
|
+
source_only_context = self._build_quickmenu_document_context(mode="source")
|
|
37781
|
+
self.log(f"🔍 QuickMenu: Built SOURCE_ONLY context ({len(source_only_context)} chars)")
|
|
37782
|
+
if has_target_only:
|
|
37783
|
+
target_only_context = self._build_quickmenu_document_context(mode="target")
|
|
37784
|
+
self.log(f"🔍 QuickMenu: Built TARGET_ONLY context ({len(target_only_context)} chars)")
|
|
37785
|
+
else:
|
|
37786
|
+
if has_source_target:
|
|
37787
|
+
self.log("⚠️ QuickMenu: {{SOURCE+TARGET_CONTEXT}} requested but no project loaded")
|
|
37788
|
+
if has_source_only:
|
|
37789
|
+
self.log("⚠️ QuickMenu: {{SOURCE_CONTEXT}} requested but no project loaded")
|
|
37790
|
+
if has_target_only:
|
|
37791
|
+
self.log("⚠️ QuickMenu: {{TARGET_CONTEXT}} requested but no project loaded")
|
|
37745
37792
|
|
|
37746
37793
|
# Replace placeholders in the prompt content
|
|
37747
37794
|
prompt_content = prompt_content.replace("{{SOURCE_LANGUAGE}}", source_lang)
|
|
37748
37795
|
prompt_content = prompt_content.replace("{{TARGET_LANGUAGE}}", target_lang)
|
|
37749
37796
|
prompt_content = prompt_content.replace("{{SOURCE_TEXT}}", source_text)
|
|
37750
37797
|
prompt_content = prompt_content.replace("{{SELECTION}}", source_text) # Alternative placeholder
|
|
37751
|
-
prompt_content = prompt_content.replace("{{
|
|
37798
|
+
prompt_content = prompt_content.replace("{{SOURCE+TARGET_CONTEXT}}", source_target_context)
|
|
37799
|
+
prompt_content = prompt_content.replace("{{SOURCE_CONTEXT}}", source_only_context)
|
|
37800
|
+
prompt_content = prompt_content.replace("{{TARGET_CONTEXT}}", target_only_context)
|
|
37801
|
+
|
|
37802
|
+
# Debug: Log the final prompt being sent
|
|
37803
|
+
self.log(f"📝 QuickMenu: Final prompt ({len(prompt_content)} chars):")
|
|
37804
|
+
self.log("─" * 80)
|
|
37805
|
+
self.log(prompt_content[:500] + ("..." if len(prompt_content) > 500 else ""))
|
|
37806
|
+
self.log("─" * 80)
|
|
37752
37807
|
|
|
37753
37808
|
# If the prompt doesn't contain the selection/text, append it
|
|
37754
37809
|
if "{{SOURCE_TEXT}}" not in prompt_data.get('content', '') and "{{SELECTION}}" not in prompt_data.get('content', ''):
|
|
@@ -37756,9 +37811,15 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37756
37811
|
|
|
37757
37812
|
return prompt_content
|
|
37758
37813
|
|
|
37759
|
-
def _build_quickmenu_document_context(self) -> str:
|
|
37814
|
+
def _build_quickmenu_document_context(self, mode: str = "both") -> str:
|
|
37760
37815
|
"""Build document context for QuickMenu prompts.
|
|
37761
37816
|
|
|
37817
|
+
Args:
|
|
37818
|
+
mode: One of:
|
|
37819
|
+
- "both": Include both source and target text (for proofreading)
|
|
37820
|
+
- "source": Include only source text (for translation/terminology questions)
|
|
37821
|
+
- "target": Include only target text (for consistency/style analysis)
|
|
37822
|
+
|
|
37762
37823
|
Returns a formatted string with segments from the project for context.
|
|
37763
37824
|
Uses the 'quickmenu_context_segments' setting (default: 50% of total segments).
|
|
37764
37825
|
"""
|
|
@@ -37767,7 +37828,7 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37767
37828
|
|
|
37768
37829
|
try:
|
|
37769
37830
|
# Get settings
|
|
37770
|
-
general_prefs = self.
|
|
37831
|
+
general_prefs = self.load_general_settings()
|
|
37771
37832
|
context_percent = general_prefs.get('quickmenu_context_percent', 50) # Default: 50%
|
|
37772
37833
|
max_context_segments = general_prefs.get('quickmenu_context_max', 100) # Safety limit
|
|
37773
37834
|
|
|
@@ -37784,18 +37845,26 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37784
37845
|
# Get segments (from start of document)
|
|
37785
37846
|
context_segments = self.current_project.segments[:num_segments]
|
|
37786
37847
|
|
|
37787
|
-
# Format segments
|
|
37848
|
+
# Format segments based on mode
|
|
37788
37849
|
context_parts = []
|
|
37789
|
-
|
|
37850
|
+
mode_labels = {"both": "SOURCE + TARGET", "source": "SOURCE ONLY", "target": "TARGET ONLY"}
|
|
37851
|
+
context_parts.append(f"=== DOCUMENT CONTEXT ({mode_labels.get(mode, 'UNKNOWN')}) ===")
|
|
37790
37852
|
context_parts.append(f"(Showing {num_segments} of {total_segments} segments - {context_percent}%)")
|
|
37791
37853
|
context_parts.append("")
|
|
37792
37854
|
|
|
37793
37855
|
for seg in context_segments:
|
|
37794
|
-
|
|
37795
|
-
|
|
37796
|
-
|
|
37797
|
-
|
|
37798
|
-
|
|
37856
|
+
if mode == "both":
|
|
37857
|
+
# Source + Target
|
|
37858
|
+
context_parts.append(f"[{seg.id}] {seg.source}")
|
|
37859
|
+
if seg.target and seg.target.strip():
|
|
37860
|
+
context_parts.append(f" → {seg.target}")
|
|
37861
|
+
elif mode == "source":
|
|
37862
|
+
# Source only
|
|
37863
|
+
context_parts.append(f"[{seg.id}] {seg.source}")
|
|
37864
|
+
elif mode == "target":
|
|
37865
|
+
# Target only (skip empty targets)
|
|
37866
|
+
if seg.target and seg.target.strip():
|
|
37867
|
+
context_parts.append(f"[{seg.id}] {seg.target}")
|
|
37799
37868
|
context_parts.append("") # Blank line between segments
|
|
37800
37869
|
|
|
37801
37870
|
return "\n".join(context_parts)
|
|
@@ -44474,7 +44543,7 @@ class SuperlookupTab(QWidget):
|
|
|
44474
44543
|
try:
|
|
44475
44544
|
# Use multiple methods to ensure cleanup
|
|
44476
44545
|
# Method 1: Kill by window title
|
|
44477
|
-
subprocess.run(['taskkill', '/F', '/FI', 'WINDOWTITLE eq
|
|
44546
|
+
subprocess.run(['taskkill', '/F', '/FI', 'WINDOWTITLE eq supervertaler_hotkeys.ahk*'],
|
|
44478
44547
|
capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
|
|
44479
44548
|
|
|
44480
44549
|
# Method 2: Kill AutoHotkey processes more aggressively
|
|
@@ -44486,7 +44555,7 @@ class SuperlookupTab(QWidget):
|
|
|
44486
44555
|
try:
|
|
44487
44556
|
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
|
|
44488
44557
|
try:
|
|
44489
|
-
if '
|
|
44558
|
+
if 'supervertaler_hotkeys' in ' '.join(proc.cmdline() or []):
|
|
44490
44559
|
proc.kill()
|
|
44491
44560
|
except:
|
|
44492
44561
|
pass
|
|
@@ -44499,8 +44568,8 @@ class SuperlookupTab(QWidget):
|
|
|
44499
44568
|
ahk_exe, source = self._find_autohotkey_executable()
|
|
44500
44569
|
|
|
44501
44570
|
if not ahk_exe:
|
|
44502
|
-
print("[
|
|
44503
|
-
print("[
|
|
44571
|
+
print("[Hotkeys] AutoHotkey not found.")
|
|
44572
|
+
print("[Hotkeys] Global hotkeys (Ctrl+Alt+L, Shift+Shift) will not be available.")
|
|
44504
44573
|
self.hotkey_registered = False
|
|
44505
44574
|
# Show setup dialog (deferred to avoid blocking startup) - unless user opted out
|
|
44506
44575
|
if self.main_window and hasattr(self.main_window, 'general_settings'):
|
|
@@ -44510,11 +44579,11 @@ class SuperlookupTab(QWidget):
|
|
|
44510
44579
|
QTimer.singleShot(2000, self._show_autohotkey_setup_dialog)
|
|
44511
44580
|
return
|
|
44512
44581
|
|
|
44513
|
-
print(f"[
|
|
44582
|
+
print(f"[Hotkeys] Found AutoHotkey at: {ahk_exe} (source: {source})")
|
|
44514
44583
|
|
|
44515
|
-
ahk_script = Path(__file__).parent / "
|
|
44516
|
-
print(f"[
|
|
44517
|
-
print(f"[
|
|
44584
|
+
ahk_script = Path(__file__).parent / "supervertaler_hotkeys.ahk"
|
|
44585
|
+
print(f"[Hotkeys] Looking for script at: {ahk_script}")
|
|
44586
|
+
print(f"[Hotkeys] Script exists: {ahk_script.exists()}")
|
|
44518
44587
|
|
|
44519
44588
|
if ahk_script.exists():
|
|
44520
44589
|
# Start AHK script in background (hidden)
|
|
@@ -44522,16 +44591,16 @@ class SuperlookupTab(QWidget):
|
|
|
44522
44591
|
creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0)
|
|
44523
44592
|
# Store in global variable for atexit cleanup
|
|
44524
44593
|
_ahk_process = self.ahk_process
|
|
44525
|
-
print(f"[
|
|
44594
|
+
print(f"[Hotkeys] AHK hotkeys registered (Ctrl+Alt+L, Shift+Shift)")
|
|
44526
44595
|
|
|
44527
44596
|
# Start file watcher
|
|
44528
44597
|
self.start_file_watcher()
|
|
44529
44598
|
self.hotkey_registered = True
|
|
44530
44599
|
else:
|
|
44531
|
-
print(f"[
|
|
44600
|
+
print(f"[Hotkeys] AHK script not found: {ahk_script}")
|
|
44532
44601
|
self.hotkey_registered = False
|
|
44533
44602
|
except Exception as e:
|
|
44534
|
-
print(f"[
|
|
44603
|
+
print(f"[Hotkeys] Could not start AHK hotkeys: {e}")
|
|
44535
44604
|
self.hotkey_registered = False
|
|
44536
44605
|
|
|
44537
44606
|
def start_file_watcher(self):
|
modules/shortcut_manager.py
CHANGED
|
@@ -555,6 +555,14 @@ class ShortcutManager:
|
|
|
555
555
|
"action": "add_word_to_dictionary",
|
|
556
556
|
"context": "grid_editor"
|
|
557
557
|
},
|
|
558
|
+
"editor_show_context_menu_double_shift": {
|
|
559
|
+
"category": "Editor",
|
|
560
|
+
"description": "Show context menu (double-tap Shift)",
|
|
561
|
+
"default": "", # Requires AutoHotkey script: supervertaler_hotkeys.ahk
|
|
562
|
+
"action": "show_context_menu_double_shift",
|
|
563
|
+
"context": "grid_editor",
|
|
564
|
+
"note": "Requires AutoHotkey. Run supervertaler_hotkeys.ahk for this feature."
|
|
565
|
+
},
|
|
558
566
|
|
|
559
567
|
# Filter Operations
|
|
560
568
|
"filter_selected_text": {
|
|
@@ -908,9 +908,19 @@ class UnifiedPromptManagerQt:
|
|
|
908
908
|
"English, Spanish, Portuguese, etc."
|
|
909
909
|
),
|
|
910
910
|
(
|
|
911
|
-
"{{
|
|
912
|
-
"
|
|
911
|
+
"{{SOURCE+TARGET_CONTEXT}}",
|
|
912
|
+
"Project segments with BOTH source and target text. Use for proofreading prompts.",
|
|
913
913
|
"[1] Source text\\n → Target text\\n\\n[2] Source text\\n → Target text\\n\\n..."
|
|
914
|
+
),
|
|
915
|
+
(
|
|
916
|
+
"{{SOURCE_CONTEXT}}",
|
|
917
|
+
"Project segments with SOURCE ONLY. Use for translation/terminology questions.",
|
|
918
|
+
"[1] Source text\\n\\n[2] Source text\\n\\n[3] Source text\\n\\n..."
|
|
919
|
+
),
|
|
920
|
+
(
|
|
921
|
+
"{{TARGET_CONTEXT}}",
|
|
922
|
+
"Project segments with TARGET ONLY. Use for consistency/style analysis.",
|
|
923
|
+
"[1] Target text\\n\\n[2] Target text\\n\\n[3] Target text\\n\\n..."
|
|
914
924
|
)
|
|
915
925
|
]
|
|
916
926
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: supervertaler
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.130
|
|
4
4
|
Summary: Professional AI-powered translation workbench with multi-LLM support, glossary system, TM, spellcheck, voice commands, and PyQt6 interface. Batteries included (core).
|
|
5
5
|
Home-page: https://supervertaler.com
|
|
6
6
|
Author: Michael Beijer
|
|
@@ -71,7 +71,7 @@ Dynamic: home-page
|
|
|
71
71
|
Dynamic: license-file
|
|
72
72
|
Dynamic: requires-python
|
|
73
73
|
|
|
74
|
-
# 🚀 Supervertaler v1.9.
|
|
74
|
+
# 🚀 Supervertaler v1.9.128
|
|
75
75
|
|
|
76
76
|
[](https://pypi.org/project/Supervertaler/)
|
|
77
77
|
[](https://www.python.org/downloads/)
|
|
@@ -79,7 +79,11 @@ Dynamic: requires-python
|
|
|
79
79
|
|
|
80
80
|
AI-enhanced CAT tool with multi-LLM support (GPT-4, Claude, Gemini, Ollama), innovative Superlookup concordance system offering access to multiple terminology sources (TMs, glossaries, web resources, etc.), and seamless CAT tool integration (memoQ, Trados, CafeTran, Phrase).
|
|
81
81
|
|
|
82
|
-
**Current Version:** v1.9.
|
|
82
|
+
**Current Version:** v1.9.130 (January 20, 2026)
|
|
83
|
+
|
|
84
|
+
### ENHANCED in v1.9.128 - 📝 Placeholders Tab Layout Optimization
|
|
85
|
+
|
|
86
|
+
**Better Use of Space:** The Placeholders reference tab in the Prompt Manager now uses a compact sidebar layout for Usage Tips, giving the placeholders table much more vertical space. Matches the clean, efficient layout style of other tools like AutoFingers and TMX Editor.
|
|
83
87
|
|
|
84
88
|
### FIXED in v1.9.125 - 🐛 Prompt Save Crash
|
|
85
89
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Supervertaler.py,sha256=
|
|
1
|
+
Supervertaler.py,sha256=eJ5_bOujQP7K5tJcAUb0j8-vq_jepeHj4yKo9rlfq04,2140984
|
|
2
2
|
modules/__init__.py,sha256=G58XleS-EJ2sX4Kehm-3N2m618_W2Es0Kg8CW_eBG7g,327
|
|
3
3
|
modules/ai_actions.py,sha256=i5MJcM-7Y6CAvKUwxmxrVHeoZAVtAP7aRDdWM5KLkO0,33877
|
|
4
4
|
modules/ai_attachment_manager.py,sha256=mA5ISI22qN9mH3DQFF4gOTciDyBt5xVR7sHTkgkTIlw,11361
|
|
@@ -41,7 +41,7 @@ modules/quick_access_sidebar.py,sha256=RPn5ssvYXlitNMWFZN9Yxv7So8u_z5RGNpHN6N-SF
|
|
|
41
41
|
modules/ribbon_widget.py,sha256=QNGKxmit_oM5C5nJViadYYEzeRlIdIsla8Bzu_RNGO0,21990
|
|
42
42
|
modules/sdlppx_handler.py,sha256=o6Rj_T0B94toiYlvDDwMYLSz4q6kANgegFaDK5i3yhs,33538
|
|
43
43
|
modules/setup_wizard.py,sha256=1prK5GPrUU4U4CqdT3G1RA3iy8FG1Z4jgPmPPZXOOEA,13115
|
|
44
|
-
modules/shortcut_manager.py,sha256=
|
|
44
|
+
modules/shortcut_manager.py,sha256=HbrMeHY9RzgreqjBhtY3YhQYH_FvSgFO2qzOxyaPXl8,31737
|
|
45
45
|
modules/simple_segmenter.py,sha256=-V7L-tjajW1M3DADxvcYEgBu0VLJvmRQl6VB9OshiuM,4480
|
|
46
46
|
modules/spellcheck_manager.py,sha256=jwduHJ66pOKv1MtzSAltxpP8LPgz11FvF6j8h7BiRZY,27592
|
|
47
47
|
modules/statuses.py,sha256=t6TCA9pNZHDw3SbKTxT73uKezJhwWk9gFLr0NOgEufs,6911
|
|
@@ -73,13 +73,13 @@ modules/translation_memory.py,sha256=U-deNPybG2PKeEt2LSTZv0Ziu5VwxkH2BsuCCXbpalc
|
|
|
73
73
|
modules/translation_results_panel.py,sha256=DmEe0pZRSfcZFg2cWeEREK7H9vrTcPkgeuMW54Pgrys,92505
|
|
74
74
|
modules/translation_services.py,sha256=lyVpWuZK1wtVtYZMDMdLoq1DHBoSaeAnp-Yejb0TlVQ,10530
|
|
75
75
|
modules/unified_prompt_library.py,sha256=L3do_T-7NHnC5CxJ1TDq63iVM60XLkvovDJ9g4cJmZQ,26016
|
|
76
|
-
modules/unified_prompt_manager_qt.py,sha256=
|
|
76
|
+
modules/unified_prompt_manager_qt.py,sha256=kpR-Tk1xmVyJGHnZdHm6NbGQPTZ1jB8t4tI_Y93hXwY,171495
|
|
77
77
|
modules/voice_commands.py,sha256=iBb-gjWxRMLhFH7-InSRjYJz1EIDBNA2Pog8V7TtJaY,38516
|
|
78
78
|
modules/voice_dictation.py,sha256=QmitXfkG-vRt5hIQATjphHdhXfqmwhzcQcbXB6aRzIg,16386
|
|
79
79
|
modules/voice_dictation_lite.py,sha256=jorY0BmWE-8VczbtGrWwt1zbnOctMoSlWOsQrcufBcc,9423
|
|
80
|
-
supervertaler-1.9.
|
|
81
|
-
supervertaler-1.9.
|
|
82
|
-
supervertaler-1.9.
|
|
83
|
-
supervertaler-1.9.
|
|
84
|
-
supervertaler-1.9.
|
|
85
|
-
supervertaler-1.9.
|
|
80
|
+
supervertaler-1.9.130.dist-info/licenses/LICENSE,sha256=m28u-4qL5nXIWnJ6xlQVw__H30rWFtRK3pCOais2OuY,1092
|
|
81
|
+
supervertaler-1.9.130.dist-info/METADATA,sha256=av1kXTxICFggrHAUMtQ0rl77MkSvmiSLHAi6gwNX1NY,42458
|
|
82
|
+
supervertaler-1.9.130.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
83
|
+
supervertaler-1.9.130.dist-info/entry_points.txt,sha256=NP4hiCvx-_30YYKqgr-jfJYQvHr1qTYBMfoVmKIXSM8,53
|
|
84
|
+
supervertaler-1.9.130.dist-info/top_level.txt,sha256=9tUHBYUSfaE4S2E4W3eavJsDyYymkwLfeWAHHAPT6Dk,22
|
|
85
|
+
supervertaler-1.9.130.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|