Skip to content

Commit 1c58008

Browse files
committed
Added internationalization support to PyInstaller, Nuitka, and cx_Freeze engines
1 parent eaa72ea commit 1c58008

9 files changed

Lines changed: 342 additions & 3 deletions

File tree

ENGINES/cx_freeze/__init__.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,5 +256,74 @@ def should_compile_file(self, gui, file: str, selected_files: list[str], python_
256256

257257
def apply_i18n(self, gui, tr: dict) -> None:
258258
"""Apply internationalization translations to the engine UI."""
259-
pass
259+
try:
260+
from Core.engines_loader.registry import resolve_language_code
261+
262+
# Resolve language code
263+
code = resolve_language_code(gui, tr)
264+
265+
# Load engine-local translations
266+
lang_data = self._load_language_file(code)
267+
268+
# Apply translations to UI elements if they exist
269+
if hasattr(self, "_cx_onefile") and "onefile_checkbox" in lang_data:
270+
self._cx_onefile.setText(lang_data["onefile_checkbox"])
271+
if hasattr(self, "_cx_windowed") and "windowed_checkbox" in lang_data:
272+
self._cx_windowed.setText(lang_data["windowed_checkbox"])
273+
if hasattr(self, "_cx_btn_select_icon") and "icon_button" in lang_data:
274+
self._cx_btn_select_icon.setText(lang_data["icon_button"])
275+
if hasattr(self, "_cx_output_dir") and "output_placeholder" in lang_data:
276+
self._cx_output_dir.setPlaceholderText(lang_data["output_placeholder"])
277+
except Exception:
278+
pass
279+
280+
def _load_language_file(self, code: str) -> dict:
281+
"""Load language file for the given code."""
282+
try:
283+
import importlib.resources as ilr
284+
import json
285+
286+
pkg = __package__
287+
lang_data = {}
288+
289+
# Try exact code first
290+
try:
291+
with ilr.as_file(
292+
ilr.files(pkg).joinpath("languages", f"{code}.json")
293+
) as p:
294+
if os.path.isfile(str(p)):
295+
with open(str(p), encoding="utf-8") as f:
296+
lang_data = json.load(f) or {}
297+
return lang_data
298+
except Exception:
299+
pass
300+
301+
# Fallback to base language (e.g., "fr" from "fr-CA")
302+
if "-" in code:
303+
base = code.split("-", 1)[0]
304+
try:
305+
with ilr.as_file(
306+
ilr.files(pkg).joinpath("languages", f"{base}.json")
307+
) as p:
308+
if os.path.isfile(str(p)):
309+
with open(str(p), encoding="utf-8") as f:
310+
lang_data = json.load(f) or {}
311+
return lang_data
312+
except Exception:
313+
pass
314+
315+
# Final fallback to English
316+
try:
317+
with ilr.as_file(
318+
ilr.files(pkg).joinpath("languages", "en.json")
319+
) as p:
320+
if os.path.isfile(str(p)):
321+
with open(str(p), encoding="utf-8") as f:
322+
lang_data = json.load(f) or {}
323+
except Exception:
324+
pass
325+
326+
return lang_data
327+
except Exception:
328+
return {}
260329

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"_meta": {
3+
"code": "en",
4+
"name": "English"
5+
},
6+
"tab_label": "CX_Freeze",
7+
"mode_label": "Mode:",
8+
"onefile_checkbox": "Onefile",
9+
"console_label": "Console:",
10+
"windowed_checkbox": "Windowed",
11+
"icon_button": "🎨 Choose icon (.ico)",
12+
"output_placeholder": "Output directory"
13+
}
14+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"_meta": {
3+
"code": "fr",
4+
"name": "Français"
5+
},
6+
"tab_label": "CX_Freeze",
7+
"mode_label": "Mode :",
8+
"onefile_checkbox": "Onefile",
9+
"console_label": "Console :",
10+
"windowed_checkbox": "Windowed",
11+
"icon_button": "🎨 Choisir une icône (.ico)",
12+
"output_placeholder": "Dossier de sortie"
13+
}
14+

