Commits

Diego Búrigo Zacarão committed 6d29889

Added Publican like docs support

- This TransManager allows to handle Publican and PHP
like docs.
- Disclaimer: It's NOT an ideal solution for big projects yet,
but it's the first step. :)

  • Participants
  • Parent commits 6d830ef

Comments (0)

Files changed (4)

transifex/projects/handlers/types/publican.py

+from projects.handlers.types import pot
+from translations.lib.types.publican import PublicanManager
+from txcommon.log import logger
+
+class PublicanHandler(pot.POTHandler):
+    """
+    A POTHandler abstraction for Publican projects.
+
+    https://fedorahosted.org/publican
+
+    Use this higher-level object to interact with a component's statistics instead of meddling with the lower-level POTManager. 
+
+    Each Component object gets one of these as ``component.trans``.
+    """
+    def __init__(self, component):
+        self.component = component
+        # TODO: Make Unit init the browser on its own 
+        component.unit._init_browser()
+        browser = component.unit.browser
+        if hasattr(browser, 'filepath'):
+            filepath = browser.filepath
+        else:
+            filepath = None
+        logger.debug('File path: %s' % filepath)
+        self.tm = PublicanManager(component.get_files(), browser.path, 
+            component.source_lang, component.file_filter, filepath)
+
+    def set_stats(self):
+        """Calculate stats for all translations of the component."""
+
+        logger.debug("Setting stats for %s" % self.component)
+
+        # Copying the source file to the static dir
+        try:
+            logger.debug("Copying source files of %s to static dir" % self.component)
+            potfiles = self.tm.get_source_files()
+            for potfile in potfiles:
+                self.tm.copy_file_to_static_dir(potfile)
+        except (AttributeError, IOError):
+            logger.debug("Error copying source files. There is no source file (POT)")
+            pass
+
+        logger.debug("Calc stats for the source files of %s" % self.component)
+        # Set the source file (pot) to the database
+        self.tm.set_source_stats(self.component, False)
+
+        logger.debug("Calc stats for the translation files of %s" % self.component)
+        for lang in self.tm.get_langs():
+            self.set_stats_for_lang(lang, False)
+
+        self.clear_old_stats()

transifex/projects/views.py

 from txcommon.log import logger
 from actionlog.models import action_logging
 from translations.lib.types.pot import FileFilterError
+from translations.lib.types.publican import PotDirError
 from translations.models import (POFile, POFileLock)
 from languages.models import Language
 from txcommon.decorators import perm_required_with_403, one_perm_required_or_403
         request.user.message_set.create(message = _(
             "The file filter of this intltool POT-based component does not "
             " seem to allow the POTFILES.in file. Please fix it."))
+
+    except PotDirError:
+        logger.debug("There is no 'pot' directory in the set of files. %s does "
+                     "not seem to be a Publian like project."
+                     % component.full_name)
+        request.user.message_set.create(message = _("There is no 'pot' "
+            "directory named in the set of files of this Publian like "
+            "component. Maybe its file filter is not allowing access to it."))
+
     return HttpResponseRedirect(reverse('projects.views.component_detail', 
                                 args=(project_slug, component_slug,)))
 

transifex/settings/70-translation.conf

 # Our Translation Handler choices.
 TRANS_CHOICES = {'POT': 'POT files',
-                 'INTLTOOL': 'POT files using intltool',}
+                 'INTLTOOL': 'POT files using intltool',
+                 'PUBLICAN': 'Publican like docs',}
+
 
 # The classes which implement the TransHandler support. The full "path"
 # to the class is the concatenation of the BASE and the NAME of the class.
 TRANS_CLASS_BASE = 'projects.handlers.types'
 TRANS_CLASS_NAMES = {'POT': 'pot.POTHandler',
-                     'INTLTOOL': 'intltool.IntltoolHandler',}
+                     'INTLTOOL': 'intltool.IntltoolHandler',
+                     'PUBLICAN': 'publican.PublicanHandler',}
 
 #####################
 # msgmerge settings

