1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
from __future__ import annotations
import subprocess
from pathlib import Path
from PyQt6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QPushButton, QPlainTextEdit, QTextBrowser,
)
from PyQt6.QtCore import pyqtSignal
from core.models import Article
from core.frontmatter import parse_frontmatter
from workers.translation_worker import TranslationWorker
import re
def _strip_shortcodes(text: str) -> str:
return re.sub(r'\{\{[^}]+\}\}', '[shortcode]', text)
class TranslationView(QWidget):
push_master = pyqtSignal()
publish = pyqtSignal()
def __init__(self, transart_script: str, typora_bin: str, parent=None):
super().__init__(parent)
self._transart_script = transart_script
self._typora_bin = typora_bin
self._article: Article | None = None
self._worker: TranslationWorker | None = None
self._output_path: str = ""
self._build_ui()
def _build_ui(self):
layout = QVBoxLayout(self)
self._header = QLabel("")
self._header.setStyleSheet("color:#fff;font-weight:bold;font-size:13px;padding:10px;")
layout.addWidget(self._header)
log_label = QLabel("Output traduzione:")
log_label.setStyleSheet("color:#a855f7;font-size:9px;text-transform:uppercase;letter-spacing:1px;padding:0 10px;")
layout.addWidget(log_label)
self._log = QPlainTextEdit()
self._log.setReadOnly(True)
self._log.setStyleSheet("background:#0a0a12;color:#00ff88;font-family:monospace;font-size:11px;")
self._log.setMaximumHeight(180)
layout.addWidget(self._log)
preview_label = QLabel("Preview traduzione:")
preview_label.setStyleSheet("color:#a855f7;font-size:9px;text-transform:uppercase;letter-spacing:1px;padding:0 10px;")
layout.addWidget(preview_label)
self._preview = QTextBrowser()
self._preview.setStyleSheet("background:#0d0d1a;color:#ccc;border:none;")
layout.addWidget(self._preview, stretch=1)
self._action_bar = QWidget()
btns = QHBoxLayout(self._action_bar)
btns.setContentsMargins(10, 6, 10, 6)
self._btn_typora = QPushButton("✏️ Apri in Typora")
self._btn_typora.clicked.connect(self._open_typora)
self._btn_retry = QPushButton("🔄 Rigenera")
self._btn_retry.clicked.connect(self._retry)
self._btn_master = QPushButton("🧪 Push master")
self._btn_master.clicked.connect(self.push_master.emit)
self._btn_publish = QPushButton("🚢 Pubblica")
self._btn_publish.clicked.connect(self.publish.emit)
for btn in (self._btn_typora, self._btn_retry, self._btn_master, self._btn_publish):
btns.addWidget(btn)
btns.addStretch()
self._action_bar.setVisible(False)
layout.addWidget(self._action_bar)
def start_translation(self, article: Article):
if self._worker is not None:
self._worker.log_line.disconnect()
self._worker.finished.disconnect()
self._worker.error.disconnect()
self._article = article
self._log.clear()
self._preview.clear()
self._action_bar.setVisible(False)
direction = "it-en" if article.lang == "it" else "en-it"
self._header.setText(f"Traduzione: {article.slug} ({article.lang.upper()} → {('EN' if article.lang == 'it' else 'IT')})")
self._worker = TranslationWorker(
Path(self._transart_script),
article.path,
direction,
parent=self,
)
self._worker.log_line.connect(self._log.appendPlainText)
self._worker.finished.connect(self._on_finished)
self._worker.error.connect(lambda e: self._log.appendPlainText(f"[ERRORE] {e}"))
self._worker.start()
def _on_finished(self, success: bool, output_path: str):
self._output_path = output_path
if success and Path(output_path).exists():
try:
_, body = parse_frontmatter(Path(output_path))
self._preview.setMarkdown(_strip_shortcodes(body))
except Exception as e:
self._preview.setPlainText(f"[Errore preview: {e}]")
self._action_bar.setVisible(True)
def _open_typora(self):
if self._output_path:
subprocess.Popen([self._typora_bin, self._output_path])
def _retry(self):
if self._article:
self.start_translation(self._article)
|