ENGINES/nuitka/__init__.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,82 @@ def should_compile_file(self, gui, file: str, selected_files: list[str], python_
305305

306306
def apply_i18n(self, gui, tr: dict) -> None:
307307
"""Apply internationalization translations to the engine UI."""
308-
pass
308+
try:
309+
from Core.engines_loader.registry import resolve_language_code
310+
311+
# Resolve language code
312+
code = resolve_language_code(gui, tr)
313+
314+
# Load engine-local translations
315+
lang_data = self._load_language_file(code)
316+
317+
# Apply translations to UI elements if they exist
318+
if hasattr(self, "_nuitka_onefile") and "onefile_checkbox" in lang_data:
319+
self._nuitka_onefile.setText(lang_data["onefile_checkbox"])
320+
if hasattr(self, "_nuitka_standalone") and "standalone_checkbox" in lang_data:
321+
self._nuitka_standalone.setText(lang_data["standalone_checkbox"])
322+
if hasattr(self, "_nuitka_disable_console") and "disable_console_checkbox" in lang_data:
323+
self._nuitka_disable_console.setText(lang_data["disable_console_checkbox"])
324+
if hasattr(self, "_nuitka_show_progress") and "show_progress_checkbox" in lang_data:
325+
self._nuitka_show_progress.setText(lang_data["show_progress_checkbox"])
326+
if hasattr(self, "_nuitka_add_data") and "add_data_button" in lang_data:
327+
self._nuitka_add_data.setText(lang_data["add_data_button"])
328+
if hasattr(self, "_nuitka_output_dir") and "output_placeholder" in lang_data:
329+
self._nuitka_output_dir.setPlaceholderText(lang_data["output_placeholder"])
330+
if hasattr(self, "_btn_nuitka_icon") and "icon_button" in lang_data:
331+
self._btn_nuitka_icon.setText(lang_data["icon_button"])
332+
except Exception:
333+
pass
334+
335+
def _load_language_file(self, code: str) -> dict:
336+
"""Load language file for the given code."""
337+
try:
338+
import importlib.resources as ilr
339+
import json
340+
341+
pkg = __package__
342+
lang_data = {}
343+
344+
# Try exact code first
345+
try:
346+
with ilr.as_file(
347+
ilr.files(pkg).joinpath("languages", f"{code}.json")
348+
) as p:
349+
if os.path.isfile(str(p)):
350+
with open(str(p), encoding="utf-8") as f:
351+
lang_data = json.load(f) or {}
352+
return lang_data
353+
except Exception:
354+
pass
355+
356+
# Fallback to base language (e.g., "fr" from "fr-CA")
357+
if "-" in code:
358+
base = code.split("-", 1)[0]
359+
try:
360+
with ilr.as_file(
361+
ilr.files(pkg).joinpath("languages", f"{base}.json")
362+
) as p:
363+
if os.path.isfile(str(p)):
364+
with open(str(p), encoding="utf-8") as f:
365+
lang_data = json.load(f) or {}
366+
return lang_data
367+
except Exception:
368+
pass
369+
370+
# Final fallback to English
371+
try:
372+
with ilr.as_file(
373+
ilr.files(pkg).joinpath("languages", "en.json")
374+
) as p:
375+
if os.path.isfile(str(p)):
376+
with open(str(p), encoding="utf-8") as f:
377+
lang_data = json.load(f) or {}
378+
except Exception:
379+
pass
380+
381+
return lang_data
382+
except Exception:
383+
return {}
309384

310385
def add_data(self) -> None:
311386
"""Add data files or directories to be included with Nuitka."""

ENGINES/nuitka/languages/en.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"_meta": {
3+
"code": "en",
4+
"name": "English"
5+
},
6+
"tab_label": "Nuitka",
7+
"mode_label": "Mode:",
8+
"onefile_checkbox": "Onefile (--onefile)",
9+
"type_label": "Type:",
10+
"standalone_checkbox": "Standalone (--standalone)",
11+
"console_label": "Console:",
12+
"disable_console_checkbox": "Disable Windows console (--windows-disable-console)",
13+
"progress_label": "Progress:",
14+
"show_progress_checkbox": "Show progress (--show-progress)",
15+
"add_data_button": "add_data",
16+
"output_placeholder": "Output directory (--output-dir)",
17+
"icon_button": "🎨 Choose icon (.ico) Nuitka"
18+
}
19+

ENGINES/nuitka/languages/fr.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"_meta": {
3+
"code": "fr",
4+
"name": "Français"
5+
},
6+
"tab_label": "Nuitka",
7+
"mode_label": "Mode :",
8+
"onefile_checkbox": "Onefile (--onefile)",
9+
"type_label": "Type :",
10+
"standalone_checkbox": "Standalone (--standalone)",
11+
"console_label": "Console :",
12+
"disable_console_checkbox": "Désactiver la console Windows (--windows-disable-console)",
13+
"progress_label": "Progression :",
14+
"show_progress_checkbox": "Afficher la progression (--show-progress)",
15+
"add_data_button": "add_data",
16+
"output_placeholder": "Dossier de sortie (--output-dir)",
17+
"icon_button": "🎨 Choisir une icône (.ico) Nuitka"
18+
}
19+

