diff -r 866adc8c315b -r 0acf98cd089a eric6/Project/ProjectTranslationsBrowser.py --- a/eric6/Project/ProjectTranslationsBrowser.py Sun Jan 17 13:53:08 2021 +0100 +++ b/eric6/Project/ProjectTranslationsBrowser.py Mon Feb 01 10:38:16 2021 +0100 @@ -26,6 +26,7 @@ from .ProjectBaseBrowser import ProjectBaseBrowser import UI.PixmapCache +from UI.NotificationWidget import NotificationTypes import Preferences import Utilities @@ -102,7 +103,8 @@ self.menu = QMenu(self) if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: act = self.menu.addAction( self.tr('Generate translation'), self.__generateSelected) @@ -229,7 +231,8 @@ self.backMenu = QMenu(self) if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: act = self.backMenu.addAction( self.tr('Generate all translations'), @@ -290,7 +293,8 @@ # create the menu for multiple selected files self.multiMenu = QMenu(self) if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: act = self.multiMenu.addAction( self.tr('Generate translations'), @@ -374,7 +378,8 @@ self.dirMenu = QMenu(self) if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: act = self.dirMenu.addAction( self.tr('Generate all translations'), @@ -492,7 +497,8 @@ Private slot called by the menu aboutToShow signal. """ if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: tsFiles = 0 qmFiles = 0 @@ -536,7 +542,8 @@ Private slot called by the multiMenu aboutToShow signal. """ if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: tsFiles = 0 qmFiles = 0 @@ -578,7 +585,8 @@ Private slot called by the dirMenu aboutToShow signal. """ if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: if self.pylupdateProcRunning: for act in self.tsprocDirMenuActions: @@ -598,7 +606,8 @@ Private slot called by the backMenu aboutToShow signal. """ if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: if self.pylupdateProcRunning: for act in self.tsprocBackMenuActions: @@ -871,7 +880,7 @@ def __readStderrLupdate(self, proc): """ Private slot to handle the readyReadStandardError signal of the - pylupdate5/pyside2-lupdate process. + pylupdate5 / pylupdate6 / pyside2-lupdate / pyside6-lupdate process. @param proc reference to the process @type QProcess @@ -926,52 +935,48 @@ @param exitStatus exit status of the process @type QProcess.ExitStatus """ + ui = e5App().getObject("UserInterface") if exitStatus == QProcess.NormalExit and exitCode == 0: - ui = e5App().getObject("UserInterface") - if ui.notificationsEnabled(): - ui.showNotification( - UI.PixmapCache.getPixmap("linguist48"), - self.tr("Translation file generation"), - self.tr( - "The generation of the translation files (*.ts)" - " was successful.")) - else: - E5MessageBox.information( - self, - self.tr("Translation file generation"), - self.tr( - "The generation of the translation files (*.ts)" - " was successful.")) + ui.showNotification( + UI.PixmapCache.getPixmap("linguist48"), + self.tr("Translation file generation"), + self.tr( + "The generation of the translation files (*.ts)" + " was successful.")) else: if exitStatus == QProcess.CrashExit: info = self.tr(" The process has crashed.") else: info = "" - E5MessageBox.critical( - self, + ui.showNotification( + UI.PixmapCache.getPixmap("linguist48"), self.tr("Translation file generation"), self.tr( "The generation of the translation files (*.ts) has" - " failed.{0}").format(info)) + " failed.{0}").format(info), + kind=NotificationTypes.Critical, + timeout=0) for index in range(len(self.__pylupdateProcesses)): if proc == self.__pylupdateProcesses[index][0]: - try: - self.__tmpProjects.remove( - self.__pylupdateProcesses[index][1]) - os.remove(self.__pylupdateProcesses[index][1]) - except OSError: - pass + tmpProjectFile = self.__pylupdateProcesses[index][1] + if tmpProjectFile: + try: + self.__tmpProjects.remove(tmpProjectFile) + os.remove(tmpProjectFile) + except OSError: + pass del self.__pylupdateProcesses[index] break + if not self.__pylupdateProcesses: # all done self.pylupdateProcRunning = False def __generateTSFile(self, noobsolete=False, generateAll=True): """ - Private method used to run pylupdate5/pyside2-lupdate to - generate the .ts files. + Private method used to run pylupdate5 / pylupdate6 / pyside2-lupdate / + pyside6-lupdate to generate the .ts files. @param noobsolete flag indicating whether obsolete entries should be kept (boolean) @@ -1009,68 +1014,130 @@ self.hooks["generateSelectedWithObsolete"](li) return - # generate a minimal temporary projectfile suitable for pylupdate + # generate a minimal temporary project file suitable for pylupdate self.__tmpProjects = [] if self.project.getProjectLanguage() in [ "Python", "Python3" ]: - ok = self.__writeTempProjectFile(langs, [".py"]) + if self.project.getProjectType() not in ["PyQt6", "PyQt6C"]: + ok = self.__writeTempProjectFile(langs, [".py"]) + if not ok: + return else: - ok = False - if not ok: return if self.project.getProjectType() in ["PyQt5", "PyQt5C"]: self.pylupdate = Utilities.generatePyQtToolPath('pylupdate5') + elif self.project.getProjectType() in ["PyQt6", "PyQt6C"]: + self.pylupdate = Utilities.generatePyQtToolPath('pylupdate6') elif self.project.getProjectType() in ["E6Plugin"]: self.pylupdate = Utilities.generatePyQtToolPath('pylupdate5') elif self.project.getProjectType() in ["PySide2", "PySide2C"]: self.pylupdate = Utilities.generatePySideToolPath( - 'pyside2-lupdate') + 'pyside2-lupdate', variant=2) + elif self.project.getProjectType() in ["PySide6", "PySide6C"]: + self.pylupdate = Utilities.generatePySideToolPath( + 'pyside6-lupdate', variant=6) else: return self.__pylupdateProcesses = [] - for tempProjectFile in self.__tmpProjects[:]: - proc = QProcess() - args = [] + if self.project.getProjectType() in ["PyQt6", "PyQt6C"]: + if langs: + langs = [self.project.getRelativePath(lang.fileName()) + for lang in langs if lang.fileName().endswith('.ts')] + else: + try: + pattern = self.project.pdata["TRANSLATIONPATTERN"].replace( + "%language%", "*") + langs = [ + lang for lang in self.project.pdata["TRANSLATIONS"] + if fnmatch.fnmatch(lang, pattern) + ] + except IndexError: + langs = [] + if not langs: + E5MessageBox.warning( + self, + self.tr("Translation file generation"), + self.tr("""No translation files (*.ts) selected.""")) + return + for lang in langs: + proc = QProcess() + args = [] - if noobsolete: - args.append('-noobsolete') - - args.append('-verbose') - path, filename = os.path.split(tempProjectFile) - args.append(filename) - proc.setWorkingDirectory(os.path.join(self.project.ppath, path)) - proc.finished.connect( - functools.partial(self.__generateTSFileDone, proc) - ) - proc.readyReadStandardOutput.connect( - functools.partial(self.__readStdoutLupdate, proc) - ) - proc.readyReadStandardError.connect( - functools.partial(self.__readStderrLupdate, proc) - ) - - proc.start(self.pylupdate, args) - procStarted = proc.waitForStarted() - if procStarted: - self.pylupdateProcRunning = True - self.__pylupdateProcesses.append((proc, tempProjectFile)) - else: - E5MessageBox.critical( - self, - self.tr('Process Generation Error'), - self.tr( - 'Could not start {0}.<br>' - 'Ensure that it is in the search path.' - ).format(self.pylupdate)) - # cleanup - try: - self.__tmpProjects.remove(tempProjectFile) - os.remove(tempProjectFile) - except OSError: - pass + if noobsolete: + args.append('--no-obsolete') + + args += ["--ts", lang] + args.append(".") + + proc.setWorkingDirectory(self.project.ppath) + proc.finished.connect( + functools.partial(self.__generateTSFileDone, proc) + ) + proc.readyReadStandardOutput.connect( + functools.partial(self.__readStdoutLupdate, proc) + ) + proc.readyReadStandardError.connect( + functools.partial(self.__readStderrLupdate, proc) + ) + + proc.start(self.pylupdate, args) + procStarted = proc.waitForStarted() + if procStarted: + self.pylupdateProcRunning = True + self.__pylupdateProcesses.append((proc, "")) + else: + E5MessageBox.critical( + self, + self.tr('Process Generation Error'), + self.tr( + 'Could not start {0}.<br>' + 'Ensure that it is in the search path.' + ).format(self.pylupdate)) + else: + for tempProjectFile in self.__tmpProjects[:]: + proc = QProcess() + args = [] + + if noobsolete: + args.append('-noobsolete') + + args.append('-verbose') + path, filename = os.path.split(tempProjectFile) + args.append(filename) + proc.setWorkingDirectory( + os.path.join(self.project.ppath, path)) + proc.finished.connect( + functools.partial(self.__generateTSFileDone, proc) + ) + proc.readyReadStandardOutput.connect( + functools.partial(self.__readStdoutLupdate, proc) + ) + proc.readyReadStandardError.connect( + functools.partial(self.__readStderrLupdate, proc) + ) + + proc.start(self.pylupdate, args) + procStarted = proc.waitForStarted() + if procStarted: + self.pylupdateProcRunning = True + self.__pylupdateProcesses.append((proc, tempProjectFile)) + else: + E5MessageBox.critical( + self, + self.tr('Process Generation Error'), + self.tr( + 'Could not start {0}.<br>' + 'Ensure that it is in the search path.' + ).format(self.pylupdate)) + # cleanup + try: + self.__tmpProjects.remove(tempProjectFile) + os.remove(tempProjectFile) + except OSError: + pass def __generateAll(self): """ @@ -1121,20 +1188,13 @@ @param exitStatus exit status of the process @type QProcess.ExitStatus """ + ui = e5App().getObject("UserInterface") if exitStatus == QProcess.NormalExit and exitCode == 0: - ui = e5App().getObject("UserInterface") - if ui.notificationsEnabled(): - ui.showNotification( - UI.PixmapCache.getPixmap("linguist48"), - self.tr("Translation file release"), - self.tr("The release of the translation files (*.qm)" - " was successful.")) - else: - E5MessageBox.information( - self, - self.tr("Translation file release"), - self.tr("The release of the translation files (*.qm)" - " was successful.")) + ui.showNotification( + UI.PixmapCache.getPixmap("linguist48"), + self.tr("Translation file release"), + self.tr("The release of the translation files (*.qm)" + " was successful.")) if self.project.pdata["TRANSLATIONSBINPATH"]: target = os.path.join( self.project.ppath, @@ -1146,11 +1206,13 @@ if os.path.exists(qmFile): shutil.move(qmFile, target) else: - E5MessageBox.critical( - self, + ui.showNotification( + UI.PixmapCache.getPixmap("linguist48"), self.tr("Translation file release"), self.tr( - "The release of the translation files (*.qm) has failed.")) + "The release of the translation files (*.qm) has failed."), + kind=NotificationTypes.Critical, + timeout=0) for index in range(len(self.__lreleaseProcesses)): if proc == self.__lreleaseProcesses[index]: @@ -1186,7 +1248,8 @@ return if self.project.getProjectType() in [ - "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" + "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", + "PySide2", "PySide2C", "PySide6", "PySide6C" ]: lrelease = os.path.join( Utilities.getQtBinariesPath(),