Skip to content

Commit a27e51e

Browse files
committed
Translate UI and report template to English
Converted all user-facing text in patternanalyzer/tui.py and templates/report_template.html from Turkish to English for improved accessibility. Updated .gitignore to include crypto_report.html and crypto_report.json.
1 parent 5b6d1f3 commit a27e51e

3 files changed

Lines changed: 114 additions & 112 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,5 @@ report.json
185185
report.html
186186
report.json
187187
/bench_results
188+
crypto_report.html
189+
crypto_report.json

patternanalyzer/tui.py

Lines changed: 80 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
"""patternanalyzer.tui — Basit Textual TUI uygulaması."""
2-
1+
"""patternanalyzer.tui — Simple Textual TUI application."""
2+
33
from typing import Optional
44
from textual.app import App, ComposeResult
55
# ScrollView API moved between textual versions; try importing from widgets first,
@@ -27,15 +27,15 @@ class ScrollView(Container): # type: ignore
2727
import json
2828

2929
class PatternAnalyzerTUI(App):
30-
"""Textual.app tabanlı basit uygulama.
31-
32-
Bu arayüz sadece istenen widget'ları sağlar:
33-
- Dosya seçimi için DirectoryTree
34-
- Çalıştırılacak testleri seçmek için Checkbox'lar (engine.get_available_tests())
35-
- Başlat ve Çıkış için Button'lar
36-
- Analiz sonuçları için DataTable ve tıklanabilir sonuç listesi (modal ile metrik gösterimi)
30+
"""Simple application based on Textual.app.
31+
32+
This interface only provides the required widgets:
33+
- DirectoryTree for file selection
34+
- Checkboxes for selecting tests to run (engine.get_available_tests())
35+
- Start and Exit buttons
36+
- DataTable for analysis results and clickable results list (modal for metric display)
3737
"""
38-
38+
3939
CSS = """
4040
#body { height: 1fr; }
4141
#left { width: 50%; min-width: 30; }
@@ -47,59 +47,59 @@ class PatternAnalyzerTUI(App):
4747
#results_table { height: 1fr; border: round $accent; padding: 1; }
4848
#results_scroll { height: 10; border: round $accent; padding: 1; }
4949
"""
50-
50+
5151
def compose(self) -> ComposeResult:
52-
"""Bileşenleri oluştur."""
52+
"""Compose the components."""
5353
yield Header()
5454
with Container(id="body"):
5555
with Horizontal():
56-
# Sol: dosya ağacı / seçici
56+
# Left: file tree / selector
5757
yield Vertical(
58-
Static("Dosya seçimi", id="file_label"),
58+
Static("File Selection", id="file_label"),
5959
DirectoryTree(".", id="file_tree"),
6060
id="left",
6161
)
62-
# Sağ: test listesi, sonuçlar ve kontrol düğmeleri
62+
# Right: test list, results, and control buttons
6363
yield Vertical(
64-
Static("Mevcut Testler (Checkbox ile seçin)", id="tests_label"),
64+
Static("Available Tests (Select with Checkboxes)", id="tests_label"),
6565
ScrollView(id="tests_scroll"),
6666
Static("Scorecard", id="score_label"),
6767
Static("", id="scorecard", expand=False),
68-
Static("Sonuçlar (tablo)", id="results_label"),
68+
Static("Results (Table)", id="results_label"),
6969
DataTable(id="results_table"),
70-
Static("Tıklanabilir sonuç listesi", id="results_list_label"),
70+
Static("Clickable Results List", id="results_list_label"),
7171
ScrollView(id="results_scroll"),
72-
Static("", id="status", expand=False), # Status mesajları için
72+
Static("", id="status", expand=False), # For status messages
7373
Horizontal(
74-
Button("Başlat", id="start_btn", variant="success"),
75-
Button("Çıkış", id="exit_btn", variant="error"),
74+
Button("Start", id="start_btn", variant="success"),
75+
Button("Exit", id="exit_btn", variant="error"),
7676
id="controls",
7777
),
7878
id="right",
7979
)
8080
yield Footer()
81-
81+
8282
def on_mount(self) -> None:
83-
"""Uygulama mount edildikten sonra test checkbox'larını yükle."""
84-
# Başlangıçta analiz çalışmıyor
83+
"""Load test checkboxes after the app is mounted."""
84+
# Analysis not running initially
8585
self._analysis_running = False
8686
# Mapping for clickable result buttons -> metrics
8787
self._result_metrics = {}
88-
89-
# Motor örneği sadece test isimlerini almak için kullanılır; çalıştırma yapılmayacak.
88+
89+
# Engine instance used only to get test names; no execution will be performed.
9090
try:
9191
eng = Engine()
9292
tests = eng.get_available_tests()
9393
except Exception:
9494
tests = []
95-
95+
9696
tests_scroll: Optional[ScrollView] = self.query_one("#tests_scroll", ScrollView)
97-
# Dynamic olarak Checkbox'ları ekle
97+
# Dynamically add Checkboxes
9898
for i, tname in enumerate(tests):
9999
cb = Checkbox(tname, id=f"test_{i}")
100100
tests_scroll.mount(cb)
101-
102-
# Prepare DataTable columns (keşif amaçlı, tekrar oluşturmayı önlemek için)
101+
102+
# Prepare DataTable columns (for discovery, to avoid recreation)
103103
try:
104104
table = self.query_one("#results_table", DataTable)
105105
# clear any existing columns/rows
@@ -116,9 +116,9 @@ def on_mount(self) -> None:
116116
pass
117117
except Exception:
118118
pass
119-
119+
120120
def _format_scorecard(self, scorecard: dict) -> str:
121-
"""Scorecard'ı biçimlendirilmiş metin olarak döndür."""
121+
"""Format the scorecard as formatted text."""
122122
try:
123123
lines = []
124124
lines.append(f"Failed tests: {scorecard.get('failed_tests')}")
@@ -134,23 +134,23 @@ def _format_scorecard(self, scorecard: dict) -> str:
134134
return "\n".join(lines)
135135
except Exception:
136136
return json.dumps(scorecard, indent=2, ensure_ascii=False)
137-
137+
138138
def _display_results(self, output: dict) -> None:
139-
"""Engine.analyze çıktısını UI içinde göster: scorecard ve sonuç listesi."""
139+
"""Display Engine.analyze output in the UI: scorecard and results list."""
140140
try:
141141
scorecard = output.get("scorecard", {}) if isinstance(output, dict) else {}
142142
results = output.get("results", []) if isinstance(output, dict) else []
143143
except Exception:
144144
scorecard = {}
145145
results = []
146-
146+
147147
# Update scorecard Static
148148
try:
149149
sc = self.query_one("#scorecard", Static)
150150
sc.update(self._format_scorecard(scorecard))
151151
except Exception:
152152
pass
153-
153+
154154
# Populate DataTable summary
155155
try:
156156
table = self.query_one("#results_table", DataTable)
@@ -196,7 +196,7 @@ def _display_results(self, output: dict) -> None:
196196
self._result_metrics[f"res_btn_{i}"] = {"test_name": tname, "metrics": metrics}
197197
except Exception:
198198
pass
199-
199+
200200
# Populate clickable results list (Buttons inside ScrollView)
201201
try:
202202
rs = self.query_one("#results_scroll", ScrollView)
@@ -212,62 +212,62 @@ def _display_results(self, output: dict) -> None:
212212
rs.mount(btn)
213213
except Exception:
214214
pass
215-
215+
216216
def _show_loading(self) -> None:
217-
"""LoadingIndicator'ı sağ panelde göster."""
218-
# Eğer zaten gösteriliyorsa yeniden mount etme
217+
"""Show LoadingIndicator in the right panel."""
218+
# If already shown, do not remount
219219
if self.query("#loading"):
220220
return
221221
try:
222222
right = self.query_one("#right", Vertical)
223223
right.mount(LoadingIndicator(id="loading"))
224224
except Exception:
225225
pass
226-
226+
227227
def _hide_loading(self) -> None:
228-
"""LoadingIndicator'ı kaldır."""
228+
"""Remove the LoadingIndicator."""
229229
try:
230230
loading = self.query_one("#loading")
231231
loading.remove()
232232
except Exception:
233233
pass
234-
234+
235235
def on_button_pressed(self, event: Button.Pressed) -> None:
236-
"""Butonlara basılınca çalışır: Başlat, Çıkış, sonuç butonları ve modal kapatma."""
236+
"""Triggered when buttons are pressed: Start, Exit, result buttons, and modal close."""
237237
btn_id = getattr(event.button, "id", None)
238238
if btn_id == "exit_btn":
239239
self.exit()
240240
return
241-
241+
242242
if btn_id == "start_btn":
243-
# Seçili testleri ve seçili dosya yolunu topla
243+
# Collect selected tests and selected file path
244244
selected_tests = [cb.label for cb in self.query(Checkbox) if getattr(cb, "id", "").startswith("test_") and cb.value]
245245
file_tree = self.query_one(DirectoryTree)
246-
# DirectoryTree içindeki seçili dosya bilgisini güvenli okumaya çalış
246+
# Safely read selected file info from DirectoryTree
247247
file_path = None
248248
for attr in ("path", "cursor_path", "selected_path", "cursor", "selected_node"):
249249
val = getattr(file_tree, attr, None)
250250
if val:
251-
# selected_node olabilir; path özniteliği varsa kullan
251+
# selected_node may exist; use path attribute if available
252252
if hasattr(val, "path"):
253253
file_path = getattr(val, "path")
254254
else:
255255
file_path = str(val)
256256
break
257-
257+
258258
status = self.query_one("#status", Static)
259-
260-
# Eğer analiz zaten çalışıyorsa yeni analiz başlatma
259+
260+
# If analysis is already running, do not start a new one
261261
if getattr(self, "_analysis_running", False):
262-
status.update("Analiz zaten çalışıyor")
262+
status.update("Analysis is already running")
263263
return
264-
265-
# Hazırlık: Loading göster, flag set
264+
265+
# Preparation: Show loading, set flag
266266
self._analysis_running = True
267267
self._show_loading()
268-
status.update(f"Analiz başlatıldıseçili testler: {len(selected_tests)}")
269-
270-
# Worker fonksiyonu: Engine.analyze'ı arka planda çağırır
268+
status.update(f"Analysis startedselected tests: {len(selected_tests)}")
269+
270+
# Worker function: Calls Engine.analyze in the background
271271
def _worker():
272272
try:
273273
eng = Engine()
@@ -279,49 +279,49 @@ def _worker():
279279
except Exception:
280280
data = b""
281281
config = {"tests": [{"name": t, "params": {}} for t in selected_tests]}
282-
# Motorun ağır işi burada yapılır
282+
# Engine's heavy work is done here
283283
return eng.analyze(data, config)
284284
except Exception as e:
285285
return {"error": str(e)}
286-
287-
# tamamlandığında çağrılacak callback
286+
287+
# Callback to be called when done
288288
def _on_done(result):
289289
self._analysis_running = False
290290
self._hide_loading()
291291
try:
292292
if isinstance(result, dict) and "error" in result:
293-
status.update(f"Analiz hatası: {result['error']}")
293+
status.update(f"Analysis error: {result['error']}")
294294
else:
295-
status.update("Analiz tamamlandısonuçlar gösteriliyor")
295+
status.update("Analysis completedresults displayed")
296296
self._display_results(result or {})
297297
except Exception as e:
298-
status.update(f"Görüntüleme hatası: {e}")
299-
300-
# Standart threading ile arka plan çalıştır
298+
status.update(f"Display error: {e}")
299+
300+
# Run in background with standard threading
301301
try:
302302
import threading
303303
def _thread_worker():
304304
result = _worker()
305-
# Callback'i main thread'de çalıştır
305+
# Run callback in main thread
306306
self.call_from_thread(_on_done, result)
307307
thread = threading.Thread(target=_thread_worker, daemon=True)
308308
thread.start()
309309
except Exception as e:
310-
# Hata durumunda temizle
310+
# Clean up in case of error
311311
self._analysis_running = False
312312
self._hide_loading()
313-
status.update(f"Analiz başlatılamadı: {e}")
313+
status.update(f"Analysis could not start: {e}")
314314
return
315-
316-
# Modal kapatma düğmesi
315+
316+
# Modal close button
317317
if btn_id == "modal_close":
318318
try:
319319
self.pop_screen()
320320
except Exception:
321321
pass
322322
return
323-
324-
# Sonuç listesi butonlarına tıklama: modal içinde metrikleri göster
323+
324+
# Clicking on result list buttons: show metrics in modal
325325
if isinstance(btn_id, str) and btn_id.startswith("res_btn_"):
326326
info = self._result_metrics.get(btn_id)
327327
if not info:
@@ -337,19 +337,19 @@ def _thread_worker():
337337
self.push_screen(MetricsModal(test_name, metrics_text))
338338
except Exception:
339339
pass
340-
341-
# Ek event handlerler veya yardımcılar gerektiğinde buraya eklenebilir.
342-
340+
341+
# Additional event handlers or helpers can be added here if needed.
342+
343343
class MetricsModal(ModalScreen):
344-
"""Basit modal ekran: seçili testin metriklerini gösterir."""
344+
"""Simple modal screen: displays metrics for the selected test."""
345345
def __init__(self, test_name: str, metrics_text: str) -> None:
346346
super().__init__()
347347
self.test_name = test_name
348348
self.metrics_text = metrics_text
349-
349+
350350
def compose(self) -> ComposeResult:
351351
yield Vertical(
352-
Static(f"Metrikler{self.test_name}", id="modal_title"),
352+
Static(f"Metrics{self.test_name}", id="modal_title"),
353353
(
354354
Static(self.metrics_text, id="modal_metrics")
355355
if _SCROLL_SRC == 'fallback'
@@ -360,9 +360,9 @@ def compose(self) -> ComposeResult:
360360
ScrollView(Static(self.metrics_text), id="modal_metrics")
361361
),
362362
Horizontal(
363-
Button("Kapat", id="modal_close", variant="primary"),
363+
Button("Close", id="modal_close", variant="primary"),
364364
),
365365
)
366-
366+
367367
if __name__ == "__main__":
368368
PatternAnalyzerTUI().run()

0 commit comments

Comments
 (0)