Skip to content

Commit 449afcb

Browse files
committed
Simplifie l'i18n des engines et harmonise leurs tabs
Introduit une utilisation centralisee de engine_translate dans les engines integres pour eviter que chaque onglet recharge lui-meme ses fichiers de langue et pour conserver une synchronisation automatique avec apply_i18n. Met a jour PyInstaller, Nuitka et CX_Freeze afin qu'ils s'appuient sur la nouvelle facade de traduction tout en conservant les memes attributs attendus par le compilateur, la persistance de configuration et les hooks existants. Refond en parallele les tabs engines selon un design plus structure inspire du plugin Cleaner, avec sections QGroupBox, marges et espacements homogenes, puis des hints compacts qui reduisent l'effet de panneau brut sans changer le contrat fonctionnel. Actualise la documentation engine pour presenter clairement les deux approches i18n, le mode simple via engine_translate et le mode de rafraichissement via apply_i18n. Ajoute enfin un test unitaire cible pour verrouiller le cache des traductions engines, le fallback sur les traductions globales et la compatibilite avec le hook apply_i18n.
1 parent 572ee0f commit 449afcb

5 files changed

Lines changed: 321 additions & 140 deletions

File tree

ENGINES/cx_freeze/__init__.py

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,9 @@ def create_tab(self, gui):
190190
from PySide6.QtWidgets import (
191191
QCheckBox,
192192
QFormLayout,
193-
QHBoxLayout,
194-
QLineEdit,
195-
QPushButton,
193+
QLabel,
194+
QGroupBox,
195+
QSizePolicy,
196196
QVBoxLayout,
197197
QWidget,
198198
)
@@ -203,54 +203,80 @@ def create_tab(self, gui):
203203

204204
# Create main layout
205205
layout = QVBoxLayout(tab)
206-
layout.setSpacing(10)
206+
layout.setSpacing(8)
207+
layout.setContentsMargins(8, 8, 8, 8)
207208

208-
# Create form layout for options
209-
form_layout = QFormLayout()
210-
form_layout.setSpacing(8)
209+
build_group = QGroupBox("Build", tab)
210+
build_layout = QFormLayout()
211+
build_layout.setSpacing(6)
211212

212213
# Windowed option
213214
self._cx_windowed = add_form_checkbox(
214-
form_layout, "Console:", "No console", "cx_windowed_dynamic"
215+
build_layout, "Console:", "No console", "cx_windowed_dynamic"
215216
)
216217
self._cx_windowed.setToolTip("Disable the console window.")
218+
build_group.setLayout(build_layout)
217219

218-
layout.addLayout(form_layout)
220+
diagnostics_group = QGroupBox("Diagnostics", tab)
221+
diagnostics_layout = QVBoxLayout()
222+
diagnostics_layout.setSpacing(4)
219223

220-
# Icon button + path input
221-
self._cx_btn_select_icon, self._cx_icon_path_input = add_icon_selector(
222-
layout,
223-
"Choisir une icône (.ico)",
224-
self.select_icon,
225-
"cx_btn_select_icon_dynamic",
226-
"cx_icon_path_input_dynamic",
227-
)
228-
if self._cx_icon_path_input is not None:
229-
self._cx_icon_path_input.textChanged.connect(self._on_icon_path_changed)
230-
231-
# Debug / verbose
232224
self._cx_debug = QCheckBox("Debug")
233225
self._cx_debug.setObjectName("cx_debug_dynamic")
234226
self._cx_debug.setToolTip("Enable debug output.")
235-
layout.addWidget(self._cx_debug)
227+
diagnostics_layout.addWidget(self._cx_debug)
236228

237229
self._cx_verbose = QCheckBox("Verbose")
238230
self._cx_verbose.setObjectName("cx_verbose_dynamic")
239231
self._cx_verbose.setToolTip("Enable verbose output.")
240-
layout.addWidget(self._cx_verbose)
232+
diagnostics_layout.addWidget(self._cx_verbose)
233+
diagnostics_group.setLayout(diagnostics_layout)
234+
235+
output_group = QGroupBox("Output", tab)
236+
output_layout = QVBoxLayout()
237+
output_layout.setSpacing(6)
241238

