11from PyQt6 .QtWidgets import (QDialog , QVBoxLayout , QHBoxLayout , QTabWidget ,
22 QLineEdit , QComboBox , QCheckBox ,
33 QPushButton , QSpinBox , QTextEdit , QGroupBox ,
4- QFormLayout )
4+ QFormLayout , QLabel )
55import json
66import os
77
88class SettingsDialog (QDialog ):
99 def __init__ (self , parent = None ):
1010 super ().__init__ (parent )
11- self .setWindowTitle ("Settings" )
12- self .setMinimumWidth (500 )
13- self .setMinimumHeight (400 )
11+ # Initialize translations
12+ self .translations = {
13+ 'en' : {
14+ 'settings' : 'Settings' ,
15+ 'general' : 'General' ,
16+ 'models' : 'Models' ,
17+ 'advanced' : 'Advanced' ,
18+ 'save' : 'Save' ,
19+ 'cancel' : 'Cancel' ,
20+ 'general_settings' : 'General Settings' ,
21+ 'theme' : 'Theme:' ,
22+ 'language' : 'Language:' ,
23+ 'font_size' : 'Font Size:' ,
24+ 'max_history' : 'Max History Items:' ,
25+ 'enable_tts' : 'Enable Text-to-Speech:' ,
26+ 'model_settings' : 'Model Settings' ,
27+ 'default_model' : 'Default Model:' ,
28+ 'enable_streaming' : 'Enable Streaming:' ,
29+ 'system_prompt' : 'System Prompt:' ,
30+ 'advanced_settings' : 'Advanced Settings' ,
31+ 'api_url' : 'API URL:' ,
32+ 'temperature' : 'Temperature:'
33+ },
34+ 'fr' : {
35+ 'settings' : 'Paramètres' ,
36+ 'general' : 'Général' ,
37+ 'models' : 'Modèles' ,
38+ 'advanced' : 'Avancé' ,
39+ 'save' : 'Enregistrer' ,
40+ 'cancel' : 'Annuler' ,
41+ 'general_settings' : 'Paramètres Généraux' ,
42+ 'theme' : 'Thème:' ,
43+ 'language' : 'Langue:' ,
44+ 'font_size' : 'Taille de Police:' ,
45+ 'max_history' : 'Nombre Maximum d\' Éléments d\' Historique:' ,
46+ 'enable_tts' : 'Activer la Synthèse Vocale:' ,
47+ 'model_settings' : 'Paramètres du Modèle' ,
48+ 'default_model' : 'Modèle par Défaut:' ,
49+ 'enable_streaming' : 'Activer le Streaming:' ,
50+ 'system_prompt' : 'Invite Système:' ,
51+ 'advanced_settings' : 'Paramètres Avancés' ,
52+ 'api_url' : 'URL de l\' API:' ,
53+ 'temperature' : 'Température:'
54+ }
55+ }
1456
1557 # Load current settings
1658 self .settings = self .load_settings ()
1759
60+ # Set current language
61+ self .current_language = self .settings .get ('language' , 'en' )
62+
63+ self .setWindowTitle (self .tr ('settings' ))
64+ self .setMinimumWidth (500 )
65+ self .setMinimumHeight (400 )
66+
1867 self .init_ui ()
1968
69+ def tr (self , key ):
70+ """Translate a string using the current language"""
71+ return self .translations .get (self .current_language , {}).get (key , key )
72+
2073 def load_settings (self ):
2174 # Default settings
2275 default_settings = {
@@ -26,7 +79,8 @@ def load_settings(self):
2679 'text_to_speech' : False ,
2780 'system_prompt' : '' ,
2881 'max_history' : 50 ,
29- 'font_size' : 14
82+ 'font_size' : 14 ,
83+ 'language' : 'en' # Default language code
3084 }
3185
3286 # Try to load from file
@@ -43,108 +97,171 @@ def init_ui(self):
4397 layout = QVBoxLayout (self )
4498
4599 # Create tab widget
46- tabs = QTabWidget ()
100+ self . tabs = QTabWidget ()
47101
48102 # General settings tab
49103 general_tab = self .create_general_tab ()
50- tabs .addTab (general_tab , "General" )
104+ self . tabs .addTab (general_tab , self . tr ( 'general' ) )
51105
52106 # Models tab
53107 models_tab = self .create_models_tab ()
54- tabs .addTab (models_tab , "Models" )
108+ self . tabs .addTab (models_tab , self . tr ( 'models' ) )
55109
56110 # Advanced tab
57111 advanced_tab = self .create_advanced_tab ()
58- tabs .addTab (advanced_tab , "Advanced" )
112+ self . tabs .addTab (advanced_tab , self . tr ( 'advanced' ) )
59113
60114 # Add tab widget to layout
61- layout .addWidget (tabs )
115+ layout .addWidget (self . tabs )
62116
63117 # Add save/cancel buttons
64118 button_layout = QHBoxLayout ()
65- save_button = QPushButton ("Save" )
66- save_button .clicked .connect (self .save_settings )
67- cancel_button = QPushButton ("Cancel" )
68- cancel_button .clicked .connect (self .reject )
119+ self . save_button = QPushButton (self . tr ( 'save' ) )
120+ self . save_button .clicked .connect (self .save_settings )
121+ self . cancel_button = QPushButton (self . tr ( 'cancel' ) )
122+ self . cancel_button .clicked .connect (self .reject )
69123
70124 button_layout .addStretch ()
71- button_layout .addWidget (save_button )
72- button_layout .addWidget (cancel_button )
125+ button_layout .addWidget (self . save_button )
126+ button_layout .addWidget (self . cancel_button )
73127
74128 layout .addLayout (button_layout )
75129
76130 def create_general_tab (self ):
77- tab = QGroupBox ("General Settings" )
78- layout = QFormLayout (tab )
131+ self . general_group = QGroupBox (self . tr ( 'general_settings' ) )
132+ layout = QFormLayout (self . general_group )
79133
80134 # Theme selection
81135 self .theme_combo = QComboBox ()
82136 self .theme_combo .addItems (["dark" , "light" ])
83137 self .theme_combo .setCurrentText (self .settings .get ('theme' , 'dark' ))
84- layout .addRow ("Theme:" , self .theme_combo )
138+ self .theme_label = QLabel (self .tr ('theme' ))
139+ layout .addRow (self .theme_label , self .theme_combo )
140+
141+ # Language selection
142+ self .language_combo = QComboBox ()
143+ languages = [("English" , "en" ), ("Français" , "fr" )]
144+ for display , code in languages :
145+ self .language_combo .addItem (display , code )
146+
147+ # Set current language
148+ index = self .language_combo .findData (self .settings .get ('language' , 'en' ))
149+ if index >= 0 :
150+ self .language_combo .setCurrentIndex (index )
151+ self .language_combo .currentIndexChanged .connect (self .on_language_changed )
152+
153+ self .language_label = QLabel (self .tr ('language' ))
154+ layout .addRow (self .language_label , self .language_combo )
85155
86156 # Font size
87157 self .font_size = QSpinBox ()
88158 self .font_size .setRange (8 , 24 )
89159 self .font_size .setValue (self .settings .get ('font_size' , 14 ))
90- layout .addRow ("Font Size:" , self .font_size )
160+ self .font_size_label = QLabel (self .tr ('font_size' ))
161+ layout .addRow (self .font_size_label , self .font_size )
91162
92163 # Max history
93164 self .max_history = QSpinBox ()
94165 self .max_history .setRange (10 , 1000 )
95166 self .max_history .setValue (self .settings .get ('max_history' , 50 ))
96- layout .addRow ("Max History Items:" , self .max_history )
167+ self .max_history_label = QLabel (self .tr ('max_history' ))
168+ layout .addRow (self .max_history_label , self .max_history )
97169
98170 # Text to speech
99171 self .text_to_speech = QCheckBox ()
100172 self .text_to_speech .setChecked (self .settings .get ('text_to_speech' , False ))
101- layout .addRow ("Enable Text-to-Speech:" , self .text_to_speech )
173+ self .tts_label = QLabel (self .tr ('enable_tts' ))
174+ layout .addRow (self .tts_label , self .text_to_speech )
102175
103- return tab
176+ return self . general_group
104177
105178 def create_models_tab (self ):
106- tab = QGroupBox ("Model Settings" )
107- layout = QFormLayout (tab )
179+ self . models_group = QGroupBox (self . tr ( 'model_settings' ) )
180+ layout = QFormLayout (self . models_group )
108181
109182 # Default model
110183 self .default_model = QComboBox ()
111184 self .default_model .addItems (["llama3.2:1b" , "deepseek-r1" , "mistral:7b" , "llama2:13b" ])
112185 self .default_model .setCurrentText (self .settings .get ('default_model' , 'llama3.2:1b' ))
113- layout .addRow ("Default Model:" , self .default_model )
186+ self .model_label = QLabel (self .tr ('default_model' ))
187+ layout .addRow (self .model_label , self .default_model )
114188
115189 # Streaming
116190 self .streaming = QCheckBox ()
117191 self .streaming .setChecked (self .settings .get ('streaming' , True ))
118- layout .addRow ("Enable Streaming:" , self .streaming )
192+ self .streaming_label = QLabel (self .tr ('enable_streaming' ))
193+ layout .addRow (self .streaming_label , self .streaming )
119194
120195 # System prompt
121196 self .system_prompt = QTextEdit ()
122197 self .system_prompt .setPlainText (self .settings .get ('system_prompt' , '' ))
123198 self .system_prompt .setMaximumHeight (100 )
124- layout .addRow ("System Prompt:" , self .system_prompt )
199+ self .prompt_label = QLabel (self .tr ('system_prompt' ))
200+ layout .addRow (self .prompt_label , self .system_prompt )
125201
126- return tab
202+ return self . models_group
127203
128204 def create_advanced_tab (self ):
129- tab = QGroupBox ("Advanced Settings" )
130- layout = QFormLayout (tab )
205+ self . advanced_group = QGroupBox (self . tr ( 'advanced_settings' ) )
206+ layout = QFormLayout (self . advanced_group )
131207
132208 # API URL
133209 self .api_url = QLineEdit ()
134210 self .api_url .setText (self .settings .get ('api_url' , 'http://localhost:11434' ))
135- layout .addRow ("API URL:" , self .api_url )
211+ self .api_url_label = QLabel (self .tr ('api_url' ))
212+ layout .addRow (self .api_url_label , self .api_url )
136213
137214 # Temperature
138215 self .temperature = QSpinBox ()
139216 self .temperature .setRange (0 , 100 )
140217 self .temperature .setValue (int (self .settings .get ('temperature' , 70 )))
141- layout .addRow ("Temperature:" , self .temperature )
218+ self .temp_label = QLabel (self .tr ('temperature' ))
219+ layout .addRow (self .temp_label , self .temperature )
220+
221+ return self .advanced_group
222+
223+ def on_language_changed (self , index ):
224+ """Update UI language when selection changes"""
225+ lang_code = self .language_combo .itemData (index )
226+ if lang_code != self .current_language :
227+ self .current_language = lang_code
228+ self .update_ui_language ()
229+
230+ def update_ui_language (self ):
231+ """Update all UI elements to the current language"""
232+ # Update window title
233+ self .setWindowTitle (self .tr ('settings' ))
234+
235+ # Update tab names
236+ self .tabs .setTabText (0 , self .tr ('general' ))
237+ self .tabs .setTabText (1 , self .tr ('models' ))
238+ self .tabs .setTabText (2 , self .tr ('advanced' ))
239+
240+ # Update group titles
241+ self .general_group .setTitle (self .tr ('general_settings' ))
242+ self .models_group .setTitle (self .tr ('model_settings' ))
243+ self .advanced_group .setTitle (self .tr ('advanced_settings' ))
244+
245+ # Update labels
246+ self .theme_label .setText (self .tr ('theme' ))
247+ self .language_label .setText (self .tr ('language' ))
248+ self .font_size_label .setText (self .tr ('font_size' ))
249+ self .max_history_label .setText (self .tr ('max_history' ))
250+ self .tts_label .setText (self .tr ('enable_tts' ))
251+ self .model_label .setText (self .tr ('default_model' ))
252+ self .streaming_label .setText (self .tr ('enable_streaming' ))
253+ self .prompt_label .setText (self .tr ('system_prompt' ))
254+ self .api_url_label .setText (self .tr ('api_url' ))
255+ self .temp_label .setText (self .tr ('temperature' ))
142256
143- return tab
257+ # Update buttons
258+ self .save_button .setText (self .tr ('save' ))
259+ self .cancel_button .setText (self .tr ('cancel' ))
144260
145261 def save_settings (self ):
146262 # Update settings from UI
147263 self .settings ['theme' ] = self .theme_combo .currentText ()
264+ self .settings ['language' ] = self .language_combo .currentData () # Use code, not display name
148265 self .settings ['font_size' ] = self .font_size .value ()
149266 self .settings ['max_history' ] = self .max_history .value ()
150267 self .settings ['text_to_speech' ] = self .text_to_speech .isChecked ()
0 commit comments