ENGINES/pyinstaller/__init__.py

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,88 @@ def should_compile_file(self, gui, file: str, selected_files: list[str], python_
330330

331331
def apply_i18n(self, gui, tr: dict) -> None:
332332
"""Apply internationalization translations to the engine UI."""
333-
pass
333+
try:
334+
from Core.engines_loader.registry import resolve_language_code
335+
336+
# Resolve language code
337+
code = resolve_language_code(gui, tr)
338+
339+
# Load engine-local translations
340+
lang_data = self._load_language_file(code)
341+
342+
# Apply translations to UI elements if they exist
343+
if hasattr(self, "_opt_onefile") and "onefile_checkbox" in lang_data:
344+
self._opt_onefile.setText(lang_data["onefile_checkbox"])
345+
if hasattr(self, "_opt_windowed") and "windowed_checkbox" in lang_data:
346+
self._opt_windowed.setText(lang_data["windowed_checkbox"])
347+
if hasattr(self, "_opt_noconfirm") and "noconfirm_checkbox" in lang_data:
348+
self._opt_noconfirm.setText(lang_data["noconfirm_checkbox"])
349+
if hasattr(self, "_opt_clean") and "clean_checkbox" in lang_data:
350+
self._opt_clean.setText(lang_data["clean_checkbox"])
351+
if hasattr(self, "_opt_noupx") and "noupx_checkbox" in lang_data:
352+
self._opt_noupx.setText(lang_data["noupx_checkbox"])
353+
if hasattr(self, "_opt_main_only") and "main_only_checkbox" in lang_data:
354+
self._opt_main_only.setText(lang_data["main_only_checkbox"])
355+
if hasattr(self, "_btn_select_icon") and "icon_button" in lang_data:
356+
self._btn_select_icon.setText(lang_data["icon_button"])
357+
if hasattr(self, "_opt_debug") and "debug_checkbox" in lang_data:
358+
self._opt_debug.setText(lang_data["debug_checkbox"])
359+
if hasattr(self, "_pyinstaller_add_data") and "add_data_button" in lang_data:
360+
self._pyinstaller_add_data.setText(lang_data["add_data_button"])
361+
if hasattr(self, "_output_dir_input") and "output_placeholder" in lang_data:
362+
self._output_dir_input.setPlaceholderText(lang_data["output_placeholder"])
363+
except Exception:
364+
pass
365+
366+
def _load_language_file(self, code: str) -> dict:
367+
"""Load language file for the given code."""
368+
try:
369+
import importlib.resources as ilr
370+
import json
371+
372+
pkg = __package__
373+
lang_data = {}
374+
375+
# Try exact code first
376+
try:
377+
with ilr.as_file(
378+
ilr.files(pkg).joinpath("languages", f"{code}.json")
379+
) as p:
380+
if os.path.isfile(str(p)):
381+
with open(str(p), encoding="utf-8") as f:
382+
lang_data = json.load(f) or {}
383+
return lang_data
384+
except Exception:
385+
pass
386+
387+
# Fallback to base language (e.g., "fr" from "fr-CA")
388+
if "-" in code:
389+
base = code.split("-", 1)[0]
390+
try:
391+
with ilr.as_file(
392+
ilr.files(pkg).joinpath("languages", f"{base}.json")
393+
) as p:
394+
if os.path.isfile(str(p)):
395+
with open(str(p), encoding="utf-8") as f:
396+
lang_data = json.load(f) or {}
397+
return lang_data
398+
except Exception:
399+
pass
400+
401+
# Final fallback to English
402+
try:
403+
with ilr.as_file(
404+
ilr.files(pkg).joinpath("languages", "en.json")
405+
) as p:
406+
if os.path.isfile(str(p)):
407+
with open(str(p), encoding="utf-8") as f:
408+
lang_data = json.load(f) or {}
409+
except Exception:
410+
pass
411+
412+
return lang_data
413+
except Exception:
414+
return {}
334415

335416
def add_data(self) -> None:
336417
"""Add data files or directories to be included with PyInstaller."""
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"_meta": {
3+
"code": "en",
4+
"name": "English"
5+
},
6+
"tab_label": "PyInstaller",
7+
"mode_label": "Mode:",
8+
"onefile_checkbox": "Onefile",
9+
"console_label": "Console:",
10+
"windowed_checkbox": "Windowed",
11+
"confirmation_label": "Confirmation:",
12+
"noconfirm_checkbox": "Noconfirm",
13+
"cleanup_label": "Cleanup:",
14+
"clean_checkbox": "Clean",
15+
"compression_label": "Compression:",
16+
"noupx_checkbox": "No UPX",
17+
"files_label": "Files:",
18+
"main_only_checkbox": "Compile only main.py or app.py",
19+
"icon_button": "🎨 Choose icon (.ico)",
20+
"debug_checkbox": "Debug mode (--debug)",
21+
"add_data_button": "add_data",
22+
"output_placeholder": "Output directory (--distpath). Leave empty for ./dist"
23+
}
24+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"_meta": {
3+
"code": "fr",
4+
"name": "Français"
5+
},
6+
"tab_label": "PyInstaller",
7+
"mode_label": "Mode :",
8+
"onefile_checkbox": "Onefile",
9+
"console_label": "Console :",
10+
"windowed_checkbox": "Windowed",
11+
"confirmation_label": "Confirmation :",
12+
"noconfirm_checkbox": "Noconfirm",
13+
"cleanup_label": "Nettoyage :",
14+
"clean_checkbox": "Clean",
15+
"compression_label": "Compression :",
16+
"noupx_checkbox": "No UPX",
17+
"files_label": "Fichiers :",
18+
"main_only_checkbox": "Compiler uniquement main.py ou app.py",
19+
"icon_button": "🎨 Choisir une icône (.ico)",
20+
"debug_checkbox": "Mode debug (--debug)",
21+
"add_data_button": "add_data",
22+
"output_placeholder": "Dossier de sortie (--distpath). Laisser vide pour ./dist"
23+
}
24+

0 commit comments

Comments
 (0)