242239
# Target name
243240
self._cx_target_name = add_output_dir(
244-
layout,
241+
output_layout,
245242
"Nom de sortie (--target-name)",
246243
"cx_target_name_dynamic",
247244
)
248245

249246
# Output directory
250247
self._cx_output_dir = add_output_dir(
251-
layout, "Dossier de sortie", "cx_output_dir_dynamic"
248+
output_layout, "Dossier de sortie", "cx_output_dir_dynamic"
249+
)
250+
output_group.setLayout(output_layout)
251+
252+
assets_group = QGroupBox("Assets", tab)
253+
assets_layout = QVBoxLayout()
254+
assets_layout.setSpacing(6)
255+
256+
# Icon button + path input
257+
self._cx_btn_select_icon, self._cx_icon_path_input = add_icon_selector(
258+
assets_layout,
259+
"Choisir une icône (.ico)",
260+
self.select_icon,
261+
"cx_btn_select_icon_dynamic",
262+
"cx_icon_path_input_dynamic",
252263
)
264+
if self._cx_icon_path_input is not None:
265+
self._cx_icon_path_input.textChanged.connect(self._on_icon_path_changed)
266+
assets_group.setLayout(assets_layout)
253267

268+
hint = QLabel(
269+
"Tip: use target name for the executable label, and keep debug or verbose only when diagnosing builds.",
270+
tab,
271+
)
272+
hint.setStyleSheet("color: #888; font-size: 11px;")
273+
hint.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
274+
275+
layout.addWidget(build_group)
276+
layout.addWidget(diagnostics_group)
277+
layout.addWidget(output_group)
278+
layout.addWidget(assets_group)
279+
layout.addWidget(hint)
254280
layout.addStretch()
255281

256282
# Store references in the engine instance for build_command access
@@ -377,38 +403,39 @@ def get_log_prefix(self, file_basename: str) -> str:
377403
def apply_i18n(self, gui, tr: dict) -> None:
378404
"""Apply internationalization translations to the engine UI."""
379405
try:
380-
from engine_sdk import resolve_language_code, load_engine_language_file
381-
382-
# Resolve language code
383-
code = resolve_language_code(gui, tr)
384-
385-
# Load engine-local translations
386-
lang_data = load_engine_language_file(__package__, code)
387-
388406
# Apply translations to UI elements if they exist
389-
if hasattr(self, "_cx_windowed") and "windowed_checkbox" in lang_data:
390-
self._cx_windowed.setText(lang_data["windowed_checkbox"])
391-
if hasattr(self, "_cx_windowed") and "tt_windowed" in lang_data:
392-
self._cx_windowed.setToolTip(lang_data["tt_windowed"])
393-
if hasattr(self, "_cx_btn_select_icon") and "icon_button" in lang_data:
394-
self._cx_btn_select_icon.setText(lang_data["icon_button"])
395-
if hasattr(self, "_cx_debug") and "debug_checkbox" in lang_data:
396-
self._cx_debug.setText(lang_data["debug_checkbox"])
397-
if hasattr(self, "_cx_debug") and "tt_debug" in lang_data:
398-
self._cx_debug.setToolTip(lang_data["tt_debug"])
399-
if hasattr(self, "_cx_verbose") and "verbose_checkbox" in lang_data:
400-
self._cx_verbose.setText(lang_data["verbose_checkbox"])
401-
if hasattr(self, "_cx_verbose") and "tt_verbose" in lang_data:
402-
self._cx_verbose.setToolTip(lang_data["tt_verbose"])
403-
if (
404-
hasattr(self, "_cx_target_name")
405-
and "target_name_placeholder" in lang_data
406-
):
407+
if hasattr(self, "_cx_windowed"):
408+
self._cx_windowed.setText(
409+
self.engine_translate("windowed_checkbox", "Windowed")
410+
)
411+
if hasattr(self, "_cx_windowed"):
412+
self._cx_windowed.setToolTip(self.engine_translate("tt_windowed", ""))
413+
if hasattr(self, "_cx_btn_select_icon"):
414+
self._cx_btn_select_icon.setText(
415+
self.engine_translate("icon_button", "Select icon")
416+
)
417+
if hasattr(self, "_cx_debug"):
418+
self._cx_debug.setText(
419+
self.engine_translate("debug_checkbox", "Debug mode")
420+
)
421+
if hasattr(self, "_cx_debug"):
422+
self._cx_debug.setToolTip(self.engine_translate("tt_debug", ""))
423+
if hasattr(self, "_cx_verbose"):
424+
self._cx_verbose.setText(
425+
self.engine_translate("verbose_checkbox", "Verbose output")
426+
)
427+
if hasattr(self, "_cx_verbose"):
428+
self._cx_verbose.setToolTip(self.engine_translate("tt_verbose", ""))
429+
if hasattr(self, "_cx_target_name"):
407430
self._cx_target_name.setPlaceholderText(
408-
lang_data["target_name_placeholder"]
431+
self.engine_translate(
432+
"target_name_placeholder", "Target executable name"
433+
)
434+
)
435+
if hasattr(self, "_cx_output_dir"):
436+
self._cx_output_dir.setPlaceholderText(
437+
self.engine_translate("output_placeholder", "Output directory")
409438
)
410-
if hasattr(self, "_cx_output_dir") and "output_placeholder" in lang_data:
411-
self._cx_output_dir.setPlaceholderText(lang_data["output_placeholder"])
412439
except Exception:
413440
pass
414441

