100 self.tsprocBackMenuActions = [] |
101 self.tsprocBackMenuActions = [] |
101 self.qmprocBackMenuActions = [] |
102 self.qmprocBackMenuActions = [] |
102 |
103 |
103 self.menu = QMenu(self) |
104 self.menu = QMenu(self) |
104 if self.project.getProjectType() in [ |
105 if self.project.getProjectType() in [ |
105 "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" |
106 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", |
|
107 "PySide2", "PySide2C", "PySide6", "PySide6C" |
106 ]: |
108 ]: |
107 act = self.menu.addAction( |
109 act = self.menu.addAction( |
108 self.tr('Generate translation'), self.__generateSelected) |
110 self.tr('Generate translation'), self.__generateSelected) |
109 self.tsMenuActions.append(act) |
111 self.tsMenuActions.append(act) |
110 self.tsprocMenuActions.append(act) |
112 self.tsprocMenuActions.append(act) |
288 self.backMenu.setEnabled(False) |
291 self.backMenu.setEnabled(False) |
289 |
292 |
290 # create the menu for multiple selected files |
293 # create the menu for multiple selected files |
291 self.multiMenu = QMenu(self) |
294 self.multiMenu = QMenu(self) |
292 if self.project.getProjectType() in [ |
295 if self.project.getProjectType() in [ |
293 "PyQt5", "PyQt5C", "E6Plugin", "PySide2", "PySide2C" |
296 "PyQt5", "PyQt5C", "PyQt6", "PyQt6C", "E6Plugin", |
|
297 "PySide2", "PySide2C", "PySide6", "PySide6C" |
294 ]: |
298 ]: |
295 act = self.multiMenu.addAction( |
299 act = self.multiMenu.addAction( |
296 self.tr('Generate translations'), |
300 self.tr('Generate translations'), |
297 self.__generateSelected) |
301 self.__generateSelected) |
298 self.tsMultiMenuActions.append(act) |
302 self.tsMultiMenuActions.append(act) |
924 @param exitCode exit code of the process |
933 @param exitCode exit code of the process |
925 @type int |
934 @type int |
926 @param exitStatus exit status of the process |
935 @param exitStatus exit status of the process |
927 @type QProcess.ExitStatus |
936 @type QProcess.ExitStatus |
928 """ |
937 """ |
|
938 ui = e5App().getObject("UserInterface") |
929 if exitStatus == QProcess.NormalExit and exitCode == 0: |
939 if exitStatus == QProcess.NormalExit and exitCode == 0: |
930 ui = e5App().getObject("UserInterface") |
940 ui.showNotification( |
931 if ui.notificationsEnabled(): |
941 UI.PixmapCache.getPixmap("linguist48"), |
932 ui.showNotification( |
942 self.tr("Translation file generation"), |
933 UI.PixmapCache.getPixmap("linguist48"), |
943 self.tr( |
934 self.tr("Translation file generation"), |
944 "The generation of the translation files (*.ts)" |
935 self.tr( |
945 " was successful.")) |
936 "The generation of the translation files (*.ts)" |
|
937 " was successful.")) |
|
938 else: |
|
939 E5MessageBox.information( |
|
940 self, |
|
941 self.tr("Translation file generation"), |
|
942 self.tr( |
|
943 "The generation of the translation files (*.ts)" |
|
944 " was successful.")) |
|
945 else: |
946 else: |
946 if exitStatus == QProcess.CrashExit: |
947 if exitStatus == QProcess.CrashExit: |
947 info = self.tr(" The process has crashed.") |
948 info = self.tr(" The process has crashed.") |
948 else: |
949 else: |
949 info = "" |
950 info = "" |
950 E5MessageBox.critical( |
951 ui.showNotification( |
951 self, |
952 UI.PixmapCache.getPixmap("linguist48"), |
952 self.tr("Translation file generation"), |
953 self.tr("Translation file generation"), |
953 self.tr( |
954 self.tr( |
954 "The generation of the translation files (*.ts) has" |
955 "The generation of the translation files (*.ts) has" |
955 " failed.{0}").format(info)) |
956 " failed.{0}").format(info), |
|
957 kind=NotificationTypes.Critical, |
|
958 timeout=0) |
956 |
959 |
957 for index in range(len(self.__pylupdateProcesses)): |
960 for index in range(len(self.__pylupdateProcesses)): |
958 if proc == self.__pylupdateProcesses[index][0]: |
961 if proc == self.__pylupdateProcesses[index][0]: |
959 try: |
962 tmpProjectFile = self.__pylupdateProcesses[index][1] |
960 self.__tmpProjects.remove( |
963 if tmpProjectFile: |
961 self.__pylupdateProcesses[index][1]) |
964 try: |
962 os.remove(self.__pylupdateProcesses[index][1]) |
965 self.__tmpProjects.remove(tmpProjectFile) |
963 except OSError: |
966 os.remove(tmpProjectFile) |
964 pass |
967 except OSError: |
|
968 pass |
965 del self.__pylupdateProcesses[index] |
969 del self.__pylupdateProcesses[index] |
966 break |
970 break |
|
971 |
967 if not self.__pylupdateProcesses: |
972 if not self.__pylupdateProcesses: |
968 # all done |
973 # all done |
969 self.pylupdateProcRunning = False |
974 self.pylupdateProcRunning = False |
970 |
975 |
971 def __generateTSFile(self, noobsolete=False, generateAll=True): |
976 def __generateTSFile(self, noobsolete=False, generateAll=True): |
972 """ |
977 """ |
973 Private method used to run pylupdate5/pyside2-lupdate to |
978 Private method used to run pylupdate5 / pylupdate6 / pyside2-lupdate / |
974 generate the .ts files. |
979 pyside6-lupdate to generate the .ts files. |
975 |
980 |
976 @param noobsolete flag indicating whether obsolete entries should be |
981 @param noobsolete flag indicating whether obsolete entries should be |
977 kept (boolean) |
982 kept (boolean) |
978 @param generateAll flag indicating whether all translations should be |
983 @param generateAll flag indicating whether all translations should be |
979 generated (boolean) |
984 generated (boolean) |
1007 li = [self.project.getRelativePath(lang.fileName()) |
1012 li = [self.project.getRelativePath(lang.fileName()) |
1008 for lang in langs] |
1013 for lang in langs] |
1009 self.hooks["generateSelectedWithObsolete"](li) |
1014 self.hooks["generateSelectedWithObsolete"](li) |
1010 return |
1015 return |
1011 |
1016 |
1012 # generate a minimal temporary projectfile suitable for pylupdate |
1017 # generate a minimal temporary project file suitable for pylupdate |
1013 self.__tmpProjects = [] |
1018 self.__tmpProjects = [] |
1014 if self.project.getProjectLanguage() in [ |
1019 if self.project.getProjectLanguage() in [ |
1015 "Python", "Python3" |
1020 "Python", "Python3" |
1016 ]: |
1021 ]: |
1017 ok = self.__writeTempProjectFile(langs, [".py"]) |
1022 if self.project.getProjectType() not in ["PyQt6", "PyQt6C"]: |
1018 else: |
1023 ok = self.__writeTempProjectFile(langs, [".py"]) |
1019 ok = False |
1024 if not ok: |
1020 if not ok: |
1025 return |
|
1026 else: |
1021 return |
1027 return |
1022 |
1028 |
1023 if self.project.getProjectType() in ["PyQt5", "PyQt5C"]: |
1029 if self.project.getProjectType() in ["PyQt5", "PyQt5C"]: |
1024 self.pylupdate = Utilities.generatePyQtToolPath('pylupdate5') |
1030 self.pylupdate = Utilities.generatePyQtToolPath('pylupdate5') |
|
1031 elif self.project.getProjectType() in ["PyQt6", "PyQt6C"]: |
|
1032 self.pylupdate = Utilities.generatePyQtToolPath('pylupdate6') |
1025 elif self.project.getProjectType() in ["E6Plugin"]: |
1033 elif self.project.getProjectType() in ["E6Plugin"]: |
1026 self.pylupdate = Utilities.generatePyQtToolPath('pylupdate5') |
1034 self.pylupdate = Utilities.generatePyQtToolPath('pylupdate5') |
1027 elif self.project.getProjectType() in ["PySide2", "PySide2C"]: |
1035 elif self.project.getProjectType() in ["PySide2", "PySide2C"]: |
1028 self.pylupdate = Utilities.generatePySideToolPath( |
1036 self.pylupdate = Utilities.generatePySideToolPath( |
1029 'pyside2-lupdate') |
1037 'pyside2-lupdate', variant=2) |
|
1038 elif self.project.getProjectType() in ["PySide6", "PySide6C"]: |
|
1039 self.pylupdate = Utilities.generatePySideToolPath( |
|
1040 'pyside6-lupdate', variant=6) |
1030 else: |
1041 else: |
1031 return |
1042 return |
1032 |
1043 |
1033 self.__pylupdateProcesses = [] |
1044 self.__pylupdateProcesses = [] |
1034 for tempProjectFile in self.__tmpProjects[:]: |
1045 if self.project.getProjectType() in ["PyQt6", "PyQt6C"]: |
1035 proc = QProcess() |
1046 if langs: |
1036 args = [] |
1047 langs = [self.project.getRelativePath(lang.fileName()) |
1037 |
1048 for lang in langs if lang.fileName().endswith('.ts')] |
1038 if noobsolete: |
|
1039 args.append('-noobsolete') |
|
1040 |
|
1041 args.append('-verbose') |
|
1042 path, filename = os.path.split(tempProjectFile) |
|
1043 args.append(filename) |
|
1044 proc.setWorkingDirectory(os.path.join(self.project.ppath, path)) |
|
1045 proc.finished.connect( |
|
1046 functools.partial(self.__generateTSFileDone, proc) |
|
1047 ) |
|
1048 proc.readyReadStandardOutput.connect( |
|
1049 functools.partial(self.__readStdoutLupdate, proc) |
|
1050 ) |
|
1051 proc.readyReadStandardError.connect( |
|
1052 functools.partial(self.__readStderrLupdate, proc) |
|
1053 ) |
|
1054 |
|
1055 proc.start(self.pylupdate, args) |
|
1056 procStarted = proc.waitForStarted() |
|
1057 if procStarted: |
|
1058 self.pylupdateProcRunning = True |
|
1059 self.__pylupdateProcesses.append((proc, tempProjectFile)) |
|
1060 else: |
1049 else: |
1061 E5MessageBox.critical( |
1050 try: |
|
1051 pattern = self.project.pdata["TRANSLATIONPATTERN"].replace( |
|
1052 "%language%", "*") |
|
1053 langs = [ |
|
1054 lang for lang in self.project.pdata["TRANSLATIONS"] |
|
1055 if fnmatch.fnmatch(lang, pattern) |
|
1056 ] |
|
1057 except IndexError: |
|
1058 langs = [] |
|
1059 if not langs: |
|
1060 E5MessageBox.warning( |
1062 self, |
1061 self, |
1063 self.tr('Process Generation Error'), |
1062 self.tr("Translation file generation"), |
1064 self.tr( |
1063 self.tr("""No translation files (*.ts) selected.""")) |
1065 'Could not start {0}.<br>' |
1064 return |
1066 'Ensure that it is in the search path.' |
1065 for lang in langs: |
1067 ).format(self.pylupdate)) |
1066 proc = QProcess() |
1068 # cleanup |
1067 args = [] |
1069 try: |
1068 |
1070 self.__tmpProjects.remove(tempProjectFile) |
1069 if noobsolete: |
1071 os.remove(tempProjectFile) |
1070 args.append('--no-obsolete') |
1072 except OSError: |
1071 |
1073 pass |
1072 args += ["--ts", lang] |
|
1073 args.append(".") |
|
1074 |
|
1075 proc.setWorkingDirectory(self.project.ppath) |
|
1076 proc.finished.connect( |
|
1077 functools.partial(self.__generateTSFileDone, proc) |
|
1078 ) |
|
1079 proc.readyReadStandardOutput.connect( |
|
1080 functools.partial(self.__readStdoutLupdate, proc) |
|
1081 ) |
|
1082 proc.readyReadStandardError.connect( |
|
1083 functools.partial(self.__readStderrLupdate, proc) |
|
1084 ) |
|
1085 |
|
1086 proc.start(self.pylupdate, args) |
|
1087 procStarted = proc.waitForStarted() |
|
1088 if procStarted: |
|
1089 self.pylupdateProcRunning = True |
|
1090 self.__pylupdateProcesses.append((proc, "")) |
|
1091 else: |
|
1092 E5MessageBox.critical( |
|
1093 self, |
|
1094 self.tr('Process Generation Error'), |
|
1095 self.tr( |
|
1096 'Could not start {0}.<br>' |
|
1097 'Ensure that it is in the search path.' |
|
1098 ).format(self.pylupdate)) |
|
1099 else: |
|
1100 for tempProjectFile in self.__tmpProjects[:]: |
|
1101 proc = QProcess() |
|
1102 args = [] |
|
1103 |
|
1104 if noobsolete: |
|
1105 args.append('-noobsolete') |
|
1106 |
|
1107 args.append('-verbose') |
|
1108 path, filename = os.path.split(tempProjectFile) |
|
1109 args.append(filename) |
|
1110 proc.setWorkingDirectory( |
|
1111 os.path.join(self.project.ppath, path)) |
|
1112 proc.finished.connect( |
|
1113 functools.partial(self.__generateTSFileDone, proc) |
|
1114 ) |
|
1115 proc.readyReadStandardOutput.connect( |
|
1116 functools.partial(self.__readStdoutLupdate, proc) |
|
1117 ) |
|
1118 proc.readyReadStandardError.connect( |
|
1119 functools.partial(self.__readStderrLupdate, proc) |
|
1120 ) |
|
1121 |
|
1122 proc.start(self.pylupdate, args) |
|
1123 procStarted = proc.waitForStarted() |
|
1124 if procStarted: |
|
1125 self.pylupdateProcRunning = True |
|
1126 self.__pylupdateProcesses.append((proc, tempProjectFile)) |
|
1127 else: |
|
1128 E5MessageBox.critical( |
|
1129 self, |
|
1130 self.tr('Process Generation Error'), |
|
1131 self.tr( |
|
1132 'Could not start {0}.<br>' |
|
1133 'Ensure that it is in the search path.' |
|
1134 ).format(self.pylupdate)) |
|
1135 # cleanup |
|
1136 try: |
|
1137 self.__tmpProjects.remove(tempProjectFile) |
|
1138 os.remove(tempProjectFile) |
|
1139 except OSError: |
|
1140 pass |
1074 |
1141 |
1075 def __generateAll(self): |
1142 def __generateAll(self): |
1076 """ |
1143 """ |
1077 Private method to generate all translation files (.ts) for Qt Linguist. |
1144 Private method to generate all translation files (.ts) for Qt Linguist. |
1078 |
1145 |
1119 @param exitCode exit code of the process |
1186 @param exitCode exit code of the process |
1120 @type int |
1187 @type int |
1121 @param exitStatus exit status of the process |
1188 @param exitStatus exit status of the process |
1122 @type QProcess.ExitStatus |
1189 @type QProcess.ExitStatus |
1123 """ |
1190 """ |
|
1191 ui = e5App().getObject("UserInterface") |
1124 if exitStatus == QProcess.NormalExit and exitCode == 0: |
1192 if exitStatus == QProcess.NormalExit and exitCode == 0: |
1125 ui = e5App().getObject("UserInterface") |
1193 ui.showNotification( |
1126 if ui.notificationsEnabled(): |
1194 UI.PixmapCache.getPixmap("linguist48"), |
1127 ui.showNotification( |
1195 self.tr("Translation file release"), |
1128 UI.PixmapCache.getPixmap("linguist48"), |
1196 self.tr("The release of the translation files (*.qm)" |
1129 self.tr("Translation file release"), |
1197 " was successful.")) |
1130 self.tr("The release of the translation files (*.qm)" |
|
1131 " was successful.")) |
|
1132 else: |
|
1133 E5MessageBox.information( |
|
1134 self, |
|
1135 self.tr("Translation file release"), |
|
1136 self.tr("The release of the translation files (*.qm)" |
|
1137 " was successful.")) |
|
1138 if self.project.pdata["TRANSLATIONSBINPATH"]: |
1198 if self.project.pdata["TRANSLATIONSBINPATH"]: |
1139 target = os.path.join( |
1199 target = os.path.join( |
1140 self.project.ppath, |
1200 self.project.ppath, |
1141 self.project.pdata["TRANSLATIONSBINPATH"]) |
1201 self.project.pdata["TRANSLATIONSBINPATH"]) |
1142 for langFile in self.project.pdata["TRANSLATIONS"][:]: |
1202 for langFile in self.project.pdata["TRANSLATIONS"][:]: |
1144 qmFile = os.path.join(self.project.ppath, |
1204 qmFile = os.path.join(self.project.ppath, |
1145 langFile.replace('.ts', '.qm')) |
1205 langFile.replace('.ts', '.qm')) |
1146 if os.path.exists(qmFile): |
1206 if os.path.exists(qmFile): |
1147 shutil.move(qmFile, target) |
1207 shutil.move(qmFile, target) |
1148 else: |
1208 else: |
1149 E5MessageBox.critical( |
1209 ui.showNotification( |
1150 self, |
1210 UI.PixmapCache.getPixmap("linguist48"), |
1151 self.tr("Translation file release"), |
1211 self.tr("Translation file release"), |
1152 self.tr( |
1212 self.tr( |
1153 "The release of the translation files (*.qm) has failed.")) |
1213 "The release of the translation files (*.qm) has failed."), |
|
1214 kind=NotificationTypes.Critical, |
|
1215 timeout=0) |
1154 |
1216 |
1155 for index in range(len(self.__lreleaseProcesses)): |
1217 for index in range(len(self.__lreleaseProcesses)): |
1156 if proc == self.__lreleaseProcesses[index]: |
1218 if proc == self.__lreleaseProcesses[index]: |
1157 del self.__lreleaseProcesses[index] |
1219 del self.__lreleaseProcesses[index] |
1158 break |
1220 break |