Add code to localise graph templates
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 26 Oct 2015 15:49:12 +0000 (16:49 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 26 Oct 2015 15:49:12 +0000 (16:49 +0100)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/collecty/daemon.py
src/collecty/locales.py [new file with mode: 0644]
src/collecty/plugins/base.py

index 0b7e299..34a26d2 100644 (file)
@@ -79,6 +79,7 @@ collecty_PYTHON = \
        src/collecty/daemon.py \
        src/collecty/errors.py \
        src/collecty/i18n.py \
+       src/collecty/locales.py \
        src/collecty/logger.py
 
 collectydir = $(pythondir)/collecty
index eb64571..27c587f 100644 (file)
@@ -29,6 +29,7 @@ import threading
 import time
 
 from . import bus
+from . import locales
 from . import plugins
 
 from .constants import *
@@ -80,6 +81,8 @@ class Collecty(object):
                log.debug(_("Collecty successfully initialized with %s plugins") \
                        % len(self.plugins))
 
+               log.debug(_("Supported locales: %s") % ", ".join(locales.get_supported_locales()))
+
        def add_plugin(self, plugin_class):
                # Try initialising a new plugin. If that fails, we will log the
                # error and try to go on.
diff --git a/src/collecty/locales.py b/src/collecty/locales.py
new file mode 100644 (file)
index 0000000..199ab49
--- /dev/null
@@ -0,0 +1,124 @@
+#!/usr/bin/python3
+###############################################################################
+#                                                                             #
+# collecty - A system statistics collection daemon for IPFire                 #
+# Copyright (C) 2015 IPFire development team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+import gettext
+import os
+
+from .constants import *
+from .i18n import TEXTDOMAIN
+
+import logging
+log = logging.getLogger("collecty.locale")
+log.propagate = 1
+
+class Locale(object):
+       def __init__(self, lang):
+               self.lang = lang
+
+       def translate(self, message, plural_message=None, count=None):
+               if plural_message is not None:
+                       assert count is not None
+
+                       # Replace the message by the plural message if
+                       # we are using plural.
+                       if count > 1:
+                               message = plural_message
+
+               return message
+
+
+class GettextLocale(Locale):
+       def __init__(self, lang, translation):
+               Locale.__init__(self, lang)
+
+               self.translation = translation
+
+               # Bind gettext functions
+               self.gettext = self.translation.gettext
+               self.ngettext = self.translation.ngettext
+
+       def translate(self, message, plural_message=None, count=None):
+               if plural_message is not None:
+                       assert count is not None
+                       return self.ngettext(message, plural_message, count)
+
+               return self.gettext(message)
+
+
+def _find_all_locales(domain, directory):
+       locales = {
+               DEFAULT_LOCALE : Locale(DEFAULT_LOCALE),
+       }
+
+       for lang in os.listdir(directory):
+               if lang.startswith("."):
+                       continue
+
+               filename = os.path.join(directory, lang, "LC_MESSAGES",
+                       "%s.mo" % domain)
+
+               # Check if a translation file exists and go on if not
+               if not os.path.exists(filename):
+                       continue
+
+               try:
+                       translation = gettext.translation(domain,
+                               directory, languages=[lang])
+               except Exception as e:
+                       log.error("Cound not load translation for %s: %s" \
+                               % (lang, e))
+                       continue
+
+               locales[lang] = GettextLocale(lang, translation)
+
+       log.debug("Loaded translations: %s" % ", ".join(locales.keys()))
+
+       return locales
+
+_locales = _find_all_locales(TEXTDOMAIN, "/usr/share/locale")
+
+def get_supported_locales():
+       return list(_locales.keys())
+
+def get_closest(*langs):
+       for lang in langs:
+               if not lang:
+                       continue
+
+               lang = lang.replace("-", "_")
+               parts = lang.split("_")
+
+               if len(parts) > 2:
+                       continue
+
+               elif len(parts) == 2:
+                       parts[0] = parts[0].lower()
+                       parts[1] = parts[1].upper()
+                       lang = "_".join(parts)
+
+               for l in (lang, parts[0]):
+                       try:
+                               return _locales[l]
+                       except KeyError:
+                               pass
+
+def get(*langs):
+       return get_closest(*langs) or _locale.get(DEFAULT_LOCALE, None)
index ecf1af7..c9e815c 100644 (file)
@@ -29,6 +29,7 @@ import threading
 import time
 import unicodedata
 
+from .. import locales
 from ..constants import *
 from ..i18n import _
 
@@ -230,15 +231,17 @@ class Plugin(object, metaclass=PluginRegistration):
 
                        return object
 
-       def get_template(self, template_name, object_id):
+       def get_template(self, template_name, object_id, locale=None, timezone=None):
                for template in self.templates:
                        if not template.name == template_name:
                                continue
 
-                       return template(self, object_id)
+                       return template(self, object_id, locale=locale, timezone=timezone)
 
-       def generate_graph(self, template_name, object_id="default", **kwargs):
-               template = self.get_template(template_name, object_id=object_id)
+       def generate_graph(self, template_name, object_id="default",
+                       timezone=None, locale=None, **kwargs):
+               template = self.get_template(template_name, object_id=object_id,
+                       timezone=timezone, locale=locale)
                if not template:
                        raise RuntimeError("Could not find template %s" % template_name)
 
@@ -436,9 +439,13 @@ class GraphTemplate(object):
        height = GRAPH_DEFAULT_HEIGHT
        width  = GRAPH_DEFAULT_WIDTH
 
-       def __init__(self, plugin, object_id):
+       def __init__(self, plugin, object_id, locale=None, timezone=None):
                self.plugin = plugin
 
+               # Save localisation parameters
+               self.locale = locales.get(locale)
+               self.timezone = timezone
+
                # Get all required RRD objects
                self.object_id = object_id
 
@@ -521,7 +528,7 @@ class GraphTemplate(object):
 
                return files
 
-       def generate_graph(self, interval=None, timezone=None, locale=None, **kwargs):
+       def generate_graph(self, interval=None, **kwargs):
                args = self._make_command_line(interval, **kwargs)
 
                self.log.info(_("Generating graph %s") % self)
@@ -540,7 +547,7 @@ class GraphTemplate(object):
                # Convert arguments to string
                args = [str(e) for e in args]
 
-               with Environment(timezone, locale):
+               with Environment(self.timezone, self.locale.lang):
                        graph = rrdtool.graphv("-", *args)
 
                return graph.get("image")