Started implementing pybabel translations support.

Wed, 18 Nov 2020 20:16:06 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 18 Nov 2020 20:16:06 +0100
changeset 13
ed33cdfca13d
parent 12
68ee221cd0cb
child 14
d2da14b2a233

Started implementing pybabel translations support.

PluginFlask.e4p file | annotate | diff | comparison | revisions
ProjectFlask/Project.py file | annotate | diff | comparison | revisions
ProjectFlask/PyBabelConfigDialog.py file | annotate | diff | comparison | revisions
ProjectFlask/PyBabelConfigDialog.ui file | annotate | diff | comparison | revisions
--- 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>

eric ide

mercurial