supervertaler 1.9.186__py3-none-any.whl → 1.9.188__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.
- Supervertaler.py +193 -3
- {supervertaler-1.9.186.dist-info → supervertaler-1.9.188.dist-info}/METADATA +1 -1
- {supervertaler-1.9.186.dist-info → supervertaler-1.9.188.dist-info}/RECORD +7 -7
- {supervertaler-1.9.186.dist-info → supervertaler-1.9.188.dist-info}/WHEEL +0 -0
- {supervertaler-1.9.186.dist-info → supervertaler-1.9.188.dist-info}/entry_points.txt +0 -0
- {supervertaler-1.9.186.dist-info → supervertaler-1.9.188.dist-info}/licenses/LICENSE +0 -0
- {supervertaler-1.9.186.dist-info → supervertaler-1.9.188.dist-info}/top_level.txt +0 -0
Supervertaler.py
CHANGED
|
@@ -32,7 +32,7 @@ License: MIT
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
# Version Information.
|
|
35
|
-
__version__ = "1.9.
|
|
35
|
+
__version__ = "1.9.188"
|
|
36
36
|
__phase__ = "0.9"
|
|
37
37
|
__release_date__ = "2026-02-01"
|
|
38
38
|
__edition__ = "Qt"
|
|
@@ -20348,7 +20348,68 @@ class SupervertalerQt(QMainWindow):
|
|
|
20348
20348
|
advanced_filter_btn.clicked.connect(self.show_advanced_filters_dialog)
|
|
20349
20349
|
advanced_filter_btn.setMaximumWidth(160)
|
|
20350
20350
|
advanced_filter_btn.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold;")
|
|
20351
|
-
|
|
20351
|
+
|
|
20352
|
+
# Sort dropdown button (similar to memoQ)
|
|
20353
|
+
sort_btn = QPushButton("⇅ Sort")
|
|
20354
|
+
sort_btn.setMaximumWidth(100)
|
|
20355
|
+
sort_btn.setStyleSheet("background-color: #FF9800; color: white; font-weight: bold;")
|
|
20356
|
+
sort_menu = QMenu(self)
|
|
20357
|
+
|
|
20358
|
+
# Initialize sort state if not exists
|
|
20359
|
+
if not hasattr(self, 'current_sort'):
|
|
20360
|
+
self.current_sort = None # None = document order
|
|
20361
|
+
|
|
20362
|
+
# Sort by source text
|
|
20363
|
+
sort_menu.addAction("📝 Source A → Z", lambda: self.apply_sort('source_asc'))
|
|
20364
|
+
sort_menu.addAction("📝 Source Z → A", lambda: self.apply_sort('source_desc'))
|
|
20365
|
+
|
|
20366
|
+
sort_menu.addSeparator()
|
|
20367
|
+
|
|
20368
|
+
# Sort by target text
|
|
20369
|
+
sort_menu.addAction("📄 Target A → Z", lambda: self.apply_sort('target_asc'))
|
|
20370
|
+
sort_menu.addAction("📄 Target Z → A", lambda: self.apply_sort('target_desc'))
|
|
20371
|
+
|
|
20372
|
+
sort_menu.addSeparator()
|
|
20373
|
+
|
|
20374
|
+
# Sort by text length
|
|
20375
|
+
sort_menu.addAction("📏 Source (longer first)", lambda: self.apply_sort('source_length_desc'))
|
|
20376
|
+
sort_menu.addAction("📏 Source (shorter first)", lambda: self.apply_sort('source_length_asc'))
|
|
20377
|
+
sort_menu.addAction("📏 Target (longer first)", lambda: self.apply_sort('target_length_desc'))
|
|
20378
|
+
sort_menu.addAction("📏 Target (shorter first)", lambda: self.apply_sort('target_length_asc'))
|
|
20379
|
+
|
|
20380
|
+
sort_menu.addSeparator()
|
|
20381
|
+
|
|
20382
|
+
# Sort by match rate
|
|
20383
|
+
sort_menu.addAction("🎯 Match Rate (higher first)", lambda: self.apply_sort('match_desc'))
|
|
20384
|
+
sort_menu.addAction("🎯 Match Rate (lower first)", lambda: self.apply_sort('match_asc'))
|
|
20385
|
+
|
|
20386
|
+
sort_menu.addSeparator()
|
|
20387
|
+
|
|
20388
|
+
# Sort by frequency
|
|
20389
|
+
sort_menu.addAction("📊 Source Frequency (higher first)", lambda: self.apply_sort('source_freq_desc'))
|
|
20390
|
+
sort_menu.addAction("📊 Source Frequency (lower first)", lambda: self.apply_sort('source_freq_asc'))
|
|
20391
|
+
sort_menu.addAction("📊 Target Frequency (higher first)", lambda: self.apply_sort('target_freq_desc'))
|
|
20392
|
+
sort_menu.addAction("📊 Target Frequency (lower first)", lambda: self.apply_sort('target_freq_asc'))
|
|
20393
|
+
|
|
20394
|
+
sort_menu.addSeparator()
|
|
20395
|
+
|
|
20396
|
+
# Sort by last changed
|
|
20397
|
+
sort_menu.addAction("🕒 Last Changed (newest first)", lambda: self.apply_sort('modified_desc'))
|
|
20398
|
+
sort_menu.addAction("🕒 Last Changed (oldest first)", lambda: self.apply_sort('modified_asc'))
|
|
20399
|
+
|
|
20400
|
+
sort_menu.addSeparator()
|
|
20401
|
+
|
|
20402
|
+
# Sort by row status
|
|
20403
|
+
sort_menu.addAction("🚦 Row Status", lambda: self.apply_sort('status'))
|
|
20404
|
+
|
|
20405
|
+
sort_menu.addSeparator()
|
|
20406
|
+
|
|
20407
|
+
# Reset to document order
|
|
20408
|
+
sort_menu.addAction("↩️ Document Order (default)", lambda: self.apply_sort(None))
|
|
20409
|
+
|
|
20410
|
+
sort_btn.setMenu(sort_menu)
|
|
20411
|
+
sort_btn.setToolTip("Sort segments by various criteria")
|
|
20412
|
+
|
|
20352
20413
|
# File filter dropdown (for multi-file projects)
|
|
20353
20414
|
self.file_filter_combo = QComboBox()
|
|
20354
20415
|
self.file_filter_combo.setMinimumWidth(150)
|
|
@@ -20442,6 +20503,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
20442
20503
|
filter_layout.addWidget(clear_filters_btn)
|
|
20443
20504
|
filter_layout.addWidget(quick_filter_btn)
|
|
20444
20505
|
filter_layout.addWidget(advanced_filter_btn)
|
|
20506
|
+
filter_layout.addWidget(sort_btn) # Sort dropdown
|
|
20445
20507
|
filter_layout.addWidget(self.file_filter_combo) # File filter for multi-file projects
|
|
20446
20508
|
filter_layout.addWidget(show_invisibles_btn_home)
|
|
20447
20509
|
filter_layout.addWidget(self.spellcheck_btn)
|
|
@@ -37616,7 +37678,135 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37616
37678
|
self.table.setUpdatesEnabled(True)
|
|
37617
37679
|
|
|
37618
37680
|
self.log(f"🔍 Advanced filters: showing {visible_count} of {len(self.current_project.segments)} segments")
|
|
37619
|
-
|
|
37681
|
+
|
|
37682
|
+
def apply_sort(self, sort_type: str = None):
|
|
37683
|
+
"""Sort segments by various criteria (similar to memoQ)"""
|
|
37684
|
+
if not self.current_project or not hasattr(self, 'table') or self.table is None:
|
|
37685
|
+
return
|
|
37686
|
+
|
|
37687
|
+
if not self.current_project.segments:
|
|
37688
|
+
return
|
|
37689
|
+
|
|
37690
|
+
# Store original document order if not already stored
|
|
37691
|
+
if not hasattr(self, '_original_segment_order'):
|
|
37692
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
37693
|
+
|
|
37694
|
+
# Update current sort state
|
|
37695
|
+
self.current_sort = sort_type
|
|
37696
|
+
|
|
37697
|
+
# If sort_type is None, restore document order
|
|
37698
|
+
if sort_type is None:
|
|
37699
|
+
self.current_project.segments = self._original_segment_order.copy()
|
|
37700
|
+
|
|
37701
|
+
# Set pagination to "All" to show all segments
|
|
37702
|
+
if hasattr(self, 'page_size_combo') and self._widget_is_alive(self.page_size_combo):
|
|
37703
|
+
self.page_size_combo.blockSignals(True)
|
|
37704
|
+
self.page_size_combo.setCurrentText("All")
|
|
37705
|
+
self.page_size_combo.blockSignals(False)
|
|
37706
|
+
# Update the internal page size variable
|
|
37707
|
+
if hasattr(self, 'grid_page_size'):
|
|
37708
|
+
self.grid_page_size = 999999
|
|
37709
|
+
|
|
37710
|
+
self.load_segments_to_grid()
|
|
37711
|
+
self.log("↩️ Restored document order (showing all segments)")
|
|
37712
|
+
return
|
|
37713
|
+
|
|
37714
|
+
# Helper function to get text without tags for more accurate sorting
|
|
37715
|
+
def strip_tags(text: str) -> str:
|
|
37716
|
+
"""Remove HTML/XML tags from text for sorting"""
|
|
37717
|
+
import re
|
|
37718
|
+
return re.sub(r'<[^>]+>', '', text).strip()
|
|
37719
|
+
|
|
37720
|
+
# Calculate frequency maps if needed
|
|
37721
|
+
frequency_cache = {}
|
|
37722
|
+
if 'freq' in sort_type:
|
|
37723
|
+
from collections import Counter
|
|
37724
|
+
if 'source' in sort_type:
|
|
37725
|
+
counter = Counter(strip_tags(seg.source).lower() for seg in self.current_project.segments)
|
|
37726
|
+
frequency_cache = {strip_tags(seg.source).lower(): counter[strip_tags(seg.source).lower()]
|
|
37727
|
+
for seg in self.current_project.segments}
|
|
37728
|
+
else: # target frequency
|
|
37729
|
+
counter = Counter(strip_tags(seg.target).lower() for seg in self.current_project.segments if seg.target)
|
|
37730
|
+
frequency_cache = {strip_tags(seg.target).lower(): counter[strip_tags(seg.target).lower()]
|
|
37731
|
+
for seg in self.current_project.segments if seg.target}
|
|
37732
|
+
|
|
37733
|
+
# Sort based on selected criterion
|
|
37734
|
+
try:
|
|
37735
|
+
if sort_type == 'source_asc':
|
|
37736
|
+
self.current_project.segments.sort(key=lambda s: strip_tags(s.source).lower())
|
|
37737
|
+
sort_name = "Source A → Z"
|
|
37738
|
+
elif sort_type == 'source_desc':
|
|
37739
|
+
self.current_project.segments.sort(key=lambda s: strip_tags(s.source).lower(), reverse=True)
|
|
37740
|
+
sort_name = "Source Z → A"
|
|
37741
|
+
elif sort_type == 'target_asc':
|
|
37742
|
+
self.current_project.segments.sort(key=lambda s: strip_tags(s.target).lower() if s.target else "")
|
|
37743
|
+
sort_name = "Target A → Z"
|
|
37744
|
+
elif sort_type == 'target_desc':
|
|
37745
|
+
self.current_project.segments.sort(key=lambda s: strip_tags(s.target).lower() if s.target else "", reverse=True)
|
|
37746
|
+
sort_name = "Target Z → A"
|
|
37747
|
+
elif sort_type == 'source_length_asc':
|
|
37748
|
+
self.current_project.segments.sort(key=lambda s: len(strip_tags(s.source)))
|
|
37749
|
+
sort_name = "Source (shorter first)"
|
|
37750
|
+
elif sort_type == 'source_length_desc':
|
|
37751
|
+
self.current_project.segments.sort(key=lambda s: len(strip_tags(s.source)), reverse=True)
|
|
37752
|
+
sort_name = "Source (longer first)"
|
|
37753
|
+
elif sort_type == 'target_length_asc':
|
|
37754
|
+
self.current_project.segments.sort(key=lambda s: len(strip_tags(s.target)) if s.target else 0)
|
|
37755
|
+
sort_name = "Target (shorter first)"
|
|
37756
|
+
elif sort_type == 'target_length_desc':
|
|
37757
|
+
self.current_project.segments.sort(key=lambda s: len(strip_tags(s.target)) if s.target else 0, reverse=True)
|
|
37758
|
+
sort_name = "Target (longer first)"
|
|
37759
|
+
elif sort_type == 'match_asc':
|
|
37760
|
+
self.current_project.segments.sort(key=lambda s: getattr(s, 'match_percent', 0) or 0)
|
|
37761
|
+
sort_name = "Match Rate (lower first)"
|
|
37762
|
+
elif sort_type == 'match_desc':
|
|
37763
|
+
self.current_project.segments.sort(key=lambda s: getattr(s, 'match_percent', 0) or 0, reverse=True)
|
|
37764
|
+
sort_name = "Match Rate (higher first)"
|
|
37765
|
+
elif sort_type == 'source_freq_asc':
|
|
37766
|
+
self.current_project.segments.sort(key=lambda s: frequency_cache.get(strip_tags(s.source).lower(), 0))
|
|
37767
|
+
sort_name = "Source Frequency (lower first)"
|
|
37768
|
+
elif sort_type == 'source_freq_desc':
|
|
37769
|
+
self.current_project.segments.sort(key=lambda s: frequency_cache.get(strip_tags(s.source).lower(), 0), reverse=True)
|
|
37770
|
+
sort_name = "Source Frequency (higher first)"
|
|
37771
|
+
elif sort_type == 'target_freq_asc':
|
|
37772
|
+
self.current_project.segments.sort(key=lambda s: frequency_cache.get(strip_tags(s.target).lower(), 0) if s.target else 0)
|
|
37773
|
+
sort_name = "Target Frequency (lower first)"
|
|
37774
|
+
elif sort_type == 'target_freq_desc':
|
|
37775
|
+
self.current_project.segments.sort(key=lambda s: frequency_cache.get(strip_tags(s.target).lower(), 0) if s.target else 0, reverse=True)
|
|
37776
|
+
sort_name = "Target Frequency (higher first)"
|
|
37777
|
+
elif sort_type == 'modified_asc':
|
|
37778
|
+
self.current_project.segments.sort(key=lambda s: s.modified_at if s.modified_at else "")
|
|
37779
|
+
sort_name = "Last Changed (oldest first)"
|
|
37780
|
+
elif sort_type == 'modified_desc':
|
|
37781
|
+
self.current_project.segments.sort(key=lambda s: s.modified_at if s.modified_at else "", reverse=True)
|
|
37782
|
+
sort_name = "Last Changed (newest first)"
|
|
37783
|
+
elif sort_type == 'status':
|
|
37784
|
+
# Sort by status in a logical order: not_started, draft, translated, confirmed
|
|
37785
|
+
status_order = {'not_started': 0, 'draft': 1, 'translated': 2, 'confirmed': 3}
|
|
37786
|
+
self.current_project.segments.sort(key=lambda s: status_order.get(s.status, 99))
|
|
37787
|
+
sort_name = "Row Status"
|
|
37788
|
+
else:
|
|
37789
|
+
self.log(f"⚠️ Unknown sort type: {sort_type}")
|
|
37790
|
+
return
|
|
37791
|
+
|
|
37792
|
+
# Set pagination to "All" to show all sorted segments
|
|
37793
|
+
if hasattr(self, 'page_size_combo') and self._widget_is_alive(self.page_size_combo):
|
|
37794
|
+
self.page_size_combo.blockSignals(True)
|
|
37795
|
+
self.page_size_combo.setCurrentText("All")
|
|
37796
|
+
self.page_size_combo.blockSignals(False)
|
|
37797
|
+
# Update the internal page size variable
|
|
37798
|
+
if hasattr(self, 'grid_page_size'):
|
|
37799
|
+
self.grid_page_size = 999999
|
|
37800
|
+
|
|
37801
|
+
# Reload grid to reflect new order
|
|
37802
|
+
self.load_segments_to_grid()
|
|
37803
|
+
self.log(f"⇅ Sorted by: {sort_name} (showing all segments)")
|
|
37804
|
+
|
|
37805
|
+
except Exception as e:
|
|
37806
|
+
self.log(f"❌ Error sorting segments: {e}")
|
|
37807
|
+
import traceback
|
|
37808
|
+
traceback.print_exc()
|
|
37809
|
+
|
|
37620
37810
|
# ========================================================================
|
|
37621
37811
|
# TABBED SEGMENT EDITOR METHODS (for Grid view)
|
|
37622
37812
|
# ========================================================================
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: supervertaler
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.188
|
|
4
4
|
Summary: Professional AI-enhanced 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
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Supervertaler.py,sha256=
|
|
1
|
+
Supervertaler.py,sha256=A1mrclFgUCGhQmplbECjOl66vWosWT0npDn-dgzmiPA,2352573
|
|
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=juZlrW3UPkIkcnj0SREgOQkQROLf0fcu3ShZcKXMxsI,11361
|
|
@@ -79,9 +79,9 @@ modules/unified_prompt_manager_qt.py,sha256=HkGUnH0wlfxt-hVe-nKCeWLyProYdefuuq2s
|
|
|
79
79
|
modules/voice_commands.py,sha256=iBb-gjWxRMLhFH7-InSRjYJz1EIDBNA2Pog8V7TtJaY,38516
|
|
80
80
|
modules/voice_dictation.py,sha256=QmitXfkG-vRt5hIQATjphHdhXfqmwhzcQcbXB6aRzIg,16386
|
|
81
81
|
modules/voice_dictation_lite.py,sha256=jorY0BmWE-8VczbtGrWwt1zbnOctMoSlWOsQrcufBcc,9423
|
|
82
|
-
supervertaler-1.9.
|
|
83
|
-
supervertaler-1.9.
|
|
84
|
-
supervertaler-1.9.
|
|
85
|
-
supervertaler-1.9.
|
|
86
|
-
supervertaler-1.9.
|
|
87
|
-
supervertaler-1.9.
|
|
82
|
+
supervertaler-1.9.188.dist-info/licenses/LICENSE,sha256=m28u-4qL5nXIWnJ6xlQVw__H30rWFtRK3pCOais2OuY,1092
|
|
83
|
+
supervertaler-1.9.188.dist-info/METADATA,sha256=yQEbyUHJJ3bownTFzAotI23O-tVUEvW61TK6j1jJplQ,5725
|
|
84
|
+
supervertaler-1.9.188.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
85
|
+
supervertaler-1.9.188.dist-info/entry_points.txt,sha256=NP4hiCvx-_30YYKqgr-jfJYQvHr1qTYBMfoVmKIXSM8,53
|
|
86
|
+
supervertaler-1.9.188.dist-info/top_level.txt,sha256=9tUHBYUSfaE4S2E4W3eavJsDyYymkwLfeWAHHAPT6Dk,22
|
|
87
|
+
supervertaler-1.9.188.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|