Wed, 18 Nov 2020 20:16:06 +0100
Started implementing pybabel translations support.
--- a/PluginFlask.e4p Tue Nov 17 19:49:24 2020 +0100 +++ b/PluginFlask.e4p Wed Nov 18 20:16:06 2020 +0100 @@ -21,6 +21,7 @@ <Source>ProjectFlask/FlaskBabelDetector.py</Source> <Source>ProjectFlask/FlaskCommandDialog.py</Source> <Source>ProjectFlask/Project.py</Source> + <Source>ProjectFlask/PyBabelConfigDialog.py</Source> <Source>ProjectFlask/RoutesDialog.py</Source> <Source>ProjectFlask/RunServerDialog.py</Source> <Source>ProjectFlask/ServerStartOptionsDialog.py</Source> @@ -30,6 +31,7 @@ <Forms> <Form>ProjectFlask/ConfigurationPage/FlaskPage.ui</Form> <Form>ProjectFlask/FlaskCommandDialog.ui</Form> + <Form>ProjectFlask/PyBabelConfigDialog.ui</Form> <Form>ProjectFlask/RoutesDialog.ui</Form> <Form>ProjectFlask/RunServerDialog.ui</Form> <Form>ProjectFlask/ServerStartOptionsDialog.ui</Form>
--- a/ProjectFlask/Project.py Tue Nov 17 19:49:24 2020 +0100 +++ b/ProjectFlask/Project.py Wed Nov 18 20:16:06 2020 +0100 @@ -12,7 +12,7 @@ from PyQt5.QtCore import ( pyqtSlot, QObject, QProcess, QProcessEnvironment, QTimer ) -from PyQt5.QtWidgets import QMenu +from PyQt5.QtWidgets import QMenu, QDialog from E5Gui import E5MessageBox from E5Gui.E5Action import E5Action @@ -23,10 +23,6 @@ import UI.PixmapCache import Utilities -from .RunServerDialog import RunServerDialog -from .RoutesDialog import RoutesDialog -from .FlaskCommandDialog import FlaskCommandDialog - class Project(QObject): """ @@ -180,6 +176,24 @@ self.actions.append(self.initDatabaseAct) ################################## + ## database action below ## + ################################## + + self.pybabelConfigAct = E5Action( + self.tr('Configure PyBabel'), + self.tr('Configure Py&Babel'), + 0, 0, + self, 'flask_config_pybabel') + self.pybabelConfigAct.setStatusTip(self.tr( + 'Shows a dialog to edit the configuration for pybabel')) + self.pybabelConfigAct.setWhatsThis(self.tr( + """<b>Configure PyBabel</b>""" + """<p>Shows a dialog to edit the configuration for pybabel.</p>""" + )) + self.pybabelConfigAct.triggered.connect(self.__configurePybabel) + self.actions.append(self.pybabelConfigAct) + + ################################## ## documentation action below ## ################################## @@ -237,6 +251,8 @@ menu.addAction(self.showRoutesAct) menu.addSection("flask init-db") menu.addAction(self.initDatabaseAct) + menu.addSection(self.tr("Translations")) + menu.addAction(self.pybabelConfigAct) menu.addSection(self.tr("Various")) menu.addAction(self.documentationAct) menu.addSeparator() @@ -581,9 +597,14 @@ self.__projectData[category] = data data = self.__projectData[category] - if key in data: + if not key: + # return complete category dictionary + return data + elif key in data: + # return individual entry return data[key] else: + # failure return None def setData(self, category, key, value): @@ -606,7 +627,12 @@ if data is not None: self.__projectData[category] = data - self.__projectData[category][key] = value + if not key: + # update the complete category + self.__projectData[category] = value + else: + # update individual entry + self.__projectData[category][key] = value self.__e5project.setData( "PROJECTTYPESPECIFICDATA", category, self.__projectData[category]) @@ -634,6 +660,8 @@ @param development flag indicating development mode @type bool """ + from .RunServerDialog import RunServerDialog + if self.__serverDialog is not None: self.__serverDialog.close() @@ -709,6 +737,8 @@ """ Private slot showing all URL dispatch routes. """ + from .RoutesDialog import RoutesDialog + if self.__routesDialog is not None: self.__routesDialog.close() @@ -722,6 +752,8 @@ """ Private slot showing the result of the database creation. """ + from .FlaskCommandDialog import FlaskCommandDialog + dlg = FlaskCommandDialog(self) if dlg.startCommand("init-db"): dlg.exec() @@ -752,6 +784,34 @@ return False + @pyqtSlot() + def __configurePybabel(self): + """ + Private slot to show a dialog to edit the pybabel configuration. + """ + # TODO: implement this + from .PyBabelConfigDialog import PyBabelConfigDialog + + config = self.getData("pybabel", "") + dlg = PyBabelConfigDialog(config) + if dlg.exec() == QDialog.Accepted: + config = dlg.getConfiguration() + self.setData("pybabel", "", config) + + if not os.path.exists(config["configFile"]): + self.__createBabelCfg(config["configFile"]) + + def __createBabelCfg(self, configFile): + """ + Private method to create a template pybabel configuration file. + """ + template = ( + "[python: {0}/**.py]\n" + "[jinja2: {0}/templates/**.html]\n" + "extensions=jinja2.ext.autoescape,jinja2.ext.with_\n" + ) + # TODO: determine app name and write file + def __projectLanguageAdded(self, code): # TODO: implement this with pybabel ... pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/PyBabelConfigDialog.py Wed Nov 18 20:16:06 2020 +0100 @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to edit the PyBabel configuration. +""" + +from PyQt5.QtCore import pyqtSlot, Qt +from PyQt5.QtWidgets import QDialog, QDialogButtonBox + +from E5Gui.E5PathPicker import E5PathPickerModes +from E5Gui.E5Application import e5App + +from .Ui_PyBabelConfigDialog import Ui_PyBabelConfigDialog + + +class PyBabelConfigDialog(QDialog, Ui_PyBabelConfigDialog): + """ + Class implementing a dialog to edit the PyBabel configuration. + """ + def __init__(self, configuration, parent=None): + """ + Constructor + + @param configuration current pybabel configuration + @type dict + @param parent reference to the parent widget + @type QWidget + """ + super(PyBabelConfigDialog, self).__init__(parent) + self.setupUi(self) + + e5project = e5App().getObject("Project") + + self.configFilePicker.setMode(E5PathPickerModes.OpenFileMode) + self.configFilePicker.setFilters(self.tr( + "Configuration Files (*.cfg);;" + "All Files (*)" + )) + self.configFilePicker.setDefaultDirectory(e5project.getProjectPath()) + + self.catalogFilePicker.setMode(E5PathPickerModes.OpenFileMode) + self.catalogFilePicker.setFilters(self.tr( + "Message Catalog Files (*.pot);;" + "All Files (*)" + )) + self.catalogFilePicker.setDefaultDirectory(e5project.getProjectPath()) + + self.configFilePicker.setFocus(Qt.OtherFocusReason) + + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) + + if "configFile" in configuration: + self.configFilePicker.setText(configuration["configFile"]) + if "catalogFile" in configuration: + self.catalogFilePicker.setText(configuration["catalogFile"]) + if "markersList" in configuration: + self.markersEdit.setText(" ".join(configuration["markersList"])) + + def getConfiguration(self): + """ + Public method to get the entered configuration data. + + @return pybabel configuration + @rtype dict + """ + configuration = { + "configFile": self.configFilePicker.text(), + "catalogFile": self.catalogFilePicker.text(), + } + if self.markersEdit.text(): + configuration["markersList"] = self.markersEdit.text().split() + + return configuration + + def __updateOK(self): + enable = ( + bool(self.configFilePicker.text()) and + bool(self.catalogFilePicker.text()) + ) + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) + + @pyqtSlot(str) + def on_configFilePicker_textChanged(self, txt): + """ + Private slot to handle a change of the configuration file name. + + @param txt configuration file name + @type str + """ + self.__updateOK() + + @pyqtSlot(str) + def on_catalogFilePicker_textChanged(self, txt): + """ + Private slot to handle a change of the catalog file name. + + @param txt configuration file name + @type str + """ + self.__updateOK()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProjectFlask/PyBabelConfigDialog.ui Wed Nov 18 20:16:06 2020 +0100 @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PyBabelConfigDialog</class> + <widget class="QDialog" name="PyBabelConfigDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>124</height> + </rect> + </property> + <property name="windowTitle"> + <string>PyBabel Configuration</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Configuration File:</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Message Catalog:</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Translation Markers:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="markersEdit"> + <property name="toolTip"> + <string>Enter the translation markers separated by space (_ is included by default)</string> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="E5PathPicker" name="configFilePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the name of the PyBabel configuration file</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="E5PathPicker" name="catalogFilePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the name of the message catalog file</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5PathPicker</class> + <extends>QWidget</extends> + <header>E5Gui/E5PathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>configFilePicker</tabstop> + <tabstop>catalogFilePicker</tabstop> + <tabstop>markersEdit</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>PyBabelConfigDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>PyBabelConfigDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>