transifex/translations/lib/types/publican.py

+import os, codecs
+from django.conf import settings
+
+from translations.lib.types.pot import POTManager
+
+class PotDirError(StandardError):
+    pass
+
+class PublicanManager(POTManager):
+    """A browser class for PO files on Publican like structure."""
+
+    def __init__(self, file_set, path, source_lang, file_filter,
+        filepath=None):
+        self.file_set = file_set
+        if filepath is None:
+            filepath = path
+        self.path = filepath
+        self.source_lang = source_lang
+        self.file_filter = file_filter
+        self.msgmerge_path = os.path.join(settings.MSGMERGE_DIR, 
+                                     os.path.basename(path))
+
+
+    def pot_dir_position(self):
+        """
+        Return the index position of the 'pot' dir in the file_set.
+
+        Example: pot/manual/file.pot -> ['pot', 'manual', 'file.pot']
+                 It retuns 0 as the index position.
+
+        Have a 'pot' dir name in the file_set is mandatory.
+        """
+
+        # Get the first pot file that it can find
+        pot_file = None
+        for f in self.file_set:
+            f = '/%s' % f
+            if '/pot/' in f and f.endswith('.pot'):
+                pot_file = f
+                break
+        try:
+            dirs = pot_file.split('/')
+            index=0
+            # Find the index of 'pot' dir name in that pot file path
+            for d in dirs:
+                if d == 'pot':
+                    return index
+                index = index+1
+        except AttributeError:
+            raise PotDirError("There is no 'pot' directory named in the set "
+                              "of files.")
+
+
+    def get_langs_from_makefile(self):
+        """ 
+        Return the languages available in the OTHER_LANGS setting of the 
+        Makefile. Case it does not exist return an empty list.
+
+        Makefile setting example:
+
+            OTHER_LANGS = as-IN bn-IN da de-DE el es-ES
+        """
+        for filename in self.file_set:
+            if 'Makefile' in filename:
+                try:
+                    makefile = codecs.open(os.path.join(self.path, filename), 'r')
+                    for l in makefile.readlines():
+                        l = l.strip()
+                        if l and not l.startswith('#'):
+                            if 'OTHER_LANGS' in l:
+                                return l.split('=')[1].split()
+                except IOError, e:
+                    logging.error('The Makefile file could not be opened: %s' % e)
+        return []
+
+
+    def guess_language(self, filepath, pot_dir_index=None):
+        """ 
+        Guess a language code from a filepath by finding the 'pot' dir position
+
+        The method for looking for the language code consist on finding a 
+        'pot' dir in the file_set and return the dir name of the same position 
+        from filepath, using it as the language code name:
+
+        Example: pot/manual/file.pot -> ['pot', 'manual', 'file.pot']
+                 pt-BR/manual/file.po  -> ['pt-BR', 'manual', 'file.pot']
+
+        Splitting the path the 'pot' dir can be found in the position/index
+        0 of the list of dir names. In this case for the filepath passed 
+        by parameter, it will be returned the dir name positioned in same
+        index (pt-BR).
+
+        Another example:
+                 /foo/pot/file.pot (index 1)
+                 /foo/bar/file.po -> bar
+        """
+        if not pot_dir_index:
+            pot_dir_index = self.pot_dir_position()
+        filepath = '/%s' % filepath
+        return os.path.basename(filepath.split('/')[pot_dir_index])
+
+
+    def get_langs(self):
+        """
+        Return either the langs present in the OTHER_LANGS setting of the 
+        Makefile or all langs that have a po file for a object.
+        """
+        langs = self.get_langs_from_makefile()
+        if langs:
+            return langs
+        else:
+            pot_dir_index = self.pot_dir_position()
+            for filepath in self.get_po_files():
+                lang_code = self.guess_language(filepath, pot_dir_index)
+                if lang_code not in langs:
+                    langs.append(lang_code)
+            langs.sort()
+        return langs