supervertaler 1.9.203__py3-none-any.whl → 1.9.205__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 +246 -89
- modules/ai_actions.py +14 -2
- modules/quicktrans.py +3 -0
- modules/termbase_entry_editor.py +9 -0
- modules/theme_manager.py +10 -1
- modules/translation_results_panel.py +6 -0
- modules/unified_prompt_manager_qt.py +206 -4
- modules/voice_dictation.py +9 -0
- {supervertaler-1.9.203.dist-info → supervertaler-1.9.205.dist-info}/METADATA +1 -1
- {supervertaler-1.9.203.dist-info → supervertaler-1.9.205.dist-info}/RECORD +14 -14
- {supervertaler-1.9.203.dist-info → supervertaler-1.9.205.dist-info}/WHEEL +0 -0
- {supervertaler-1.9.203.dist-info → supervertaler-1.9.205.dist-info}/entry_points.txt +0 -0
- {supervertaler-1.9.203.dist-info → supervertaler-1.9.205.dist-info}/licenses/LICENSE +0 -0
- {supervertaler-1.9.203.dist-info → supervertaler-1.9.205.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.204"
|
|
36
36
|
__phase__ = "0.9"
|
|
37
37
|
__release_date__ = "2026-02-03"
|
|
38
38
|
__edition__ = "Qt"
|
|
@@ -7945,19 +7945,36 @@ class SupervertalerQt(QMainWindow):
|
|
|
7945
7945
|
import_menu.addAction(import_review_table_action)
|
|
7946
7946
|
|
|
7947
7947
|
export_menu = file_menu.addMenu("&Export")
|
|
7948
|
-
|
|
7948
|
+
|
|
7949
|
+
# --- Monolingual (target-only) exports at top ---
|
|
7950
|
+
export_target_docx_action = QAction("&Target Only (DOCX)...", self)
|
|
7951
|
+
export_target_docx_action.triggered.connect(self.export_target_only_docx)
|
|
7952
|
+
export_menu.addAction(export_target_docx_action)
|
|
7953
|
+
|
|
7954
|
+
export_txt_action = QAction("Simple &Text File - Translated (TXT)...", self)
|
|
7955
|
+
export_txt_action.triggered.connect(self.export_simple_txt)
|
|
7956
|
+
export_menu.addAction(export_txt_action)
|
|
7957
|
+
|
|
7958
|
+
export_ai_action = QAction("📄 &AI-Readable Markdown (.md)...", self)
|
|
7959
|
+
export_ai_action.triggered.connect(self.export_bilingual_table_markdown)
|
|
7960
|
+
export_ai_action.setToolTip("Export segments in [SEGMENT] format for AI translation/review")
|
|
7961
|
+
export_menu.addAction(export_ai_action)
|
|
7962
|
+
|
|
7963
|
+
export_menu.addSeparator()
|
|
7964
|
+
|
|
7965
|
+
# --- Bilingual CAT tool exports ---
|
|
7949
7966
|
export_memoq_action = QAction("memoQ &Bilingual Table - Translated (DOCX)...", self)
|
|
7950
7967
|
export_memoq_action.triggered.connect(self.export_memoq_bilingual)
|
|
7951
7968
|
export_menu.addAction(export_memoq_action)
|
|
7952
|
-
|
|
7969
|
+
|
|
7953
7970
|
export_memoq_xliff_action = QAction("memoQ &XLIFF - Translated (.mqxliff)...", self)
|
|
7954
7971
|
export_memoq_xliff_action.triggered.connect(self.export_memoq_xliff)
|
|
7955
7972
|
export_menu.addAction(export_memoq_xliff_action)
|
|
7956
|
-
|
|
7973
|
+
|
|
7957
7974
|
export_cafetran_action = QAction("&CafeTran Bilingual Table - Translated (DOCX)...", self)
|
|
7958
7975
|
export_cafetran_action.triggered.connect(self.export_cafetran_bilingual)
|
|
7959
7976
|
export_menu.addAction(export_cafetran_action)
|
|
7960
|
-
|
|
7977
|
+
|
|
7961
7978
|
# Trados submenu - group all Trados exports together
|
|
7962
7979
|
trados_export_submenu = export_menu.addMenu("&Trados Studio")
|
|
7963
7980
|
|
|
@@ -7978,20 +7995,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
7978
7995
|
export_dejavu_action = QAction("&Déjà Vu X3 Bilingual - Translated (RTF)...", self)
|
|
7979
7996
|
export_dejavu_action.triggered.connect(self.export_dejavu_bilingual)
|
|
7980
7997
|
export_menu.addAction(export_dejavu_action)
|
|
7981
|
-
|
|
7982
|
-
export_target_docx_action = QAction("&Target Only (DOCX)...", self)
|
|
7983
|
-
export_target_docx_action.triggered.connect(self.export_target_only_docx)
|
|
7984
|
-
export_menu.addAction(export_target_docx_action)
|
|
7985
|
-
|
|
7986
|
-
export_txt_action = QAction("Simple &Text File - Translated (TXT)...", self)
|
|
7987
|
-
export_txt_action.triggered.connect(self.export_simple_txt)
|
|
7988
|
-
export_menu.addAction(export_txt_action)
|
|
7989
|
-
|
|
7990
|
-
export_ai_action = QAction("📄 &AI-Readable Markdown (.md)...", self)
|
|
7991
|
-
export_ai_action.triggered.connect(self.export_bilingual_table_markdown)
|
|
7992
|
-
export_ai_action.setToolTip("Export segments in [SEGMENT] format for AI translation/review")
|
|
7993
|
-
export_menu.addAction(export_ai_action)
|
|
7994
|
-
|
|
7998
|
+
|
|
7995
7999
|
export_menu.addSeparator()
|
|
7996
8000
|
|
|
7997
8001
|
# Multi-file folder export
|
|
@@ -9540,6 +9544,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
9540
9544
|
QPushButton:hover {
|
|
9541
9545
|
background-color: #2980b9;
|
|
9542
9546
|
}
|
|
9547
|
+
QPushButton:focus {
|
|
9548
|
+
outline: none;
|
|
9549
|
+
}
|
|
9543
9550
|
""")
|
|
9544
9551
|
extract_btn.clicked.connect(self._on_extract_images)
|
|
9545
9552
|
header_layout.addWidget(extract_btn)
|
|
@@ -11257,8 +11264,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
11257
11264
|
text = re.sub(r'</?li>', '', text) # <li>, </li>
|
|
11258
11265
|
text = re.sub(r'</?[biu]>', '', text) # <b>, </b>, <i>, </i>, <u>, </u>
|
|
11259
11266
|
text = re.sub(r'</?bi>', '', text) # <bi>, </bi>
|
|
11267
|
+
text = re.sub(r'</?sub>', '', text) # <sub>, </sub>
|
|
11268
|
+
text = re.sub(r'</?sup>', '', text) # <sup>, </sup>
|
|
11260
11269
|
return text.strip()
|
|
11261
|
-
|
|
11270
|
+
|
|
11262
11271
|
def clean_special_chars(text):
|
|
11263
11272
|
"""Remove problematic Unicode characters like object replacement char"""
|
|
11264
11273
|
# Remove Unicode Object Replacement Character (U+FFFC) and similar
|
|
@@ -11272,34 +11281,48 @@ class SupervertalerQt(QMainWindow):
|
|
|
11272
11281
|
"""
|
|
11273
11282
|
Replace paragraph text with tagged text, applying bold/italic/underline formatting.
|
|
11274
11283
|
Parses tags like <b>, <i>, <u>, <bi> and creates appropriate runs.
|
|
11284
|
+
Preserves original font name and size from the first run.
|
|
11275
11285
|
"""
|
|
11276
11286
|
# Clean special characters first
|
|
11277
11287
|
text = clean_special_chars(tagged_text)
|
|
11278
|
-
|
|
11288
|
+
|
|
11279
11289
|
# Strip list tags - they don't affect formatting
|
|
11280
11290
|
text = re.sub(r'</?li-[bo]>', '', text)
|
|
11281
11291
|
text = re.sub(r'</?li>', '', text)
|
|
11282
|
-
|
|
11292
|
+
|
|
11293
|
+
# Capture original font properties BEFORE clearing runs
|
|
11294
|
+
original_font_name = None
|
|
11295
|
+
original_font_size = None
|
|
11296
|
+
original_all_caps = None
|
|
11297
|
+
if para.runs:
|
|
11298
|
+
first_run = para.runs[0]
|
|
11299
|
+
if first_run.font:
|
|
11300
|
+
original_font_name = first_run.font.name
|
|
11301
|
+
original_font_size = first_run.font.size
|
|
11302
|
+
original_all_caps = first_run.font.all_caps
|
|
11303
|
+
|
|
11283
11304
|
# Clear existing runs
|
|
11284
11305
|
for run in para.runs:
|
|
11285
11306
|
run.clear()
|
|
11286
11307
|
# Remove the cleared runs
|
|
11287
11308
|
for run in list(para.runs):
|
|
11288
11309
|
run._element.getparent().remove(run._element)
|
|
11289
|
-
|
|
11310
|
+
|
|
11290
11311
|
# Parse tags and create runs with formatting
|
|
11291
11312
|
# Pattern matches tags or text between tags
|
|
11292
|
-
tag_pattern = re.compile(r'(</?(?:b|i|u|bi)>)')
|
|
11313
|
+
tag_pattern = re.compile(r'(</?(?:b|i|u|bi|sub|sup)>)')
|
|
11293
11314
|
parts = tag_pattern.split(text)
|
|
11294
|
-
|
|
11315
|
+
|
|
11295
11316
|
is_bold = False
|
|
11296
11317
|
is_italic = False
|
|
11297
11318
|
is_underline = False
|
|
11298
|
-
|
|
11319
|
+
is_subscript = False
|
|
11320
|
+
is_superscript = False
|
|
11321
|
+
|
|
11299
11322
|
for part in parts:
|
|
11300
11323
|
if not part:
|
|
11301
11324
|
continue
|
|
11302
|
-
|
|
11325
|
+
|
|
11303
11326
|
# Check if this is a tag
|
|
11304
11327
|
if part == '<b>':
|
|
11305
11328
|
is_bold = True
|
|
@@ -11319,6 +11342,14 @@ class SupervertalerQt(QMainWindow):
|
|
|
11319
11342
|
elif part == '</bi>':
|
|
11320
11343
|
is_bold = False
|
|
11321
11344
|
is_italic = False
|
|
11345
|
+
elif part == '<sub>':
|
|
11346
|
+
is_subscript = True
|
|
11347
|
+
elif part == '</sub>':
|
|
11348
|
+
is_subscript = False
|
|
11349
|
+
elif part == '<sup>':
|
|
11350
|
+
is_superscript = True
|
|
11351
|
+
elif part == '</sup>':
|
|
11352
|
+
is_superscript = False
|
|
11322
11353
|
else:
|
|
11323
11354
|
# This is text content - create a run with current formatting
|
|
11324
11355
|
if part.strip() or part: # Include whitespace
|
|
@@ -11326,6 +11357,17 @@ class SupervertalerQt(QMainWindow):
|
|
|
11326
11357
|
run.bold = is_bold
|
|
11327
11358
|
run.italic = is_italic
|
|
11328
11359
|
run.underline = is_underline
|
|
11360
|
+
if is_subscript:
|
|
11361
|
+
run.font.subscript = True
|
|
11362
|
+
if is_superscript:
|
|
11363
|
+
run.font.superscript = True
|
|
11364
|
+
# Restore original font properties
|
|
11365
|
+
if original_font_name:
|
|
11366
|
+
run.font.name = original_font_name
|
|
11367
|
+
if original_font_size:
|
|
11368
|
+
run.font.size = original_font_size
|
|
11369
|
+
if original_all_caps:
|
|
11370
|
+
run.font.all_caps = original_all_caps
|
|
11329
11371
|
|
|
11330
11372
|
# Build a mapping of source text (without tags) to raw target text (with tags)
|
|
11331
11373
|
text_map = {}
|
|
@@ -11338,16 +11380,14 @@ class SupervertalerQt(QMainWindow):
|
|
|
11338
11380
|
if source_clean and target_raw:
|
|
11339
11381
|
text_map[source_clean] = target_raw
|
|
11340
11382
|
|
|
11341
|
-
def
|
|
11342
|
-
"""Replace all matching segments in text,
|
|
11383
|
+
def replace_segments_in_text_with_tags(original_text, text_map):
|
|
11384
|
+
"""Replace all matching segments in text, preserving formatting tags."""
|
|
11343
11385
|
result = original_text
|
|
11344
11386
|
# Sort by length (longest first) to avoid partial replacement issues
|
|
11345
11387
|
for source_clean, target_raw in sorted(text_map.items(), key=lambda x: len(x[0]), reverse=True):
|
|
11346
11388
|
if source_clean in result:
|
|
11347
|
-
#
|
|
11348
|
-
|
|
11349
|
-
target_clean = clean_special_chars(target_clean)
|
|
11350
|
-
result = result.replace(source_clean, target_clean)
|
|
11389
|
+
# Keep target WITH tags for formatting preservation
|
|
11390
|
+
result = result.replace(source_clean, target_raw)
|
|
11351
11391
|
return result
|
|
11352
11392
|
|
|
11353
11393
|
replaced_count = 0
|
|
@@ -11363,17 +11403,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
11363
11403
|
replaced_count += 1
|
|
11364
11404
|
else:
|
|
11365
11405
|
# Try partial replacement (paragraph contains multiple segments)
|
|
11366
|
-
new_text =
|
|
11406
|
+
new_text = replace_segments_in_text_with_tags(para_text, text_map)
|
|
11367
11407
|
if new_text != para_text:
|
|
11368
|
-
# Text was changed -
|
|
11369
|
-
#
|
|
11370
|
-
|
|
11371
|
-
run.clear()
|
|
11372
|
-
for run in list(para.runs):
|
|
11373
|
-
run._element.getparent().remove(run._element)
|
|
11374
|
-
para.add_run(new_text)
|
|
11408
|
+
# Text was changed - use apply_formatted_text_to_paragraph
|
|
11409
|
+
# to preserve inline formatting tags (bold, italic, sub, sup, etc.)
|
|
11410
|
+
apply_formatted_text_to_paragraph(para, new_text)
|
|
11375
11411
|
replaced_count += 1
|
|
11376
|
-
|
|
11412
|
+
|
|
11377
11413
|
# Replace text in tables
|
|
11378
11414
|
for table in doc.tables:
|
|
11379
11415
|
for row in table.rows:
|
|
@@ -11388,15 +11424,12 @@ class SupervertalerQt(QMainWindow):
|
|
|
11388
11424
|
replaced_count += 1
|
|
11389
11425
|
else:
|
|
11390
11426
|
# Try partial replacement
|
|
11391
|
-
new_text =
|
|
11427
|
+
new_text = replace_segments_in_text_with_tags(para_text, text_map)
|
|
11392
11428
|
if new_text != para_text:
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
for run in list(para.runs):
|
|
11396
|
-
run._element.getparent().remove(run._element)
|
|
11397
|
-
para.add_run(new_text)
|
|
11429
|
+
# Use apply_formatted_text_to_paragraph to preserve formatting
|
|
11430
|
+
apply_formatted_text_to_paragraph(para, new_text)
|
|
11398
11431
|
replaced_count += 1
|
|
11399
|
-
|
|
11432
|
+
|
|
11400
11433
|
doc.save(file_path)
|
|
11401
11434
|
self.log(f"✓ Replaced {replaced_count} text segments in original document structure")
|
|
11402
11435
|
|
|
@@ -11412,8 +11445,10 @@ class SupervertalerQt(QMainWindow):
|
|
|
11412
11445
|
text = re.sub(r'</?li>', '', text) # <li>, </li>
|
|
11413
11446
|
text = re.sub(r'</?[biu]>', '', text) # <b>, </b>, <i>, </i>, <u>, </u>
|
|
11414
11447
|
text = re.sub(r'</?bi>', '', text) # <bi>, </bi>
|
|
11448
|
+
text = re.sub(r'</?sub>', '', text) # <sub>, </sub>
|
|
11449
|
+
text = re.sub(r'</?sup>', '', text) # <sup>, </sup>
|
|
11415
11450
|
return text.strip()
|
|
11416
|
-
|
|
11451
|
+
|
|
11417
11452
|
def clean_special_chars(text):
|
|
11418
11453
|
"""Remove problematic Unicode characters"""
|
|
11419
11454
|
text = text.replace('\ufffc', '') # Object Replacement Character
|
|
@@ -11432,13 +11467,15 @@ class SupervertalerQt(QMainWindow):
|
|
|
11432
11467
|
text = re.sub(r'</?li>', '', text)
|
|
11433
11468
|
|
|
11434
11469
|
# Parse and apply formatting
|
|
11435
|
-
tag_pattern = re.compile(r'(</?(?:b|i|u|bi)>)')
|
|
11470
|
+
tag_pattern = re.compile(r'(</?(?:b|i|u|bi|sub|sup)>)')
|
|
11436
11471
|
parts = tag_pattern.split(text)
|
|
11437
|
-
|
|
11472
|
+
|
|
11438
11473
|
is_bold = False
|
|
11439
11474
|
is_italic = False
|
|
11440
11475
|
is_underline = False
|
|
11441
|
-
|
|
11476
|
+
is_subscript = False
|
|
11477
|
+
is_superscript = False
|
|
11478
|
+
|
|
11442
11479
|
for part in parts:
|
|
11443
11480
|
if not part:
|
|
11444
11481
|
continue
|
|
@@ -11460,13 +11497,25 @@ class SupervertalerQt(QMainWindow):
|
|
|
11460
11497
|
elif part == '</bi>':
|
|
11461
11498
|
is_bold = False
|
|
11462
11499
|
is_italic = False
|
|
11500
|
+
elif part == '<sub>':
|
|
11501
|
+
is_subscript = True
|
|
11502
|
+
elif part == '</sub>':
|
|
11503
|
+
is_subscript = False
|
|
11504
|
+
elif part == '<sup>':
|
|
11505
|
+
is_superscript = True
|
|
11506
|
+
elif part == '</sup>':
|
|
11507
|
+
is_superscript = False
|
|
11463
11508
|
else:
|
|
11464
11509
|
if part:
|
|
11465
11510
|
run = para.add_run(part)
|
|
11466
11511
|
run.bold = is_bold
|
|
11467
11512
|
run.italic = is_italic
|
|
11468
11513
|
run.underline = is_underline
|
|
11469
|
-
|
|
11514
|
+
if is_subscript:
|
|
11515
|
+
run.font.subscript = True
|
|
11516
|
+
if is_superscript:
|
|
11517
|
+
run.font.superscript = True
|
|
11518
|
+
|
|
11470
11519
|
doc = Document()
|
|
11471
11520
|
|
|
11472
11521
|
for seg in segments:
|
|
@@ -21144,6 +21193,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
21144
21193
|
QPushButton:hover:!checked {
|
|
21145
21194
|
background-color: #858585;
|
|
21146
21195
|
}
|
|
21196
|
+
QPushButton:focus {
|
|
21197
|
+
outline: none;
|
|
21198
|
+
}
|
|
21147
21199
|
""")
|
|
21148
21200
|
wysiwyg_btn.clicked.connect(lambda: self.toggle_tag_view(False, None))
|
|
21149
21201
|
view_mode_group.addButton(wysiwyg_btn, 0)
|
|
@@ -21170,6 +21222,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
21170
21222
|
QPushButton:hover:!checked {
|
|
21171
21223
|
background-color: #858585;
|
|
21172
21224
|
}
|
|
21225
|
+
QPushButton:focus {
|
|
21226
|
+
outline: none;
|
|
21227
|
+
}
|
|
21173
21228
|
""")
|
|
21174
21229
|
tags_btn.clicked.connect(lambda: self.toggle_tag_view(True, None))
|
|
21175
21230
|
view_mode_group.addButton(tags_btn, 1)
|
|
@@ -21227,6 +21282,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
21227
21282
|
QPushButton:checked {
|
|
21228
21283
|
background-color: #2E7D32;
|
|
21229
21284
|
}
|
|
21285
|
+
QPushButton:focus {
|
|
21286
|
+
outline: none;
|
|
21287
|
+
}
|
|
21230
21288
|
""")
|
|
21231
21289
|
alwayson_btn.setToolTip("Toggle always-on voice listening\n\nWhen ON: Listens continuously for voice commands\nNo need to press F9")
|
|
21232
21290
|
alwayson_btn.clicked.connect(lambda checked: self._toggle_alwayson_from_grid_btn(checked, alwayson_btn))
|
|
@@ -21986,6 +22044,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
21986
22044
|
QPushButton:pressed {
|
|
21987
22045
|
background-color: #1565C0;
|
|
21988
22046
|
}
|
|
22047
|
+
QPushButton:focus {
|
|
22048
|
+
outline: none;
|
|
22049
|
+
}
|
|
21989
22050
|
""")
|
|
21990
22051
|
self.scroll_up_btn.setToolTip("Scroll up one row (Precision scroll)")
|
|
21991
22052
|
self.scroll_up_btn.clicked.connect(lambda: self.precision_scroll(-1))
|
|
@@ -22012,6 +22073,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
22012
22073
|
QPushButton:pressed {
|
|
22013
22074
|
background-color: #1565C0;
|
|
22014
22075
|
}
|
|
22076
|
+
QPushButton:focus {
|
|
22077
|
+
outline: none;
|
|
22078
|
+
}
|
|
22015
22079
|
""")
|
|
22016
22080
|
self.scroll_down_btn.setToolTip("Scroll down one row (Precision scroll)")
|
|
22017
22081
|
self.scroll_down_btn.clicked.connect(lambda: self.precision_scroll(1))
|
|
@@ -24632,6 +24696,11 @@ class SupervertalerQt(QMainWindow):
|
|
|
24632
24696
|
# Set as current project and load into grid
|
|
24633
24697
|
self.current_project = project
|
|
24634
24698
|
self.current_document_path = file_path # Store document path
|
|
24699
|
+
|
|
24700
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
24701
|
+
# This prevents old segments from being saved instead of new ones
|
|
24702
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
24703
|
+
|
|
24635
24704
|
self.load_segments_to_grid()
|
|
24636
24705
|
|
|
24637
24706
|
# Initialize TM for this project
|
|
@@ -24866,14 +24935,18 @@ class SupervertalerQt(QMainWindow):
|
|
|
24866
24935
|
# Set as current project and load into grid
|
|
24867
24936
|
self.current_project = project
|
|
24868
24937
|
self.current_document_path = file_path
|
|
24938
|
+
|
|
24939
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
24940
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
24941
|
+
|
|
24869
24942
|
self.load_segments_to_grid()
|
|
24870
|
-
|
|
24943
|
+
|
|
24871
24944
|
# Initialize TM for this project
|
|
24872
24945
|
self.initialize_tm_database()
|
|
24873
|
-
|
|
24946
|
+
|
|
24874
24947
|
# Initialize spellcheck for target language
|
|
24875
24948
|
self._initialize_spellcheck_for_target_language(target_lang)
|
|
24876
|
-
|
|
24949
|
+
|
|
24877
24950
|
# Update status
|
|
24878
24951
|
empty_count = sum(1 for seg in segments if not seg.source.strip())
|
|
24879
24952
|
file_type = "Markdown file" if is_markdown else "text file"
|
|
@@ -24933,6 +25006,8 @@ class SupervertalerQt(QMainWindow):
|
|
|
24933
25006
|
project.original_txt_path = file_path
|
|
24934
25007
|
self.current_project = project
|
|
24935
25008
|
self.current_document_path = file_path
|
|
25009
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
25010
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
24936
25011
|
self.load_segments_to_grid()
|
|
24937
25012
|
self.initialize_tm_database()
|
|
24938
25013
|
self.log(f"✓ Loaded {len(segments)} lines from text file")
|
|
@@ -26261,10 +26336,13 @@ class SupervertalerQt(QMainWindow):
|
|
|
26261
26336
|
# Set as current project
|
|
26262
26337
|
self.current_project = project
|
|
26263
26338
|
self.current_document_path = folder_path
|
|
26264
|
-
|
|
26339
|
+
|
|
26340
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
26341
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
26342
|
+
|
|
26265
26343
|
# Load into grid
|
|
26266
26344
|
self.load_segments_to_grid()
|
|
26267
|
-
|
|
26345
|
+
|
|
26268
26346
|
# Initialize TM
|
|
26269
26347
|
self.initialize_tm_database()
|
|
26270
26348
|
|
|
@@ -27137,10 +27215,14 @@ class SupervertalerQt(QMainWindow):
|
|
|
27137
27215
|
# Update UI
|
|
27138
27216
|
self.project_file_path = None
|
|
27139
27217
|
self.project_modified = True
|
|
27218
|
+
|
|
27219
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
27220
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
27221
|
+
|
|
27140
27222
|
self.update_window_title()
|
|
27141
27223
|
self.load_segments_to_grid()
|
|
27142
27224
|
self.initialize_tm_database()
|
|
27143
|
-
|
|
27225
|
+
|
|
27144
27226
|
# Deactivate all resources for new project, then auto-activate language-matching ones
|
|
27145
27227
|
self._deactivate_all_resources_for_new_project()
|
|
27146
27228
|
|
|
@@ -27153,7 +27235,7 @@ class SupervertalerQt(QMainWindow):
|
|
|
27153
27235
|
# If smart formatting was used, auto-enable Tags view so user sees the tags
|
|
27154
27236
|
if self.memoq_smart_formatting:
|
|
27155
27237
|
self._enable_tag_view_after_import()
|
|
27156
|
-
|
|
27238
|
+
|
|
27157
27239
|
self.log(f"✓ Imported memoQ bilingual DOCX: {len(source_segments)} segments from {Path(file_path).name}")
|
|
27158
27240
|
|
|
27159
27241
|
# Store current document path for AI Assistant
|
|
@@ -27646,10 +27728,14 @@ class SupervertalerQt(QMainWindow):
|
|
|
27646
27728
|
# Update UI
|
|
27647
27729
|
self.project_file_path = None
|
|
27648
27730
|
self.project_modified = True
|
|
27731
|
+
|
|
27732
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
27733
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
27734
|
+
|
|
27649
27735
|
self.update_window_title()
|
|
27650
27736
|
self.load_segments_to_grid()
|
|
27651
27737
|
self.initialize_tm_database()
|
|
27652
|
-
|
|
27738
|
+
|
|
27653
27739
|
# Deactivate all resources for new project, then auto-activate language-matching ones
|
|
27654
27740
|
self._deactivate_all_resources_for_new_project()
|
|
27655
27741
|
|
|
@@ -27925,10 +28011,14 @@ class SupervertalerQt(QMainWindow):
|
|
|
27925
28011
|
# Update UI
|
|
27926
28012
|
self.project_file_path = None
|
|
27927
28013
|
self.project_modified = True
|
|
28014
|
+
|
|
28015
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
28016
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
28017
|
+
|
|
27928
28018
|
self.update_window_title()
|
|
27929
28019
|
self.load_segments_to_grid()
|
|
27930
28020
|
self.initialize_tm_database()
|
|
27931
|
-
|
|
28021
|
+
|
|
27932
28022
|
# Deactivate all resources for new project, then auto-activate language-matching ones
|
|
27933
28023
|
self._deactivate_all_resources_for_new_project()
|
|
27934
28024
|
|
|
@@ -28146,6 +28236,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
28146
28236
|
# Store Trados source path in project for persistence across saves
|
|
28147
28237
|
self.current_project.trados_source_path = file_path
|
|
28148
28238
|
|
|
28239
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
28240
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
28241
|
+
|
|
28149
28242
|
# Sync global language settings with imported project languages
|
|
28150
28243
|
self.source_language = source_lang
|
|
28151
28244
|
self.target_language = target_lang
|
|
@@ -28510,6 +28603,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
28510
28603
|
self.sdlppx_source_file = file_path
|
|
28511
28604
|
self.current_project.sdlppx_source_path = file_path
|
|
28512
28605
|
|
|
28606
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
28607
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
28608
|
+
|
|
28513
28609
|
# Sync global language settings with imported project languages
|
|
28514
28610
|
self.source_language = source_lang
|
|
28515
28611
|
self.target_language = target_lang
|
|
@@ -28846,6 +28942,9 @@ class SupervertalerQt(QMainWindow):
|
|
|
28846
28942
|
# Store Phrase source path in project for persistence across saves
|
|
28847
28943
|
self.current_project.phrase_source_path = file_path
|
|
28848
28944
|
|
|
28945
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
28946
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
28947
|
+
|
|
28849
28948
|
# Sync global language settings with imported project languages
|
|
28850
28949
|
self.source_language = source_lang
|
|
28851
28950
|
self.target_language = target_lang
|
|
@@ -29148,20 +29247,23 @@ class SupervertalerQt(QMainWindow):
|
|
|
29148
29247
|
dejavu_row_index=seg_data.row_index,
|
|
29149
29248
|
)
|
|
29150
29249
|
self.current_project.segments.append(segment)
|
|
29151
|
-
|
|
29250
|
+
|
|
29251
|
+
# CRITICAL: Update _original_segment_order for new import
|
|
29252
|
+
self._original_segment_order = self.current_project.segments.copy()
|
|
29253
|
+
|
|
29152
29254
|
# Update UI
|
|
29153
29255
|
self.project_file_path = None
|
|
29154
29256
|
self.project_modified = True
|
|
29155
29257
|
self.update_window_title()
|
|
29156
29258
|
self.load_segments_to_grid()
|
|
29157
29259
|
self.initialize_tm_database()
|
|
29158
|
-
|
|
29260
|
+
|
|
29159
29261
|
# Auto-resize rows for better initial display
|
|
29160
29262
|
self.auto_resize_rows()
|
|
29161
|
-
|
|
29263
|
+
|
|
29162
29264
|
# Initialize spellcheck for target language
|
|
29163
29265
|
self._initialize_spellcheck_for_target_language(target_lang)
|
|
29164
|
-
|
|
29266
|
+
|
|
29165
29267
|
self.log(f"✓ Imported Déjà Vu X3 bilingual RTF: {len(segments_data)} segments from {Path(file_path).name}")
|
|
29166
29268
|
|
|
29167
29269
|
# Store current document path for AI Assistant
|
|
@@ -44559,12 +44661,25 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
44559
44661
|
|
|
44560
44662
|
translator = deepl.Translator(api_key)
|
|
44561
44663
|
|
|
44562
|
-
#
|
|
44563
|
-
|
|
44664
|
+
# Map full language names to ISO codes
|
|
44665
|
+
lang_name_to_code = {
|
|
44666
|
+
'english': 'en', 'dutch': 'nl', 'german': 'de', 'french': 'fr',
|
|
44667
|
+
'spanish': 'es', 'italian': 'it', 'portuguese': 'pt', 'russian': 'ru',
|
|
44668
|
+
'chinese': 'zh', 'japanese': 'ja', 'korean': 'ko', 'arabic': 'ar',
|
|
44669
|
+
'polish': 'pl', 'swedish': 'sv', 'norwegian': 'no', 'danish': 'da',
|
|
44670
|
+
'finnish': 'fi', 'greek': 'el', 'turkish': 'tr', 'czech': 'cs',
|
|
44671
|
+
'hungarian': 'hu', 'romanian': 'ro', 'bulgarian': 'bg', 'ukrainian': 'uk',
|
|
44672
|
+
}
|
|
44673
|
+
|
|
44674
|
+
# Convert source language - try name mapping first, then code extraction
|
|
44675
|
+
src_lower = source_lang.lower().strip()
|
|
44676
|
+
src_base = lang_name_to_code.get(src_lower, src_lower.split('-')[0].split('_')[0])
|
|
44677
|
+
src_code = src_base.upper()
|
|
44564
44678
|
|
|
44565
|
-
# Convert target language
|
|
44566
|
-
|
|
44567
|
-
|
|
44679
|
+
# Convert target language - try name mapping first, then handle DeepL variants
|
|
44680
|
+
tgt_lower = target_lang.lower().strip()
|
|
44681
|
+
tgt_base = lang_name_to_code.get(tgt_lower, tgt_lower)
|
|
44682
|
+
tgt_upper = tgt_base.upper().replace('_', '-')
|
|
44568
44683
|
|
|
44569
44684
|
# DeepL target language mapping - some require specific variants
|
|
44570
44685
|
deepl_target_map = {
|
|
@@ -44610,19 +44725,33 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
44610
44725
|
"""Call Microsoft Azure Translator API"""
|
|
44611
44726
|
try:
|
|
44612
44727
|
import requests
|
|
44613
|
-
|
|
44728
|
+
|
|
44614
44729
|
api_keys = self.load_api_keys()
|
|
44615
44730
|
if not api_key:
|
|
44616
44731
|
api_key = api_keys.get("microsoft_translate") or api_keys.get("azure_translate")
|
|
44617
44732
|
if not region:
|
|
44618
44733
|
region = api_keys.get("microsoft_translate_region") or api_keys.get("azure_region") or "global"
|
|
44619
|
-
|
|
44734
|
+
|
|
44620
44735
|
if not api_key:
|
|
44621
44736
|
return "[Microsoft Translator requires API key]"
|
|
44622
|
-
|
|
44623
|
-
#
|
|
44624
|
-
|
|
44625
|
-
|
|
44737
|
+
|
|
44738
|
+
# Map full language names to ISO codes
|
|
44739
|
+
lang_name_to_code = {
|
|
44740
|
+
'english': 'en', 'dutch': 'nl', 'german': 'de', 'french': 'fr',
|
|
44741
|
+
'spanish': 'es', 'italian': 'it', 'portuguese': 'pt', 'russian': 'ru',
|
|
44742
|
+
'chinese': 'zh', 'japanese': 'ja', 'korean': 'ko', 'arabic': 'ar',
|
|
44743
|
+
'polish': 'pl', 'swedish': 'sv', 'norwegian': 'no', 'danish': 'da',
|
|
44744
|
+
'finnish': 'fi', 'greek': 'el', 'turkish': 'tr', 'czech': 'cs',
|
|
44745
|
+
'hungarian': 'hu', 'romanian': 'ro', 'bulgarian': 'bg', 'ukrainian': 'uk',
|
|
44746
|
+
'hebrew': 'he', 'thai': 'th', 'vietnamese': 'vi', 'indonesian': 'id',
|
|
44747
|
+
}
|
|
44748
|
+
|
|
44749
|
+
# Convert language - try name mapping first, then code extraction
|
|
44750
|
+
src_lower = source_lang.lower().strip()
|
|
44751
|
+
tgt_lower = target_lang.lower().strip()
|
|
44752
|
+
|
|
44753
|
+
src_code = lang_name_to_code.get(src_lower, src_lower.split('-')[0].split('_')[0])
|
|
44754
|
+
tgt_code = lang_name_to_code.get(tgt_lower, tgt_lower.split('-')[0].split('_')[0])
|
|
44626
44755
|
|
|
44627
44756
|
# Microsoft Translator API v3.0
|
|
44628
44757
|
endpoint = f"https://api.cognitive.microsofttranslator.com/translate"
|
|
@@ -44710,17 +44839,30 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
44710
44839
|
"""Call ModernMT API"""
|
|
44711
44840
|
try:
|
|
44712
44841
|
import requests
|
|
44713
|
-
|
|
44842
|
+
|
|
44714
44843
|
api_keys = self.load_api_keys()
|
|
44715
44844
|
if not api_key:
|
|
44716
44845
|
api_key = api_keys.get("modernmt")
|
|
44717
|
-
|
|
44846
|
+
|
|
44718
44847
|
if not api_key:
|
|
44719
44848
|
return "[ModernMT requires API key]"
|
|
44720
|
-
|
|
44721
|
-
#
|
|
44722
|
-
|
|
44723
|
-
|
|
44849
|
+
|
|
44850
|
+
# Map full language names to ISO codes
|
|
44851
|
+
lang_name_to_code = {
|
|
44852
|
+
'english': 'en', 'dutch': 'nl', 'german': 'de', 'french': 'fr',
|
|
44853
|
+
'spanish': 'es', 'italian': 'it', 'portuguese': 'pt', 'russian': 'ru',
|
|
44854
|
+
'chinese': 'zh', 'japanese': 'ja', 'korean': 'ko', 'arabic': 'ar',
|
|
44855
|
+
'polish': 'pl', 'swedish': 'sv', 'norwegian': 'no', 'danish': 'da',
|
|
44856
|
+
'finnish': 'fi', 'greek': 'el', 'turkish': 'tr', 'czech': 'cs',
|
|
44857
|
+
'hungarian': 'hu', 'romanian': 'ro', 'bulgarian': 'bg', 'ukrainian': 'uk',
|
|
44858
|
+
}
|
|
44859
|
+
|
|
44860
|
+
# Convert language - try name mapping first, then code extraction
|
|
44861
|
+
src_lower = source_lang.lower().strip()
|
|
44862
|
+
tgt_lower = target_lang.lower().strip()
|
|
44863
|
+
|
|
44864
|
+
src_code = lang_name_to_code.get(src_lower, src_lower.split('-')[0].split('_')[0])
|
|
44865
|
+
tgt_code = lang_name_to_code.get(tgt_lower, tgt_lower.split('-')[0].split('_')[0])
|
|
44724
44866
|
|
|
44725
44867
|
# ModernMT API endpoint
|
|
44726
44868
|
url = "https://api.modernmt.com/translate"
|
|
@@ -44749,14 +44891,29 @@ OUTPUT ONLY THE SEGMENT MARKERS. DO NOT ADD EXPLANATIONS BEFORE OR AFTER."""
|
|
|
44749
44891
|
"""Call MyMemory Translation API (free tier available, simple REST API)"""
|
|
44750
44892
|
try:
|
|
44751
44893
|
import requests
|
|
44752
|
-
|
|
44894
|
+
|
|
44753
44895
|
# MyMemory is free, but API key provides higher limits
|
|
44754
44896
|
api_keys = self.load_api_keys()
|
|
44755
44897
|
api_key = api_key or api_keys.get("mymemory") # Optional, works without key
|
|
44756
|
-
|
|
44757
|
-
#
|
|
44758
|
-
|
|
44759
|
-
|
|
44898
|
+
|
|
44899
|
+
# Map full language names to ISO codes
|
|
44900
|
+
lang_name_to_code = {
|
|
44901
|
+
'english': 'en', 'dutch': 'nl', 'german': 'de', 'french': 'fr',
|
|
44902
|
+
'spanish': 'es', 'italian': 'it', 'portuguese': 'pt', 'russian': 'ru',
|
|
44903
|
+
'chinese': 'zh', 'japanese': 'ja', 'korean': 'ko', 'arabic': 'ar',
|
|
44904
|
+
'polish': 'pl', 'swedish': 'sv', 'norwegian': 'no', 'danish': 'da',
|
|
44905
|
+
'finnish': 'fi', 'greek': 'el', 'turkish': 'tr', 'czech': 'cs',
|
|
44906
|
+
'hungarian': 'hu', 'romanian': 'ro', 'bulgarian': 'bg', 'ukrainian': 'uk',
|
|
44907
|
+
'hebrew': 'he', 'thai': 'th', 'vietnamese': 'vi', 'indonesian': 'id',
|
|
44908
|
+
'malay': 'ms', 'hindi': 'hi', 'bengali': 'bn', 'tamil': 'ta',
|
|
44909
|
+
}
|
|
44910
|
+
|
|
44911
|
+
# Convert language - try name mapping first, then code extraction
|
|
44912
|
+
src_lower = source_lang.lower().strip()
|
|
44913
|
+
tgt_lower = target_lang.lower().strip()
|
|
44914
|
+
|
|
44915
|
+
src_code = lang_name_to_code.get(src_lower, src_lower.split('-')[0].split('_')[0])
|
|
44916
|
+
tgt_code = lang_name_to_code.get(tgt_lower, tgt_lower.split('-')[0].split('_')[0])
|
|
44760
44917
|
|
|
44761
44918
|
# MyMemory API endpoint
|
|
44762
44919
|
url = "https://api.mymemory.translated.net/get"
|
modules/ai_actions.py
CHANGED
|
@@ -168,9 +168,10 @@ class AIActionSystem:
|
|
|
168
168
|
|
|
169
169
|
except json.JSONDecodeError as e:
|
|
170
170
|
self.log(f"✗ Failed to parse action parameters: {e}")
|
|
171
|
+
self.log(f"[DEBUG] Raw params_str: {params_str[:500]}...") # Log what we tried to parse
|
|
171
172
|
action_results.append({
|
|
172
173
|
'action': action_name,
|
|
173
|
-
'params': params_str,
|
|
174
|
+
'params': params_str[:200], # Truncate for display
|
|
174
175
|
'success': False,
|
|
175
176
|
'error': f"Invalid JSON parameters: {e}"
|
|
176
177
|
})
|
|
@@ -325,7 +326,15 @@ class AIActionSystem:
|
|
|
325
326
|
content = params.get('content')
|
|
326
327
|
|
|
327
328
|
if not name or not content:
|
|
328
|
-
|
|
329
|
+
# Log what we actually received for debugging
|
|
330
|
+
self.log(f"[DEBUG] create_prompt received params: {params}")
|
|
331
|
+
self.log(f"[DEBUG] name={repr(name)}, content={repr(content)[:100] if content else None}")
|
|
332
|
+
missing = []
|
|
333
|
+
if not name:
|
|
334
|
+
missing.append("name")
|
|
335
|
+
if not content:
|
|
336
|
+
missing.append("content")
|
|
337
|
+
raise ValueError(f"Missing required parameters: {', '.join(missing)}. Received keys: {list(params.keys())}")
|
|
329
338
|
|
|
330
339
|
# Build relative path
|
|
331
340
|
folder = params.get('folder', '')
|
|
@@ -960,5 +969,8 @@ PARAMS: {
|
|
|
960
969
|
output += "\n"
|
|
961
970
|
else:
|
|
962
971
|
output += f"\n✗ **{action_name}**: {result['error']}\n"
|
|
972
|
+
# Show hint for common errors
|
|
973
|
+
if 'Missing required parameters' in result['error']:
|
|
974
|
+
output += " _Hint: The AI may not have generated the correct format. Try clicking the button again._\n"
|
|
963
975
|
|
|
964
976
|
return output
|
modules/quicktrans.py
CHANGED
modules/termbase_entry_editor.py
CHANGED
|
@@ -447,6 +447,9 @@ class TermbaseEntryEditor(QDialog):
|
|
|
447
447
|
QPushButton:hover {
|
|
448
448
|
background-color: #d32f2f;
|
|
449
449
|
}
|
|
450
|
+
QPushButton:focus {
|
|
451
|
+
outline: none;
|
|
452
|
+
}
|
|
450
453
|
""")
|
|
451
454
|
self.delete_btn.clicked.connect(self.delete_term)
|
|
452
455
|
buttons_layout.addWidget(self.delete_btn)
|
|
@@ -465,6 +468,9 @@ class TermbaseEntryEditor(QDialog):
|
|
|
465
468
|
QPushButton:hover {
|
|
466
469
|
background-color: #e0e0e0;
|
|
467
470
|
}
|
|
471
|
+
QPushButton:focus {
|
|
472
|
+
outline: none;
|
|
473
|
+
}
|
|
468
474
|
""")
|
|
469
475
|
self.cancel_btn.clicked.connect(self.reject)
|
|
470
476
|
buttons_layout.addWidget(self.cancel_btn)
|
|
@@ -483,6 +489,9 @@ class TermbaseEntryEditor(QDialog):
|
|
|
483
489
|
QPushButton:hover {
|
|
484
490
|
background-color: #45a049;
|
|
485
491
|
}
|
|
492
|
+
QPushButton:focus {
|
|
493
|
+
outline: none;
|
|
494
|
+
}
|
|
486
495
|
""")
|
|
487
496
|
self.save_btn.clicked.connect(self.save_term)
|
|
488
497
|
buttons_layout.addWidget(self.save_btn)
|
modules/theme_manager.py
CHANGED
|
@@ -370,7 +370,16 @@ class ThemeManager:
|
|
|
370
370
|
QPushButton:disabled {{
|
|
371
371
|
color: {theme.text_disabled};
|
|
372
372
|
}}
|
|
373
|
-
|
|
373
|
+
|
|
374
|
+
/* Remove focus rectangles from buttons */
|
|
375
|
+
QPushButton:focus {{
|
|
376
|
+
outline: none;
|
|
377
|
+
}}
|
|
378
|
+
|
|
379
|
+
QToolButton:focus {{
|
|
380
|
+
outline: none;
|
|
381
|
+
}}
|
|
382
|
+
|
|
374
383
|
/* Combo boxes */
|
|
375
384
|
QComboBox {{
|
|
376
385
|
background-color: {theme.base};
|
|
@@ -1190,6 +1190,9 @@ class TranslationResultsPanel(QWidget):
|
|
|
1190
1190
|
QPushButton:hover {
|
|
1191
1191
|
background-color: #0b7dda;
|
|
1192
1192
|
}
|
|
1193
|
+
QPushButton:focus {
|
|
1194
|
+
outline: none;
|
|
1195
|
+
}
|
|
1193
1196
|
""")
|
|
1194
1197
|
self.termbase_refresh_btn.setFixedHeight(20)
|
|
1195
1198
|
self.termbase_refresh_btn.setToolTip("Refresh entry from database")
|
|
@@ -1210,6 +1213,9 @@ class TranslationResultsPanel(QWidget):
|
|
|
1210
1213
|
QPushButton:hover {
|
|
1211
1214
|
background-color: #45a049;
|
|
1212
1215
|
}
|
|
1216
|
+
QPushButton:focus {
|
|
1217
|
+
outline: none;
|
|
1218
|
+
}
|
|
1213
1219
|
""")
|
|
1214
1220
|
self.termbase_edit_btn.setFixedHeight(20)
|
|
1215
1221
|
self.termbase_edit_btn.clicked.connect(self._on_edit_termbase_entry)
|
|
@@ -595,6 +595,10 @@ class UnifiedPromptManagerQt:
|
|
|
595
595
|
log_callback=self.log_message
|
|
596
596
|
)
|
|
597
597
|
|
|
598
|
+
# Context inclusion toggles for AI Assistant
|
|
599
|
+
self.include_tm_data = False
|
|
600
|
+
self.include_termbase_data = False
|
|
601
|
+
|
|
598
602
|
self._init_llm_client()
|
|
599
603
|
self._load_conversation_history()
|
|
600
604
|
self._load_persisted_attachments()
|
|
@@ -824,6 +828,9 @@ class UnifiedPromptManagerQt:
|
|
|
824
828
|
QPushButton:pressed {
|
|
825
829
|
background-color: #0D47A1;
|
|
826
830
|
}
|
|
831
|
+
QPushButton:focus {
|
|
832
|
+
outline: none;
|
|
833
|
+
}
|
|
827
834
|
""")
|
|
828
835
|
action_btn.clicked.connect(self._analyze_and_generate)
|
|
829
836
|
layout.addWidget(action_btn, 0)
|
|
@@ -1046,14 +1053,16 @@ class UnifiedPromptManagerQt:
|
|
|
1046
1053
|
"Click to include TM data"
|
|
1047
1054
|
)
|
|
1048
1055
|
self.context_tms.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
1056
|
+
self.context_tms.mousePressEvent = lambda e: self._toggle_tm_inclusion()
|
|
1049
1057
|
content_layout.addWidget(self.context_tms)
|
|
1050
|
-
|
|
1058
|
+
|
|
1051
1059
|
# Termbases
|
|
1052
1060
|
self.context_termbases = self._create_context_section(
|
|
1053
1061
|
"📚 Termbases",
|
|
1054
1062
|
"Click to include termbase data"
|
|
1055
1063
|
)
|
|
1056
1064
|
self.context_termbases.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
1065
|
+
self.context_termbases.mousePressEvent = lambda e: self._toggle_termbase_inclusion()
|
|
1057
1066
|
content_layout.addWidget(self.context_termbases)
|
|
1058
1067
|
|
|
1059
1068
|
content_layout.addStretch()
|
|
@@ -1094,6 +1103,95 @@ class UnifiedPromptManagerQt:
|
|
|
1094
1103
|
|
|
1095
1104
|
return frame
|
|
1096
1105
|
|
|
1106
|
+
def _toggle_tm_inclusion(self):
|
|
1107
|
+
"""Toggle inclusion of TM data in AI context"""
|
|
1108
|
+
self.include_tm_data = not self.include_tm_data
|
|
1109
|
+
self._update_tm_section_display()
|
|
1110
|
+
|
|
1111
|
+
# Show feedback
|
|
1112
|
+
status = "enabled" if self.include_tm_data else "disabled"
|
|
1113
|
+
self._add_chat_message("system", f"💾 Translation Memory inclusion **{status}**")
|
|
1114
|
+
|
|
1115
|
+
def _toggle_termbase_inclusion(self):
|
|
1116
|
+
"""Toggle inclusion of termbase data in AI context"""
|
|
1117
|
+
self.include_termbase_data = not self.include_termbase_data
|
|
1118
|
+
self._update_termbase_section_display()
|
|
1119
|
+
|
|
1120
|
+
# Show feedback
|
|
1121
|
+
status = "enabled" if self.include_termbase_data else "disabled"
|
|
1122
|
+
self._add_chat_message("system", f"📚 Termbase inclusion **{status}**")
|
|
1123
|
+
|
|
1124
|
+
def _update_tm_section_display(self):
|
|
1125
|
+
"""Update TM section visual state"""
|
|
1126
|
+
if self.include_tm_data:
|
|
1127
|
+
self.context_tms.setStyleSheet("""
|
|
1128
|
+
QFrame {
|
|
1129
|
+
background-color: #E3F2FD;
|
|
1130
|
+
border: 2px solid #1976D2;
|
|
1131
|
+
border-radius: 5px;
|
|
1132
|
+
padding: 8px;
|
|
1133
|
+
}
|
|
1134
|
+
""")
|
|
1135
|
+
# Update description label
|
|
1136
|
+
for child in self.context_tms.findChildren(QLabel):
|
|
1137
|
+
if "Click to" in child.text() or "✓" in child.text():
|
|
1138
|
+
child.setText("✓ TM data will be included")
|
|
1139
|
+
child.setStyleSheet("color: #1976D2; font-size: 8pt; font-weight: bold;")
|
|
1140
|
+
break
|
|
1141
|
+
else:
|
|
1142
|
+
self.context_tms.setStyleSheet("""
|
|
1143
|
+
QFrame {
|
|
1144
|
+
background-color: #F5F5F5;
|
|
1145
|
+
border: 1px solid #E0E0E0;
|
|
1146
|
+
border-radius: 5px;
|
|
1147
|
+
padding: 8px;
|
|
1148
|
+
}
|
|
1149
|
+
QFrame:hover {
|
|
1150
|
+
background-color: #EEEEEE;
|
|
1151
|
+
border: 1px solid #BDBDBD;
|
|
1152
|
+
}
|
|
1153
|
+
""")
|
|
1154
|
+
for child in self.context_tms.findChildren(QLabel):
|
|
1155
|
+
if "✓" in child.text() or "Click to" in child.text():
|
|
1156
|
+
child.setText("Click to include TM data")
|
|
1157
|
+
child.setStyleSheet("color: #666; font-size: 8pt;")
|
|
1158
|
+
break
|
|
1159
|
+
|
|
1160
|
+
def _update_termbase_section_display(self):
|
|
1161
|
+
"""Update termbase section visual state"""
|
|
1162
|
+
if self.include_termbase_data:
|
|
1163
|
+
self.context_termbases.setStyleSheet("""
|
|
1164
|
+
QFrame {
|
|
1165
|
+
background-color: #E8F5E9;
|
|
1166
|
+
border: 2px solid #4CAF50;
|
|
1167
|
+
border-radius: 5px;
|
|
1168
|
+
padding: 8px;
|
|
1169
|
+
}
|
|
1170
|
+
""")
|
|
1171
|
+
for child in self.context_termbases.findChildren(QLabel):
|
|
1172
|
+
if "Click to" in child.text() or "✓" in child.text():
|
|
1173
|
+
child.setText("✓ Termbase data will be included")
|
|
1174
|
+
child.setStyleSheet("color: #4CAF50; font-size: 8pt; font-weight: bold;")
|
|
1175
|
+
break
|
|
1176
|
+
else:
|
|
1177
|
+
self.context_termbases.setStyleSheet("""
|
|
1178
|
+
QFrame {
|
|
1179
|
+
background-color: #F5F5F5;
|
|
1180
|
+
border: 1px solid #E0E0E0;
|
|
1181
|
+
border-radius: 5px;
|
|
1182
|
+
padding: 8px;
|
|
1183
|
+
}
|
|
1184
|
+
QFrame:hover {
|
|
1185
|
+
background-color: #EEEEEE;
|
|
1186
|
+
border: 1px solid #BDBDBD;
|
|
1187
|
+
}
|
|
1188
|
+
""")
|
|
1189
|
+
for child in self.context_termbases.findChildren(QLabel):
|
|
1190
|
+
if "✓" in child.text() or "Click to" in child.text():
|
|
1191
|
+
child.setText("Click to include termbase data")
|
|
1192
|
+
child.setStyleSheet("color: #666; font-size: 8pt;")
|
|
1193
|
+
break
|
|
1194
|
+
|
|
1097
1195
|
def _create_attached_files_section(self) -> QFrame:
|
|
1098
1196
|
"""Create expandable attached files section with view/remove buttons"""
|
|
1099
1197
|
frame = QFrame()
|
|
@@ -1125,6 +1223,9 @@ class UnifiedPromptManagerQt:
|
|
|
1125
1223
|
QPushButton:hover {
|
|
1126
1224
|
background-color: #E0E0E0;
|
|
1127
1225
|
}
|
|
1226
|
+
QPushButton:focus {
|
|
1227
|
+
outline: none;
|
|
1228
|
+
}
|
|
1128
1229
|
""")
|
|
1129
1230
|
self.attached_files_expand_btn.clicked.connect(self._toggle_attached_files)
|
|
1130
1231
|
header_layout.addWidget(self.attached_files_expand_btn)
|
|
@@ -1149,6 +1250,9 @@ class UnifiedPromptManagerQt:
|
|
|
1149
1250
|
QPushButton:hover {
|
|
1150
1251
|
background-color: #1565C0;
|
|
1151
1252
|
}
|
|
1253
|
+
QPushButton:focus {
|
|
1254
|
+
outline: none;
|
|
1255
|
+
}
|
|
1152
1256
|
""")
|
|
1153
1257
|
attach_btn.clicked.connect(self._attach_file)
|
|
1154
1258
|
header_layout.addWidget(attach_btn)
|
|
@@ -1253,6 +1357,9 @@ class UnifiedPromptManagerQt:
|
|
|
1253
1357
|
QPushButton:hover {
|
|
1254
1358
|
background-color: #1565C0;
|
|
1255
1359
|
}
|
|
1360
|
+
QPushButton:focus {
|
|
1361
|
+
outline: none;
|
|
1362
|
+
}
|
|
1256
1363
|
""")
|
|
1257
1364
|
view_btn.clicked.connect(lambda: self._view_file(file_data))
|
|
1258
1365
|
btn_layout.addWidget(view_btn)
|
|
@@ -1270,6 +1377,9 @@ class UnifiedPromptManagerQt:
|
|
|
1270
1377
|
QPushButton:hover {
|
|
1271
1378
|
background-color: #b71c1c;
|
|
1272
1379
|
}
|
|
1380
|
+
QPushButton:focus {
|
|
1381
|
+
outline: none;
|
|
1382
|
+
}
|
|
1273
1383
|
""")
|
|
1274
1384
|
remove_btn.clicked.connect(lambda: self._remove_file(file_data))
|
|
1275
1385
|
btn_layout.addWidget(remove_btn)
|
|
@@ -1405,6 +1515,9 @@ class UnifiedPromptManagerQt:
|
|
|
1405
1515
|
QPushButton:pressed {
|
|
1406
1516
|
background-color: #424242;
|
|
1407
1517
|
}
|
|
1518
|
+
QPushButton:focus {
|
|
1519
|
+
outline: none;
|
|
1520
|
+
}
|
|
1408
1521
|
""")
|
|
1409
1522
|
clear_btn.clicked.connect(self._clear_chat)
|
|
1410
1523
|
toolbar_layout.addWidget(clear_btn)
|
|
@@ -1456,6 +1569,9 @@ class UnifiedPromptManagerQt:
|
|
|
1456
1569
|
QPushButton:pressed {
|
|
1457
1570
|
background-color: #0D47A1;
|
|
1458
1571
|
}
|
|
1572
|
+
QPushButton:focus {
|
|
1573
|
+
outline: none;
|
|
1574
|
+
}
|
|
1459
1575
|
""")
|
|
1460
1576
|
send_btn.clicked.connect(self._send_chat_message)
|
|
1461
1577
|
input_layout.addWidget(send_btn)
|
|
@@ -3217,9 +3333,17 @@ If the text refers to figures (e.g., 'Figure 1A'), relevant images may be provid
|
|
|
3217
3333
|
PROJECT CONTEXT:
|
|
3218
3334
|
{context}
|
|
3219
3335
|
|
|
3220
|
-
|
|
3336
|
+
**CRITICAL INSTRUCTIONS:**
|
|
3337
|
+
1. You MUST output exactly ONE ACTION block in the following format
|
|
3338
|
+
2. The JSON MUST be valid and complete
|
|
3339
|
+
3. Both "name" and "content" are REQUIRED fields
|
|
3340
|
+
|
|
3341
|
+
**EXACT FORMAT TO USE:**
|
|
3221
3342
|
|
|
3222
|
-
ACTION:create_prompt PARAMS:{{"name": "
|
|
3343
|
+
ACTION:create_prompt PARAMS:{{"name": "Your Prompt Name Here", "content": "Your full prompt content here", "folder": "Project Prompts", "description": "Auto-generated prompt", "activate": true}}
|
|
3344
|
+
|
|
3345
|
+
**EXAMPLE:**
|
|
3346
|
+
ACTION:create_prompt PARAMS:{{"name": "Legal Translation EN-NL", "content": "You are an expert legal translator...\\n\\n# TERMINOLOGY\\n| Source | Target |\\n...", "folder": "Project Prompts", "description": "Auto-generated", "activate": true}}
|
|
3223
3347
|
|
|
3224
3348
|
Prompt must include:
|
|
3225
3349
|
|
|
@@ -3317,6 +3441,18 @@ Output complete ACTION."""
|
|
|
3317
3441
|
preview = file['content'][:200].replace('\n', ' ')
|
|
3318
3442
|
context_parts.append(f" Preview: {preview}...")
|
|
3319
3443
|
|
|
3444
|
+
# Translation Memory data (if enabled)
|
|
3445
|
+
if self.include_tm_data:
|
|
3446
|
+
tm_data = self._get_tm_context_data()
|
|
3447
|
+
if tm_data:
|
|
3448
|
+
context_parts.append(f"\n**Translation Memory Matches:**\n{tm_data}")
|
|
3449
|
+
|
|
3450
|
+
# Termbase data (if enabled)
|
|
3451
|
+
if self.include_termbase_data:
|
|
3452
|
+
tb_data = self._get_termbase_context_data()
|
|
3453
|
+
if tb_data:
|
|
3454
|
+
context_parts.append(f"\n**Termbase Entries:**\n{tb_data}")
|
|
3455
|
+
|
|
3320
3456
|
return "\n".join(context_parts) if context_parts else "No context available"
|
|
3321
3457
|
|
|
3322
3458
|
def _list_available_prompts(self) -> str:
|
|
@@ -3334,7 +3470,73 @@ Output complete ACTION."""
|
|
|
3334
3470
|
lines.append(f"... and {len(self.library.prompts) - 20} more")
|
|
3335
3471
|
|
|
3336
3472
|
return "\n".join(lines)
|
|
3337
|
-
|
|
3473
|
+
|
|
3474
|
+
def _get_tm_context_data(self) -> str:
|
|
3475
|
+
"""Get Translation Memory data for AI context"""
|
|
3476
|
+
try:
|
|
3477
|
+
if not hasattr(self.parent_app, 'tm_databases') or not self.parent_app.tm_databases:
|
|
3478
|
+
return "No translation memories loaded"
|
|
3479
|
+
|
|
3480
|
+
lines = []
|
|
3481
|
+
total_entries = 0
|
|
3482
|
+
|
|
3483
|
+
for tm_name, tm_db in self.parent_app.tm_databases.items():
|
|
3484
|
+
if hasattr(tm_db, 'entries'):
|
|
3485
|
+
count = len(tm_db.entries)
|
|
3486
|
+
total_entries += count
|
|
3487
|
+
lines.append(f"- **{tm_name}**: {count} entries")
|
|
3488
|
+
|
|
3489
|
+
# Show sample entries (first 10)
|
|
3490
|
+
for i, entry in enumerate(list(tm_db.entries.values())[:10]):
|
|
3491
|
+
if hasattr(entry, 'source') and hasattr(entry, 'target'):
|
|
3492
|
+
lines.append(f" {i+1}. {entry.source[:50]}... → {entry.target[:50]}...")
|
|
3493
|
+
|
|
3494
|
+
if not lines:
|
|
3495
|
+
return "Translation memories are empty"
|
|
3496
|
+
|
|
3497
|
+
return f"Total: {total_entries} TM entries\n" + "\n".join(lines)
|
|
3498
|
+
|
|
3499
|
+
except Exception as e:
|
|
3500
|
+
return f"Error loading TM data: {e}"
|
|
3501
|
+
|
|
3502
|
+
def _get_termbase_context_data(self) -> str:
|
|
3503
|
+
"""Get Termbase data for AI context"""
|
|
3504
|
+
try:
|
|
3505
|
+
if not hasattr(self.parent_app, 'termbases') or not self.parent_app.termbases:
|
|
3506
|
+
# Try to get termbase entries from the termbase manager
|
|
3507
|
+
if hasattr(self.parent_app, 'termbase_manager'):
|
|
3508
|
+
terms = self.parent_app.termbase_manager.get_all_terms()
|
|
3509
|
+
if terms:
|
|
3510
|
+
lines = [f"Total: {len(terms)} termbase entries\n"]
|
|
3511
|
+
for i, term in enumerate(terms[:50]): # First 50 terms
|
|
3512
|
+
source = term.get('source_term', term.get('source', ''))
|
|
3513
|
+
target = term.get('target_term', term.get('target', ''))
|
|
3514
|
+
if source and target:
|
|
3515
|
+
lines.append(f"| {source} | {target} |")
|
|
3516
|
+
return "\n".join(lines)
|
|
3517
|
+
return "No termbases loaded"
|
|
3518
|
+
|
|
3519
|
+
lines = []
|
|
3520
|
+
total_terms = 0
|
|
3521
|
+
|
|
3522
|
+
for tb_name, tb in self.parent_app.termbases.items():
|
|
3523
|
+
if hasattr(tb, 'terms'):
|
|
3524
|
+
count = len(tb.terms)
|
|
3525
|
+
total_terms += count
|
|
3526
|
+
lines.append(f"- **{tb_name}**: {count} terms")
|
|
3527
|
+
|
|
3528
|
+
# Show sample terms (first 20)
|
|
3529
|
+
for i, (source, target) in enumerate(list(tb.terms.items())[:20]):
|
|
3530
|
+
lines.append(f" | {source} | {target} |")
|
|
3531
|
+
|
|
3532
|
+
if not lines:
|
|
3533
|
+
return "Termbases are empty"
|
|
3534
|
+
|
|
3535
|
+
return f"Total: {total_terms} terms\n" + "\n".join(lines)
|
|
3536
|
+
|
|
3537
|
+
except Exception as e:
|
|
3538
|
+
return f"Error loading termbase data: {e}"
|
|
3539
|
+
|
|
3338
3540
|
def _attach_file(self):
|
|
3339
3541
|
"""Attach a file to the conversation"""
|
|
3340
3542
|
file_path, _ = QFileDialog.getOpenFileName(
|
modules/voice_dictation.py
CHANGED
|
@@ -240,6 +240,9 @@ class VoiceDictationWidget(QWidget):
|
|
|
240
240
|
QPushButton:disabled {
|
|
241
241
|
background-color: #BDBDBD;
|
|
242
242
|
}
|
|
243
|
+
QPushButton:focus {
|
|
244
|
+
outline: none;
|
|
245
|
+
}
|
|
243
246
|
""")
|
|
244
247
|
self.record_btn.clicked.connect(self.toggle_recording)
|
|
245
248
|
controls_layout.addWidget(self.record_btn)
|
|
@@ -345,6 +348,9 @@ class VoiceDictationWidget(QWidget):
|
|
|
345
348
|
QPushButton:hover {
|
|
346
349
|
background-color: #C62828;
|
|
347
350
|
}
|
|
351
|
+
QPushButton:focus {
|
|
352
|
+
outline: none;
|
|
353
|
+
}
|
|
348
354
|
""")
|
|
349
355
|
|
|
350
356
|
# Disable controls
|
|
@@ -380,6 +386,9 @@ class VoiceDictationWidget(QWidget):
|
|
|
380
386
|
QPushButton:hover {
|
|
381
387
|
background-color: #1976D2;
|
|
382
388
|
}
|
|
389
|
+
QPushButton:focus {
|
|
390
|
+
outline: none;
|
|
391
|
+
}
|
|
383
392
|
""")
|
|
384
393
|
|
|
385
394
|
# Start transcription
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: supervertaler
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.205
|
|
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,6 +1,6 @@
|
|
|
1
|
-
Supervertaler.py,sha256=
|
|
1
|
+
Supervertaler.py,sha256=Q4pIpw6ZFn6DcIsX7oPk0iyZKRLg2HQFnIvhzZ98MrY,2403906
|
|
2
2
|
modules/__init__.py,sha256=G58XleS-EJ2sX4Kehm-3N2m618_W2Es0Kg8CW_eBG7g,327
|
|
3
|
-
modules/ai_actions.py,sha256=
|
|
3
|
+
modules/ai_actions.py,sha256=rU7h1TOkhPk_UaO6sxqj7V3FFUfo5Aj03Q6kSEllXyk,34688
|
|
4
4
|
modules/ai_attachment_manager.py,sha256=juZlrW3UPkIkcnj0SREgOQkQROLf0fcu3ShZcKXMxsI,11361
|
|
5
5
|
modules/ai_file_viewer_dialog.py,sha256=lKKqUUlOEVgHmmu6aRxqH7P6ds-7dRLk4ltDyjCwGxs,6246
|
|
6
6
|
modules/autofingers_engine.py,sha256=eJ7tBi7YJvTToe5hYTfnyGXB-qme_cHrOPZibaoR2Xw,17061
|
|
@@ -40,7 +40,7 @@ modules/prompt_assistant.py,sha256=shkZqNTvyQKNDO_9aFEu1_gN0zQq0fR5krXkWfnTR2Y,1
|
|
|
40
40
|
modules/prompt_library.py,sha256=t5w4cqB6_Sin4BQDVNALKpfB1EN_oaDeHFwlHxILLSY,26894
|
|
41
41
|
modules/prompt_library_migration.py,sha256=fv3RHhe2-EnH50XW5tyTWy0YP_KJ2EsESuTxR8klfmI,17639
|
|
42
42
|
modules/quick_access_sidebar.py,sha256=RPn5ssvYXlitNMWFZN9Yxv7So8u_z5RGNpHN6N-SFDI,10151
|
|
43
|
-
modules/quicktrans.py,sha256=
|
|
43
|
+
modules/quicktrans.py,sha256=uoEWb3MALfSR2nn07-hpBIsaQookqzcX9vAlKLGtOrE,26371
|
|
44
44
|
modules/ribbon_widget.py,sha256=QNGKxmit_oM5C5nJViadYYEzeRlIdIsla8Bzu_RNGO0,21990
|
|
45
45
|
modules/sdlppx_handler.py,sha256=o6Rj_T0B94toiYlvDDwMYLSz4q6kANgegFaDK5i3yhs,33538
|
|
46
46
|
modules/setup_wizard.py,sha256=7apNkeTcmMyw8pzJOWAmTOncxFvt3klOtmg-kKjQNgQ,13091
|
|
@@ -59,11 +59,11 @@ modules/superlookup.py,sha256=0SnIv-L8xNhAS5JuvoFPdp4BoScgACLFUB1fVwFe36Y,8980
|
|
|
59
59
|
modules/tag_cleaner.py,sha256=u7VOchIWzD4sAhFs3X1Vuo3hX6X72zESQ0AGZE83cYc,8703
|
|
60
60
|
modules/tag_manager.py,sha256=g66S0JSxdguN9AhWzZG3hsIz87Ul51wQ3c2wOCTZVSk,12789
|
|
61
61
|
modules/term_extractor.py,sha256=qPvKNCVXFTGEGwXNvvC0cfCmdb5c3WhzE38EOgKdKUI,11253
|
|
62
|
-
modules/termbase_entry_editor.py,sha256=
|
|
62
|
+
modules/termbase_entry_editor.py,sha256=V2IzVar8noU_SDhqkcZLg2NOtyAIhalSa5E6bLGcGUc,36070
|
|
63
63
|
modules/termbase_import_export.py,sha256=16IAY04IS_rgt0GH5UOUzUI5NoqAli4JMfMquxmFBm0,23552
|
|
64
64
|
modules/termbase_manager.py,sha256=XAVrz-wt8jKcjoD6ocHoXewY5PN0A0GeqFEctsv0jS8,48697
|
|
65
65
|
modules/termview_widget.py,sha256=FsNnSWh86PCnmKcC3fFJS8MJNdVvRpgE5e8-u4jAosY,55742
|
|
66
|
-
modules/theme_manager.py,sha256=
|
|
66
|
+
modules/theme_manager.py,sha256=EkiAviQ31ewzhMM0XaP4NkDJ2LZwRg8oXCy7BLQhc0k,18842
|
|
67
67
|
modules/tm_editor_dialog.py,sha256=AzGwq4QW641uFJdF8DljLTRRp4FLoYX3Pe4rlTjQWNg,3517
|
|
68
68
|
modules/tm_manager_qt.py,sha256=h2bvXkRuboHf_RRz9-5FX35GVRlpXgRDWeXyj1QWtPs,54406
|
|
69
69
|
modules/tm_metadata_manager.py,sha256=NTsaI_YjQnVOpU_scAwK9uR1Tcl9pzKD1GwLVy7sx2g,23590
|
|
@@ -73,16 +73,16 @@ modules/tmx_generator.py,sha256=pNkxwdMLvSRMMru0lkB1gvViIpg9BQy1EVhRbwoef3k,9426
|
|
|
73
73
|
modules/tracked_changes.py,sha256=S_BIEC6r7wVAwjG42aSy_RgH4KaMAC8GS5thEvqrYdE,39480
|
|
74
74
|
modules/trados_docx_handler.py,sha256=VPRAQ73cUHs_SEj6x81z1PmSxfjnwPBp9P4fXeK3KpQ,16363
|
|
75
75
|
modules/translation_memory.py,sha256=LnG8csZNL2GTHXT4zk0uecJEtvRc-MKwv7Pt7EX3s7s,28002
|
|
76
|
-
modules/translation_results_panel.py,sha256=
|
|
76
|
+
modules/translation_results_panel.py,sha256=HbYYjvRNqaJrJNLYLX-YanamMm6aRdLzLjn5rWIfk3U,92198
|
|
77
77
|
modules/translation_services.py,sha256=lyVpWuZK1wtVtYZMDMdLoq1DHBoSaeAnp-Yejb0TlVQ,10530
|
|
78
78
|
modules/unified_prompt_library.py,sha256=96u4WlMwnmmhD4uNJHZ-qVQj8v9_8dA2AVCWpBcwTrg,26006
|
|
79
|
-
modules/unified_prompt_manager_qt.py,sha256=
|
|
79
|
+
modules/unified_prompt_manager_qt.py,sha256=L96tgYpSLI0ZjD-R8eyxbwNYo_Vi1fyREFYriAR-Vlo,181992
|
|
80
80
|
modules/voice_commands.py,sha256=iBb-gjWxRMLhFH7-InSRjYJz1EIDBNA2Pog8V7TtJaY,38516
|
|
81
|
-
modules/voice_dictation.py,sha256=
|
|
81
|
+
modules/voice_dictation.py,sha256=7TlTTILSW4KwpTi1rDeKfvTwd5z3_XtNSzNIo35VAWU,16617
|
|
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.205.dist-info/licenses/LICENSE,sha256=m28u-4qL5nXIWnJ6xlQVw__H30rWFtRK3pCOais2OuY,1092
|
|
84
|
+
supervertaler-1.9.205.dist-info/METADATA,sha256=hX2ysmA8ur00DXX7Ua21H9t4Ct620QB1vAH7iwqVILs,5725
|
|
85
|
+
supervertaler-1.9.205.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
86
|
+
supervertaler-1.9.205.dist-info/entry_points.txt,sha256=NP4hiCvx-_30YYKqgr-jfJYQvHr1qTYBMfoVmKIXSM8,53
|
|
87
|
+
supervertaler-1.9.205.dist-info/top_level.txt,sha256=9tUHBYUSfaE4S2E4W3eavJsDyYymkwLfeWAHHAPT6Dk,22
|
|
88
|
+
supervertaler-1.9.205.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|