15:3f5c05eb2d5f | 16:dd3f6bfb85f7 |
---|---|
6 """ | 6 """ |
7 Module implementing the Flask project support. | 7 Module implementing the Flask project support. |
8 """ | 8 """ |
9 | 9 |
10 import os | 10 import os |
11 import re | |
11 | 12 |
12 from PyQt5.QtCore import ( | 13 from PyQt5.QtCore import ( |
13 pyqtSlot, QObject, QProcess, QProcessEnvironment, QTimer | 14 pyqtSlot, QObject, QProcess, QProcessEnvironment, QTimer |
14 ) | 15 ) |
15 from PyQt5.QtWidgets import QMenu, QDialog | 16 from PyQt5.QtWidgets import QMenu, QDialog |
22 | 23 |
23 import UI.PixmapCache | 24 import UI.PixmapCache |
24 import Utilities | 25 import Utilities |
25 | 26 |
26 from .FlaskCommandDialog import FlaskCommandDialog | 27 from .FlaskCommandDialog import FlaskCommandDialog |
28 from .PyBabelCommandDialog import PyBabelCommandDialog | |
27 | 29 |
28 | 30 |
31 # TODO: move PyBabel related code to a separate package (FlaskBabelExtension) | |
32 # TODO: move database related code to a separate package (FlaskMigrateExtension) | |
29 class Project(QObject): | 33 class Project(QObject): |
30 """ | 34 """ |
31 Class implementing the Flask project support. | 35 Class implementing the Flask project support. |
32 """ | 36 """ |
33 def __init__(self, plugin, iconSuffix, parent=None): | 37 def __init__(self, plugin, iconSuffix, parent=None): |
64 | 68 |
65 self.__flaskVersions = { | 69 self.__flaskVersions = { |
66 "python": "", | 70 "python": "", |
67 "flask": "", | 71 "flask": "", |
68 "werkzeug": "", | 72 "werkzeug": "", |
73 } | |
74 | |
75 self.__capabilities = { | |
76 "pybabel": False, | |
77 "migrate": False, | |
69 } | 78 } |
70 | 79 |
71 def initActions(self): | 80 def initActions(self): |
72 """ | 81 """ |
73 Public method to define the Flask actions. | 82 Public method to define the Flask actions. |
176 )) | 185 )) |
177 self.initDatabaseAct.triggered.connect(self.__initDatabase) | 186 self.initDatabaseAct.triggered.connect(self.__initDatabase) |
178 self.actions.append(self.initDatabaseAct) | 187 self.actions.append(self.initDatabaseAct) |
179 | 188 |
180 ################################## | 189 ################################## |
181 ## database action below ## | 190 ## pybabel action below ## |
182 ################################## | 191 ################################## |
183 | 192 |
184 self.pybabelConfigAct = E5Action( | 193 self.pybabelConfigAct = E5Action( |
185 self.tr('Configure PyBabel'), | 194 self.tr('Configure PyBabel'), |
186 self.tr('Configure Py&Babel'), | 195 self.tr('Configure Py&Babel'), |
241 self.__menus = {} # clear menus references | 250 self.__menus = {} # clear menus references |
242 | 251 |
243 menu = QMenu(self.tr('&Flask'), self.__ui) | 252 menu = QMenu(self.tr('&Flask'), self.__ui) |
244 menu.setTearOffEnabled(True) | 253 menu.setTearOffEnabled(True) |
245 | 254 |
246 menu.addSection("flask run") | |
247 menu.addAction(self.runServerAct) | 255 menu.addAction(self.runServerAct) |
248 menu.addAction(self.runDevServerAct) | 256 menu.addAction(self.runDevServerAct) |
249 menu.addAction(self.askForServerOptionsAct) | 257 menu.addAction(self.askForServerOptionsAct) |
250 menu.addSection("flask shell") | 258 menu.addSeparator() |
251 menu.addAction(self.runPythonShellAct) | 259 menu.addAction(self.runPythonShellAct) |
252 menu.addSection("flask routes") | 260 menu.addSeparator() |
253 menu.addAction(self.showRoutesAct) | 261 menu.addAction(self.showRoutesAct) |
254 menu.addSection("flask init-db") | 262 menu.addSeparator() |
255 menu.addAction(self.initDatabaseAct) | 263 menu.addAction(self.initDatabaseAct) |
256 menu.addSection(self.tr("Translations")) | 264 menu.addSeparator() |
257 menu.addAction(self.pybabelConfigAct) | 265 menu.addAction(self.pybabelConfigAct) |
258 menu.addSection(self.tr("Various")) | 266 menu.addSeparator() |
259 menu.addAction(self.documentationAct) | 267 menu.addAction(self.documentationAct) |
260 menu.addSeparator() | 268 menu.addSeparator() |
261 menu.addAction(self.aboutFlaskAct) | 269 menu.addAction(self.aboutFlaskAct) |
262 | 270 |
263 self.__menus["main"] = menu | 271 self.__menus["main"] = menu |
306 def projectOpenedHooks(self): | 314 def projectOpenedHooks(self): |
307 """ | 315 """ |
308 Public method to add our hook methods. | 316 Public method to add our hook methods. |
309 """ | 317 """ |
310 if self.__e5project.getProjectType() == "Flask": | 318 if self.__e5project.getProjectType() == "Flask": |
319 # TODO: add some methods for standard templates | |
311 ## self.__formsBrowser = ( | 320 ## self.__formsBrowser = ( |
312 ## e5App().getObject("ProjectBrowser") | 321 ## e5App().getObject("ProjectBrowser") |
313 ## .getProjectBrowser("forms")) | 322 ## .getProjectBrowser("forms")) |
314 ## self.__formsBrowser.addHookMethodAndMenuEntry( | 323 ## self.__formsBrowser.addHookMethodAndMenuEntry( |
315 ## "newForm", self.newForm, self.tr("New template...")) | 324 ## "newForm", self.newForm, self.tr("New template...")) |
316 ## | 325 ## |
317 if self.flaskBabelAvailable(): | 326 self.__determineCapabilities() |
327 | |
328 if self.__capabilities["pybabel"]: | |
318 self.__e5project.projectLanguageAddedByCode.connect( | 329 self.__e5project.projectLanguageAddedByCode.connect( |
319 self.__projectLanguageAdded) | 330 self.__projectLanguageAdded) |
320 self.__translationsBrowser = ( | 331 self.__translationsBrowser = ( |
321 e5App().getObject("ProjectBrowser") | 332 e5App().getObject("ProjectBrowser") |
322 .getProjectBrowser("translations")) | 333 .getProjectBrowser("translations")) |
331 self.tr("Compile Selected Catalogs")) | 342 self.tr("Compile Selected Catalogs")) |
332 self.__translationsBrowser.addHookMethodAndMenuEntry( | 343 self.__translationsBrowser.addHookMethodAndMenuEntry( |
333 "generateAll", self.updateCatalogs, | 344 "generateAll", self.updateCatalogs, |
334 self.tr("Update All Catalogs")) | 345 self.tr("Update All Catalogs")) |
335 self.__translationsBrowser.addHookMethodAndMenuEntry( | 346 self.__translationsBrowser.addHookMethodAndMenuEntry( |
347 "generateAllWithObsolete", self.updateCatalogsObsolete, | |
348 self.tr("Update All Catalogs (with obsolete)")) | |
349 self.__translationsBrowser.addHookMethodAndMenuEntry( | |
336 "generateSelected", self.updateSelectedCatalogs, | 350 "generateSelected", self.updateSelectedCatalogs, |
337 self.tr("Update Selected Catalogs")) | 351 self.tr("Update Selected Catalogs")) |
352 self.__translationsBrowser.addHookMethodAndMenuEntry( | |
353 "generateSelectedWithObsolete", | |
354 self.updateSelectedCatalogsObsolete, | |
355 self.tr("Update Selected Catalogs (with obsolete)")) | |
338 | 356 |
339 self.__hooksInstalled = True | 357 self.__hooksInstalled = True |
340 | 358 |
341 self.registerOpenHook() | 359 self.registerOpenHook() |
342 | 360 |
348 ## self.__formsBrowser.removeHookMethod("newForm") | 366 ## self.__formsBrowser.removeHookMethod("newForm") |
349 ## self.__formsBrowser = None | 367 ## self.__formsBrowser = None |
350 ## | 368 ## |
351 self.__e5project.projectLanguageAddedByCode.disconnect( | 369 self.__e5project.projectLanguageAddedByCode.disconnect( |
352 self.__projectLanguageAdded) | 370 self.__projectLanguageAdded) |
353 self.__translationsBrowser.removeHookMethod("extractMessages") | 371 self.__translationsBrowser.removeHookMethod( |
354 self.__translationsBrowser.removeHookMethod("releaseAll") | 372 "extractMessages") |
355 self.__translationsBrowser.removeHookMethod("releaseSelected") | 373 self.__translationsBrowser.removeHookMethod( |
356 self.__translationsBrowser.removeHookMethod("generateAll") | 374 "releaseAll") |
357 self.__translationsBrowser.removeHookMethod("generateSelected") | 375 self.__translationsBrowser.removeHookMethod( |
358 self.__translationsBrowser.removeHookMethod("open") | 376 "releaseSelected") |
377 self.__translationsBrowser.removeHookMethod( | |
378 "generateAll") | |
379 self.__translationsBrowser.removeHookMethod( | |
380 "generateAllWithObsolete") | |
381 self.__translationsBrowser.removeHookMethod( | |
382 "generateSelected") | |
383 self.__translationsBrowser.removeHookMethod( | |
384 "generateSelectedWithObsolete") | |
385 self.__translationsBrowser.removeHookMethod( | |
386 "open") | |
359 self.__translationsBrowser = None | 387 self.__translationsBrowser = None |
360 | 388 |
361 self.__hooksInstalled = False | 389 self.__hooksInstalled = False |
362 | 390 |
363 ################################################################## | 391 ################################################################## |
647 self.__projectData[category][key] = value | 675 self.__projectData[category][key] = value |
648 | 676 |
649 self.__e5project.setData( | 677 self.__e5project.setData( |
650 "PROJECTTYPESPECIFICDATA", category, self.__projectData[category]) | 678 "PROJECTTYPESPECIFICDATA", category, self.__projectData[category]) |
651 | 679 |
652 ################################################################## | 680 def __determineCapabilities(self): |
653 ## slots below implement documentation functions | 681 """ |
682 Private method to determine capabilities provided by supported | |
683 extensions. | |
684 """ | |
685 # 1. support for flask-babel (i.e. pybabel) | |
686 self.__capabilities["pybabel"] = self.flaskBabelAvailable() | |
687 self.pybabelConfigAct.setEnabled(self.__capabilities["pybabel"]) | |
688 | |
689 # 2. support for flask-migrate | |
690 # TODO: add support for flask-migrate | |
691 | |
692 ################################################################## | |
693 ## slot below implements project specific flask configuration | |
694 ################################################################## | |
695 | |
696 @pyqtSlot() | |
697 def __configureFlaskForProject(self): | |
698 """ | |
699 Private slot to configure the project specific flask parameters. | |
700 """ | |
701 # TODO: implement the flask project config dialog | |
702 # 1. check boxes to override flask-babel and flask-migrate | |
703 # 2. support for project specific virtual environment | |
704 | |
705 ################################################################## | |
706 ## slot below implements documentation function | |
654 ################################################################## | 707 ################################################################## |
655 | 708 |
656 def __showDocumentation(self): | 709 def __showDocumentation(self): |
657 """ | 710 """ |
658 Private slot to show the helpviewer with the Flask documentation. | 711 Private slot to show the helpviewer with the Flask documentation. |
757 dlg = RoutesDialog(self) | 810 dlg = RoutesDialog(self) |
758 if dlg.showRoutes(): | 811 if dlg.showRoutes(): |
759 dlg.show() | 812 dlg.show() |
760 self.__routesDialog = dlg | 813 self.__routesDialog = dlg |
761 | 814 |
815 # TODO: replace this by commands made by flask-migrate (flask db ...) | |
762 @pyqtSlot() | 816 @pyqtSlot() |
763 def __initDatabase(self): | 817 def __initDatabase(self): |
764 """ | 818 """ |
765 Private slot showing the result of the database creation. | 819 Private slot showing the result of the database creation. |
766 """ | 820 """ |
767 dlg = FlaskCommandDialog(self) | 821 dlg = FlaskCommandDialog(self) |
768 if dlg.startFlaskCommand("init-db"): | 822 if dlg.startCommand("init-db"): |
769 dlg.exec() | 823 dlg.exec() |
770 | 824 |
771 ################################################################## | 825 ################################################################## |
772 ## slots and methods below implement i18n and l10n support | 826 ## slots and methods below implement i18n and l10n support |
773 ################################################################## | 827 ################################################################## |
797 @pyqtSlot() | 851 @pyqtSlot() |
798 def __configurePybabel(self): | 852 def __configurePybabel(self): |
799 """ | 853 """ |
800 Private slot to show a dialog to edit the pybabel configuration. | 854 Private slot to show a dialog to edit the pybabel configuration. |
801 """ | 855 """ |
802 # TODO: implement this | |
803 from .PyBabelConfigDialog import PyBabelConfigDialog | 856 from .PyBabelConfigDialog import PyBabelConfigDialog |
804 | 857 |
805 config = self.getData("pybabel", "") | 858 config = self.getData("pybabel", "") |
806 dlg = PyBabelConfigDialog(config) | 859 dlg = PyBabelConfigDialog(config) |
807 if dlg.exec() == QDialog.Accepted: | 860 if dlg.exec() == QDialog.Accepted: |
808 config = dlg.getConfiguration() | 861 config = dlg.getConfiguration() |
809 self.setData("pybabel", "", config) | 862 self.setData("pybabel", "", config) |
863 | |
864 self.__e5project.setTranslationPattern(os.path.join( | |
865 config["translationsDirectory"], "%language%", "LC_MESSAGES", | |
866 "{0}.po".format(config["domain"]) | |
867 )) | |
868 self.__e5project.setDirty(True) | |
810 | 869 |
811 cfgFileName = self.__e5project.getAbsoluteUniversalPath( | 870 cfgFileName = self.__e5project.getAbsoluteUniversalPath( |
812 config["configFile"]) | 871 config["configFile"]) |
813 if not os.path.exists(cfgFileName): | 872 if not os.path.exists(cfgFileName): |
814 self.__createBabelCfg(cfgFileName) | 873 self.__createBabelCfg(cfgFileName) |
838 | 897 |
839 def __createBabelCfg(self, configFile): | 898 def __createBabelCfg(self, configFile): |
840 """ | 899 """ |
841 Private method to create a template pybabel configuration file. | 900 Private method to create a template pybabel configuration file. |
842 | 901 |
902 @param configFile name of the configuration file to be created | |
903 @type str | |
843 @return flag indicating successful configuration file creation | 904 @return flag indicating successful configuration file creation |
844 @rtype bool | 905 @rtype bool |
845 """ | 906 """ |
846 _, app = self.getApplication() | 907 _, app = self.getApplication() |
847 if app.endswith(".py"): | 908 if app.endswith(".py"): |
876 """ generated.</p><p>Reason: {0}</p>""") | 937 """ generated.</p><p>Reason: {0}</p>""") |
877 .format(str(err)) | 938 .format(str(err)) |
878 ) | 939 ) |
879 return False | 940 return False |
880 | 941 |
881 def __projectLanguageAdded(self, code): | 942 def __getLocale(self, filename): |
882 # TODO: implement this with pybabel ... | 943 """ |
883 pass | 944 Private method to extract the locale out of a file name. |
945 | |
946 @param filename name of the file used for extraction | |
947 @type str | |
948 @return extracted locale | |
949 @rtype str or None | |
950 """ | |
951 if self.__e5project.getTranslationPattern(): | |
952 filename = os.path.splitext(filename)[0] + ".po" | |
953 | |
954 # On Windows, path typically contains backslashes. This leads | |
955 # to an invalid search pattern '...\(' because the opening bracket | |
956 # will be escaped. | |
957 pattern = self.__e5project.getTranslationPattern() | |
958 pattern = os.path.normpath(pattern) | |
959 pattern = pattern.replace("%language%", "(.*?)") | |
960 pattern = pattern.replace('\\', '\\\\') | |
961 match = re.search(pattern, filename) | |
962 if match is not None: | |
963 return match.group(1) | |
964 | |
965 return None | |
884 | 966 |
885 def openPOEditor(self, poFile): | 967 def openPOEditor(self, poFile): |
886 """ | 968 """ |
887 Public method to edit the given file in an external .po editor. | 969 Public method to edit the given file in an external .po editor. |
888 | 970 |
905 """ | 987 """ |
906 Public method to extract the messages catalog template file. | 988 Public method to extract the messages catalog template file. |
907 """ | 989 """ |
908 title = self.tr("Extract messages") | 990 title = self.tr("Extract messages") |
909 if self.__ensurePybabelConfigured(): | 991 if self.__ensurePybabelConfigured(): |
992 workdir = self.getApplication()[0] | |
910 potFile = self.__e5project.getAbsoluteUniversalPath( | 993 potFile = self.__e5project.getAbsoluteUniversalPath( |
911 self.getData("pybabel", "catalogFile")) | 994 self.getData("pybabel", "catalogFile")) |
912 | 995 |
913 try: | 996 try: |
914 potFilePath = os.path.dirname(potFile) | 997 potFilePath = os.path.dirname(potFile) |
916 except EnvironmentError: | 999 except EnvironmentError: |
917 pass | 1000 pass |
918 | 1001 |
919 args = [ | 1002 args = [ |
920 "-F", | 1003 "-F", |
921 self.__e5project.getAbsoluteUniversalPath( | 1004 os.path.relpath( |
922 self.getData("pybabel", "configFile")) | 1005 self.__e5project.getAbsoluteUniversalPath( |
1006 self.getData("pybabel", "configFile")), | |
1007 workdir | |
1008 ) | |
923 ] | 1009 ] |
924 if self.getData("pybabel", "markersList"): | 1010 if self.getData("pybabel", "markersList"): |
925 for marker in self.getData("pybabel", "markersList"): | 1011 for marker in self.getData("pybabel", "markersList"): |
926 args += ["-k", marker] | 1012 args += ["-k", marker] |
927 args += [ | 1013 args += [ |
928 "-o", | 1014 "-o", |
929 potFile, | 1015 os.path.relpath(potFile, workdir), |
930 "." | 1016 "." |
931 ] | 1017 ] |
932 | 1018 |
933 dlg = FlaskCommandDialog(self) | 1019 dlg = PyBabelCommandDialog( |
934 res = dlg.startBabelCommand( | 1020 self, title, |
935 "extract", args, title, | |
936 msgSuccess=self.tr("\nMessages extracted successfully.") | 1021 msgSuccess=self.tr("\nMessages extracted successfully.") |
937 ) | 1022 ) |
1023 res = dlg.startCommand("extract", args, workdir) | |
938 if res: | 1024 if res: |
939 dlg.exec() | 1025 dlg.exec() |
940 self.__e5project.appendFile(potFile) | 1026 self.__e5project.appendFile(potFile) |
941 # TODO: implement this with pybabel ... | 1027 |
942 pass | 1028 def __projectLanguageAdded(self, code): |
943 | 1029 """ |
944 def compileCatalogs(self): | 1030 Private slot handling the addition of a new language. |
945 # TODO: implement this with pybabel ... | 1031 |
946 pass | 1032 @param code language code of the new language |
947 | 1033 @type str |
948 def compileSelectedCatalogs(self): | 1034 """ |
949 # TODO: implement this with pybabel ... | 1035 title = self.tr( |
950 pass | 1036 "Initializing message catalog for '{0}'").format(code) |
951 | 1037 |
952 def updateCatalogs(self): | 1038 if self.__ensurePybabelConfigured(): |
953 # TODO: implement this with pybabel ... | 1039 workdir = self.getApplication()[0] |
954 pass | 1040 langFile = self.__e5project.getAbsoluteUniversalPath( |
955 | 1041 self.__e5project.getTranslationPattern().replace( |
956 def updateSelectedCatalogs(self): | 1042 "%language%", code)) |
957 # TODO: implement this with pybabel ... | 1043 potFile = self.__e5project.getAbsoluteUniversalPath( |
958 pass | 1044 self.getData("pybabel", "catalogFile")) |
1045 | |
1046 args = [ | |
1047 "--domain={0}".format(self.getData("pybabel", "domain")), | |
1048 "--input-file={0}".format(os.path.relpath(potFile, workdir)), | |
1049 "--output-file={0}".format(os.path.relpath(langFile, workdir)), | |
1050 "--locale={0}".format(code), | |
1051 ] | |
1052 | |
1053 dlg = PyBabelCommandDialog( | |
1054 self, title, | |
1055 msgSuccess=self.tr( | |
1056 "\nMessage catalog initialized successfully.") | |
1057 ) | |
1058 res = dlg.startCommand("init", args, workdir) | |
1059 if res: | |
1060 dlg.exec() | |
1061 | |
1062 self.__e5project.appendFile(langFile) | |
1063 | |
1064 def compileCatalogs(self, filenames): | |
1065 """ | |
1066 Public method to compile the message catalogs. | |
1067 | |
1068 @param filenames list of filenames (not used) | |
1069 @type list of str | |
1070 """ | |
1071 title = self.tr("Compiling message catalogs") | |
1072 | |
1073 if self.__ensurePybabelConfigured(): | |
1074 workdir = self.getApplication()[0] | |
1075 translationsDirectory = self.__e5project.getAbsoluteUniversalPath( | |
1076 self.getData("pybabel", "translationsDirectory")) | |
1077 | |
1078 args = [ | |
1079 "--domain={0}".format(self.getData("pybabel", "domain")), | |
1080 "--directory={0}".format( | |
1081 os.path.relpath(translationsDirectory, workdir)), | |
1082 "--use-fuzzy", | |
1083 "--statistics", | |
1084 ] | |
1085 | |
1086 dlg = PyBabelCommandDialog( | |
1087 self, title, | |
1088 msgSuccess=self.tr("\nMessage catalogs compiled successfully.") | |
1089 ) | |
1090 res = dlg.startCommand("compile", args, workdir) | |
1091 if res: | |
1092 dlg.exec() | |
1093 | |
1094 for entry in os.walk(translationsDirectory): | |
1095 for fileName in entry[2]: | |
1096 fullName = os.path.join(entry[0], fileName) | |
1097 if fullName.endswith('.mo'): | |
1098 self.__e5project.appendFile(fullName) | |
1099 | |
1100 def compileSelectedCatalogs(self, filenames): | |
1101 """ | |
1102 Public method to update the message catalogs. | |
1103 | |
1104 @param filenames list of file names | |
1105 @type list of str | |
1106 """ | |
1107 title = self.tr("Compiling message catalogs") | |
1108 | |
1109 locales = {self.__getLocale(f) for f in filenames} | |
1110 | |
1111 if len(locales) == 0: | |
1112 E5MessageBox.warning( | |
1113 self.__ui, | |
1114 title, | |
1115 self.tr('No locales detected. Aborting...')) | |
1116 return | |
1117 | |
1118 if self.__ensurePybabelConfigured(): | |
1119 workdir = self.getApplication()[0] | |
1120 translationsDirectory = self.__e5project.getAbsoluteUniversalPath( | |
1121 self.getData("pybabel", "translationsDirectory")) | |
1122 | |
1123 argsList = [] | |
1124 for loc in locales: | |
1125 argsList.append([ | |
1126 "compile", | |
1127 "--domain={0}".format(self.getData("pybabel", "domain")), | |
1128 "--directory={0}".format( | |
1129 os.path.relpath(translationsDirectory, workdir)), | |
1130 "--use-fuzzy", | |
1131 "--statistics", | |
1132 "--locale={0}".format(loc), | |
1133 ]) | |
1134 | |
1135 dlg = PyBabelCommandDialog( | |
1136 self, title=title, | |
1137 msgSuccess=self.tr("\nMessage catalogs compiled successfully.") | |
1138 ) | |
1139 res = dlg.startBatchCommand(argsList, workdir) | |
1140 if res: | |
1141 dlg.exec() | |
1142 | |
1143 for entry in os.walk(translationsDirectory): | |
1144 for fileName in entry[2]: | |
1145 fullName = os.path.join(entry[0], fileName) | |
1146 if fullName.endswith('.mo'): | |
1147 self.__e5project.appendFile(fullName) | |
1148 | |
1149 def updateCatalogs(self, filenames, withObsolete=False): | |
1150 """ | |
1151 Public method to update the message catalogs. | |
1152 | |
1153 @param filenames list of filenames (not used) | |
1154 @type list of str | |
1155 @param withObsolete flag indicating to keep obsolete translations | |
1156 @type bool | |
1157 """ | |
1158 title = self.tr("Updating message catalogs") | |
1159 | |
1160 if self.__ensurePybabelConfigured(): | |
1161 workdir = self.getApplication()[0] | |
1162 translationsDirectory = self.__e5project.getAbsoluteUniversalPath( | |
1163 self.getData("pybabel", "translationsDirectory")) | |
1164 potFile = self.__e5project.getAbsoluteUniversalPath( | |
1165 self.getData("pybabel", "catalogFile")) | |
1166 | |
1167 args = [ | |
1168 "--domain={0}".format(self.getData("pybabel", "domain")), | |
1169 "--input-file={0}".format(os.path.relpath(potFile, workdir)), | |
1170 "--output-dir={0}".format( | |
1171 os.path.relpath(translationsDirectory, workdir)), | |
1172 ] | |
1173 if not withObsolete: | |
1174 args.append("--ignore-obsolete") | |
1175 | |
1176 dlg = PyBabelCommandDialog( | |
1177 self, title, | |
1178 msgSuccess=self.tr("\nMessage catalogs updated successfully.") | |
1179 ) | |
1180 res = dlg.startCommand("update", args, workdir) | |
1181 if res: | |
1182 dlg.exec() | |
1183 | |
1184 def updateCatalogsObsolete(self, filenames): | |
1185 """ | |
1186 Public method to update the message catalogs keeping obsolete | |
1187 translations. | |
1188 | |
1189 @param filenames list of filenames (not used) | |
1190 @type list of str | |
1191 """ | |
1192 self.updateCatalogs(filenames, withObsolete=True) | |
1193 | |
1194 def updateSelectedCatalogs(self, filenames, withObsolete=False): | |
1195 """ | |
1196 Public method to update the selected message catalogs. | |
1197 | |
1198 @param filenames list of filenames | |
1199 @type list of str | |
1200 @param withObsolete flag indicating to keep obsolete translations | |
1201 @type bool | |
1202 """ | |
1203 title = self.tr("Updating message catalogs") | |
1204 | |
1205 locales = {self.__getLocale(f) for f in filenames} | |
1206 | |
1207 if len(locales) == 0: | |
1208 E5MessageBox.warning( | |
1209 self.__ui, | |
1210 title, | |
1211 self.tr('No locales detected. Aborting...')) | |
1212 return | |
1213 | |
1214 if self.__ensurePybabelConfigured(): | |
1215 workdir = self.getApplication()[0] | |
1216 translationsDirectory = self.__e5project.getAbsoluteUniversalPath( | |
1217 self.getData("pybabel", "translationsDirectory")) | |
1218 potFile = self.__e5project.getAbsoluteUniversalPath( | |
1219 self.getData("pybabel", "catalogFile")) | |
1220 argsList = [] | |
1221 for loc in locales: | |
1222 args = [ | |
1223 "update", | |
1224 "--domain={0}".format(self.getData("pybabel", "domain")), | |
1225 "--input-file={0}".format( | |
1226 os.path.relpath(potFile, workdir)), | |
1227 "--output-dir={0}".format( | |
1228 os.path.relpath(translationsDirectory, workdir)), | |
1229 "--locale={0}".format(loc), | |
1230 ] | |
1231 if not withObsolete: | |
1232 args.append("--ignore-obsolete") | |
1233 argsList.append(args) | |
1234 | |
1235 dlg = PyBabelCommandDialog( | |
1236 self, title=title, | |
1237 msgSuccess=self.tr("\nMessage catalogs updated successfully.") | |
1238 ) | |
1239 res = dlg.startBatchCommand(argsList, workdir) | |
1240 if res: | |
1241 dlg.exec() | |
1242 | |
1243 def updateSelectedCatalogsObsolete(self, filenames): | |
1244 """ | |
1245 Public method to update the message catalogs keeping obsolete | |
1246 translations. | |
1247 | |
1248 @param filenames list of filenames (not used) | |
1249 @type list of str | |
1250 """ | |
1251 self.updateSelectedCatalogs(filenames, withObsolete=True) |