supervertaler 1.9.197__py3-none-any.whl → 1.9.202__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 +198 -74
- {supervertaler-1.9.197.dist-info → supervertaler-1.9.202.dist-info}/METADATA +1 -1
- {supervertaler-1.9.197.dist-info → supervertaler-1.9.202.dist-info}/RECORD +7 -7
- {supervertaler-1.9.197.dist-info → supervertaler-1.9.202.dist-info}/WHEEL +0 -0
- {supervertaler-1.9.197.dist-info → supervertaler-1.9.202.dist-info}/entry_points.txt +0 -0
- {supervertaler-1.9.197.dist-info → supervertaler-1.9.202.dist-info}/licenses/LICENSE +0 -0
- {supervertaler-1.9.197.dist-info → supervertaler-1.9.202.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.198"
|
|
36
36
|
__phase__ = "0.9"
|
|
37
37
|
__release_date__ = "2026-02-02"
|
|
38
38
|
__edition__ = "Qt"
|
|
@@ -17781,10 +17781,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
17781
17781
|
hide_wrapping_tags_check = CheckmarkCheckBox("Hide outer wrapping tags in grid (e.g. <li-o>...</li-o>)")
|
|
17782
17782
|
hide_wrapping_tags_check.setChecked(font_settings.get('hide_outer_wrapping_tags', False))
|
|
17783
17783
|
hide_wrapping_tags_check.setToolTip(
|
|
17784
|
-
"When enabled, structural tags that wrap the entire segment (like <li-o>, <p>, <td>) are hidden
|
|
17785
|
-
"
|
|
17786
|
-
"
|
|
17787
|
-
"
|
|
17784
|
+
"When enabled, structural tags that wrap the entire segment (like <li-o>, <p>, <td>) are hidden.\n"
|
|
17785
|
+
"Tags are automatically restored when saving. List items show visual prefixes (1. 2. or •).\n"
|
|
17786
|
+
"The segment type is shown in the Type column, so outer tags are redundant.\n"
|
|
17787
|
+
"Inner formatting tags like <b>bold</b> are still shown."
|
|
17788
17788
|
)
|
|
17789
17789
|
hide_wrapping_tags_layout.addWidget(hide_wrapping_tags_check)
|
|
17790
17790
|
hide_wrapping_tags_layout.addStretch()
|
|
@@ -20405,8 +20405,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
20405
20405
|
|
|
20406
20406
|
# Add hide outer wrapping tags setting if provided
|
|
20407
20407
|
if hide_wrapping_tags_check is not None:
|
|
20408
|
-
|
|
20409
|
-
|
|
20408
|
+
hide_tags_value = hide_wrapping_tags_check.isChecked()
|
|
20409
|
+
general_settings['hide_outer_wrapping_tags'] = hide_tags_value
|
|
20410
|
+
self.hide_outer_wrapping_tags = hide_tags_value
|
|
20410
20411
|
|
|
20411
20412
|
# Add focus border settings if provided
|
|
20412
20413
|
if border_color_btn is not None:
|
|
@@ -23770,6 +23771,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
23770
23771
|
- 'latest': Overwrites existing entries with same source (keeps only newest translation)
|
|
23771
23772
|
- 'all': Keeps all translations with different targets (default SQLite behavior)
|
|
23772
23773
|
|
|
23774
|
+
If hide_outer_wrapping_tags is enabled, strips structural tags (like <li-o>, <p>)
|
|
23775
|
+
before saving to TM for better matching leverage.
|
|
23776
|
+
|
|
23773
23777
|
Args:
|
|
23774
23778
|
source: Source text
|
|
23775
23779
|
target: Target text
|
|
@@ -23777,6 +23781,11 @@ class SupervertalerQt(QMainWindow):
|
|
|
23777
23781
|
if not self.current_project:
|
|
23778
23782
|
return
|
|
23779
23783
|
|
|
23784
|
+
# Strip outer structural tags if setting is enabled (for cleaner TM matching)
|
|
23785
|
+
if self.hide_outer_wrapping_tags:
|
|
23786
|
+
source, _ = strip_outer_wrapping_tags(source)
|
|
23787
|
+
target, _ = strip_outer_wrapping_tags(target)
|
|
23788
|
+
|
|
23780
23789
|
if not hasattr(self.current_project, 'source_lang') or not hasattr(self.current_project, 'target_lang'):
|
|
23781
23790
|
return
|
|
23782
23791
|
|
|
@@ -29918,34 +29927,46 @@ class SupervertalerQt(QMainWindow):
|
|
|
29918
29927
|
# Source - Use read-only QTextEdit widget for easy text selection
|
|
29919
29928
|
# Strip outer wrapping tags if setting is enabled (display only, data unchanged)
|
|
29920
29929
|
source_for_display = segment.source
|
|
29930
|
+
stripped_source_tag = None
|
|
29921
29931
|
if self.hide_outer_wrapping_tags:
|
|
29922
|
-
stripped,
|
|
29932
|
+
stripped, stripped_source_tag = strip_outer_wrapping_tags(segment.source)
|
|
29923
29933
|
source_for_display = stripped
|
|
29924
29934
|
# Apply invisible character replacements for display only
|
|
29925
29935
|
source_display_text = self.apply_invisible_replacements(source_for_display)
|
|
29926
29936
|
source_editor = ReadOnlyGridTextEditor(source_display_text, self.table, row)
|
|
29927
|
-
|
|
29937
|
+
|
|
29928
29938
|
# Initialize empty termbase matches (will be populated lazily on segment selection or by background worker)
|
|
29929
29939
|
source_editor.termbase_matches = {}
|
|
29930
|
-
|
|
29940
|
+
|
|
29931
29941
|
# Set font to match grid
|
|
29932
29942
|
font = QFont(self.default_font_family, self.default_font_size)
|
|
29933
29943
|
source_editor.setFont(font)
|
|
29934
|
-
|
|
29944
|
+
|
|
29935
29945
|
# Set as cell widget (allows easy text selection)
|
|
29936
29946
|
self.table.setCellWidget(row, 2, source_editor)
|
|
29937
|
-
|
|
29947
|
+
|
|
29938
29948
|
# Also set a placeholder item for row height calculation
|
|
29939
29949
|
source_item = QTableWidgetItem()
|
|
29940
29950
|
source_item.setFlags(Qt.ItemFlag.NoItemFlags) # No interaction
|
|
29941
29951
|
self.table.setItem(row, 2, source_item)
|
|
29942
|
-
|
|
29952
|
+
|
|
29943
29953
|
# Target - Use editable QTextEdit widget for easy text selection and editing
|
|
29944
|
-
#
|
|
29954
|
+
# Strip outer wrapping tags if enabled (will be auto-restored when saving)
|
|
29955
|
+
target_for_display = segment.target
|
|
29956
|
+
stripped_target_tag = None
|
|
29957
|
+
if self.hide_outer_wrapping_tags:
|
|
29958
|
+
stripped, stripped_target_tag = strip_outer_wrapping_tags(segment.target)
|
|
29959
|
+
target_for_display = stripped
|
|
29960
|
+
# Store stripped tag on segment for restore during save
|
|
29961
|
+
# Use source tag as reference (target should match source structure)
|
|
29962
|
+
segment._stripped_outer_tag = stripped_source_tag or stripped_target_tag
|
|
29963
|
+
|
|
29945
29964
|
# Apply invisible character replacements for display (will be reversed when saving)
|
|
29946
|
-
target_display_text = self.apply_invisible_replacements(
|
|
29965
|
+
target_display_text = self.apply_invisible_replacements(target_for_display)
|
|
29947
29966
|
target_editor = EditableGridTextEditor(target_display_text, self.table, row, self.table)
|
|
29948
29967
|
target_editor.setFont(font)
|
|
29968
|
+
# Store stripped tag on editor for auto-restore
|
|
29969
|
+
target_editor._stripped_outer_tag = stripped_source_tag or stripped_target_tag
|
|
29949
29970
|
|
|
29950
29971
|
# Connect text changes to update segment
|
|
29951
29972
|
# Use a factory function to create a proper closure that captures the segment ID
|
|
@@ -29960,6 +29981,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
29960
29981
|
# Reverse invisible character replacements before saving
|
|
29961
29982
|
new_text = self.reverse_invisible_replacements(new_text)
|
|
29962
29983
|
|
|
29984
|
+
# Auto-restore stripped outer wrapping tags if they were hidden
|
|
29985
|
+
stripped_tag = getattr(editor_widget, '_stripped_outer_tag', None)
|
|
29986
|
+
if stripped_tag and self.hide_outer_wrapping_tags:
|
|
29987
|
+
# Only re-add if the text doesn't already have the tag
|
|
29988
|
+
if not new_text.strip().startswith(f'<{stripped_tag}'):
|
|
29989
|
+
new_text = f'<{stripped_tag}>{new_text}</{stripped_tag}>'
|
|
29990
|
+
|
|
29963
29991
|
# DEBUG: Log EVERY call to catch the culprit (only in debug mode)
|
|
29964
29992
|
if self.debug_mode_enabled:
|
|
29965
29993
|
self.log(f"🔔 textChanged FIRED: segment_id={segment_id}, new_text='{new_text[:20] if new_text else 'EMPTY'}...'")
|
|
@@ -31046,14 +31074,15 @@ class SupervertalerQt(QMainWindow):
|
|
|
31046
31074
|
import re
|
|
31047
31075
|
list_numbers = {} # {segment_id: list_number}
|
|
31048
31076
|
list_counter = 0
|
|
31049
|
-
|
|
31077
|
+
prev_was_ordered_list = False
|
|
31078
|
+
|
|
31050
31079
|
for seg in self.current_project.segments:
|
|
31051
31080
|
source_text = seg.source.strip() if seg.source else ""
|
|
31052
|
-
|
|
31081
|
+
|
|
31053
31082
|
# Check for list tags (new <li-o>, <li-b> and legacy <li>)
|
|
31054
31083
|
has_li_ordered = '<li-o>' in source_text or ('<li>' in source_text and '<li-b>' not in source_text)
|
|
31055
31084
|
has_li_bullet = '<li-b>' in source_text
|
|
31056
|
-
|
|
31085
|
+
|
|
31057
31086
|
if has_li_ordered:
|
|
31058
31087
|
# Check for explicit number in text
|
|
31059
31088
|
num_match = re.match(r'^<li(?:-o)?>\s*(\d+)[.)\s]', source_text)
|
|
@@ -31061,8 +31090,15 @@ class SupervertalerQt(QMainWindow):
|
|
|
31061
31090
|
list_numbers[seg.id] = int(num_match.group(1))
|
|
31062
31091
|
list_counter = int(num_match.group(1))
|
|
31063
31092
|
else:
|
|
31093
|
+
# Reset counter if starting a new list (gap since last ordered item)
|
|
31094
|
+
if not prev_was_ordered_list:
|
|
31095
|
+
list_counter = 0
|
|
31064
31096
|
list_counter += 1
|
|
31065
31097
|
list_numbers[seg.id] = list_counter
|
|
31098
|
+
prev_was_ordered_list = True
|
|
31099
|
+
else:
|
|
31100
|
+
# Not an ordered list item - mark gap for potential new list
|
|
31101
|
+
prev_was_ordered_list = False
|
|
31066
31102
|
|
|
31067
31103
|
# Render all segments
|
|
31068
31104
|
current_segment_id = self._get_current_segment_id()
|
|
@@ -31077,12 +31113,20 @@ class SupervertalerQt(QMainWindow):
|
|
|
31077
31113
|
# Type field values: "para", "heading", "list_item", "table_cell", "Sub", "¶", etc.
|
|
31078
31114
|
seg_type_lower = seg_type.lower() if seg_type else 'para'
|
|
31079
31115
|
|
|
31116
|
+
# Check if this is a list item (need source_text first)
|
|
31117
|
+
source_text = seg.source.strip() if seg.source else ""
|
|
31118
|
+
|
|
31080
31119
|
# Check if this is a heading/subtitle
|
|
31081
|
-
|
|
31120
|
+
# Also detect bold-wrapped short text as section headings (e.g., <b>TECHNICAL FIELD</b>)
|
|
31121
|
+
is_heading = ('Heading' in style or 'Title' in style or 'Subtitle' in style
|
|
31082
31122
|
or seg_type_lower in ('heading', 'sub', 'subtitle', 'title'))
|
|
31083
|
-
|
|
31084
|
-
#
|
|
31085
|
-
|
|
31123
|
+
|
|
31124
|
+
# Detect bold section headings: <b>TEXT</b> where text is short and likely a heading
|
|
31125
|
+
if not is_heading and source_text.startswith('<b>') and source_text.endswith('</b>'):
|
|
31126
|
+
inner_text = source_text[3:-4].strip() # Remove <b> and </b>
|
|
31127
|
+
# Short text (under 80 chars) that's bold is likely a section heading
|
|
31128
|
+
if len(inner_text) < 80 and '<' not in inner_text:
|
|
31129
|
+
is_heading = True
|
|
31086
31130
|
is_list_item = ('<li-o>' in source_text or '<li-b>' in source_text or
|
|
31087
31131
|
'<li>' in source_text or seg_type_lower == 'list_item')
|
|
31088
31132
|
|
|
@@ -31101,9 +31145,15 @@ class SupervertalerQt(QMainWindow):
|
|
|
31101
31145
|
prev_type = getattr(prev_seg, 'type', 'para') or 'para'
|
|
31102
31146
|
prev_type_lower = prev_type.lower() if prev_type else 'para'
|
|
31103
31147
|
|
|
31104
|
-
prev_is_heading = ('Heading' in prev_style or 'Title' in prev_style or
|
|
31105
|
-
'Subtitle' in prev_style or
|
|
31148
|
+
prev_is_heading = ('Heading' in prev_style or 'Title' in prev_style or
|
|
31149
|
+
'Subtitle' in prev_style or
|
|
31106
31150
|
prev_type_lower in ('heading', 'sub', 'subtitle', 'title'))
|
|
31151
|
+
# Also detect bold section headings in previous segment
|
|
31152
|
+
prev_source = prev_seg.source.strip() if prev_seg.source else ""
|
|
31153
|
+
if not prev_is_heading and prev_source.startswith('<b>') and prev_source.endswith('</b>'):
|
|
31154
|
+
prev_inner = prev_source[3:-4].strip()
|
|
31155
|
+
if len(prev_inner) < 80 and '<' not in prev_inner:
|
|
31156
|
+
prev_is_heading = True
|
|
31107
31157
|
prev_is_paragraph = prev_type == '¶' or prev_type_lower == 'para'
|
|
31108
31158
|
prev_is_list = prev_type_lower == 'list_item' or '<li' in (prev_seg.source or '')
|
|
31109
31159
|
|
|
@@ -31125,9 +31175,15 @@ class SupervertalerQt(QMainWindow):
|
|
|
31125
31175
|
else:
|
|
31126
31176
|
# Same paragraph, running text
|
|
31127
31177
|
need_space = True
|
|
31128
|
-
# 4. List items:
|
|
31178
|
+
# 4. List items: ordered list items (like claims) get paragraph spacing
|
|
31129
31179
|
elif is_list_item or prev_is_list:
|
|
31130
|
-
|
|
31180
|
+
# Ordered list items (<li-o>) get double breaks for visual separation
|
|
31181
|
+
is_ordered_list = '<li-o>' in source_text or ('<li>' in source_text and '<li-b>' not in source_text)
|
|
31182
|
+
prev_is_ordered = '<li-o>' in (prev_seg.source or '') or ('<li>' in (prev_seg.source or '') and '<li-b>' not in (prev_seg.source or ''))
|
|
31183
|
+
if is_ordered_list or prev_is_ordered:
|
|
31184
|
+
need_double_break = True # Paragraph-like spacing for numbered items
|
|
31185
|
+
else:
|
|
31186
|
+
need_single_break = True # Bullet lists stay compact
|
|
31131
31187
|
# 5. Default: space (running text)
|
|
31132
31188
|
else:
|
|
31133
31189
|
need_space = True
|
|
@@ -31162,6 +31218,11 @@ class SupervertalerQt(QMainWindow):
|
|
|
31162
31218
|
char_format.setFontPointSize(13)
|
|
31163
31219
|
char_format.setFontWeight(QFont.Weight.Bold)
|
|
31164
31220
|
char_format.setForeground(QColor('#1f4068'))
|
|
31221
|
+
elif is_heading:
|
|
31222
|
+
# Bold section headings detected from <b>TEXT</b> pattern
|
|
31223
|
+
char_format.setFontPointSize(12)
|
|
31224
|
+
char_format.setFontWeight(QFont.Weight.Bold)
|
|
31225
|
+
char_format.setForeground(QColor('#1a365d'))
|
|
31165
31226
|
else:
|
|
31166
31227
|
char_format.setFontPointSize(11)
|
|
31167
31228
|
char_format.setForeground(QColor('#2d2d2d'))
|
|
@@ -34820,12 +34881,20 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
34820
34881
|
self.log("💡 Tip: Go to Resources tab to activate TMs and glossaries for this project")
|
|
34821
34882
|
|
|
34822
34883
|
def search_and_display_tm_matches(self, source_text: str):
|
|
34823
|
-
"""Search TM and Termbases and display matches with visual diff for fuzzy matches
|
|
34884
|
+
"""Search TM and Termbases and display matches with visual diff for fuzzy matches.
|
|
34885
|
+
|
|
34886
|
+
If hide_outer_wrapping_tags is enabled, strips structural tags (like <li-o>, <p>)
|
|
34887
|
+
from the query before searching for better TM matching.
|
|
34888
|
+
"""
|
|
34824
34889
|
self.log(f"🚨 search_and_display_tm_matches called with source_text: '{source_text[:50]}...'")
|
|
34825
34890
|
if not source_text or not source_text.strip():
|
|
34826
34891
|
if hasattr(self, 'tm_display'):
|
|
34827
34892
|
self.tm_display.clear()
|
|
34828
34893
|
return
|
|
34894
|
+
|
|
34895
|
+
# Strip outer structural tags if setting is enabled (for cleaner TM matching)
|
|
34896
|
+
if self.hide_outer_wrapping_tags:
|
|
34897
|
+
source_text, _ = strip_outer_wrapping_tags(source_text)
|
|
34829
34898
|
|
|
34830
34899
|
# Initialize TM if not already done
|
|
34831
34900
|
if not self.tm_database and self.current_project:
|
|
@@ -34902,14 +34971,18 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
34902
34971
|
# Update grid (using cell widget)
|
|
34903
34972
|
target_widget = self.table.cellWidget(current_row, 3)
|
|
34904
34973
|
if target_widget and isinstance(target_widget, EditableGridTextEditor):
|
|
34905
|
-
|
|
34906
|
-
|
|
34974
|
+
# Strip outer wrapping tags if setting is enabled
|
|
34975
|
+
display_text = segment.target
|
|
34976
|
+
if self.hide_outer_wrapping_tags:
|
|
34977
|
+
display_text, _ = strip_outer_wrapping_tags(display_text)
|
|
34978
|
+
target_widget.setPlainText(display_text)
|
|
34979
|
+
|
|
34907
34980
|
# Update status column
|
|
34908
34981
|
status_item = self.table.item(current_row, 1)
|
|
34909
34982
|
if status_item:
|
|
34910
34983
|
status_item.setText("Translated")
|
|
34911
34984
|
status_item.setBackground(QColor("#d1fae5")) # Light green for translated
|
|
34912
|
-
|
|
34985
|
+
|
|
34913
34986
|
# Update project modified status (progress is handled by status bar)
|
|
34914
34987
|
self.log(f"✨ Auto-propagated 100% TM match for segment #{current_row + 1}")
|
|
34915
34988
|
|
|
@@ -35967,7 +36040,11 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
35967
36040
|
target_widget = self.table.cellWidget(row, 3)
|
|
35968
36041
|
if target_widget and hasattr(target_widget, 'setPlainText'):
|
|
35969
36042
|
target_widget.blockSignals(True)
|
|
35970
|
-
|
|
36043
|
+
# Strip outer wrapping tags if setting is enabled
|
|
36044
|
+
display_text = segment.target
|
|
36045
|
+
if self.hide_outer_wrapping_tags:
|
|
36046
|
+
display_text, _ = strip_outer_wrapping_tags(display_text)
|
|
36047
|
+
target_widget.setPlainText(display_text)
|
|
35971
36048
|
target_widget.blockSignals(False)
|
|
35972
36049
|
self.table.viewport().update()
|
|
35973
36050
|
|
|
@@ -36416,7 +36493,11 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
36416
36493
|
cell_widget = self.table.cellWidget(row, col)
|
|
36417
36494
|
if cell_widget and hasattr(cell_widget, 'setPlainText'):
|
|
36418
36495
|
cell_widget.blockSignals(True)
|
|
36419
|
-
|
|
36496
|
+
# Strip outer wrapping tags if setting is enabled
|
|
36497
|
+
display_text = new_text
|
|
36498
|
+
if self.hide_outer_wrapping_tags:
|
|
36499
|
+
display_text, _ = strip_outer_wrapping_tags(display_text)
|
|
36500
|
+
cell_widget.setPlainText(display_text)
|
|
36420
36501
|
cell_widget.blockSignals(False)
|
|
36421
36502
|
|
|
36422
36503
|
self.project_modified = True
|
|
@@ -37530,32 +37611,20 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
37530
37611
|
self.load_segments_to_grid()
|
|
37531
37612
|
|
|
37532
37613
|
def _refresh_source_column_display(self):
|
|
37533
|
-
"""Refresh
|
|
37614
|
+
"""Refresh grid to reflect hide_outer_wrapping_tags setting.
|
|
37615
|
+
|
|
37616
|
+
Reloads the entire grid to properly handle:
|
|
37617
|
+
- Tag stripping on both Source and Target columns
|
|
37618
|
+
- WYSIWYG list numbering/bullet prefixes
|
|
37619
|
+
- Proper list position calculation
|
|
37620
|
+
"""
|
|
37534
37621
|
if not hasattr(self, 'table') or not self.table:
|
|
37535
37622
|
return
|
|
37536
37623
|
if not hasattr(self, 'current_project') or not self.current_project:
|
|
37537
37624
|
return
|
|
37538
37625
|
|
|
37539
|
-
#
|
|
37540
|
-
|
|
37541
|
-
if row >= len(self.current_project.segments):
|
|
37542
|
-
continue
|
|
37543
|
-
|
|
37544
|
-
segment = self.current_project.segments[row]
|
|
37545
|
-
source_widget = self.table.cellWidget(row, 2)
|
|
37546
|
-
|
|
37547
|
-
if source_widget and hasattr(source_widget, 'setPlainText'):
|
|
37548
|
-
# Calculate display text with or without outer wrapping tags
|
|
37549
|
-
source_for_display = segment.source
|
|
37550
|
-
if self.hide_outer_wrapping_tags:
|
|
37551
|
-
stripped, _ = strip_outer_wrapping_tags(segment.source)
|
|
37552
|
-
source_for_display = stripped
|
|
37553
|
-
source_display_text = self.apply_invisible_replacements(source_for_display)
|
|
37554
|
-
source_widget.setPlainText(source_display_text)
|
|
37555
|
-
|
|
37556
|
-
# Re-apply highlighting
|
|
37557
|
-
if hasattr(source_widget, 'highlighter'):
|
|
37558
|
-
source_widget.highlighter.rehighlight()
|
|
37626
|
+
# Reload grid to apply changes with proper list numbering calculation
|
|
37627
|
+
self.load_segments_to_grid()
|
|
37559
37628
|
|
|
37560
37629
|
def apply_invisible_replacements(self, text):
|
|
37561
37630
|
"""Apply invisible character replacements to text based on settings"""
|
|
@@ -39518,13 +39587,19 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
39518
39587
|
if target_widget and isinstance(target_widget, QTextEdit):
|
|
39519
39588
|
from PyQt6.QtGui import QTextCursor
|
|
39520
39589
|
|
|
39590
|
+
# Strip outer wrapping tags for display if setting is enabled
|
|
39591
|
+
display_text = new_text
|
|
39592
|
+
if self.hide_outer_wrapping_tags:
|
|
39593
|
+
display_text, _ = strip_outer_wrapping_tags(display_text)
|
|
39594
|
+
|
|
39521
39595
|
cursor = target_widget.textCursor()
|
|
39522
39596
|
cursor.beginEditBlock()
|
|
39523
39597
|
cursor.select(QTextCursor.SelectionType.Document)
|
|
39524
|
-
cursor.insertText(
|
|
39598
|
+
cursor.insertText(display_text)
|
|
39525
39599
|
cursor.endEditBlock()
|
|
39526
39600
|
|
|
39527
|
-
|
|
39601
|
+
# Store full text (with tags) in segment, but use displayed text if tags are hidden
|
|
39602
|
+
segment.target = new_text # Keep full text with tags
|
|
39528
39603
|
target_widget.setFocus()
|
|
39529
39604
|
target_widget.moveCursor(QTextCursor.MoveOperation.End)
|
|
39530
39605
|
|
|
@@ -39536,7 +39611,11 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
39536
39611
|
# Fallback: no editor widget, update data and (if possible) update cell
|
|
39537
39612
|
segment.target = new_text
|
|
39538
39613
|
if target_widget and hasattr(target_widget, 'setPlainText'):
|
|
39539
|
-
|
|
39614
|
+
# Strip outer wrapping tags if setting is enabled
|
|
39615
|
+
display_text = new_text
|
|
39616
|
+
if self.hide_outer_wrapping_tags:
|
|
39617
|
+
display_text, _ = strip_outer_wrapping_tags(display_text)
|
|
39618
|
+
target_widget.setPlainText(display_text)
|
|
39540
39619
|
label = f" ({source_label})" if source_label else ""
|
|
39541
39620
|
self.log(f"✓ Replaced target text in segment {segment_id}{label}")
|
|
39542
39621
|
self._play_sound_effect('match_inserted')
|
|
@@ -40499,24 +40578,37 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
40499
40578
|
"""Refresh all visible cells to reflect current tag view mode"""
|
|
40500
40579
|
if not hasattr(self, 'table') or not self.current_project:
|
|
40501
40580
|
return
|
|
40502
|
-
|
|
40581
|
+
|
|
40503
40582
|
# Get current visible rows
|
|
40504
40583
|
for row in range(self.table.rowCount()):
|
|
40505
40584
|
# Get segment for this row
|
|
40506
40585
|
if row >= len(self.current_project.segments):
|
|
40507
40586
|
continue
|
|
40508
|
-
|
|
40587
|
+
|
|
40509
40588
|
segment = self.current_project.segments[row]
|
|
40510
|
-
|
|
40589
|
+
|
|
40590
|
+
# Apply tag stripping if enabled
|
|
40591
|
+
source_for_display = segment.source
|
|
40592
|
+
target_for_display = segment.target
|
|
40593
|
+
|
|
40594
|
+
if self.hide_outer_wrapping_tags:
|
|
40595
|
+
# Strip outer wrapping tags from source
|
|
40596
|
+
stripped_source, _ = strip_outer_wrapping_tags(segment.source)
|
|
40597
|
+
source_for_display = stripped_source
|
|
40598
|
+
|
|
40599
|
+
# Strip outer wrapping tags from target
|
|
40600
|
+
stripped_target, _ = strip_outer_wrapping_tags(segment.target)
|
|
40601
|
+
target_for_display = stripped_target
|
|
40602
|
+
|
|
40511
40603
|
# Update source cell (column 2)
|
|
40512
40604
|
source_widget = self.table.cellWidget(row, 2)
|
|
40513
40605
|
if source_widget and hasattr(source_widget, 'update_display_mode'):
|
|
40514
|
-
source_widget.update_display_mode(
|
|
40515
|
-
|
|
40606
|
+
source_widget.update_display_mode(source_for_display, self.show_tags)
|
|
40607
|
+
|
|
40516
40608
|
# Update target cell (column 3)
|
|
40517
40609
|
target_widget = self.table.cellWidget(row, 3)
|
|
40518
40610
|
if target_widget and hasattr(target_widget, 'update_display_mode'):
|
|
40519
|
-
target_widget.update_display_mode(
|
|
40611
|
+
target_widget.update_display_mode(target_for_display, self.show_tags)
|
|
40520
40612
|
|
|
40521
40613
|
def update_tab_segment_editor(self, segment_id: int, source_text: str, target_text: str,
|
|
40522
40614
|
status: str = "untranslated", notes: str = ""):
|
|
@@ -42038,15 +42130,20 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
42038
42130
|
tm_ids = self.tm_metadata_mgr.get_active_tm_ids(project_id)
|
|
42039
42131
|
|
|
42040
42132
|
try:
|
|
42133
|
+
# Strip outer structural tags if setting is enabled (for cleaner TM matching)
|
|
42134
|
+
search_source = segment.source
|
|
42135
|
+
if self.hide_outer_wrapping_tags:
|
|
42136
|
+
search_source, _ = strip_outer_wrapping_tags(search_source)
|
|
42137
|
+
|
|
42041
42138
|
if check_tm_exact_only:
|
|
42042
42139
|
# Use exact match only (faster - O(1) hash lookup)
|
|
42043
|
-
exact_match = self.tm_database.get_exact_match(
|
|
42140
|
+
exact_match = self.tm_database.get_exact_match(search_source, tm_ids=tm_ids)
|
|
42044
42141
|
if exact_match:
|
|
42045
42142
|
tm_match = exact_match.get('target_text', '')
|
|
42046
42143
|
self.log(f"✓ Found 100% TM match (exact) for segment #{segment.id}")
|
|
42047
42144
|
else:
|
|
42048
42145
|
# Use fuzzy search (includes 100% matches)
|
|
42049
|
-
matches = self.tm_database.search_all(
|
|
42146
|
+
matches = self.tm_database.search_all(search_source, tm_ids=tm_ids, enabled_only=False, max_matches=1)
|
|
42050
42147
|
if matches and matches[0].get('match_pct', 0) == 100:
|
|
42051
42148
|
tm_match = matches[0].get('target', '')
|
|
42052
42149
|
self.log(f"✓ Found 100% TM match for segment #{segment.id}")
|
|
@@ -43146,10 +43243,15 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43146
43243
|
|
|
43147
43244
|
try:
|
|
43148
43245
|
match = None
|
|
43149
|
-
|
|
43246
|
+
|
|
43247
|
+
# Strip outer structural tags if setting is enabled (for cleaner TM matching)
|
|
43248
|
+
search_source = segment.source
|
|
43249
|
+
if self.hide_outer_wrapping_tags:
|
|
43250
|
+
search_source, _ = strip_outer_wrapping_tags(search_source)
|
|
43251
|
+
|
|
43150
43252
|
if tm_exact_only:
|
|
43151
43253
|
# Exact match only - use hash lookup (fast)
|
|
43152
|
-
match = self.tm_database.get_exact_match(
|
|
43254
|
+
match = self.tm_database.get_exact_match(search_source, tm_ids=tm_ids)
|
|
43153
43255
|
print(f"DEBUG get_exact_match returned: type={type(match)}, value={match}")
|
|
43154
43256
|
if match and isinstance(match, dict):
|
|
43155
43257
|
segment.target = match.get('target_text', '')
|
|
@@ -43161,7 +43263,7 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43161
43263
|
else:
|
|
43162
43264
|
# Fuzzy matching enabled - get best match ≥75%
|
|
43163
43265
|
matches = self.tm_database.search_all(
|
|
43164
|
-
|
|
43266
|
+
search_source,
|
|
43165
43267
|
tm_ids=tm_ids,
|
|
43166
43268
|
enabled_only=False,
|
|
43167
43269
|
max_matches=1
|
|
@@ -43183,7 +43285,11 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43183
43285
|
if segment.target:
|
|
43184
43286
|
target_widget = self.table.cellWidget(row_index, 3)
|
|
43185
43287
|
if target_widget and isinstance(target_widget, EditableGridTextEditor):
|
|
43186
|
-
|
|
43288
|
+
# Strip outer wrapping tags if setting is enabled
|
|
43289
|
+
display_text = segment.target
|
|
43290
|
+
if self.hide_outer_wrapping_tags:
|
|
43291
|
+
display_text, _ = strip_outer_wrapping_tags(display_text)
|
|
43292
|
+
target_widget.setPlainText(display_text)
|
|
43187
43293
|
self.update_status_icon(row_index, segment.status)
|
|
43188
43294
|
QApplication.processEvents()
|
|
43189
43295
|
|
|
@@ -43252,11 +43358,15 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43252
43358
|
if success and current <= len(segments_needing_translation):
|
|
43253
43359
|
row_index, segment = segments_needing_translation[current - 1]
|
|
43254
43360
|
if row_index < self.table.rowCount():
|
|
43361
|
+
# Strip outer wrapping tags if setting is enabled
|
|
43362
|
+
display_text = segment.target
|
|
43363
|
+
if self.hide_outer_wrapping_tags:
|
|
43364
|
+
display_text, _ = strip_outer_wrapping_tags(display_text)
|
|
43255
43365
|
target_widget = self.table.cellWidget(row_index, 3)
|
|
43256
43366
|
if target_widget and isinstance(target_widget, EditableGridTextEditor):
|
|
43257
|
-
target_widget.setPlainText(
|
|
43367
|
+
target_widget.setPlainText(display_text)
|
|
43258
43368
|
else:
|
|
43259
|
-
self.table.setItem(row_index, 3, QTableWidgetItem(
|
|
43369
|
+
self.table.setItem(row_index, 3, QTableWidgetItem(display_text))
|
|
43260
43370
|
self.update_status_icon(row_index, segment.status)
|
|
43261
43371
|
|
|
43262
43372
|
def handle_translation_complete(final_success_count, final_error_count):
|
|
@@ -43424,9 +43534,14 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43424
43534
|
# Check each segment against TM
|
|
43425
43535
|
for row_index, segment in segments_to_translate:
|
|
43426
43536
|
try:
|
|
43537
|
+
# Strip outer structural tags if setting is enabled (for cleaner TM matching)
|
|
43538
|
+
search_source = segment.source
|
|
43539
|
+
if self.hide_outer_wrapping_tags:
|
|
43540
|
+
search_source, _ = strip_outer_wrapping_tags(search_source)
|
|
43541
|
+
|
|
43427
43542
|
if check_tm_exact_only:
|
|
43428
43543
|
# Use exact match only (faster - O(1) hash lookup)
|
|
43429
|
-
exact_match = self.tm_database.get_exact_match(
|
|
43544
|
+
exact_match = self.tm_database.get_exact_match(search_source, tm_ids=tm_ids)
|
|
43430
43545
|
if exact_match:
|
|
43431
43546
|
# Found 100% exact match - auto-insert it
|
|
43432
43547
|
tm_match = exact_match.get('target_text', '')
|
|
@@ -43450,7 +43565,7 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43450
43565
|
segments_needing_translation.append((row_index, segment))
|
|
43451
43566
|
else:
|
|
43452
43567
|
# Use fuzzy search (includes 100% matches)
|
|
43453
|
-
matches = self.tm_database.search_all(
|
|
43568
|
+
matches = self.tm_database.search_all(search_source, tm_ids=tm_ids, enabled_only=False, max_matches=1)
|
|
43454
43569
|
if matches and matches[0].get('match_pct', 0) == 100:
|
|
43455
43570
|
# Found 100% match - auto-insert it
|
|
43456
43571
|
tm_match = matches[0].get('target', '')
|
|
@@ -43529,8 +43644,13 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
43529
43644
|
# Translate each segment from TM
|
|
43530
43645
|
for row_index, segment in segments_needing_translation:
|
|
43531
43646
|
try:
|
|
43647
|
+
# Strip outer structural tags if setting is enabled (for cleaner TM matching)
|
|
43648
|
+
search_source = segment.source
|
|
43649
|
+
if self.hide_outer_wrapping_tags:
|
|
43650
|
+
search_source, _ = strip_outer_wrapping_tags(search_source)
|
|
43651
|
+
|
|
43532
43652
|
# Search TM for best match
|
|
43533
|
-
matches = self.tm_database.search_all(
|
|
43653
|
+
matches = self.tm_database.search_all(search_source, tm_ids=tm_ids, enabled_only=False, max_matches=1)
|
|
43534
43654
|
|
|
43535
43655
|
if matches and len(matches) > 0:
|
|
43536
43656
|
match = matches[0]
|
|
@@ -45336,8 +45456,12 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
45336
45456
|
if tm_ids is not None and isinstance(tm_ids, list) and len(tm_ids) == 0:
|
|
45337
45457
|
all_tm_matches = []
|
|
45338
45458
|
else:
|
|
45459
|
+
# Strip outer structural tags if setting is enabled (for cleaner TM matching)
|
|
45460
|
+
search_source = segment.source
|
|
45461
|
+
if self.hide_outer_wrapping_tags:
|
|
45462
|
+
search_source, _ = strip_outer_wrapping_tags(search_source)
|
|
45339
45463
|
# Search using TMDatabase (includes bidirectional + base language matching)
|
|
45340
|
-
all_tm_matches = self.tm_database.search_all(
|
|
45464
|
+
all_tm_matches = self.tm_database.search_all(search_source, tm_ids=tm_ids, enabled_only=False, max_matches=10)
|
|
45341
45465
|
|
|
45342
45466
|
# Single consolidated log message for TM search results
|
|
45343
45467
|
if all_tm_matches:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: supervertaler
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.202
|
|
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=yYljYTFunua83fL9AjIEWd5e4lO56lbwR6T3X9ZYcmU,2395306
|
|
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
|
|
@@ -80,9 +80,9 @@ modules/unified_prompt_manager_qt.py,sha256=y7xAIM9X7f1afXGE1tOcAc5EY7BKFy53Rgqi
|
|
|
80
80
|
modules/voice_commands.py,sha256=iBb-gjWxRMLhFH7-InSRjYJz1EIDBNA2Pog8V7TtJaY,38516
|
|
81
81
|
modules/voice_dictation.py,sha256=QmitXfkG-vRt5hIQATjphHdhXfqmwhzcQcbXB6aRzIg,16386
|
|
82
82
|
modules/voice_dictation_lite.py,sha256=jorY0BmWE-8VczbtGrWwt1zbnOctMoSlWOsQrcufBcc,9423
|
|
83
|
-
supervertaler-1.9.
|
|
84
|
-
supervertaler-1.9.
|
|
85
|
-
supervertaler-1.9.
|
|
86
|
-
supervertaler-1.9.
|
|
87
|
-
supervertaler-1.9.
|
|
88
|
-
supervertaler-1.9.
|
|
83
|
+
supervertaler-1.9.202.dist-info/licenses/LICENSE,sha256=m28u-4qL5nXIWnJ6xlQVw__H30rWFtRK3pCOais2OuY,1092
|
|
84
|
+
supervertaler-1.9.202.dist-info/METADATA,sha256=rxqzXM85xvLcu_qHvaiCKvLx1Nh3WJE28KdNaNuP-ro,5725
|
|
85
|
+
supervertaler-1.9.202.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
86
|
+
supervertaler-1.9.202.dist-info/entry_points.txt,sha256=NP4hiCvx-_30YYKqgr-jfJYQvHr1qTYBMfoVmKIXSM8,53
|
|
87
|
+
supervertaler-1.9.202.dist-info/top_level.txt,sha256=9tUHBYUSfaE4S2E4W3eavJsDyYymkwLfeWAHHAPT6Dk,22
|
|
88
|
+
supervertaler-1.9.202.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|