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: |
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> |