ENGINES/nuitka/__init__.py

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ def create_tab(self, gui):
197197
from PySide6.QtWidgets import (
198198
QCheckBox,
199199
QFormLayout,
200+
QLabel,
201+
QGroupBox,
202+
QSizePolicy,
200203
QVBoxLayout,
201204
QWidget,
202205
)
@@ -207,40 +210,51 @@ def create_tab(self, gui):
207210

208211
# Create main layout
209212
layout = QVBoxLayout(tab)
210-
layout.setSpacing(10)
213+
layout.setSpacing(8)
214+
layout.setContentsMargins(8, 8, 8, 8)
211215

212-
# Create form layout for options
213-
form_layout = QFormLayout()
214-
form_layout.setSpacing(8)
216+
build_group = QGroupBox("Build", tab)
217+
build_layout = QFormLayout()
218+
build_layout.setSpacing(6)
215219

216220
# Onefile option
217221
self._nuitka_onefile = QCheckBox("Onefile (--onefile)")
218222
self._nuitka_onefile.setObjectName("nuitka_onefile_dynamic")
219-
form_layout.addRow("Mode:", self._nuitka_onefile)
223+
build_layout.addRow("Mode:", self._nuitka_onefile)
220224

221225
# Standalone option
222226
self._nuitka_standalone = QCheckBox("Standalone (--standalone)")
223227
self._nuitka_standalone.setObjectName("nuitka_standalone_dynamic")
224-
form_layout.addRow("Type:", self._nuitka_standalone)
228+
build_layout.addRow("Type:", self._nuitka_standalone)
225229

226230
# Disable console option
227231
self._nuitka_disable_console = QCheckBox("Disable console")
228232
self._nuitka_disable_console.setObjectName("nuitka_disable_console_dynamic")
229233
self._nuitka_disable_console.setToolTip(
230234
"Disable console window for Windows builds."
231235
)
232-
form_layout.addRow("Console:", self._nuitka_disable_console)
236+
build_layout.addRow("Console:", self._nuitka_disable_console)
237+
build_group.setLayout(build_layout)
233238

234-
layout.addLayout(form_layout)
239+
output_group = QGroupBox("Output", tab)
240+
output_layout = QVBoxLayout()
241+
output_layout.setSpacing(6)
235242

236243
# Output directory
237244
self._nuitka_output_dir = add_output_dir(
238-
layout, "Dossier de sortie (--output-dir)", "nuitka_output_dir_dynamic"
245+
output_layout,
246+
"Dossier de sortie (--output-dir)",
247+
"nuitka_output_dir_dynamic",
239248
)
249+
output_group.setLayout(output_layout)
250+
251+
assets_group = QGroupBox("Assets", tab)
252+
assets_layout = QVBoxLayout()
253+
assets_layout.setSpacing(6)
240254

