1919from dataclasses import dataclass , field
2020from functools import lru_cache
2121
22+ try :
23+ from translator import TranslationSystem
24+ except Exception : # pragma: no cover - Uebersetzung ist optional
25+ TranslationSystem = None
26+
2227# ============================================================================
2328# KONSTANTEN
2429# ============================================================================
4348EXIT_FINDINGS = 2
4449EXIT_PARTIAL_ERROR = 3
4550
51+ # ============================================================================
52+ # SPRACHE / KONFIGURATION (Welle-1 U1: sichtbarer DE/EN-Sprachschalter)
53+ # ============================================================================
54+
55+ SUPPORTED_LANGUAGES = ("de" , "en" )
56+ DEFAULT_LANGUAGE = "de"
57+
58+ # Erste Zeile der Willkommensnachricht je Sprache (fuer Live-Neurendern beim Sprachwechsel)
59+ _WELCOME_HEADS = (
60+ "Willkommen beim Python Code Analyzer!" ,
61+ "Welcome to Python Code Analyzer!" ,
62+ )
63+
64+
65+ def _config_dir () -> pathlib .Path :
66+ """Per-User-Konfigverzeichnis (auch bei read-only Store-Installation schreibbar)."""
67+ if sys .platform .startswith ("win" ):
68+ base = os .environ .get ("APPDATA" ) or os .path .expanduser ("~" )
69+ else :
70+ base = os .environ .get ("XDG_CONFIG_HOME" ) or os .path .join (
71+ os .path .expanduser ("~" ), ".config"
72+ )
73+ return pathlib .Path (base ) / "MethodenAnalyser"
74+
75+
76+ def _config_path () -> pathlib .Path :
77+ return _config_dir () / "config.json"
78+
79+
80+ def load_app_config () -> Dict [str , Any ]:
81+ """Liest die persistente App-Konfiguration (leer bei Fehlen/Korruption)."""
82+ try :
83+ with open (_config_path (), "r" , encoding = "utf-8" ) as handle :
84+ data = json .load (handle )
85+ return data if isinstance (data , dict ) else {}
86+ except (OSError , ValueError ):
87+ return {}
88+
89+
90+ def save_app_config (config : Dict [str , Any ]) -> bool :
91+ """Speichert die App-Konfiguration; True bei Erfolg."""
92+ try :
93+ _config_dir ().mkdir (parents = True , exist_ok = True )
94+ with open (_config_path (), "w" , encoding = "utf-8" ) as handle :
95+ json .dump (config , handle , indent = 2 , ensure_ascii = False )
96+ return True
97+ except OSError :
98+ return False
99+
100+
101+ def get_saved_language () -> str :
102+ """Gespeicherte Sprache oder Default, validiert gegen SUPPORTED_LANGUAGES."""
103+ lang = load_app_config ().get ("language" , DEFAULT_LANGUAGE )
104+ return lang if lang in SUPPORTED_LANGUAGES else DEFAULT_LANGUAGE
105+
106+
107+ def set_saved_language (lang : str ) -> bool :
108+ """Persistiert die gewaehlte Sprache in der App-Konfiguration."""
109+ if lang not in SUPPORTED_LANGUAGES :
110+ return False
111+ config = load_app_config ()
112+ config ["language" ] = lang
113+ return save_app_config (config )
114+
115+
116+ _TRANSLATOR = None
117+
118+
119+ def get_translator ():
120+ """Lazy-Singleton des TranslationSystem, mit gespeicherter Sprache initialisiert."""
121+ global _TRANSLATOR
122+ if _TRANSLATOR is None and TranslationSystem is not None :
123+ _TRANSLATOR = TranslationSystem (get_saved_language ())
124+ return _TRANSLATOR
125+
126+
127+ def _t (key : str ) -> str :
128+ """Uebersetzt key in die aktuelle Sprache (Fallback: key selbst)."""
129+ translator = get_translator ()
130+ return translator .t (key ) if translator is not None else key
131+
132+
46133# Analyse Konfiguration
47134SIMILARITY_THRESHOLD = 0.8
48135
@@ -1552,6 +1639,11 @@ def progress_cb(cur, tot, fp):
15521639 messagebox .showerror ("Fehler" , str (e ))
15531640
15541641
1642+ def _build_welcome_text () -> str :
1643+ """Baut die uebersetzte Willkommensnachricht inkl. eingesetztem Shortcut-Hinweis."""
1644+ return _t ("welcome_body" ).replace ("{shortcut}" , _get_keyboard_shortcut_hint ())
1645+
1646+
15551647def create_gui () -> None :
15561648 """Erstellt und startet die GUI-Anwendung."""
15571649 root = tk .Tk ()
@@ -1570,20 +1662,13 @@ def create_gui() -> None:
15701662 def show_info_dialog () -> None :
15711663 messagebox .showinfo (
15721664 "Python Code Analyzer" ,
1573- f"Python Code Analyzer v{ TOOL_VERSION } \n \n "
1574- "Analysiert Python-Dateien auf:\n "
1575- "• Fehlende Definitionen\n "
1576- "• Ungenutzte Definitionen\n "
1577- "• Ungenutzte Imports\n "
1578- "• Dynamische Aufrufe\n "
1579- "• Import-Scope-Probleme\n \n "
1580- "© 2026 - Optimierte Version"
1665+ _t ("info_body" ).replace ("{version}" , TOOL_VERSION ),
15811666 )
15821667
15831668 # Analyse-Button
15841669 btn = tk .Button (
15851670 button_frame ,
1586- text = "📂 Datei analysieren" ,
1671+ text = _t ( "btn_analyze_file" ) ,
15871672 command = lambda : run_analysis (output ),
15881673 bg = "#4CAF50" ,
15891674 fg = "white" ,
@@ -1597,7 +1682,7 @@ def show_info_dialog() -> None:
15971682 # Info-Button
15981683 info_btn = tk .Button (
15991684 button_frame ,
1600- text = "ℹ️ Info" ,
1685+ text = _t ( "btn_info" ) ,
16011686 command = show_info_dialog ,
16021687 bg = "#2196F3" ,
16031688 fg = "white" ,
@@ -1611,7 +1696,7 @@ def show_info_dialog() -> None:
16111696 # Auto-Fix Button
16121697 fix_btn = tk .Button (
16131698 button_frame ,
1614- text = "🔧 Auto-Fix Imports" ,
1699+ text = _t ( "btn_autofix" ) ,
16151700 command = lambda : auto_fix_unused_imports (output ),
16161701 bg = "#FF9800" ,
16171702 fg = "white" ,
@@ -1625,7 +1710,7 @@ def show_info_dialog() -> None:
16251710 # NEU: Projekt-Analyse Button
16261711 project_btn = tk .Button (
16271712 button_frame ,
1628- text = "Projekt analysieren" ,
1713+ text = _t ( "btn_analyze_project" ) ,
16291714 command = lambda : run_project_analysis (output ),
16301715 bg = "#9C27B0" ,
16311716 fg = "white" ,
@@ -1658,17 +1743,43 @@ def show_info_dialog() -> None:
16581743 output .pack (fill = tk .BOTH , expand = True , padx = 10 , pady = (0 , 10 ))
16591744
16601745 # Willkommensnachricht
1661- welcome_text = (
1662- "Willkommen beim Python Code Analyzer!\n \n "
1663- f"{ _get_keyboard_shortcut_hint ()} \n \n "
1664- "Klicken Sie auf 'Datei analysieren', um eine Python-Datei zu untersuchen.\n \n "
1665- "Die Analyse umfasst:\n "
1666- "• Fehlende und ungenutzte Definitionen\n "
1667- "• Import-Analyse und -Optimierung\n "
1668- "• Dynamische Methodenaufrufe\n "
1669- "• Mögliche Tippfehler\n "
1746+ output .insert (tk .END , _build_welcome_text ())
1747+
1748+ # --- Menue "Sprache / Language" (Welle-1 U1: sichtbarer DE/EN-Schalter) ---
1749+ translator = get_translator ()
1750+ current_lang = translator .get_language () if translator is not None else get_saved_language ()
1751+ lang_var = tk .StringVar (value = current_lang )
1752+
1753+ def apply_language (lang : str ) -> None :
1754+ """Wechselt Sprache, persistiert sie und stellt die Oberflaeche live um."""
1755+ if translator is not None :
1756+ translator .set_language (lang )
1757+ set_saved_language (lang )
1758+ lang_var .set (lang )
1759+ btn .config (text = _t ("btn_analyze_file" ))
1760+ info_btn .config (text = _t ("btn_info" ))
1761+ fix_btn .config (text = _t ("btn_autofix" ))
1762+ project_btn .config (text = _t ("btn_analyze_project" ))
1763+ shortcut_hint .config (text = _get_keyboard_shortcut_hint ())
1764+ # Willkommenstext nur neu rendern, solange keine Analyse-Ausgabe angezeigt wird.
1765+ if output .get ("1.0" , "1.end" ).strip () in _WELCOME_HEADS :
1766+ output .delete ("1.0" , tk .END )
1767+ output .insert (tk .END , _build_welcome_text ())
1768+ messagebox .showinfo ("Sprache / Language" , _t ("lang_switched_msg" ))
1769+
1770+ menubar = tk .Menu (root )
1771+ lang_menu = tk .Menu (menubar , tearoff = 0 )
1772+ lang_menu .add_radiobutton (
1773+ label = "Deutsch" , value = "de" , variable = lang_var ,
1774+ command = lambda : apply_language ("de" ),
16701775 )
1671- output .insert (tk .END , welcome_text )
1776+ lang_menu .add_radiobutton (
1777+ label = "English" , value = "en" , variable = lang_var ,
1778+ command = lambda : apply_language ("en" ),
1779+ )
1780+ menubar .add_cascade (label = _t ("menu_language" ), menu = lang_menu )
1781+ root .config (menu = menubar )
1782+
16721783 _register_gui_shortcuts (
16731784 root ,
16741785 analyze_file_cb = lambda : run_analysis (output ),
@@ -1683,7 +1794,7 @@ def show_info_dialog() -> None:
16831794
16841795def _get_keyboard_shortcut_hint () -> str :
16851796 """Liefert den sichtbaren Kurzhinweis für die Hauptaktionen der GUI."""
1686- return "Tastatur: Alt+D Datei | Alt+P Projekt | Alt+F Auto-Fix | F1 Info"
1797+ return _t ( "shortcut_hint" )
16871798
16881799
16891800def _register_gui_shortcuts (
0 commit comments