summaryrefslogtreecommitdiffstats
path: root/ui/translation_view.py
blob: cf72ce528e50cdf16973639011fb08e38e753c22 (plain)
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
114
115
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, typora_args: str = "", parent=None):
        super().__init__(parent)
        self._transart_script = transart_script
        self._typora_bin = typora_bin
        self._typora_args = typora_args
        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:
            _args = self._typora_args.split() if self._typora_args else []
            subprocess.Popen([self._typora_bin, *_args, self._output_path])

    def _retry(self):
        if self._article:
            self.start_translation(self._article)