241255
# Icon button + path input
242256
self._btn_nuitka_icon, self._nuitka_icon_path_input = add_icon_selector(
243-
layout,
257+
assets_layout,
244258
"🎨 Choisir une icône (.ico) Nuitka",
245259
self.select_icon,
246260
"btn_nuitka_icon_dynamic",
@@ -250,7 +264,19 @@ def create_tab(self, gui):
250264
self._nuitka_icon_path_input.textChanged.connect(
251265
self._on_icon_path_changed
252266
)
267+
assets_group.setLayout(assets_layout)
268+
269+
hint = QLabel(
270+
"Tip: combine standalone or onefile modes carefully, then tune console visibility for desktop apps.",
271+
tab,
272+
)
273+
hint.setStyleSheet("color: #888; font-size: 11px;")
274+
hint.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
253275

276+
layout.addWidget(build_group)
277+
layout.addWidget(output_group)
278+
layout.addWidget(assets_group)
279+
layout.addWidget(hint)
254280
layout.addStretch()
255281

256282
# Store references in the engine instance for build_command access
@@ -369,43 +395,33 @@ def get_log_prefix(self, file_basename: str) -> str:
369395
def apply_i18n(self, gui, tr: dict) -> None:
370396
"""Apply internationalization translations to the engine UI."""
371397
try:
372-
from engine_sdk import resolve_language_code, load_engine_language_file
373-
374-
# Resolve language code
375-
code = resolve_language_code(gui, tr)
376-
377-
# Load engine-local translations
378-
lang_data = load_engine_language_file(__package__, code)
379-
380398
# Apply translations to UI elements if they exist
381-
if hasattr(self, "_nuitka_onefile") and "onefile_checkbox" in lang_data:
382-
self._nuitka_onefile.setText(lang_data["onefile_checkbox"])
383-
if (
384-
hasattr(self, "_nuitka_standalone")
385-
and "standalone_checkbox" in lang_data
386-
):
387-
self._nuitka_standalone.setText(lang_data["standalone_checkbox"])
388-
if (
389-
hasattr(self, "_nuitka_disable_console")
390-
and "disable_console_checkbox" in lang_data
391-
):
399+
if hasattr(self, "_nuitka_onefile"):
400+
self._nuitka_onefile.setText(
401+
self.engine_translate("onefile_checkbox", "Onefile")
402+
)
403+
if hasattr(self, "_nuitka_standalone"):
404+
self._nuitka_standalone.setText(
405+
self.engine_translate("standalone_checkbox", "Standalone")
406+
)
407+
if hasattr(self, "_nuitka_disable_console"):
392408
self._nuitka_disable_console.setText(
393-
lang_data["disable_console_checkbox"]
409+
self.engine_translate(
410+
"disable_console_checkbox", "Disable console"
411+
)
394412
)
395-
if (
396-
hasattr(self, "_nuitka_disable_console")
397-
and "tt_disable_console" in lang_data
398-
):
399-
self._nuitka_disable_console.setToolTip(lang_data["tt_disable_console"])
400-
if (
401-
hasattr(self, "_nuitka_output_dir")
402-
and "output_placeholder" in lang_data
403-
):
413+
if hasattr(self, "_nuitka_disable_console"):
414+
self._nuitka_disable_console.setToolTip(
415+
self.engine_translate("tt_disable_console", "")
416+
)
417+
if hasattr(self, "_nuitka_output_dir"):
404418
self._nuitka_output_dir.setPlaceholderText(
405-
lang_data["output_placeholder"]
419+
self.engine_translate("output_placeholder", "Output directory")
420+
)
421+
if hasattr(self, "_btn_nuitka_icon"):
422+
self._btn_nuitka_icon.setText(
423+
self.engine_translate("icon_button", "Select icon")
406424
)
407-
if hasattr(self, "_btn_nuitka_icon") and "icon_button" in lang_data:
408-
self._btn_nuitka_icon.setText(lang_data["icon_button"])
409425
except Exception:
410426
pass
411427

0 commit comments

Comments
 (0)