src/eric7/Project/ProjectTranslationsBrowser.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
22 22
23 from EricWidgets import EricMessageBox 23 from EricWidgets import EricMessageBox
24 from EricWidgets.EricApplication import ericApp 24 from EricWidgets.EricApplication import ericApp
25 25
26 from .ProjectBrowserModel import ( 26 from .ProjectBrowserModel import (
27 ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem, 27 ProjectBrowserFileItem,
28 ProjectBrowserDirectoryItem, ProjectBrowserTranslationType 28 ProjectBrowserSimpleDirectoryItem,
29 ProjectBrowserDirectoryItem,
30 ProjectBrowserTranslationType,
29 ) 31 )
30 from .ProjectBaseBrowser import ProjectBaseBrowser 32 from .ProjectBaseBrowser import ProjectBaseBrowser
31 33
32 import UI.PixmapCache 34 import UI.PixmapCache
33 from UI.NotificationWidget import NotificationTypes 35 from UI.NotificationWidget import NotificationTypes
37 39
38 40
39 class ProjectTranslationsBrowser(ProjectBaseBrowser): 41 class ProjectTranslationsBrowser(ProjectBaseBrowser):
40 """ 42 """
41 A class used to display the translations part of the project. 43 A class used to display the translations part of the project.
42 44
43 @signal appendStdout(str) emitted after something was received from 45 @signal appendStdout(str) emitted after something was received from
44 a QProcess on stdout 46 a QProcess on stdout
45 @signal appendStderr(str) emitted after something was received from 47 @signal appendStderr(str) emitted after something was received from
46 a QProcess on stderr 48 a QProcess on stderr
47 @signal showMenu(str, QMenu) emitted when a menu is about to be shown. 49 @signal showMenu(str, QMenu) emitted when a menu is about to be shown.
48 The name of the menu and a reference to the menu are given. 50 The name of the menu and a reference to the menu are given.
49 """ 51 """
52
50 appendStdout = pyqtSignal(str) 53 appendStdout = pyqtSignal(str)
51 appendStderr = pyqtSignal(str) 54 appendStderr = pyqtSignal(str)
52 showMenu = pyqtSignal(str, QMenu) 55 showMenu = pyqtSignal(str, QMenu)
53 56
54 def __init__(self, project, parent=None): 57 def __init__(self, project, parent=None):
55 """ 58 """
56 Constructor 59 Constructor
57 60
58 @param project reference to the project object 61 @param project reference to the project object
59 @param parent parent widget of this browser (QWidget) 62 @param parent parent widget of this browser (QWidget)
60 """ 63 """
61 ProjectBaseBrowser.__init__(self, project, 64 ProjectBaseBrowser.__init__(
62 ProjectBrowserTranslationType, parent) 65 self, project, ProjectBrowserTranslationType, parent
66 )
63 self.isTranslationsBrowser = True 67 self.isTranslationsBrowser = True
64 68
65 self.selectedItemsFilter = [ProjectBrowserFileItem, 69 self.selectedItemsFilter = [
66 ProjectBrowserSimpleDirectoryItem] 70 ProjectBrowserFileItem,
67 71 ProjectBrowserSimpleDirectoryItem,
68 self.setWindowTitle(self.tr('Translations')) 72 ]
69 73
70 self.setWhatsThis(self.tr( 74 self.setWindowTitle(self.tr("Translations"))
71 """<b>Project Translations Browser</b>""" 75
72 """<p>This allows to easily see all translations contained in""" 76 self.setWhatsThis(
73 """ the current project. Several actions can be executed via""" 77 self.tr(
74 """ the context menu.</p>""" 78 """<b>Project Translations Browser</b>"""
75 )) 79 """<p>This allows to easily see all translations contained in"""
76 80 """ the current project. Several actions can be executed via"""
81 """ the context menu.</p>"""
82 )
83 )
84
77 self.__lreleaseProcesses = [] 85 self.__lreleaseProcesses = []
78 self.__pylupdateProcesses = [] 86 self.__pylupdateProcesses = []
79 self.lreleaseProcRunning = False 87 self.lreleaseProcRunning = False
80 self.pylupdateProcRunning = False 88 self.pylupdateProcRunning = False
81 self.__tmpProjects = [] 89 self.__tmpProjects = []
82 90
83 def _createPopupMenus(self): 91 def _createPopupMenus(self):
84 """ 92 """
85 Protected overloaded method to generate the popup menu. 93 Protected overloaded method to generate the popup menu.
86 """ 94 """
87 self.menuActions = [] 95 self.menuActions = []
88 self.multiMenuActions = [] 96 self.multiMenuActions = []
89 self.dirMenuActions = [] 97 self.dirMenuActions = []
90 self.dirMultiMenuActions = [] 98 self.dirMultiMenuActions = []
91 99
92 self.tsMenuActions = [] 100 self.tsMenuActions = []
93 self.qmMenuActions = [] 101 self.qmMenuActions = []
94 self.tsprocMenuActions = [] 102 self.tsprocMenuActions = []
95 self.qmprocMenuActions = [] 103 self.qmprocMenuActions = []
96 104
97 self.tsMultiMenuActions = [] 105 self.tsMultiMenuActions = []
98 self.qmMultiMenuActions = [] 106 self.qmMultiMenuActions = []
99 self.tsprocMultiMenuActions = [] 107 self.tsprocMultiMenuActions = []
100 self.qmprocMultiMenuActions = [] 108 self.qmprocMultiMenuActions = []
101 109
102 self.tsprocDirMenuActions = [] 110 self.tsprocDirMenuActions = []
103 self.qmprocDirMenuActions = [] 111 self.qmprocDirMenuActions = []
104 112
105 self.tsprocBackMenuActions = [] 113 self.tsprocBackMenuActions = []
106 self.qmprocBackMenuActions = [] 114 self.qmprocBackMenuActions = []
107 115
108 self.menu = QMenu(self) 116 self.menu = QMenu(self)
109 if self.project.getProjectType() in [ 117 if self.project.getProjectType() in [
110 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 118 "PyQt5",
111 "PySide2", "PySide2C", "PySide6", "PySide6C" 119 "PyQt5C",
120 "PyQt6",
121 "PyQt6C",
122 "E7Plugin",
123 "PySide2",
124 "PySide2C",
125 "PySide6",
126 "PySide6C",
112 ]: 127 ]:
113 act = self.menu.addAction( 128 act = self.menu.addAction(
114 self.tr('Generate translation'), self.__generateSelected) 129 self.tr("Generate translation"), self.__generateSelected
130 )
115 self.tsMenuActions.append(act) 131 self.tsMenuActions.append(act)
116 self.tsprocMenuActions.append(act) 132 self.tsprocMenuActions.append(act)
117 act = self.menu.addAction( 133 act = self.menu.addAction(
118 self.tr('Generate translation (with obsolete)'), 134 self.tr("Generate translation (with obsolete)"),
119 self.__generateObsoleteSelected) 135 self.__generateObsoleteSelected,
136 )
120 self.tsMenuActions.append(act) 137 self.tsMenuActions.append(act)
121 self.tsprocMenuActions.append(act) 138 self.tsprocMenuActions.append(act)
122 act = self.menu.addAction( 139 act = self.menu.addAction(
123 self.tr('Generate all translations'), self.__generateAll) 140 self.tr("Generate all translations"), self.__generateAll
141 )
124 self.tsprocMenuActions.append(act) 142 self.tsprocMenuActions.append(act)
125 act = self.menu.addAction( 143 act = self.menu.addAction(
126 self.tr('Generate all translations (with obsolete)'), 144 self.tr("Generate all translations (with obsolete)"),
127 self.__generateObsoleteAll) 145 self.__generateObsoleteAll,
146 )
128 self.tsprocMenuActions.append(act) 147 self.tsprocMenuActions.append(act)
129 self.menu.addSeparator() 148 self.menu.addSeparator()
130 act = self.menu.addAction( 149 act = self.menu.addAction(self.tr("Open in Qt-Linguist"), self._openItem)
131 self.tr('Open in Qt-Linguist'), self._openItem)
132 self.tsMenuActions.append(act) 150 self.tsMenuActions.append(act)
133 act = self.menu.addAction( 151 act = self.menu.addAction(
134 self.tr('Open in Editor'), self.__openFileInEditor) 152 self.tr("Open in Editor"), self.__openFileInEditor
153 )
135 self.tsMenuActions.append(act) 154 self.tsMenuActions.append(act)
136 self.menu.addSeparator() 155 self.menu.addSeparator()
137 act = self.menu.addAction( 156 act = self.menu.addAction(
138 self.tr('Release translation'), self.__releaseSelected) 157 self.tr("Release translation"), self.__releaseSelected
158 )
139 self.tsMenuActions.append(act) 159 self.tsMenuActions.append(act)
140 self.qmprocMenuActions.append(act) 160 self.qmprocMenuActions.append(act)
141 act = self.menu.addAction( 161 act = self.menu.addAction(
142 self.tr('Release all translations'), self.__releaseAll) 162 self.tr("Release all translations"), self.__releaseAll
163 )
143 self.qmprocMenuActions.append(act) 164 self.qmprocMenuActions.append(act)
144 self.menu.addSeparator() 165 self.menu.addSeparator()
145 act = self.menu.addAction( 166 act = self.menu.addAction(self.tr("Preview translation"), self.__TRPreview)
146 self.tr('Preview translation'), self.__TRPreview)
147 self.qmMenuActions.append(act) 167 self.qmMenuActions.append(act)
148 act = self.menu.addAction( 168 act = self.menu.addAction(
149 self.tr('Preview all translations'), self.__TRPreviewAll) 169 self.tr("Preview all translations"), self.__TRPreviewAll
170 )
150 self.menu.addSeparator() 171 self.menu.addSeparator()
151 else: 172 else:
152 if self.hooks["extractMessages"] is not None: 173 if self.hooks["extractMessages"] is not None:
153 act = self.menu.addAction( 174 act = self.menu.addAction(
154 self.hooksMenuEntries.get( 175 self.hooksMenuEntries.get(
155 "extractMessages", 176 "extractMessages", self.tr("Extract messages")
156 self.tr('Extract messages')), 177 ),
157 self.__extractMessages) 178 self.__extractMessages,
179 )
158 self.menuActions.append(act) 180 self.menuActions.append(act)
159 self.menu.addSeparator() 181 self.menu.addSeparator()
160 if self.hooks["generateSelected"] is not None: 182 if self.hooks["generateSelected"] is not None:
161 act = self.menu.addAction( 183 act = self.menu.addAction(
162 self.hooksMenuEntries.get( 184 self.hooksMenuEntries.get(
163 "generateSelected", 185 "generateSelected", self.tr("Generate translation")
164 self.tr('Generate translation')), 186 ),
165 self.__generateSelected) 187 self.__generateSelected,
188 )
166 self.tsMenuActions.append(act) 189 self.tsMenuActions.append(act)
167 self.tsprocMenuActions.append(act) 190 self.tsprocMenuActions.append(act)
168 if self.hooks["generateSelectedWithObsolete"] is not None: 191 if self.hooks["generateSelectedWithObsolete"] is not None:
169 act = self.menu.addAction( 192 act = self.menu.addAction(
170 self.hooksMenuEntries.get( 193 self.hooksMenuEntries.get(
171 "generateSelectedWithObsolete", 194 "generateSelectedWithObsolete",
172 self.tr('Generate translation (with obsolete)')), 195 self.tr("Generate translation (with obsolete)"),
173 self.__generateObsoleteSelected) 196 ),
197 self.__generateObsoleteSelected,
198 )
174 self.tsMenuActions.append(act) 199 self.tsMenuActions.append(act)
175 self.tsprocMenuActions.append(act) 200 self.tsprocMenuActions.append(act)
176 if self.hooks["generateAll"] is not None: 201 if self.hooks["generateAll"] is not None:
177 act = self.menu.addAction( 202 act = self.menu.addAction(
178 self.hooksMenuEntries.get( 203 self.hooksMenuEntries.get(
179 "generateAll", 204 "generateAll", self.tr("Generate all translations")
180 self.tr('Generate all translations')), 205 ),
181 self.__generateAll) 206 self.__generateAll,
207 )
182 self.tsprocMenuActions.append(act) 208 self.tsprocMenuActions.append(act)
183 if self.hooks["generateAllWithObsolete"] is not None: 209 if self.hooks["generateAllWithObsolete"] is not None:
184 act = self.menu.addAction( 210 act = self.menu.addAction(
185 self.hooksMenuEntries.get( 211 self.hooksMenuEntries.get(
186 "generateAllWithObsolete", 212 "generateAllWithObsolete",
187 self.tr( 213 self.tr("Generate all translations (with obsolete)"),
188 'Generate all translations (with obsolete)')), 214 ),
189 self.__generateObsoleteAll) 215 self.__generateObsoleteAll,
216 )
190 self.tsprocMenuActions.append(act) 217 self.tsprocMenuActions.append(act)
191 self.menu.addSeparator() 218 self.menu.addSeparator()
192 if self.hooks["open"] is not None: 219 if self.hooks["open"] is not None:
193 act = self.menu.addAction( 220 act = self.menu.addAction(
194 self.hooksMenuEntries.get( 221 self.hooksMenuEntries.get("open", self.tr("Open")), self._openItem
195 "open", self.tr('Open')), 222 )
196 self._openItem)
197 self.tsMenuActions.append(act) 223 self.tsMenuActions.append(act)
198 act = self.menu.addAction( 224 act = self.menu.addAction(
199 self.tr('Open in Editor'), self.__openFileInEditor) 225 self.tr("Open in Editor"), self.__openFileInEditor
226 )
200 self.tsMenuActions.append(act) 227 self.tsMenuActions.append(act)
201 self.menu.addSeparator() 228 self.menu.addSeparator()
202 if self.hooks["releaseSelected"] is not None: 229 if self.hooks["releaseSelected"] is not None:
203 act = self.menu.addAction( 230 act = self.menu.addAction(
204 self.hooksMenuEntries.get( 231 self.hooksMenuEntries.get(
205 "releaseSelected", 232 "releaseSelected", self.tr("Release translation")
206 self.tr('Release translation')), 233 ),
207 self.__releaseSelected) 234 self.__releaseSelected,
235 )
208 self.tsMenuActions.append(act) 236 self.tsMenuActions.append(act)
209 self.qmprocMenuActions.append(act) 237 self.qmprocMenuActions.append(act)
210 if self.hooks["releaseAll"] is not None: 238 if self.hooks["releaseAll"] is not None:
211 act = self.menu.addAction( 239 act = self.menu.addAction(
212 self.hooksMenuEntries.get( 240 self.hooksMenuEntries.get(
213 "releaseAll", 241 "releaseAll", self.tr("Release all translations")
214 self.tr('Release all translations')), 242 ),
215 self.__releaseAll) 243 self.__releaseAll,
244 )
216 self.qmprocMenuActions.append(act) 245 self.qmprocMenuActions.append(act)
217 self.menu.addSeparator() 246 self.menu.addSeparator()
218 act = self.menu.addAction( 247 act = self.menu.addAction(
219 self.tr('Remove from project'), self.__removeLanguageFile) 248 self.tr("Remove from project"), self.__removeLanguageFile
249 )
220 self.menuActions.append(act) 250 self.menuActions.append(act)
221 act = self.menu.addAction( 251 act = self.menu.addAction(self.tr("Delete"), self.__deleteLanguageFile)
222 self.tr('Delete'), self.__deleteLanguageFile)
223 self.menuActions.append(act) 252 self.menuActions.append(act)
224 self.menu.addSeparator() 253 self.menu.addSeparator()
225 self.__addTranslationAct = self.menu.addAction( 254 self.__addTranslationAct = self.menu.addAction(
226 self.tr('Add translation...'), self.project.addLanguage) 255 self.tr("Add translation..."), self.project.addLanguage
256 )
227 self.menu.addAction( 257 self.menu.addAction(
228 self.tr('Add translation files...'), 258 self.tr("Add translation files..."), self.__addTranslationFiles
229 self.__addTranslationFiles) 259 )
230 self.menu.addSeparator() 260 self.menu.addSeparator()
231 self.menu.addAction( 261 self.menu.addAction(self.tr("Copy Path to Clipboard"), self._copyToClipboard)
232 self.tr('Copy Path to Clipboard'), self._copyToClipboard)
233 self.menu.addSeparator() 262 self.menu.addSeparator()
234 self.menu.addAction(self.tr('Configure...'), self._configure) 263 self.menu.addAction(self.tr("Configure..."), self._configure)
235 264
236 self.backMenu = QMenu(self) 265 self.backMenu = QMenu(self)
237 if self.project.getProjectType() in [ 266 if self.project.getProjectType() in [
238 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 267 "PyQt5",
239 "PySide2", "PySide2C", "PySide6", "PySide6C" 268 "PyQt5C",
269 "PyQt6",
270 "PyQt6C",
271 "E7Plugin",
272 "PySide2",
273 "PySide2C",
274 "PySide6",
275 "PySide6C",
240 ]: 276 ]:
241 act = self.backMenu.addAction( 277 act = self.backMenu.addAction(
242 self.tr('Generate all translations'), 278 self.tr("Generate all translations"), self.__generateAll
243 self.__generateAll) 279 )
244 self.tsprocBackMenuActions.append(act) 280 self.tsprocBackMenuActions.append(act)
245 act = self.backMenu.addAction( 281 act = self.backMenu.addAction(
246 self.tr('Generate all translations (with obsolete)'), 282 self.tr("Generate all translations (with obsolete)"),
247 self.__generateObsoleteAll) 283 self.__generateObsoleteAll,
284 )
248 self.tsprocBackMenuActions.append(act) 285 self.tsprocBackMenuActions.append(act)
249 act = self.backMenu.addAction( 286 act = self.backMenu.addAction(
250 self.tr('Release all translations'), 287 self.tr("Release all translations"), self.__releaseAll
251 self.__releaseAll) 288 )
252 self.qmprocBackMenuActions.append(act) 289 self.qmprocBackMenuActions.append(act)
253 self.backMenu.addSeparator() 290 self.backMenu.addSeparator()
254 act = self.backMenu.addAction( 291 act = self.backMenu.addAction(
255 self.tr('Preview all translations'), 292 self.tr("Preview all translations"), self.__TRPreview
256 self.__TRPreview) 293 )
257 else: 294 else:
258 if self.hooks["extractMessages"] is not None: 295 if self.hooks["extractMessages"] is not None:
259 act = self.backMenu.addAction( 296 act = self.backMenu.addAction(
260 self.hooksMenuEntries.get( 297 self.hooksMenuEntries.get(
261 "extractMessages", 298 "extractMessages", self.tr("Extract messages")
262 self.tr('Extract messages')), 299 ),
263 self.__extractMessages) 300 self.__extractMessages,
301 )
264 self.backMenu.addSeparator() 302 self.backMenu.addSeparator()
265 if self.hooks["generateAll"] is not None: 303 if self.hooks["generateAll"] is not None:
266 act = self.backMenu.addAction( 304 act = self.backMenu.addAction(
267 self.hooksMenuEntries.get( 305 self.hooksMenuEntries.get(
268 "generateAll", 306 "generateAll", self.tr("Generate all translations")
269 self.tr('Generate all translations')), 307 ),
270 self.__generateAll) 308 self.__generateAll,
309 )
271 self.tsprocBackMenuActions.append(act) 310 self.tsprocBackMenuActions.append(act)
272 if self.hooks["generateAllWithObsolete"] is not None: 311 if self.hooks["generateAllWithObsolete"] is not None:
273 act = self.backMenu.addAction( 312 act = self.backMenu.addAction(
274 self.hooksMenuEntries.get( 313 self.hooksMenuEntries.get(
275 "generateAllWithObsolete", 314 "generateAllWithObsolete",
276 self.tr( 315 self.tr("Generate all translations (with obsolete)"),
277 'Generate all translations (with obsolete)')), 316 ),
278 self.__generateObsoleteAll) 317 self.__generateObsoleteAll,
318 )
279 self.tsprocBackMenuActions.append(act) 319 self.tsprocBackMenuActions.append(act)
280 if self.hooks["releaseAll"] is not None: 320 if self.hooks["releaseAll"] is not None:
281 act = self.backMenu.addAction( 321 act = self.backMenu.addAction(
282 self.hooksMenuEntries.get( 322 self.hooksMenuEntries.get(
283 "releaseAll", 323 "releaseAll", self.tr("Release all translations")
284 self.tr('Release all translations')), 324 ),
285 self.__releaseAll) 325 self.__releaseAll,
326 )
286 self.qmprocBackMenuActions.append(act) 327 self.qmprocBackMenuActions.append(act)
287 self.backMenu.addSeparator() 328 self.backMenu.addSeparator()
288 self.__addTranslationBackAct = self.backMenu.addAction( 329 self.__addTranslationBackAct = self.backMenu.addAction(
289 self.tr('Add translation...'), self.project.addLanguage) 330 self.tr("Add translation..."), self.project.addLanguage
331 )
290 self.backMenu.addAction( 332 self.backMenu.addAction(
291 self.tr('Add translation files...'), 333 self.tr("Add translation files..."), self.__addTranslationFiles
292 self.__addTranslationFiles) 334 )
293 self.backMenu.addSeparator() 335 self.backMenu.addSeparator()
294 self.backMenu.addAction(self.tr('Configure...'), self._configure) 336 self.backMenu.addAction(self.tr("Configure..."), self._configure)
295 self.backMenu.setEnabled(False) 337 self.backMenu.setEnabled(False)
296 338
297 # create the menu for multiple selected files 339 # create the menu for multiple selected files
298 self.multiMenu = QMenu(self) 340 self.multiMenu = QMenu(self)
299 if self.project.getProjectType() in [ 341 if self.project.getProjectType() in [
300 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 342 "PyQt5",
301 "PySide2", "PySide2C", "PySide6", "PySide6C" 343 "PyQt5C",
344 "PyQt6",
345 "PyQt6C",
346 "E7Plugin",
347 "PySide2",
348 "PySide2C",
349 "PySide6",
350 "PySide6C",
302 ]: 351 ]:
303 act = self.multiMenu.addAction( 352 act = self.multiMenu.addAction(
304 self.tr('Generate translations'), 353 self.tr("Generate translations"), self.__generateSelected
305 self.__generateSelected) 354 )
306 self.tsMultiMenuActions.append(act) 355 self.tsMultiMenuActions.append(act)
307 self.tsprocMultiMenuActions.append(act) 356 self.tsprocMultiMenuActions.append(act)
308 act = self.multiMenu.addAction( 357 act = self.multiMenu.addAction(
309 self.tr('Generate translations (with obsolete)'), 358 self.tr("Generate translations (with obsolete)"),
310 self.__generateObsoleteSelected) 359 self.__generateObsoleteSelected,
360 )
311 self.tsMultiMenuActions.append(act) 361 self.tsMultiMenuActions.append(act)
312 self.tsprocMultiMenuActions.append(act) 362 self.tsprocMultiMenuActions.append(act)
313 self.multiMenu.addSeparator() 363 self.multiMenu.addSeparator()
314 act = self.multiMenu.addAction( 364 act = self.multiMenu.addAction(
315 self.tr('Open in Qt-Linguist'), self._openItem) 365 self.tr("Open in Qt-Linguist"), self._openItem
366 )
316 self.tsMultiMenuActions.append(act) 367 self.tsMultiMenuActions.append(act)
317 act = self.multiMenu.addAction( 368 act = self.multiMenu.addAction(
318 self.tr('Open in Editor'), self.__openFileInEditor) 369 self.tr("Open in Editor"), self.__openFileInEditor
370 )
319 self.tsMultiMenuActions.append(act) 371 self.tsMultiMenuActions.append(act)
320 self.multiMenu.addSeparator() 372 self.multiMenu.addSeparator()
321 act = self.multiMenu.addAction( 373 act = self.multiMenu.addAction(
322 self.tr('Release translations'), self.__releaseSelected) 374 self.tr("Release translations"), self.__releaseSelected
375 )
323 self.tsMultiMenuActions.append(act) 376 self.tsMultiMenuActions.append(act)
324 self.qmprocMultiMenuActions.append(act) 377 self.qmprocMultiMenuActions.append(act)
325 self.multiMenu.addSeparator() 378 self.multiMenu.addSeparator()
326 act = self.multiMenu.addAction( 379 act = self.multiMenu.addAction(
327 self.tr('Preview translations'), self.__TRPreview) 380 self.tr("Preview translations"), self.__TRPreview
381 )
328 self.qmMultiMenuActions.append(act) 382 self.qmMultiMenuActions.append(act)
329 else: 383 else:
330 if self.hooks["extractMessages"] is not None: 384 if self.hooks["extractMessages"] is not None:
331 act = self.multiMenu.addAction( 385 act = self.multiMenu.addAction(
332 self.hooksMenuEntries.get( 386 self.hooksMenuEntries.get(
333 "extractMessages", 387 "extractMessages", self.tr("Extract messages")
334 self.tr('Extract messages')), 388 ),
335 self.__extractMessages) 389 self.__extractMessages,
390 )
336 self.multiMenuActions.append(act) 391 self.multiMenuActions.append(act)
337 self.multiMenu.addSeparator() 392 self.multiMenu.addSeparator()
338 if self.hooks["generateSelected"] is not None: 393 if self.hooks["generateSelected"] is not None:
339 act = self.multiMenu.addAction( 394 act = self.multiMenu.addAction(
340 self.hooksMenuEntries.get( 395 self.hooksMenuEntries.get(
341 "generateSelected", 396 "generateSelected", self.tr("Generate translations")
342 self.tr('Generate translations')), 397 ),
343 self.__generateSelected) 398 self.__generateSelected,
399 )
344 self.tsMultiMenuActions.append(act) 400 self.tsMultiMenuActions.append(act)
345 self.tsprocMultiMenuActions.append(act) 401 self.tsprocMultiMenuActions.append(act)
346 if self.hooks["generateSelectedWithObsolete"] is not None: 402 if self.hooks["generateSelectedWithObsolete"] is not None:
347 act = self.multiMenu.addAction( 403 act = self.multiMenu.addAction(
348 self.hooksMenuEntries.get( 404 self.hooksMenuEntries.get(
349 "generateSelectedWithObsolete", 405 "generateSelectedWithObsolete",
350 self.tr('Generate translations (with obsolete)')), 406 self.tr("Generate translations (with obsolete)"),
351 self.__generateObsoleteSelected) 407 ),
408 self.__generateObsoleteSelected,
409 )
352 self.tsMultiMenuActions.append(act) 410 self.tsMultiMenuActions.append(act)
353 self.tsprocMultiMenuActions.append(act) 411 self.tsprocMultiMenuActions.append(act)
354 self.multiMenu.addSeparator() 412 self.multiMenu.addSeparator()
355 if self.hooks["open"] is not None: 413 if self.hooks["open"] is not None:
356 act = self.multiMenu.addAction( 414 act = self.multiMenu.addAction(
357 self.hooksMenuEntries.get( 415 self.hooksMenuEntries.get("open", self.tr("Open")), self._openItem
358 "open", self.tr('Open')), 416 )
359 self._openItem)
360 self.tsMultiMenuActions.append(act) 417 self.tsMultiMenuActions.append(act)
361 act = self.multiMenu.addAction( 418 act = self.multiMenu.addAction(
362 self.tr('Open in Editor'), self.__openFileInEditor) 419 self.tr("Open in Editor"), self.__openFileInEditor
420 )
363 self.tsMultiMenuActions.append(act) 421 self.tsMultiMenuActions.append(act)
364 self.multiMenu.addSeparator() 422 self.multiMenu.addSeparator()
365 if self.hooks["releaseSelected"] is not None: 423 if self.hooks["releaseSelected"] is not None:
366 act = self.multiMenu.addAction( 424 act = self.multiMenu.addAction(
367 self.hooksMenuEntries.get( 425 self.hooksMenuEntries.get(
368 "releaseSelected", 426 "releaseSelected", self.tr("Release translations")
369 self.tr('Release translations')), 427 ),
370 self.__releaseSelected) 428 self.__releaseSelected,
429 )
371 self.tsMultiMenuActions.append(act) 430 self.tsMultiMenuActions.append(act)
372 self.qmprocMultiMenuActions.append(act) 431 self.qmprocMultiMenuActions.append(act)
373 self.multiMenu.addSeparator() 432 self.multiMenu.addSeparator()
374 act = self.multiMenu.addAction( 433 act = self.multiMenu.addAction(
375 self.tr('Remove from project'), self.__removeLanguageFile) 434 self.tr("Remove from project"), self.__removeLanguageFile
435 )
376 self.multiMenuActions.append(act) 436 self.multiMenuActions.append(act)
377 act = self.multiMenu.addAction( 437 act = self.multiMenu.addAction(self.tr("Delete"), self.__deleteLanguageFile)
378 self.tr('Delete'), self.__deleteLanguageFile)
379 self.multiMenuActions.append(act) 438 self.multiMenuActions.append(act)
380 self.multiMenu.addSeparator() 439 self.multiMenu.addSeparator()
381 self.multiMenu.addAction(self.tr('Configure...'), self._configure) 440 self.multiMenu.addAction(self.tr("Configure..."), self._configure)
382 441
383 self.dirMenu = QMenu(self) 442 self.dirMenu = QMenu(self)
384 if self.project.getProjectType() in [ 443 if self.project.getProjectType() in [
385 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 444 "PyQt5",
386 "PySide2", "PySide2C", "PySide6", "PySide6C" 445 "PyQt5C",
446 "PyQt6",
447 "PyQt6C",
448 "E7Plugin",
449 "PySide2",
450 "PySide2C",
451 "PySide6",
452 "PySide6C",
387 ]: 453 ]:
388 act = self.dirMenu.addAction( 454 act = self.dirMenu.addAction(
389 self.tr('Generate all translations'), 455 self.tr("Generate all translations"), self.__generateAll
390 self.__generateAll) 456 )
391 self.tsprocDirMenuActions.append(act) 457 self.tsprocDirMenuActions.append(act)
392 act = self.dirMenu.addAction( 458 act = self.dirMenu.addAction(
393 self.tr('Generate all translations (with obsolete)'), 459 self.tr("Generate all translations (with obsolete)"),
394 self.__generateObsoleteAll) 460 self.__generateObsoleteAll,
461 )
395 self.tsprocDirMenuActions.append(act) 462 self.tsprocDirMenuActions.append(act)
396 act = self.dirMenu.addAction( 463 act = self.dirMenu.addAction(
397 self.tr('Release all translations'), 464 self.tr("Release all translations"), self.__releaseAll
398 self.__releaseAll) 465 )
399 self.qmprocDirMenuActions.append(act) 466 self.qmprocDirMenuActions.append(act)
400 self.dirMenu.addSeparator() 467 self.dirMenu.addSeparator()
401 act = self.dirMenu.addAction( 468 act = self.dirMenu.addAction(
402 self.tr('Preview all translations'), 469 self.tr("Preview all translations"), self.__TRPreview
403 self.__TRPreview) 470 )
404 else: 471 else:
405 if self.hooks["extractMessages"] is not None: 472 if self.hooks["extractMessages"] is not None:
406 act = self.dirMenu.addAction( 473 act = self.dirMenu.addAction(
407 self.hooksMenuEntries.get( 474 self.hooksMenuEntries.get(
408 "extractMessages", 475 "extractMessages", self.tr("Extract messages")
409 self.tr('Extract messages')), 476 ),
410 self.__extractMessages) 477 self.__extractMessages,
478 )
411 self.dirMenuActions.append(act) 479 self.dirMenuActions.append(act)
412 self.dirMenu.addSeparator() 480 self.dirMenu.addSeparator()
413 if self.hooks["generateAll"] is not None: 481 if self.hooks["generateAll"] is not None:
414 act = self.dirMenu.addAction( 482 act = self.dirMenu.addAction(
415 self.hooksMenuEntries.get( 483 self.hooksMenuEntries.get(
416 "generateAll", 484 "generateAll", self.tr("Generate all translations")
417 self.tr('Generate all translations')), 485 ),
418 self.__generateAll) 486 self.__generateAll,
487 )
419 self.tsprocDirMenuActions.append(act) 488 self.tsprocDirMenuActions.append(act)
420 if self.hooks["generateAllWithObsolete"] is not None: 489 if self.hooks["generateAllWithObsolete"] is not None:
421 act = self.dirMenu.addAction( 490 act = self.dirMenu.addAction(
422 self.hooksMenuEntries.get( 491 self.hooksMenuEntries.get(
423 "generateAllWithObsolete", 492 "generateAllWithObsolete",
424 self.tr( 493 self.tr("Generate all translations (with obsolete)"),
425 'Generate all translations (with obsolete)')), 494 ),
426 self.__generateObsoleteAll) 495 self.__generateObsoleteAll,
496 )
427 self.tsprocDirMenuActions.append(act) 497 self.tsprocDirMenuActions.append(act)
428 if self.hooks["releaseAll"] is not None: 498 if self.hooks["releaseAll"] is not None:
429 act = self.dirMenu.addAction( 499 act = self.dirMenu.addAction(
430 self.hooksMenuEntries.get( 500 self.hooksMenuEntries.get(
431 "releaseAll", 501 "releaseAll", self.tr("Release all translations")
432 self.tr('Release all translations')), 502 ),
433 self.__releaseAll) 503 self.__releaseAll,
504 )
434 self.qmprocDirMenuActions.append(act) 505 self.qmprocDirMenuActions.append(act)
435 self.dirMenu.addSeparator() 506 self.dirMenu.addSeparator()
436 act = self.dirMenu.addAction( 507 act = self.dirMenu.addAction(self.tr("Delete"), self._deleteDirectory)
437 self.tr('Delete'), self._deleteDirectory)
438 self.dirMenuActions.append(act) 508 self.dirMenuActions.append(act)
439 self.dirMenu.addSeparator() 509 self.dirMenu.addSeparator()
440 self.__addTranslationDirAct = self.dirMenu.addAction( 510 self.__addTranslationDirAct = self.dirMenu.addAction(
441 self.tr('Add translation...'), self.project.addLanguage) 511 self.tr("Add translation..."), self.project.addLanguage
512 )
442 self.dirMenu.addAction( 513 self.dirMenu.addAction(
443 self.tr('Add translation files...'), 514 self.tr("Add translation files..."), self.__addTranslationFiles
444 self.__addTranslationFiles) 515 )
445 self.dirMenu.addSeparator() 516 self.dirMenu.addSeparator()
446 self.dirMenu.addAction( 517 self.dirMenu.addAction(self.tr("Copy Path to Clipboard"), self._copyToClipboard)
447 self.tr('Copy Path to Clipboard'), self._copyToClipboard)
448 self.dirMenu.addSeparator() 518 self.dirMenu.addSeparator()
449 self.dirMenu.addAction(self.tr('Configure...'), self._configure) 519 self.dirMenu.addAction(self.tr("Configure..."), self._configure)
450 520
451 self.dirMultiMenu = None 521 self.dirMultiMenu = None
452 522
453 self.menu.aboutToShow.connect(self.__showContextMenu) 523 self.menu.aboutToShow.connect(self.__showContextMenu)
454 self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti) 524 self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti)
455 self.dirMenu.aboutToShow.connect(self.__showContextMenuDir) 525 self.dirMenu.aboutToShow.connect(self.__showContextMenuDir)
456 self.backMenu.aboutToShow.connect(self.__showContextMenuBack) 526 self.backMenu.aboutToShow.connect(self.__showContextMenuBack)
457 self.mainMenu = self.menu 527 self.mainMenu = self.menu
458 528
459 def _contextMenuRequested(self, coord): 529 def _contextMenuRequested(self, coord):
460 """ 530 """
461 Protected slot to show the context menu. 531 Protected slot to show the context menu.
462 532
463 @param coord the position of the mouse pointer (QPoint) 533 @param coord the position of the mouse pointer (QPoint)
464 """ 534 """
465 if not self.project.isOpen(): 535 if not self.project.isOpen():
466 return 536 return
467 537
468 with contextlib.suppress(Exception): 538 with contextlib.suppress(Exception):
469 categories = self.getSelectedItemsCountCategorized( 539 categories = self.getSelectedItemsCountCategorized(
470 [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem]) 540 [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem]
541 )
471 cnt = categories["sum"] 542 cnt = categories["sum"]
472 if cnt <= 1: 543 if cnt <= 1:
473 index = self.indexAt(coord) 544 index = self.indexAt(coord)
474 if index.isValid(): 545 if index.isValid():
475 self._selectSingleItem(index) 546 self._selectSingleItem(index)
476 categories = self.getSelectedItemsCountCategorized( 547 categories = self.getSelectedItemsCountCategorized(
477 [ProjectBrowserFileItem, 548 [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem]
478 ProjectBrowserSimpleDirectoryItem]) 549 )
479 cnt = categories["sum"] 550 cnt = categories["sum"]
480 551
481 bfcnt = categories[str(ProjectBrowserFileItem)] 552 bfcnt = categories[str(ProjectBrowserFileItem)]
482 sdcnt = categories[str(ProjectBrowserSimpleDirectoryItem)] 553 sdcnt = categories[str(ProjectBrowserSimpleDirectoryItem)]
483 if cnt > 1 and cnt == bfcnt: 554 if cnt > 1 and cnt == bfcnt:
484 self.multiMenu.popup(self.mapToGlobal(coord)) 555 self.multiMenu.popup(self.mapToGlobal(coord))
485 else: 556 else:
491 self.dirMenu.popup(self.mapToGlobal(coord)) 562 self.dirMenu.popup(self.mapToGlobal(coord))
492 else: 563 else:
493 self.backMenu.popup(self.mapToGlobal(coord)) 564 self.backMenu.popup(self.mapToGlobal(coord))
494 else: 565 else:
495 self.backMenu.popup(self.mapToGlobal(coord)) 566 self.backMenu.popup(self.mapToGlobal(coord))
496 567
497 def __showContextMenu(self): 568 def __showContextMenu(self):
498 """ 569 """
499 Private slot called by the menu aboutToShow signal. 570 Private slot called by the menu aboutToShow signal.
500 """ 571 """
501 if self.project.getProjectType() in [ 572 if self.project.getProjectType() in [
502 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 573 "PyQt5",
503 "PySide2", "PySide2C", "PySide6", "PySide6C" 574 "PyQt5C",
575 "PyQt6",
576 "PyQt6C",
577 "E7Plugin",
578 "PySide2",
579 "PySide2C",
580 "PySide6",
581 "PySide6C",
504 ]: 582 ]:
505 tsFiles = 0 583 tsFiles = 0
506 qmFiles = 0 584 qmFiles = 0
507 itmList = self.getSelectedItems() 585 itmList = self.getSelectedItems()
508 for itm in itmList[:]: 586 for itm in itmList[:]:
509 if itm.fileName().endswith('.ts'): 587 if itm.fileName().endswith(".ts"):
510 tsFiles += 1 588 tsFiles += 1
511 elif itm.fileName().endswith('.qm'): 589 elif itm.fileName().endswith(".qm"):
512 qmFiles += 1 590 qmFiles += 1
513 if ( 591 if (tsFiles > 0 and qmFiles > 0) or (tsFiles == 0 and qmFiles == 0):
514 (tsFiles > 0 and qmFiles > 0) or
515 (tsFiles == 0 and qmFiles == 0)
516 ):
517 for act in self.tsMenuActions + self.qmMenuActions: 592 for act in self.tsMenuActions + self.qmMenuActions:
518 act.setEnabled(False) 593 act.setEnabled(False)
519 elif tsFiles > 0: 594 elif tsFiles > 0:
520 for act in self.tsMenuActions: 595 for act in self.tsMenuActions:
521 act.setEnabled(True) 596 act.setEnabled(True)
530 for act in self.tsprocMenuActions: 605 for act in self.tsprocMenuActions:
531 act.setEnabled(False) 606 act.setEnabled(False)
532 if self.lreleaseProcRunning: 607 if self.lreleaseProcRunning:
533 for act in self.qmprocMenuActions: 608 for act in self.qmprocMenuActions:
534 act.setEnabled(True) 609 act.setEnabled(True)
535 self.__addTranslationAct.setEnabled( 610 self.__addTranslationAct.setEnabled(self.project.getTranslationPattern() != "")
536 self.project.getTranslationPattern() != "") 611
537
538 ProjectBaseBrowser._showContextMenu(self, self.menu) 612 ProjectBaseBrowser._showContextMenu(self, self.menu)
539 613
540 self.showMenu.emit("Main", self.menu) 614 self.showMenu.emit("Main", self.menu)
541 615
542 def __showContextMenuMulti(self): 616 def __showContextMenuMulti(self):
543 """ 617 """
544 Private slot called by the multiMenu aboutToShow signal. 618 Private slot called by the multiMenu aboutToShow signal.
545 """ 619 """
546 if self.project.getProjectType() in [ 620 if self.project.getProjectType() in [
547 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 621 "PyQt5",
548 "PySide2", "PySide2C", "PySide6", "PySide6C" 622 "PyQt5C",
623 "PyQt6",
624 "PyQt6C",
625 "E7Plugin",
626 "PySide2",
627 "PySide2C",
628 "PySide6",
629 "PySide6C",
549 ]: 630 ]:
550 tsFiles = 0 631 tsFiles = 0
551 qmFiles = 0 632 qmFiles = 0
552 itmList = self.getSelectedItems() 633 itmList = self.getSelectedItems()
553 for itm in itmList[:]: 634 for itm in itmList[:]:
554 if itm.fileName().endswith('.ts'): 635 if itm.fileName().endswith(".ts"):
555 tsFiles += 1 636 tsFiles += 1
556 elif itm.fileName().endswith('.qm'): 637 elif itm.fileName().endswith(".qm"):
557 qmFiles += 1 638 qmFiles += 1
558 if ( 639 if (tsFiles > 0 and qmFiles > 0) or (tsFiles == 0 and qmFiles == 0):
559 (tsFiles > 0 and qmFiles > 0) or
560 (tsFiles == 0 and qmFiles == 0)
561 ):
562 for act in self.tsMultiMenuActions + self.qmMultiMenuActions: 640 for act in self.tsMultiMenuActions + self.qmMultiMenuActions:
563 act.setEnabled(False) 641 act.setEnabled(False)
564 elif tsFiles > 0: 642 elif tsFiles > 0:
565 for act in self.tsMultiMenuActions: 643 for act in self.tsMultiMenuActions:
566 act.setEnabled(True) 644 act.setEnabled(True)
575 for act in self.tsprocMultiMenuActions: 653 for act in self.tsprocMultiMenuActions:
576 act.setEnabled(False) 654 act.setEnabled(False)
577 if self.lreleaseProcRunning: 655 if self.lreleaseProcRunning:
578 for act in self.qmprocMultiMenuActions: 656 for act in self.qmprocMultiMenuActions:
579 act.setEnabled(True) 657 act.setEnabled(True)
580 658
581 ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu) 659 ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu)
582 660
583 self.showMenu.emit("MainMulti", self.multiMenu) 661 self.showMenu.emit("MainMulti", self.multiMenu)
584 662
585 def __showContextMenuDir(self): 663 def __showContextMenuDir(self):
586 """ 664 """
587 Private slot called by the dirMenu aboutToShow signal. 665 Private slot called by the dirMenu aboutToShow signal.
588 """ 666 """
589 if self.project.getProjectType() in [ 667 if self.project.getProjectType() in [
590 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 668 "PyQt5",
591 "PySide2", "PySide2C", "PySide6", "PySide6C" 669 "PyQt5C",
670 "PyQt6",
671 "PyQt6C",
672 "E7Plugin",
673 "PySide2",
674 "PySide2C",
675 "PySide6",
676 "PySide6C",
592 ]: 677 ]:
593 if self.pylupdateProcRunning: 678 if self.pylupdateProcRunning:
594 for act in self.tsprocDirMenuActions: 679 for act in self.tsprocDirMenuActions:
595 act.setEnabled(False) 680 act.setEnabled(False)
596 if self.lreleaseProcRunning: 681 if self.lreleaseProcRunning:
597 for act in self.qmprocDirMenuActions: 682 for act in self.qmprocDirMenuActions:
598 act.setEnabled(True) 683 act.setEnabled(True)
599 self.__addTranslationDirAct.setEnabled( 684 self.__addTranslationDirAct.setEnabled(
600 self.project.getTranslationPattern() != "") 685 self.project.getTranslationPattern() != ""
601 686 )
687
602 ProjectBaseBrowser._showContextMenuDir(self, self.dirMenu) 688 ProjectBaseBrowser._showContextMenuDir(self, self.dirMenu)
603 689
604 self.showMenu.emit("MainDir", self.dirMenu) 690 self.showMenu.emit("MainDir", self.dirMenu)
605 691
606 def __showContextMenuBack(self): 692 def __showContextMenuBack(self):
607 """ 693 """
608 Private slot called by the backMenu aboutToShow signal. 694 Private slot called by the backMenu aboutToShow signal.
609 """ 695 """
610 if self.project.getProjectType() in [ 696 if self.project.getProjectType() in [
611 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 697 "PyQt5",
612 "PySide2", "PySide2C", "PySide6", "PySide6C" 698 "PyQt5C",
699 "PyQt6",
700 "PyQt6C",
701 "E7Plugin",
702 "PySide2",
703 "PySide2C",
704 "PySide6",
705 "PySide6C",
613 ]: 706 ]:
614 if self.pylupdateProcRunning: 707 if self.pylupdateProcRunning:
615 for act in self.tsprocBackMenuActions: 708 for act in self.tsprocBackMenuActions:
616 act.setEnabled(False) 709 act.setEnabled(False)
617 if self.lreleaseProcRunning: 710 if self.lreleaseProcRunning:
618 for act in self.qmprocBackMenuActions: 711 for act in self.qmprocBackMenuActions:
619 act.setEnabled(True) 712 act.setEnabled(True)
620 self.__addTranslationBackAct.setEnabled( 713 self.__addTranslationBackAct.setEnabled(
621 self.project.getTranslationPattern() != "") 714 self.project.getTranslationPattern() != ""
622 715 )
716
623 self.showMenu.emit("MainBack", self.backMenu) 717 self.showMenu.emit("MainBack", self.backMenu)
624 718
625 def __addTranslationFiles(self): 719 def __addTranslationFiles(self):
626 """ 720 """
627 Private method to add translation files to the project. 721 Private method to add translation files to the project.
628 """ 722 """
629 itm = self.model().item(self.currentIndex()) 723 itm = self.model().item(self.currentIndex())
630 if isinstance(itm, ProjectBrowserFileItem): 724 if isinstance(itm, ProjectBrowserFileItem):
631 dn = os.path.dirname(itm.fileName()) 725 dn = os.path.dirname(itm.fileName())
632 elif isinstance( 726 elif isinstance(
633 itm, 727 itm, (ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem)
634 (ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem)
635 ): 728 ):
636 dn = itm.dirName() 729 dn = itm.dirName()
637 else: 730 else:
638 dn = None 731 dn = None
639 self.project.addFiles('translation', dn) 732 self.project.addFiles("translation", dn)
640 733
641 def _openItem(self): 734 def _openItem(self):
642 """ 735 """
643 Protected slot to handle the open popup menu entry. 736 Protected slot to handle the open popup menu entry.
644 """ 737 """
645 itmList = self.getSelectedItems() 738 itmList = self.getSelectedItems()
647 if isinstance(itm, ProjectBrowserFileItem): 740 if isinstance(itm, ProjectBrowserFileItem):
648 # hook support 741 # hook support
649 if self.hooks["open"] is not None: 742 if self.hooks["open"] is not None:
650 self.hooks["open"](itm.fileName()) 743 self.hooks["open"](itm.fileName())
651 elif itm.isLinguistFile(): 744 elif itm.isLinguistFile():
652 if itm.fileExt() == '.ts': 745 if itm.fileExt() == ".ts":
653 self.linguistFile.emit(itm.fileName()) 746 self.linguistFile.emit(itm.fileName())
654 else: 747 else:
655 self.trpreview.emit([itm.fileName()]) 748 self.trpreview.emit([itm.fileName()])
656 else: 749 else:
657 self.sourceFile.emit(itm.fileName()) 750 self.sourceFile.emit(itm.fileName())
658 751
659 def __openFileInEditor(self): 752 def __openFileInEditor(self):
660 """ 753 """
661 Private slot to handle the Open in Editor menu action. 754 Private slot to handle the Open in Editor menu action.
662 """ 755 """
663 itmList = self.getSelectedItems() 756 itmList = self.getSelectedItems()
664 for itm in itmList[:]: 757 for itm in itmList[:]:
665 self.sourceFile.emit(itm.fileName()) 758 self.sourceFile.emit(itm.fileName())
666 759
667 def __removeLanguageFile(self): 760 def __removeLanguageFile(self):
668 """ 761 """
669 Private method to remove a translation from the project. 762 Private method to remove a translation from the project.
670 """ 763 """
671 itmList = self.getSelectedItems() 764 itmList = self.getSelectedItems()
672 765
673 for itm in itmList[:]: 766 for itm in itmList[:]:
674 fn = itm.fileName() 767 fn = itm.fileName()
675 self.closeSourceWindow.emit(fn) 768 self.closeSourceWindow.emit(fn)
676 self.project.removeLanguageFile(fn) 769 self.project.removeLanguageFile(fn)
677 770
678 def __deleteLanguageFile(self): 771 def __deleteLanguageFile(self):
679 """ 772 """
680 Private method to delete a translation file from the project. 773 Private method to delete a translation file from the project.
681 """ 774 """
682 itmList = self.getSelectedItems() 775 itmList = self.getSelectedItems()
683 776
684 translationFiles = [itm.fileName() for itm in itmList] 777 translationFiles = [itm.fileName() for itm in itmList]
685 778
686 from UI.DeleteFilesConfirmationDialog import ( 779 from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
687 DeleteFilesConfirmationDialog 780
688 )
689 dlg = DeleteFilesConfirmationDialog( 781 dlg = DeleteFilesConfirmationDialog(
690 self.parent(), 782 self.parent(),
691 self.tr("Delete translation files"), 783 self.tr("Delete translation files"),
692 self.tr("Do you really want to delete these translation files" 784 self.tr(
693 " from the project?"), 785 "Do you really want to delete these translation files"
694 translationFiles) 786 " from the project?"
695 787 ),
788 translationFiles,
789 )
790
696 if dlg.exec() == QDialog.DialogCode.Accepted: 791 if dlg.exec() == QDialog.DialogCode.Accepted:
697 for fn in translationFiles: 792 for fn in translationFiles:
698 self.closeSourceWindow.emit(fn) 793 self.closeSourceWindow.emit(fn)
699 self.project.deleteLanguageFile(fn) 794 self.project.deleteLanguageFile(fn)
700 795
701 def __TRPreview(self, previewAll=False): 796 def __TRPreview(self, previewAll=False):
702 """ 797 """
703 Private slot to handle the Preview translations action. 798 Private slot to handle the Preview translations action.
704 799
705 @param previewAll flag indicating, that all translations 800 @param previewAll flag indicating, that all translations
706 should be previewed (boolean) 801 should be previewed (boolean)
707 """ 802 """
708 fileNames = [] 803 fileNames = []
709 itmList = self.getSelectedItems() 804 itmList = self.getSelectedItems()
711 for itm in itmList: 806 for itm in itmList:
712 if isinstance(itm, ProjectBrowserSimpleDirectoryItem): 807 if isinstance(itm, ProjectBrowserSimpleDirectoryItem):
713 dname = self.project.getRelativePath(itm.dirName()) 808 dname = self.project.getRelativePath(itm.dirName())
714 trfiles = sorted(self.project.pdata["TRANSLATIONS"][:]) 809 trfiles = sorted(self.project.pdata["TRANSLATIONS"][:])
715 for trfile in trfiles: 810 for trfile in trfiles:
716 if ( 811 if trfile.startswith(dname) and trfile not in fileNames:
717 trfile.startswith(dname) and 812 fileNames.append(os.path.join(self.project.ppath, trfile))
718 trfile not in fileNames
719 ):
720 fileNames.append(
721 os.path.join(self.project.ppath, trfile))
722 else: 813 else:
723 fn = itm.fileName() 814 fn = itm.fileName()
724 if fn not in fileNames: 815 if fn not in fileNames:
725 fileNames.append(os.path.join(self.project.ppath, fn)) 816 fileNames.append(os.path.join(self.project.ppath, fn))
726 else: 817 else:
727 trfiles = sorted(self.project.pdata["TRANSLATIONS"][:]) 818 trfiles = sorted(self.project.pdata["TRANSLATIONS"][:])
728 fileNames.extend([os.path.join(self.project.ppath, trfile) 819 fileNames.extend(
729 for trfile in trfiles 820 [
730 if trfile.endswith('.qm')]) 821 os.path.join(self.project.ppath, trfile)
822 for trfile in trfiles
823 if trfile.endswith(".qm")
824 ]
825 )
731 self.trpreview[list, bool].emit(fileNames, True) 826 self.trpreview[list, bool].emit(fileNames, True)
732 827
733 def __TRPreviewAll(self): 828 def __TRPreviewAll(self):
734 """ 829 """
735 Private slot to handle the Preview all translations action. 830 Private slot to handle the Preview all translations action.
736 """ 831 """
737 self.__TRPreview(True) 832 self.__TRPreview(True)
738 833
739 ########################################################################### 834 ###########################################################################
740 ## Methods to support the generation and release commands 835 ## Methods to support the generation and release commands
741 ########################################################################### 836 ###########################################################################
742 837
743 def __writeTempProjectFile(self, langs, filterList): 838 def __writeTempProjectFile(self, langs, filterList):
744 """ 839 """
745 Private method to write a temporary project file suitable for 840 Private method to write a temporary project file suitable for
746 pylupdate and lrelease. 841 pylupdate and lrelease.
747 842
748 @param langs list of languages to include in the process. An empty 843 @param langs list of languages to include in the process. An empty
749 list (default) means that all translations should be included. 844 list (default) means that all translations should be included.
750 (list of ProjectBrowserFileItem) 845 (list of ProjectBrowserFileItem)
751 @param filterList list of source file extension that should be 846 @param filterList list of source file extension that should be
752 considered (list of strings) 847 considered (list of strings)
753 @return flag indicating success 848 @return flag indicating success
754 """ 849 """
755 path, ext = os.path.splitext(self.project.pfile) 850 path, ext = os.path.splitext(self.project.pfile)
756 pfile = '{0}_e4x.pro'.format(path) 851 pfile = "{0}_e4x.pro".format(path)
757 852
758 # only consider files satisfying the filter criteria 853 # only consider files satisfying the filter criteria
759 _sources = [s for s in self.project.pdata["SOURCES"] 854 _sources = [
760 if os.path.splitext(s)[1] in filterList] 855 s
856 for s in self.project.pdata["SOURCES"]
857 if os.path.splitext(s)[1] in filterList
858 ]
761 sources = [] 859 sources = []
762 for s in _sources: 860 for s in _sources:
763 addIt = True 861 addIt = True
764 for transExcept in self.project.pdata["TRANSLATIONEXCEPTIONS"]: 862 for transExcept in self.project.pdata["TRANSLATIONEXCEPTIONS"]:
765 if s.startswith(transExcept): 863 if s.startswith(transExcept):
766 addIt = False 864 addIt = False
767 break 865 break
768 if addIt: 866 if addIt:
769 sources.append(s) 867 sources.append(s)
770 868
771 _forms = [f for f in self.project.pdata["FORMS"] if f.endswith('.ui')] 869 _forms = [f for f in self.project.pdata["FORMS"] if f.endswith(".ui")]
772 forms = [] 870 forms = []
773 for f in _forms: 871 for f in _forms:
774 addIt = True 872 addIt = True
775 for transExcept in self.project.pdata["TRANSLATIONEXCEPTIONS"]: 873 for transExcept in self.project.pdata["TRANSLATIONEXCEPTIONS"]:
776 if f.startswith(transExcept): 874 if f.startswith(transExcept):
777 addIt = False 875 addIt = False
778 break 876 break
779 if addIt: 877 if addIt:
780 forms.append(f) 878 forms.append(f)
781 879
782 if langs: 880 if langs:
783 langs = [self.project.getRelativePath(lang.fileName()) 881 langs = [
784 for lang in langs if lang.fileName().endswith('.ts')] 882 self.project.getRelativePath(lang.fileName())
883 for lang in langs
884 if lang.fileName().endswith(".ts")
885 ]
785 else: 886 else:
786 try: 887 try:
787 pattern = self.project.pdata["TRANSLATIONPATTERN"].replace( 888 pattern = self.project.pdata["TRANSLATIONPATTERN"].replace(
788 "%language%", "*") 889 "%language%", "*"
789 langs = [lang for lang in self.project.pdata["TRANSLATIONS"] 890 )
790 if fnmatch.fnmatch(lang, pattern)] 891 langs = [
892 lang
893 for lang in self.project.pdata["TRANSLATIONS"]
894 if fnmatch.fnmatch(lang, pattern)
895 ]
791 except IndexError: 896 except IndexError:
792 langs = [] 897 langs = []
793 if not langs: 898 if not langs:
794 EricMessageBox.warning( 899 EricMessageBox.warning(
795 self, 900 self,
796 self.tr("Write temporary project file"), 901 self.tr("Write temporary project file"),
797 self.tr("""No translation files (*.ts) selected.""")) 902 self.tr("""No translation files (*.ts) selected."""),
903 )
798 return False 904 return False
799 905
800 # create a prefix relative from the *.ts down to the project path 906 # create a prefix relative from the *.ts down to the project path
801 langLevel = {} 907 langLevel = {}
802 for lang in langs: 908 for lang in langs:
803 level = lang.count(os.sep) 909 level = lang.count(os.sep)
804 lst = langLevel.get(level, []) 910 lst = langLevel.get(level, [])
805 lst.append(lang) 911 lst.append(lang)
806 langLevel[level] = lst 912 langLevel[level] = lst
807 913
808 for level, langs in langLevel.items(): 914 for level, langs in langLevel.items():
809 prefix = '../' * level 915 prefix = "../" * level
810 sections = [ 916 sections = [("SOURCES", [prefix + src for src in sources])]
811 ("SOURCES", 917 sections.append(("FORMS", [prefix + form for form in forms]))
812 [prefix + src for src in sources])] 918 sections.append(("TRANSLATIONS", [prefix + lang for lang in langs]))
813 sections.append( 919
814 ("FORMS",
815 [prefix + form for form in forms]))
816 sections.append(
817 ("TRANSLATIONS",
818 [prefix + lang for lang in langs]))
819
820 directory, name = os.path.split(pfile) 920 directory, name = os.path.split(pfile)
821 outFile = os.path.join(directory, os.path.dirname(langs[0]), name) 921 outFile = os.path.join(directory, os.path.dirname(langs[0]), name)
822 outDir = os.path.dirname(outFile) 922 outDir = os.path.dirname(outFile)
823 if not os.path.exists(outDir): 923 if not os.path.exists(outDir):
824 os.makedirs(outDir) 924 os.makedirs(outDir)
825 try: 925 try:
826 with open(outFile, "w", encoding="utf-8") as pf: 926 with open(outFile, "w", encoding="utf-8") as pf:
827 for key, fileList in sections: 927 for key, fileList in sections:
828 if len(fileList) > 0: 928 if len(fileList) > 0:
829 pf.write('{0} = '.format(key)) 929 pf.write("{0} = ".format(key))
830 pf.write(' \\\n\t'.join( 930 pf.write(
831 [f.replace(os.sep, '/') for f in fileList])) 931 " \\\n\t".join(
832 pf.write('\n\n') 932 [f.replace(os.sep, "/") for f in fileList]
833 933 )
934 )
935 pf.write("\n\n")
936
834 self.__tmpProjects.append(outFile) 937 self.__tmpProjects.append(outFile)
835 except OSError: 938 except OSError:
836 EricMessageBox.critical( 939 EricMessageBox.critical(
837 self, 940 self,
838 self.tr("Write temporary project file"), 941 self.tr("Write temporary project file"),
839 self.tr( 942 self.tr(
840 "<p>The temporary project file <b>{0}</b> could not" 943 "<p>The temporary project file <b>{0}</b> could not"
841 " be written.</p>").format(outFile)) 944 " be written.</p>"
842 945 ).format(outFile),
946 )
947
843 if len(self.__tmpProjects) == 0: 948 if len(self.__tmpProjects) == 0:
844 return False 949 return False
845 950
846 return True 951 return True
847 952
848 def __readStdoutLupdate(self, proc): 953 def __readStdoutLupdate(self, proc):
849 """ 954 """
850 Private slot to handle the readyReadStandardOutput signal of the 955 Private slot to handle the readyReadStandardOutput signal of the
851 pylupdate process. 956 pylupdate process.
852 957
853 @param proc reference to the process 958 @param proc reference to the process
854 @type QProcess 959 @type QProcess
855 """ 960 """
856 self.__readStdout(proc, '{0}: '.format(self.pylupdate)) 961 self.__readStdout(proc, "{0}: ".format(self.pylupdate))
857 962
858 def __readStdoutLrelease(self, proc): 963 def __readStdoutLrelease(self, proc):
859 """ 964 """
860 Private slot to handle the readyReadStandardOutput signal of the 965 Private slot to handle the readyReadStandardOutput signal of the
861 lrelease process. 966 lrelease process.
862 967
863 @param proc reference to the process 968 @param proc reference to the process
864 @type QProcess 969 @type QProcess
865 """ 970 """
866 self.__readStdout(proc, 'lrelease: ') 971 self.__readStdout(proc, "lrelease: ")
867 972
868 def __readStdout(self, proc, ps): 973 def __readStdout(self, proc, ps):
869 """ 974 """
870 Private method to read from a process' stdout channel. 975 Private method to read from a process' stdout channel.
871 976
872 @param proc process to read from (QProcess) 977 @param proc process to read from (QProcess)
873 @param ps prompt string (string) 978 @param ps prompt string (string)
874 """ 979 """
875 ioEncoding = Preferences.getSystem("IOEncoding") 980 ioEncoding = Preferences.getSystem("IOEncoding")
876 981
877 proc.setReadChannel(QProcess.ProcessChannel.StandardOutput) 982 proc.setReadChannel(QProcess.ProcessChannel.StandardOutput)
878 while proc and proc.canReadLine(): 983 while proc and proc.canReadLine():
879 s = ps 984 s = ps
880 output = str(proc.readLine(), ioEncoding, 'replace') 985 output = str(proc.readLine(), ioEncoding, "replace")
881 s += output 986 s += output
882 self.appendStdout.emit(s) 987 self.appendStdout.emit(s)
883 988
884 def __readStderrLupdate(self, proc): 989 def __readStderrLupdate(self, proc):
885 """ 990 """
886 Private slot to handle the readyReadStandardError signal of the 991 Private slot to handle the readyReadStandardError signal of the
887 pylupdate5 / pylupdate6 / pyside2-lupdate / pyside6-lupdate process. 992 pylupdate5 / pylupdate6 / pyside2-lupdate / pyside6-lupdate process.
888 993
889 @param proc reference to the process 994 @param proc reference to the process
890 @type QProcess 995 @type QProcess
891 """ 996 """
892 self.__readStderr(proc, '{0}: '.format(self.pylupdate)) 997 self.__readStderr(proc, "{0}: ".format(self.pylupdate))
893 998
894 def __readStderrLrelease(self, proc): 999 def __readStderrLrelease(self, proc):
895 """ 1000 """
896 Private slot to handle the readyReadStandardError signal of the 1001 Private slot to handle the readyReadStandardError signal of the
897 lrelease process. 1002 lrelease process.
898 1003
899 @param proc reference to the process 1004 @param proc reference to the process
900 @type QProcess 1005 @type QProcess
901 """ 1006 """
902 self.__readStderr(proc, 'lrelease: ') 1007 self.__readStderr(proc, "lrelease: ")
903 1008
904 def __readStderr(self, proc, ps): 1009 def __readStderr(self, proc, ps):
905 """ 1010 """
906 Private method to read from a process' stderr channel. 1011 Private method to read from a process' stderr channel.
907 1012
908 @param proc process to read from (QProcess) 1013 @param proc process to read from (QProcess)
909 @param ps propmt string (string) 1014 @param ps propmt string (string)
910 """ 1015 """
911 ioEncoding = Preferences.getSystem("IOEncoding") 1016 ioEncoding = Preferences.getSystem("IOEncoding")
912 1017
913 proc.setReadChannel(QProcess.ProcessChannel.StandardError) 1018 proc.setReadChannel(QProcess.ProcessChannel.StandardError)
914 while proc and proc.canReadLine(): 1019 while proc and proc.canReadLine():
915 s = ps 1020 s = ps
916 error = str(proc.readLine(), ioEncoding, 'replace') 1021 error = str(proc.readLine(), ioEncoding, "replace")
917 s += error 1022 s += error
918 self.appendStderr.emit(s) 1023 self.appendStderr.emit(s)
919 1024
920 ########################################################################### 1025 ###########################################################################
921 ## Methods for the generation commands 1026 ## Methods for the generation commands
922 ########################################################################### 1027 ###########################################################################
923 1028
924 def __extractMessages(self): 1029 def __extractMessages(self):
925 """ 1030 """
926 Private slot to extract the messages to form a messages template file. 1031 Private slot to extract the messages to form a messages template file.
927 """ 1032 """
928 if self.hooks["extractMessages"] is not None: 1033 if self.hooks["extractMessages"] is not None:
929 self.hooks["extractMessages"]() 1034 self.hooks["extractMessages"]()
930 1035
931 def __generateTSFileDone(self, proc, exitCode, exitStatus): 1036 def __generateTSFileDone(self, proc, exitCode, exitStatus):
932 """ 1037 """
933 Private slot to handle the finished signal of the pylupdate process. 1038 Private slot to handle the finished signal of the pylupdate process.
934 1039
935 @param proc reference to the process 1040 @param proc reference to the process
936 @type QProcess 1041 @type QProcess
937 @param exitCode exit code of the process 1042 @param exitCode exit code of the process
938 @type int 1043 @type int
939 @param exitStatus exit status of the process 1044 @param exitStatus exit status of the process
943 if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0: 1048 if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0:
944 ui.showNotification( 1049 ui.showNotification(
945 UI.PixmapCache.getPixmap("linguist48"), 1050 UI.PixmapCache.getPixmap("linguist48"),
946 self.tr("Translation file generation"), 1051 self.tr("Translation file generation"),
947 self.tr( 1052 self.tr(
948 "The generation of the translation files (*.ts)" 1053 "The generation of the translation files (*.ts)" " was successful."
949 " was successful.")) 1054 ),
1055 )
950 else: 1056 else:
951 if exitStatus == QProcess.ExitStatus.CrashExit: 1057 if exitStatus == QProcess.ExitStatus.CrashExit:
952 info = self.tr(" The process has crashed.") 1058 info = self.tr(" The process has crashed.")
953 else: 1059 else:
954 info = "" 1060 info = ""
955 ui.showNotification( 1061 ui.showNotification(
956 UI.PixmapCache.getPixmap("linguist48"), 1062 UI.PixmapCache.getPixmap("linguist48"),
957 self.tr("Translation file generation"), 1063 self.tr("Translation file generation"),
958 self.tr( 1064 self.tr(
959 "The generation of the translation files (*.ts) has" 1065 "The generation of the translation files (*.ts) has" " failed.{0}"
960 " failed.{0}").format(info), 1066 ).format(info),
961 kind=NotificationTypes.CRITICAL, 1067 kind=NotificationTypes.CRITICAL,
962 timeout=0) 1068 timeout=0,
963 1069 )
1070
964 for index in range(len(self.__pylupdateProcesses)): 1071 for index in range(len(self.__pylupdateProcesses)):
965 if proc == self.__pylupdateProcesses[index][0]: 1072 if proc == self.__pylupdateProcesses[index][0]:
966 tmpProjectFile = self.__pylupdateProcesses[index][1] 1073 tmpProjectFile = self.__pylupdateProcesses[index][1]
967 if tmpProjectFile: 1074 if tmpProjectFile:
968 with contextlib.suppress(OSError): 1075 with contextlib.suppress(OSError):
969 self.__tmpProjects.remove(tmpProjectFile) 1076 self.__tmpProjects.remove(tmpProjectFile)
970 os.remove(tmpProjectFile) 1077 os.remove(tmpProjectFile)
971 del self.__pylupdateProcesses[index] 1078 del self.__pylupdateProcesses[index]
972 break 1079 break
973 1080
974 if not self.__pylupdateProcesses: 1081 if not self.__pylupdateProcesses:
975 # all done 1082 # all done
976 self.pylupdateProcRunning = False 1083 self.pylupdateProcRunning = False
977 1084
978 QGuiApplication.restoreOverrideCursor() 1085 QGuiApplication.restoreOverrideCursor()
979 QGuiApplication.processEvents( 1086 QGuiApplication.processEvents(
980 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) 1087 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
981 1088 )
1089
982 def __generateTSFile(self, noobsolete=False, generateAll=True): 1090 def __generateTSFile(self, noobsolete=False, generateAll=True):
983 """ 1091 """
984 Private method used to run pylupdate5 / pylupdate6 / pyside2-lupdate / 1092 Private method used to run pylupdate5 / pylupdate6 / pyside2-lupdate /
985 pyside6-lupdate to generate the .ts files. 1093 pyside6-lupdate to generate the .ts files.
986 1094
987 @param noobsolete flag indicating whether obsolete entries should be 1095 @param noobsolete flag indicating whether obsolete entries should be
988 kept (boolean) 1096 kept (boolean)
989 @param generateAll flag indicating whether all translations should be 1097 @param generateAll flag indicating whether all translations should be
990 generated (boolean) 1098 generated (boolean)
991 """ 1099 """
992 langs = [] if generateAll else self.getSelectedItems() 1100 langs = [] if generateAll else self.getSelectedItems()
993 1101
994 # Hook support 1102 # Hook support
995 if generateAll: 1103 if generateAll:
996 if noobsolete: 1104 if noobsolete:
997 if self.hooks["generateAll"] is not None: 1105 if self.hooks["generateAll"] is not None:
998 self.hooks["generateAll"]( 1106 self.hooks["generateAll"](self.project.pdata["TRANSLATIONS"])
999 self.project.pdata["TRANSLATIONS"])
1000 return 1107 return
1001 else: 1108 else:
1002 if self.hooks["generateAllWithObsolete"] is not None: 1109 if self.hooks["generateAllWithObsolete"] is not None:
1003 self.hooks["generateAllWithObsolete"]( 1110 self.hooks["generateAllWithObsolete"](
1004 self.project.pdata["TRANSLATIONS"]) 1111 self.project.pdata["TRANSLATIONS"]
1112 )
1005 return 1113 return
1006 else: 1114 else:
1007 if noobsolete: 1115 if noobsolete:
1008 if self.hooks["generateSelected"] is not None: 1116 if self.hooks["generateSelected"] is not None:
1009 li = [self.project.getRelativePath(lang.fileName()) 1117 li = [
1010 for lang in langs] 1118 self.project.getRelativePath(lang.fileName()) for lang in langs
1119 ]
1011 self.hooks["generateSelected"](li) 1120 self.hooks["generateSelected"](li)
1012 return 1121 return
1013 else: 1122 else:
1014 if self.hooks["generateSelectedWithObsolete"] is not None: 1123 if self.hooks["generateSelectedWithObsolete"] is not None:
1015 li = [self.project.getRelativePath(lang.fileName()) 1124 li = [
1016 for lang in langs] 1125 self.project.getRelativePath(lang.fileName()) for lang in langs
1126 ]
1017 self.hooks["generateSelectedWithObsolete"](li) 1127 self.hooks["generateSelectedWithObsolete"](li)
1018 return 1128 return
1019 1129
1020 # generate a minimal temporary project file suitable for pylupdate 1130 # generate a minimal temporary project file suitable for pylupdate
1021 self.__tmpProjects = [] 1131 self.__tmpProjects = []
1022 if self.project.getProjectLanguage() in [ 1132 if self.project.getProjectLanguage() in ["Python", "Python3"]:
1023 "Python", "Python3" 1133 if self.project.getProjectType() not in ["PyQt6", "PyQt6C", "E7Plugin"]:
1024 ]:
1025 if self.project.getProjectType() not in [
1026 "PyQt6", "PyQt6C", "E7Plugin"
1027 ]:
1028 ok = self.__writeTempProjectFile(langs, [".py"]) 1134 ok = self.__writeTempProjectFile(langs, [".py"])
1029 if not ok: 1135 if not ok:
1030 return 1136 return
1031 else: 1137 else:
1032 return 1138 return
1033 1139
1034 if self.project.getProjectType() in ["PyQt5", "PyQt5C"]: 1140 if self.project.getProjectType() in ["PyQt5", "PyQt5C"]:
1035 self.pylupdate = Utilities.generatePyQtToolPath('pylupdate5') 1141 self.pylupdate = Utilities.generatePyQtToolPath("pylupdate5")
1036 elif self.project.getProjectType() in ["PyQt6", "PyQt6C", "E7Plugin"]: 1142 elif self.project.getProjectType() in ["PyQt6", "PyQt6C", "E7Plugin"]:
1037 self.pylupdate = Utilities.generatePyQtToolPath('pylupdate6') 1143 self.pylupdate = Utilities.generatePyQtToolPath("pylupdate6")
1038 elif self.project.getProjectType() in ["PySide2", "PySide2C"]: 1144 elif self.project.getProjectType() in ["PySide2", "PySide2C"]:
1039 self.pylupdate = Utilities.generatePySideToolPath( 1145 self.pylupdate = Utilities.generatePySideToolPath(
1040 'pyside2-lupdate', variant=2) 1146 "pyside2-lupdate", variant=2
1147 )
1041 elif self.project.getProjectType() in ["PySide6", "PySide6C"]: 1148 elif self.project.getProjectType() in ["PySide6", "PySide6C"]:
1042 self.pylupdate = Utilities.generatePySideToolPath( 1149 self.pylupdate = Utilities.generatePySideToolPath(
1043 'pyside6-lupdate', variant=6) 1150 "pyside6-lupdate", variant=6
1151 )
1044 else: 1152 else:
1045 return 1153 return
1046 1154
1047 self.__pylupdateProcesses = [] 1155 self.__pylupdateProcesses = []
1048 if self.project.getProjectType() in ["PyQt6", "PyQt6C", "E7Plugin"]: 1156 if self.project.getProjectType() in ["PyQt6", "PyQt6C", "E7Plugin"]:
1049 if langs: 1157 if langs:
1050 langs = [self.project.getRelativePath(lang.fileName()) 1158 langs = [
1051 for lang in langs if lang.fileName().endswith('.ts')] 1159 self.project.getRelativePath(lang.fileName())
1160 for lang in langs
1161 if lang.fileName().endswith(".ts")
1162 ]
1052 else: 1163 else:
1053 try: 1164 try:
1054 pattern = self.project.pdata["TRANSLATIONPATTERN"].replace( 1165 pattern = self.project.pdata["TRANSLATIONPATTERN"].replace(
1055 "%language%", "*") 1166 "%language%", "*"
1167 )
1056 langs = [ 1168 langs = [
1057 lang for lang in self.project.pdata["TRANSLATIONS"] 1169 lang
1170 for lang in self.project.pdata["TRANSLATIONS"]
1058 if fnmatch.fnmatch(lang, pattern) 1171 if fnmatch.fnmatch(lang, pattern)
1059 ] 1172 ]
1060 except IndexError: 1173 except IndexError:
1061 langs = [] 1174 langs = []
1062 if not langs: 1175 if not langs:
1063 EricMessageBox.warning( 1176 EricMessageBox.warning(
1064 self, 1177 self,
1065 self.tr("Translation file generation"), 1178 self.tr("Translation file generation"),
1066 self.tr("""No translation files (*.ts) selected.""")) 1179 self.tr("""No translation files (*.ts) selected."""),
1180 )
1067 return 1181 return
1068 1182
1069 excludePatterns = [ 1183 excludePatterns = [
1070 pat for pat in self.project.getIgnorePatterns() 1184 pat
1185 for pat in self.project.getIgnorePatterns()
1071 if pat.endswith((".py", ".ui")) 1186 if pat.endswith((".py", ".ui"))
1072 ] 1187 ]
1073 1188
1074 QGuiApplication.setOverrideCursor( 1189 QGuiApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
1075 QCursor(Qt.CursorShape.WaitCursor))
1076 QGuiApplication.processEvents( 1190 QGuiApplication.processEvents(
1077 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) 1191 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
1078 1192 )
1193
1079 for lang in langs: 1194 for lang in langs:
1080 proc = QProcess() 1195 proc = QProcess()
1081 args = [] 1196 args = []
1082 1197
1083 for pattern in excludePatterns: 1198 for pattern in excludePatterns:
1084 args += ["--exclude", pattern] 1199 args += ["--exclude", pattern]
1085 1200
1086 if noobsolete: 1201 if noobsolete:
1087 args.append('--no-obsolete') 1202 args.append("--no-obsolete")
1088 1203
1089 args += ["--ts", lang] 1204 args += ["--ts", lang]
1090 args.append(".") 1205 args.append(".")
1091 1206
1092 proc.setWorkingDirectory(self.project.ppath) 1207 proc.setWorkingDirectory(self.project.ppath)
1093 proc.finished.connect( 1208 proc.finished.connect(
1094 functools.partial(self.__generateTSFileDone, proc) 1209 functools.partial(self.__generateTSFileDone, proc)
1095 ) 1210 )
1096 proc.readyReadStandardOutput.connect( 1211 proc.readyReadStandardOutput.connect(
1097 functools.partial(self.__readStdoutLupdate, proc) 1212 functools.partial(self.__readStdoutLupdate, proc)
1098 ) 1213 )
1099 proc.readyReadStandardError.connect( 1214 proc.readyReadStandardError.connect(
1100 functools.partial(self.__readStderrLupdate, proc) 1215 functools.partial(self.__readStderrLupdate, proc)
1101 ) 1216 )
1102 1217
1103 proc.start(self.pylupdate, args) 1218 proc.start(self.pylupdate, args)
1104 procStarted = proc.waitForStarted() 1219 procStarted = proc.waitForStarted()
1105 if procStarted: 1220 if procStarted:
1106 self.pylupdateProcRunning = True 1221 self.pylupdateProcRunning = True
1107 self.__pylupdateProcesses.append((proc, "")) 1222 self.__pylupdateProcesses.append((proc, ""))
1108 else: 1223 else:
1109 with EricOverridenCursor(): 1224 with EricOverridenCursor():
1110 EricMessageBox.critical( 1225 EricMessageBox.critical(
1111 self, 1226 self,
1112 self.tr('Process Generation Error'), 1227 self.tr("Process Generation Error"),
1113 self.tr( 1228 self.tr(
1114 'Could not start {0}.<br>' 1229 "Could not start {0}.<br>"
1115 'Ensure that it is in the search path.' 1230 "Ensure that it is in the search path."
1116 ).format(self.pylupdate)) 1231 ).format(self.pylupdate),
1117 else: 1232 )
1118 QGuiApplication.setOverrideCursor( 1233 else:
1119 QCursor(Qt.CursorShape.WaitCursor)) 1234 QGuiApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
1120 QGuiApplication.processEvents( 1235 QGuiApplication.processEvents(
1121 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) 1236 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
1122 1237 )
1238
1123 for tempProjectFile in self.__tmpProjects[:]: 1239 for tempProjectFile in self.__tmpProjects[:]:
1124 proc = QProcess() 1240 proc = QProcess()
1125 args = [] 1241 args = []
1126 1242
1127 if noobsolete: 1243 if noobsolete:
1128 args.append('-noobsolete') 1244 args.append("-noobsolete")
1129 1245
1130 args.append('-verbose') 1246 args.append("-verbose")
1131 path, filename = os.path.split(tempProjectFile) 1247 path, filename = os.path.split(tempProjectFile)
1132 args.append(filename) 1248 args.append(filename)
1133 proc.setWorkingDirectory( 1249 proc.setWorkingDirectory(os.path.join(self.project.ppath, path))
1134 os.path.join(self.project.ppath, path))
1135 proc.finished.connect( 1250 proc.finished.connect(
1136 functools.partial(self.__generateTSFileDone, proc) 1251 functools.partial(self.__generateTSFileDone, proc)
1137 ) 1252 )
1138 proc.readyReadStandardOutput.connect( 1253 proc.readyReadStandardOutput.connect(
1139 functools.partial(self.__readStdoutLupdate, proc) 1254 functools.partial(self.__readStdoutLupdate, proc)
1140 ) 1255 )
1141 proc.readyReadStandardError.connect( 1256 proc.readyReadStandardError.connect(
1142 functools.partial(self.__readStderrLupdate, proc) 1257 functools.partial(self.__readStderrLupdate, proc)
1143 ) 1258 )
1144 1259
1145 proc.start(self.pylupdate, args) 1260 proc.start(self.pylupdate, args)
1146 procStarted = proc.waitForStarted() 1261 procStarted = proc.waitForStarted()
1147 if procStarted: 1262 if procStarted:
1148 self.pylupdateProcRunning = True 1263 self.pylupdateProcRunning = True
1149 self.__pylupdateProcesses.append((proc, tempProjectFile)) 1264 self.__pylupdateProcesses.append((proc, tempProjectFile))
1150 else: 1265 else:
1151 with EricOverridenCursor(): 1266 with EricOverridenCursor():
1152 EricMessageBox.critical( 1267 EricMessageBox.critical(
1153 self, 1268 self,
1154 self.tr('Process Generation Error'), 1269 self.tr("Process Generation Error"),
1155 self.tr( 1270 self.tr(
1156 'Could not start {0}.<br>' 1271 "Could not start {0}.<br>"
1157 'Ensure that it is in the search path.' 1272 "Ensure that it is in the search path."
1158 ).format(self.pylupdate)) 1273 ).format(self.pylupdate),
1274 )
1159 # cleanup 1275 # cleanup
1160 with contextlib.suppress(OSError): 1276 with contextlib.suppress(OSError):
1161 self.__tmpProjects.remove(tempProjectFile) 1277 self.__tmpProjects.remove(tempProjectFile)
1162 os.remove(tempProjectFile) 1278 os.remove(tempProjectFile)
1163 1279
1164 if not self.__pylupdateProcesses: 1280 if not self.__pylupdateProcesses:
1165 # no processes could be started, revert override cursor 1281 # no processes could be started, revert override cursor
1166 QGuiApplication.restoreOverrideCursor() 1282 QGuiApplication.restoreOverrideCursor()
1167 QGuiApplication.processEvents( 1283 QGuiApplication.processEvents(
1168 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) 1284 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents
1169 1285 )
1286
1170 def __generateAll(self): 1287 def __generateAll(self):
1171 """ 1288 """
1172 Private method to generate all translation files (.ts) for Qt Linguist. 1289 Private method to generate all translation files (.ts) for Qt Linguist.
1173 1290
1174 All obsolete strings are removed from the .ts file. 1291 All obsolete strings are removed from the .ts file.
1175 """ 1292 """
1176 self.__generateTSFile(noobsolete=True, generateAll=True) 1293 self.__generateTSFile(noobsolete=True, generateAll=True)
1177 1294
1178 def __generateObsoleteAll(self): 1295 def __generateObsoleteAll(self):
1179 """ 1296 """
1180 Private method to generate all translation files (.ts) for Qt Linguist. 1297 Private method to generate all translation files (.ts) for Qt Linguist.
1181 1298
1182 Obsolete strings are kept. 1299 Obsolete strings are kept.
1183 """ 1300 """
1184 self.__generateTSFile(noobsolete=False, generateAll=True) 1301 self.__generateTSFile(noobsolete=False, generateAll=True)
1185 1302
1186 def __generateSelected(self): 1303 def __generateSelected(self):
1187 """ 1304 """
1188 Private method to generate selected translation files (.ts) for 1305 Private method to generate selected translation files (.ts) for
1189 Qt Linguist. 1306 Qt Linguist.
1190 1307
1191 All obsolete strings are removed from the .ts file. 1308 All obsolete strings are removed from the .ts file.
1192 """ 1309 """
1193 self.__generateTSFile(noobsolete=True, generateAll=False) 1310 self.__generateTSFile(noobsolete=True, generateAll=False)
1194 1311
1195 def __generateObsoleteSelected(self): 1312 def __generateObsoleteSelected(self):
1196 """ 1313 """
1197 Private method to generate selected translation files (.ts) for 1314 Private method to generate selected translation files (.ts) for
1198 Qt Linguist. 1315 Qt Linguist.
1199 1316
1200 Obsolete strings are kept. 1317 Obsolete strings are kept.
1201 """ 1318 """
1202 self.__generateTSFile(noobsolete=False, generateAll=False) 1319 self.__generateTSFile(noobsolete=False, generateAll=False)
1203 1320
1204 ########################################################################### 1321 ###########################################################################
1205 ## Methods for the release commands 1322 ## Methods for the release commands
1206 ########################################################################### 1323 ###########################################################################
1207 1324
1208 def __releaseTSFileDone(self, proc, exitCode, exitStatus): 1325 def __releaseTSFileDone(self, proc, exitCode, exitStatus):
1209 """ 1326 """
1210 Private slot to handle the finished signal of the lrelease process. 1327 Private slot to handle the finished signal of the lrelease process.
1211 1328
1212 @param proc reference to the process 1329 @param proc reference to the process
1213 @type QProcess 1330 @type QProcess
1214 @param exitCode exit code of the process 1331 @param exitCode exit code of the process
1215 @type int 1332 @type int
1216 @param exitStatus exit status of the process 1333 @param exitStatus exit status of the process
1219 ui = ericApp().getObject("UserInterface") 1336 ui = ericApp().getObject("UserInterface")
1220 if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0: 1337 if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0:
1221 ui.showNotification( 1338 ui.showNotification(
1222 UI.PixmapCache.getPixmap("linguist48"), 1339 UI.PixmapCache.getPixmap("linguist48"),
1223 self.tr("Translation file release"), 1340 self.tr("Translation file release"),
1224 self.tr("The release of the translation files (*.qm)" 1341 self.tr(
1225 " was successful.")) 1342 "The release of the translation files (*.qm)" " was successful."
1343 ),
1344 )
1226 if self.project.pdata["TRANSLATIONSBINPATH"]: 1345 if self.project.pdata["TRANSLATIONSBINPATH"]:
1227 target = os.path.join( 1346 target = os.path.join(
1228 self.project.ppath, 1347 self.project.ppath, self.project.pdata["TRANSLATIONSBINPATH"]
1229 self.project.pdata["TRANSLATIONSBINPATH"]) 1348 )
1230 for langFile in self.project.pdata["TRANSLATIONS"][:]: 1349 for langFile in self.project.pdata["TRANSLATIONS"][:]:
1231 if langFile.endswith('.ts'): 1350 if langFile.endswith(".ts"):
1232 qmFile = os.path.join(self.project.ppath, 1351 qmFile = os.path.join(
1233 langFile.replace('.ts', '.qm')) 1352 self.project.ppath, langFile.replace(".ts", ".qm")
1353 )
1234 if os.path.exists(qmFile): 1354 if os.path.exists(qmFile):
1235 shutil.move(qmFile, target) 1355 shutil.move(qmFile, target)
1236 else: 1356 else:
1237 ui.showNotification( 1357 ui.showNotification(
1238 UI.PixmapCache.getPixmap("linguist48"), 1358 UI.PixmapCache.getPixmap("linguist48"),
1239 self.tr("Translation file release"), 1359 self.tr("Translation file release"),
1240 self.tr( 1360 self.tr("The release of the translation files (*.qm) has failed."),
1241 "The release of the translation files (*.qm) has failed."),
1242 kind=NotificationTypes.CRITICAL, 1361 kind=NotificationTypes.CRITICAL,
1243 timeout=0) 1362 timeout=0,
1244 1363 )
1364
1245 for index in range(len(self.__lreleaseProcesses)): 1365 for index in range(len(self.__lreleaseProcesses)):
1246 if proc == self.__lreleaseProcesses[index]: 1366 if proc == self.__lreleaseProcesses[index]:
1247 del self.__lreleaseProcesses[index] 1367 del self.__lreleaseProcesses[index]
1248 break 1368 break
1249 if not self.__lreleaseProcesses: 1369 if not self.__lreleaseProcesses:
1250 # all done 1370 # all done
1251 self.lreleaseProcRunning = False 1371 self.lreleaseProcRunning = False
1252 self.project.checkLanguageFiles() 1372 self.project.checkLanguageFiles()
1253 1373
1254 def __releaseTSFile(self, generateAll=False): 1374 def __releaseTSFile(self, generateAll=False):
1255 """ 1375 """
1256 Private method to run lrelease to release the translation files (.qm). 1376 Private method to run lrelease to release the translation files (.qm).
1257 1377
1258 @param generateAll flag indicating whether all translations should be 1378 @param generateAll flag indicating whether all translations should be
1259 released (boolean) 1379 released (boolean)
1260 """ 1380 """
1261 langs = [] if generateAll else self.getSelectedItems() 1381 langs = [] if generateAll else self.getSelectedItems()
1262 1382
1263 # Hooks support 1383 # Hooks support
1264 if generateAll: 1384 if generateAll:
1265 if self.hooks["releaseAll"] is not None: 1385 if self.hooks["releaseAll"] is not None:
1266 self.hooks["releaseAll"](self.project.pdata["TRANSLATIONS"]) 1386 self.hooks["releaseAll"](self.project.pdata["TRANSLATIONS"])
1267 return 1387 return
1268 else: 1388 else:
1269 if self.hooks["releaseSelected"] is not None: 1389 if self.hooks["releaseSelected"] is not None:
1270 li = [self.project.getRelativePath(lang.fileName()) 1390 li = [self.project.getRelativePath(lang.fileName()) for lang in langs]
1271 for lang in langs]
1272 self.hooks["releaseSelected"](li) 1391 self.hooks["releaseSelected"](li)
1273 return 1392 return
1274 1393
1275 if self.project.getProjectType() in [ 1394 if self.project.getProjectType() in [
1276 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E7Plugin", 1395 "PyQt5",
1277 "PySide2", "PySide2C", "PySide6", "PySide6C" 1396 "PyQt5C",
1397 "PyQt6",
1398 "PyQt6C",
1399 "E7Plugin",
1400 "PySide2",
1401 "PySide2C",
1402 "PySide6",
1403 "PySide6C",
1278 ]: 1404 ]:
1279 lrelease = os.path.join( 1405 lrelease = os.path.join(
1280 Utilities.getQtBinariesPath(), 1406 Utilities.getQtBinariesPath(), Utilities.generateQtToolName("lrelease")
1281 Utilities.generateQtToolName("lrelease")) 1407 )
1282 else: 1408 else:
1283 return 1409 return
1284 if Utilities.isWindowsPlatform(): 1410 if Utilities.isWindowsPlatform():
1285 lrelease += '.exe' 1411 lrelease += ".exe"
1286 1412
1287 if langs: 1413 if langs:
1288 langs = [self.project.getRelativePath(lang.fileName()) 1414 langs = [
1289 for lang in langs if lang.fileName().endswith('.ts')] 1415 self.project.getRelativePath(lang.fileName())
1416 for lang in langs
1417 if lang.fileName().endswith(".ts")
1418 ]
1290 else: 1419 else:
1291 try: 1420 try:
1292 pattern = self.project.pdata["TRANSLATIONPATTERN"].replace( 1421 pattern = self.project.pdata["TRANSLATIONPATTERN"].replace(
1293 "%language%", "*") 1422 "%language%", "*"
1294 langs = [lang for lang in self.project.pdata["TRANSLATIONS"] 1423 )
1295 if fnmatch.fnmatch(lang, pattern)] 1424 langs = [
1425 lang
1426 for lang in self.project.pdata["TRANSLATIONS"]
1427 if fnmatch.fnmatch(lang, pattern)
1428 ]
1296 except IndexError: 1429 except IndexError:
1297 langs = [] 1430 langs = []
1298 if not langs: 1431 if not langs:
1299 EricMessageBox.warning( 1432 EricMessageBox.warning(
1300 self, 1433 self,
1301 self.tr("Write temporary project file"), 1434 self.tr("Write temporary project file"),
1302 self.tr("""No translation files (*.ts) selected.""")) 1435 self.tr("""No translation files (*.ts) selected."""),
1436 )
1303 return 1437 return
1304 1438
1305 self.__lreleaseProcesses = [] 1439 self.__lreleaseProcesses = []
1306 args = [] 1440 args = []
1307 args.append('-verbose') 1441 args.append("-verbose")
1308 for langFile in langs: 1442 for langFile in langs:
1309 path, filename = os.path.split(langFile) 1443 path, filename = os.path.split(langFile)
1310 args.append(filename) 1444 args.append(filename)
1311 1445
1312 proc = QProcess() 1446 proc = QProcess()
1313 proc.setWorkingDirectory(os.path.join(self.project.ppath, path)) 1447 proc.setWorkingDirectory(os.path.join(self.project.ppath, path))
1314 proc.finished.connect( 1448 proc.finished.connect(functools.partial(self.__releaseTSFileDone, proc))
1315 functools.partial(self.__releaseTSFileDone, proc)
1316 )
1317 proc.readyReadStandardOutput.connect( 1449 proc.readyReadStandardOutput.connect(
1318 functools.partial(self.__readStdoutLrelease, proc) 1450 functools.partial(self.__readStdoutLrelease, proc)
1319 ) 1451 )
1320 proc.readyReadStandardError.connect( 1452 proc.readyReadStandardError.connect(
1321 functools.partial(self.__readStderrLrelease, proc) 1453 functools.partial(self.__readStderrLrelease, proc)
1322 ) 1454 )
1323 1455
1324 proc.start(lrelease, args) 1456 proc.start(lrelease, args)
1325 procStarted = proc.waitForStarted() 1457 procStarted = proc.waitForStarted()
1326 if procStarted: 1458 if procStarted:
1327 self.lreleaseProcRunning = True 1459 self.lreleaseProcRunning = True
1328 self.__lreleaseProcesses.append(proc) 1460 self.__lreleaseProcesses.append(proc)
1329 else: 1461 else:
1330 EricMessageBox.critical( 1462 EricMessageBox.critical(
1331 self, 1463 self,
1332 self.tr('Process Generation Error'), 1464 self.tr("Process Generation Error"),
1333 self.tr( 1465 self.tr(
1334 '<p>Could not start lrelease.<br>' 1466 "<p>Could not start lrelease.<br>"
1335 'Ensure that it is available as <b>{0}</b>.</p>' 1467 "Ensure that it is available as <b>{0}</b>.</p>"
1336 ).format(lrelease)) 1468 ).format(lrelease),
1337 1469 )
1470
1338 def __releaseSelected(self): 1471 def __releaseSelected(self):
1339 """ 1472 """
1340 Private method to release the translation files (.qm). 1473 Private method to release the translation files (.qm).
1341 """ 1474 """
1342 self.__releaseTSFile(generateAll=False) 1475 self.__releaseTSFile(generateAll=False)
1343 1476
1344 def __releaseAll(self): 1477 def __releaseAll(self):
1345 """ 1478 """
1346 Private method to release the translation files (.qm). 1479 Private method to release the translation files (.qm).
1347 """ 1480 """
1348 self.__releaseTSFile(generateAll=True) 1481 self.__releaseTSFile(generateAll=True)
1349 1482
1350 ########################################################################### 1483 ###########################################################################
1351 ## Support for hooks below 1484 ## Support for hooks below
1352 ########################################################################### 1485 ###########################################################################
1353 1486
1354 def _initHookMethods(self): 1487 def _initHookMethods(self):
1355 """ 1488 """
1356 Protected method to initialize the hooks dictionary. 1489 Protected method to initialize the hooks dictionary.
1357 1490
1358 Supported hook methods are: 1491 Supported hook methods are:
1359 <ul> 1492 <ul>
1360 <li>extractMessages: takes no parameters</li> 1493 <li>extractMessages: takes no parameters</li>
1361 <li>generateAll: takes list of filenames as parameter</li> 1494 <li>generateAll: takes list of filenames as parameter</li>
1362 <li>generateAllWithObsolete: takes list of filenames as parameter</li> 1495 <li>generateAllWithObsolete: takes list of filenames as parameter</li>
1365 parameter</li> 1498 parameter</li>
1366 <li>releaseAll: takes list of filenames as parameter</li> 1499 <li>releaseAll: takes list of filenames as parameter</li>
1367 <li>releaseSelected: takes list of filenames as parameter</li> 1500 <li>releaseSelected: takes list of filenames as parameter</li>
1368 <li>open: takes a filename as parameter</li> 1501 <li>open: takes a filename as parameter</li>
1369 </ul> 1502 </ul>
1370 1503
1371 <b>Note</b>: Filenames are relative to the project directory. 1504 <b>Note</b>: Filenames are relative to the project directory.
1372 """ 1505 """
1373 self.hooks = { 1506 self.hooks = {
1374 "extractMessages": None, 1507 "extractMessages": None,
1375 "generateAll": None, 1508 "generateAll": None,

eric ide

mercurial