class CSVConverter:
    def __init__(self):
        self.log = Logger()
    
    def read_data(self, csv_file):
        data = []
        try:
            reader = csv.reader(open(csv_file, 'rb'))
            header = reader.next()
            size = len(header)
            for line in reader:
                items = {}
                entry_size = len(line)                
                for x in range(size):  
                    if x < entry_size:  
                        item = {header[x]: line[x]}
                    else:
                        item = {header[x]: ""}
                    items.update(item)
            
                data.append(items)
        except IOError:
            self.log.error("Can not find csv file: %s"%csv_file)
        
        return data

    def convert_to_json(self, filepath, locale_map, comments_header):
        data = self.read_data(filepath)
        srclocales = []
        srclocales.append('en-US')
        entries = []
        targetlocales = []
        for item in data:
            comments = []
            terms = []

            for header in comments_header:
                if item.has_key(header):                
                    comments.append(item.pop(header))
            
            for key in item.keys():
                if key == 'en':
                    term = {'locale':'en-US', 'content':item[key], 'comments':comments}
                else:
                    if key in locale_map:
                        locale = locale_map[key]
                    else:
                        locale = key
                    term = {'locale':locale, 'content':item[key], 'comments':[]}
                    if key not in targetlocales:
                        targetlocales.append(key)
                terms.append(term)

            entry = {'srcLang': 'en-US', 'glossaryTerms': terms, 'sourcereference': ''}
            entries.append(entry)

        glossary = {'sourceLocales':srclocales, 'glossaryEntries':entries, 'targetLocales':targetlocales}

        return json.dumps(glossary)
Пример #2
0
class ZanataCommand:
    def __init__(self):
        self.log = Logger()

    ##############################################
    ##
    ## Commands for interaction with zanata server 
    ##
    ############################################## 
    def check_project(self, zanataclient, command_options, project_config):
        project_id = ''
        iteration_id = ''
        if command_options.has_key('project_id'):
            project_id =  command_options['project_id'][0]['value'] 
        else:
            if project_config.has_key('project_id'):
                project_id = project_config['project_id']
        
        if command_options.has_key('project_version'):
            iteration_id = command_options['project_version'][0]['value'] 
        else:
            if project_config.has_key('project_version'):
                iteration_id = project_config['project_version']
        
        if not project_id:
            self.log.error("Please specify a valid project id in zanata.xml or with '--project-id' option")
            sys.exit(1)
        
        if not iteration_id:
            self.log.error("Please specify a valid version id in zanata.xml or with '--project-version' option")
            sys.exit(1)
        
        self.log.info("Project: %s"%project_id)
        self.log.info("Version: %s"%iteration_id)

        try:
            zanataclient.projects.get(project_id)
        except NoSuchProjectException, e:
            self.log.error(e.msg)
            sys.exit(1)
   
        try:
            zanataclient.projects.iterations.get(project_id, iteration_id)
            return project_id, iteration_id
        except NoSuchProjectException, e:
            self.log.error(e.msg)
            sys.exit(1)
Пример #3
0
    if args:
        try:
            full_path = search_file(tmlfolder, args[0])
            filelist.append(full_path)
        except NoSuchFileException, e:
            log.error(e.msg)
            sys.exit(1)
    else:
        if not command_options.has_key('srcfile'):
            #get all the pot files from the template folder
            publicanutil = PublicanUtility()
            filelist = publicanutil.get_file_list(tmlfolder, ".pot")

            if not filelist:
                log.error("The template folder is empty")
                sys.exit(1)

        if command_options.has_key('force'):
            force = True
        zanatacmd.del_server_content(zanata, tmlfolder, project_id, iteration_id, filelist, force, "gettext")

    if importpo:
        zanatacmd.push_command(zanata, filelist, tmlfolder, project_id, iteration_id, copytrans, plural_support, import_param)
    else:
        zanatacmd.push_command(zanata, filelist, tmlfolder, project_id, iteration_id, copytrans, plural_support)
    
def publican_pull(command_options, args):
    """
    Usage: zanata publican pull [OPTIONS] {documents} {lang}
Пример #4
0
            sys.exit(1)

        if args:
            try:
                full_path = self.search_file(tmlfolder, args[0])
                filelist.append(full_path)
            except NoSuchFileException, e:
                log.error(e.msg)
                sys.exit(1)
        else:
            #get all the pot files from the template folder
            publicanutil = PublicanUtility()
            filelist = publicanutil.get_file_list(tmlfolder, ".pot")

            if not filelist:
                log.error("The template folder is empty")
                sys.exit(1)
            deletefiles = True

        if command_options.has_key('force'):
            force = True

        if project_type == 'podir':
            log.info("POT directory (originals):%s" % tmlfolder)
            folder = None
        elif project_type == 'gettext':
            log.info("PO directory (originals):%s" % tmlfolder)
            folder = tmlfolder

        if pushtrans is None:
            pushtrans = self.get_pushtrans(command_options)
Пример #5
0
class PublicanUtility:
    def __init__(self):
        self.log = Logger()

    def create_txtflow(self, pofile):
        """
        Convert the content of the pot file to a list of text flow.
        @return: the dictionary object of textflow
        """
        textflows = []
        for entry in pofile:
            context = None
            reflist = []
            content = ""

            if entry.msgctxt is not None:
                hashbase = entry.msgctxt + u"\u0000" + entry.msgid
                context = entry.msgctxt
            else:
                hashbase = entry.msgid
            # pylint: disable=E1101
            m = hashlib.md5()
            m.update(hashbase.encode('utf-8'))
            textflowId = m.hexdigest()
            """
            "extensions":[{"object-type":"pot-entry-header","context":"context",
            "references":["fff"],"extractedComment":"extractedComment",
            "flags":["java-format"]}]
            """
            extracted_comment = entry.comment
            references = entry.occurrences
            for ref in references:
                node = ref[0] + ":" + ref[1]
                reflist.append(node)
            flags = entry.flags

            if entry.msgid_plural:
                content = [entry.msgid, entry.msgid_plural]
            else:
                content = entry.msgid

            if context is not None:
                extensions = [{'object-type': 'comment', 'value': extracted_comment, 'space': 'preserve'},
                              {"object-type": "pot-entry-header", "context": context, "references": reflist,
                               "extractedComment": '', "flags": flags}]
            else:
                extensions = [{'object-type': 'comment', 'value': extracted_comment, 'space': 'preserve'},
                              {"object-type": "pot-entry-header", "references": reflist, "extractedComment": '',
                               "flags": flags}]

            if entry.msgid_plural:
                textflow = {'id': textflowId, 'lang': 'en-US', 'contents': content, 'plural': 'true', 'extensions': extensions}
            else:
                textflow = {'id': textflowId, 'lang': 'en-US', 'content': content, 'plural': 'false', 'extensions': extensions}

            textflows.append(textflow)
        return textflows

    def check_empty(self, contents):
        for string in contents:
            if string != u'':
                return False
        return True

    def check_nonempty(self, contents):
        for string in contents:
            if string == u'':
                return False
        return True

    def get_contentstate(self, entry):
        """
        Determine the ContentState for a PO entry, based on contents and fuzzy flag
        @return: the state
        """
        fuzzy = False
        contents = []

        if "fuzzy" in entry.flags:
            fuzzy = True

        if entry.msgid_plural:
            keys = entry.msgstr_plural.keys()
            keys.sort()
            for key in keys:
                contents.append(entry.msgstr_plural[key])
        else:
            contents.append(entry.msgstr)

        if self.check_empty(contents):
            fuzzy = False

        if fuzzy:
            return "NeedReview"

        if self.check_nonempty(contents):
            return "Approved"
        else:
            return "New"

    def create_txtflowtarget(self, pofile):
        """
        Convert the content of the po file to a list of textflowtarget.
        @return: the dictionary object of textflow
        """
        obs_list = pofile.obsolete_entries()
        textflowtargets = []
        content = ""

        for entry in pofile:
            if entry in obs_list:
                continue

            if entry.msgctxt is not None:
                hashbase = entry.msgctxt + u"\u0000" + entry.msgid
            else:
                hashbase = entry.msgid
            # pylint: disable=E1101
            m = hashlib.md5()
            m.update(hashbase.encode('utf-8'))
            textflowId = m.hexdigest()
            translator_comment = entry.tcomment

            state = self.get_contentstate(entry)

            # create extensions
            extensions = [{"object-type": "comment", "value": translator_comment, "space": "preserve"}]

            if entry.msgid_plural:
                content = []
                keys = entry.msgstr_plural.keys()
                keys.sort()
                for key in keys:
                    content.append(entry.msgstr_plural[key])
                textflowtarget = {'resId': textflowId, 'state': state, 'contents': content, 'extensions': extensions}
            else:
                content = entry.msgstr
                textflowtarget = {'resId': textflowId, 'state': state, 'content': content, 'extensions': extensions}

            textflowtargets.append(textflowtarget)

        return textflowtargets

    def validate_content_type(self, content_type, object_type):
        PATTERN = r'.+? charset=([\w_\-:\.]+)'
        rxt = re.compile(unicode(PATTERN))

        match = rxt.search(content_type)
        if match:
            enc = match.group(1).strip()
            if enc not in ["UTF-8", "utf-8", "utf8", "ascii", "UTF8", "ASCII"]:
                if enc == 'CHARSET':
                    if object_type == 'po-target-header':
                        self.log.error("Invalid encoding CHARSET; please correct the Content-Type charset (UTF-8 recommended)")
                        sys.exit(1)
                else:
                    self.log.error("Unsupported encoding; please change the Content-Type charset (UTF-8 recommended)")
                    sys.exit(1)

    def create_extensions(self, pofile, object_type):
        """
        "extensions":[{"object-type":"po-header","comment":"comment_value", "entries":[{"key":"h1","value":"v1"}]}]
        "extensions":[{"object-type":"po-target-header", "comment":"comment_value", "entries":[{"key":"ht","value":"vt1"}]}]
        """
        entries = []
        metadatas = pofile.ordered_metadata()
        for item in metadatas:
            entry = {"key": item[0], "value": item[1]}
            entries.append(entry)

        if pofile.metadata.has_key('Content-Type'):
            self.validate_content_type(pofile.metadata['Content-Type'], object_type)

        extensions = [{"object-type": object_type, "comment": pofile.header, "entries": entries}]
        return extensions

    def create_pofile(self, path):
        """
        Convert the po file to a pofile object in polib.
        @return: pofile object
        """
        try:
            po = polib.pofile(path)
        except Exception, e:
            self.log.error(str(e))
            sys.exit(1)

        return po
Пример #6
0
class OptionsUtil:
    def __init__(self, options):
        self.command_options = options
        self.project_config = {}
        self.log = Logger()
        self.config = ZanataConfig()

    def apply_configfiles(self):
        url = self.apply_project_config()
        username, apikey = self.apply_user_config(url)

        # The value in commandline options will overwrite the value in user-config file
        if self.command_options.has_key("user_name"):
            username = self.command_options["user_name"][0]["value"]

        if self.command_options.has_key("key"):
            apikey = self.command_options["key"][0]["value"]

        self.log.info("zanata server: %s" % url)

        return url, username, apikey

    def apply_project_config(self):
        # Read the project configuration file using --project-config option
        config_file = [os.path.join(os.getcwd(), filename) for filename in ["zanata.xml", "flies.xml"]]

        if self.command_options.has_key("project_config"):
            config_file.append(self.command_options["project_config"][0]["value"])

        for path in config_file:
            if os.path.exists(path):
                self.log.info("Loading zanata project config from: %s" % path)
            self.project_config = self.config.read_project_config(path)
            break

        if not self.project_config:
            self.log.info("Can not find zanata.xml, please specify the path of zanata.xml")

        # process the url of server
        if self.project_config.has_key("project_url"):
            url = self.project_config["project_url"]

        # The value in options will override the value in project-config file
        if self.command_options.has_key("url"):
            self.log.info("Overriding url of server with command line option")
            url = self.command_options["url"][0]["value"]

        if not url or url.isspace():
            self.log.error("Please specify valid server url in zanata.xml or with '--url' option")
            sys.exit(1)

        url = self.trim_url(url)

        return url

    def trim_url(self, url):
        if " " in url or "\n" in url:
            self.log.info("Warning, the url which contains '\\n' or whitespace is not valid, please check zanata.xml")
        url = url.strip()

        if url[-1] == "/":
            url = url[:-1]

        return url

    def get_localemap(self):
        if self.project_config and self.project_config.has_key("locale_map"):
            locale_map = self.project_config["locale_map"]

        return locale_map

    def apply_user_config(self, url):
        user_name = ""
        apikey = ""
        # Try to read user-config file
        user_config = [
            os.path.join(os.path.expanduser("~") + "/.config", filename) for filename in ["zanata.ini", "flies.ini"]
        ]

        if self.command_options.has_key("user_config"):
            user_config.append(self.command_options["user_config"][0]["value"])

        for path in user_config:
            if os.path.exists(path):
                self.log.info("Loading zanata user config from: %s" % path)

            # Read the user-config file
            self.config.set_userconfig(path)

            try:
                server = self.config.get_server(url)
                if server:
                    user_name = self.config.get_config_value("username", "servers", server)
                    apikey = self.config.get_config_value("key", "servers", server)
            except Exception, e:
                self.log.info("Processing user-config file:%s" % str(e))
                break

            break

        if not (user_name, apikey):
            self.log.info("Can not find user-config file in home folder, current path or path in 'user-config' option")

        return (user_name, apikey)
class CSVConverter:
    def __init__(self):
        self.log = Logger()

    def read_data(self, csv_file):
        data = []
        try:
            reader = csv.reader(open(csv_file, 'rb'))
            header = reader.next()
            size = len(header)
            for line in reader:
                items = {}
                entry_size = len(line)
                for x in range(size):
                    if x < entry_size:
                        item = {header[x]: line[x]}
                    else:
                        item = {header[x]: ""}
                    items.update(item)

            data.append(items)
        except IOError:
            self.log.error("Can not find csv file: %s" % csv_file)

        return data

    def read_csv_file(self, csv_file):
        data = []
        try:
            reader = csv.reader(open(csv_file, 'rb'))
            data = [line for line in reader]
        except IOError:
            self.log.error("Can not find csv file: %s" % csv_file)
        return data

    def convert_to_json(self, filepath, locale_map, comments_header):
        data = self.read_csv_file(expanduser(filepath))
        srclocales = []
        # srclocales.append('en-US')
        entries = []
        targetlocales = []
        csv_locales = []
        comments = []
        for index, item in enumerate(data):
            terms = []
            if index == 0:
                # Assuming last two names refers to column names,for example consider following csv file
                # en-US,es,ko,ru,pos,description
                # Hello,Hola,test,111,noun,Greeting
                # first line always contains locales and last two specifies column names
                comments = [comm for comm in item[-2:]]
                csv_locales = [lc for lc in item[:-2]]
                continue
            else:
                glossary_len = len(item)
                csv_locales_len = len(csv_locales)
                comments_len = len(comments)
                if glossary_len != csv_locales_len + comments_len:
                    print "Wrong entries in csv file, please check your csv file"
                    print "Entry in csv file", item
                    sys.exit(1)
                glossary_comments = item[-2:]
                for j in range(csv_locales_len):
                    if j == 0:
                        term = {'locale': csv_locales[j], 'content': item[j], 'comments': glossary_comments}
                    else:
                        term = {'locale': csv_locales[j], 'content': item[j], 'comments': []}
                    terms.append(term)
            entry = {'srcLang': 'en-US', 'glossaryTerms': terms}
            entries.append(entry)

        glossary = {'sourceLocales': srclocales, 'glossaryEntries': entries, 'targetLocales': targetlocales}
        # glossary = {'source-locales':srclocales, 'glossary-entries':entries, 'target-locales':targetlocales}
        return json.dumps(glossary)
Пример #8
0
class ZanataCommand:
    def __init__(self, url, http_headers):
        self.log = Logger()
        self.zanata_resource = ZanataResource(url, http_headers)

    def disable_ssl_cert_validation(self):
        self.zanata_resource.disable_ssl_cert_validation()

    ##############################################
    #
    # Commands for interaction with zanata server
    #
    ##############################################
    def get_file_list(self, projectid, iterationid):
        return self.zanata_resource.documents.get_file_list(projectid, iterationid)

    def get_server_version(self, url):
        try:
            content = self.zanata_resource.version.get_server_version()
            if content:
                server_version = content['versionNo']
                return server_version
        except UnAvaliableResourceException:
            self.log.error("Can not retrieve the server version, server may not support the version service")
        except UnavailableServiceError:
            self.log.error("Service Temporarily Unavailable, stop processing!")
            sys.exit(1)

    """
    def check_project(self, command_options, project_config):
        project_id = ''
        iteration_id = ''
        if command_options.has_key('project_id'):
            project_id =  command_options['project_id'][0]['value']
        else:
            if project_config.has_key('project_id'):
                project_id = project_config['project_id']

        if command_options.has_key('project_version'):
            iteration_id = command_options['project_version'][0]['value']
        else:
            if project_config.has_key('project_version'):
                iteration_id = project_config['project_version']

        if not project_id:
            self.log.error("Please specify a valid project id in zanata.xml or with '--project-id' option")
            sys.exit(1)

        if not iteration_id:
            self.log.error("Please specify a valid version id in zanata.xml or with '--project-version' option")
            sys.exit(1)

        self.log.info("Project: %s"%project_id)
        self.log.info("Version: %s"%iteration_id)
        self.verify_project(project_id, iteration_id)
    """

    def verify_project(self, project_id, version_id):
        try:
            self.zanata_resource.projects.get(project_id)
        except NoSuchProjectException, e:
            self.log.error(str(e))
            sys.exit(1)

        try:
            self.zanata_resource.projects.iterations.get(project_id, version_id)
        except NoSuchProjectException, e:
            self.log.error(str(e))
            sys.exit(1)
Пример #9
0
            tmlfolder = self.process_srcdir_withsub(self.command_options)

        if self.args:
            try:
                full_path = self.search_file(tmlfolder, self.args[0])
                filelist.append(full_path)
            except NoSuchFileException, e:
                log.error(e.msg)
                sys.exit(1)
        else:
            #get all the pot files from the template folder
            publicanutil = PublicanUtility()
            filelist = publicanutil.get_file_list(tmlfolder, ".pot")

            if not filelist:
                log.error("The template folder is empty")
                sys.exit(1)
            deletefiles = True
        return project_type, deletefiles, tmlfolder, filelist

    def read_project_config(self, command_options):
        project_config = {}
        config = ZanataConfig()
        #Read the project configuration file using --project-config option
        config_file = [os.path.join(os.getcwd(), filename) for filename\
                        in ['zanata.xml', 'flies.xml']]

        if command_options.has_key('project_config'):
            config_file.append(command_options['project_config'][0]['value'])

        for path in config_file:
Пример #10
0
class OptionsUtil:
    def __init__(self, options):
        self.command_options = options
        self.project_config = {}
        self.log = Logger()
        self.config = ZanataConfig()

    def apply_configfiles(self):
        url = self.apply_project_config()
        username, apikey = self.apply_user_config(url)

        # The value in commandline options will overwrite the value in user-config file
        if self.command_options.has_key('user_name'):
            username = self.command_options['user_name'][0]['value']

        if self.command_options.has_key('key'):
            apikey = self.command_options['key'][0]['value']

        self.log.info("zanata server: %s" % url)

        return url, username, apikey

    def apply_project_config(self):
        url = ""
        # Read the project configuration file using --project-config option
        config_file = [os.path.join(os.getcwd(), filename) for filename
                       in ['zanata.xml', 'flies.xml']]

        if self.command_options.has_key('project_config'):
            config_file.append(self.command_options['project_config'][0]['value'])

        for path in config_file:

            if os.path.exists(path):
                self.log.info("Loading zanata project config from: %s" % path)
                self.project_config = self.config.read_project_config(path)
                break

        if not self.project_config:
            self.log.info("Can not find zanata.xml, please specify the path of zanata.xml")

        # process the url of server
        if self.project_config.has_key('project_url'):
            url = self.project_config['project_url']

        # The value in options will override the value in project-config file
        if self.command_options.has_key('url'):
            self.log.info("Overriding url of server with command line option")
            url = self.command_options['url'][0]['value']

        if not url or url.isspace():
            self.log.error("Please specify valid server url in zanata.xml or with '--url' option")
            sys.exit(1)

        url = self.trim_url(url)

        return url

    def trim_url(self, url):
        if ' ' in url or '\n' in url:
            self.log.info("Warning, the url which contains '\\n' or whitespace is not valid, please check zanata.xml")
        url = url.strip()

        if url[-1] == "/":
            url = url[:-1]

        return url

    def get_localemap(self):
        if self.project_config and self.project_config.has_key('locale_map'):
            locale_map = self.project_config['locale_map']

        return locale_map

    def apply_user_config(self, url):
        user_name = ""
        apikey = ""
        # Try to read user-config file
        user_config = [os.path.join(os.path.expanduser("~") + '/.config', filename) for filename in ['zanata.ini', 'flies.ini']]

        if self.command_options.has_key('user_config'):
            user_config.append(self.command_options['user_config'][0]['value'])

        for path in user_config:
            if os.path.exists(path):
                self.log.info("Loading zanata user config from: %s" % path)

            # Read the user-config file
            self.config.set_userconfig(path)

            try:
                server = self.config.get_server(url)
                if server:
                    user_name = self.config.get_config_value("username", "servers", server)
                    apikey = self.config.get_config_value("key", "servers", server)
            except Exception, e:
                self.log.info("Processing user-config file:%s" % str(e))
                break

            break

        if not (user_name, apikey):
            self.log.info("Can not find user-config file in home folder, current path or path in 'user-config' option")

        return (user_name, apikey)
Пример #11
0
class PublicanUtility:
    def __init__(self):
        self.log = Logger()

    def create_txtflow(self, pofile):
        """
        Convert the content of the pot file to a list of text flow.
        @return: the dictionary object of textflow
        """
        textflows = []
        for entry in pofile:
            context = None
            reflist = []
            content = ""

            if entry.msgctxt is not None:
                hashbase = entry.msgctxt + u"\u0000" + entry.msgid
                context = entry.msgctxt
            else:
                hashbase = entry.msgid
            # pylint: disable=E1101
            m = hashlib.md5()
            m.update(hashbase.encode('utf-8'))
            textflowId = m.hexdigest()
            """
            "extensions":[{"object-type":"pot-entry-header","context":"context",
            "references":["fff"],"extractedComment":"extractedComment",
            "flags":["java-format"]}]
            """
            extracted_comment = entry.comment
            references = entry.occurrences
            for ref in references:
                node = ref[0] + ":" + ref[1]
                reflist.append(node)
            flags = entry.flags

            if entry.msgid_plural:
                content = [entry.msgid, entry.msgid_plural]
            else:
                content = entry.msgid

            if context is not None:
                extensions = [{
                    'object-type': 'comment',
                    'value': extracted_comment,
                    'space': 'preserve'
                }, {
                    "object-type": "pot-entry-header",
                    "context": context,
                    "references": reflist,
                    "extractedComment": '',
                    "flags": flags
                }]
            else:
                extensions = [{
                    'object-type': 'comment',
                    'value': extracted_comment,
                    'space': 'preserve'
                }, {
                    "object-type": "pot-entry-header",
                    "references": reflist,
                    "extractedComment": '',
                    "flags": flags
                }]

            if entry.msgid_plural:
                textflow = {
                    'id': textflowId,
                    'lang': 'en-US',
                    'contents': content,
                    'plural': 'true',
                    'extensions': extensions
                }
            else:
                textflow = {
                    'id': textflowId,
                    'lang': 'en-US',
                    'content': content,
                    'plural': 'false',
                    'extensions': extensions
                }

            textflows.append(textflow)
        return textflows

    def check_empty(self, contents):
        for string in contents:
            if string != u'':
                return False
        return True

    def check_nonempty(self, contents):
        for string in contents:
            if string == u'':
                return False
        return True

    def get_contentstate(self, entry):
        """
        Determine the ContentState for a PO entry, based on contents and fuzzy flag
        @return: the state
        """
        fuzzy = False
        contents = []

        if "fuzzy" in entry.flags:
            fuzzy = True

        if entry.msgid_plural:
            keys = entry.msgstr_plural.keys()
            keys.sort()
            for key in keys:
                contents.append(entry.msgstr_plural[key])
        else:
            contents.append(entry.msgstr)

        if self.check_empty(contents):
            fuzzy = False

        if fuzzy:
            return "NeedReview"

        if self.check_nonempty(contents):
            return "Approved"
        else:
            return "New"

    def create_txtflowtarget(self, pofile):
        """
        Convert the content of the po file to a list of textflowtarget.
        @return: the dictionary object of textflow
        """
        obs_list = pofile.obsolete_entries()
        textflowtargets = []
        content = ""

        for entry in pofile:
            if entry in obs_list:
                continue

            if entry.msgctxt is not None:
                hashbase = entry.msgctxt + u"\u0000" + entry.msgid
            else:
                hashbase = entry.msgid
            # pylint: disable=E1101
            m = hashlib.md5()
            m.update(hashbase.encode('utf-8'))
            textflowId = m.hexdigest()
            translator_comment = entry.tcomment

            state = self.get_contentstate(entry)

            #create extensions
            extensions = [{
                "object-type": "comment",
                "value": translator_comment,
                "space": "preserve"
            }]

            if entry.msgid_plural:
                content = []
                keys = entry.msgstr_plural.keys()
                keys.sort()
                for key in keys:
                    content.append(entry.msgstr_plural[key])
                textflowtarget = {
                    'resId': textflowId,
                    'state': state,
                    'contents': content,
                    'extensions': extensions
                }
            else:
                content = entry.msgstr
                textflowtarget = {
                    'resId': textflowId,
                    'state': state,
                    'content': content,
                    'extensions': extensions
                }

            textflowtargets.append(textflowtarget)

        return textflowtargets

    def validate_content_type(self, content_type, object_type):
        PATTERN = r'.+? charset=([\w_\-:\.]+)'
        rxt = re.compile(unicode(PATTERN))

        match = rxt.search(content_type)
        if match:
            enc = match.group(1).strip()
            if enc not in ["UTF-8", "utf-8", "utf8", "ascii", "UTF8", "ASCII"]:
                if enc == 'CHARSET':
                    if object_type == 'po-target-header':
                        self.log.error(
                            "Invalid encoding CHARSET; please correct the Content-Type charset (UTF-8 recommended)"
                        )
                        sys.exit(1)
                else:
                    self.log.error(
                        "Unsupported encoding; please change the Content-Type charset (UTF-8 recommended)"
                    )
                    sys.exit(1)

    def create_extensions(self, pofile, object_type):
        """
        "extensions":[{"object-type":"po-header","comment":"comment_value", "entries":[{"key":"h1","value":"v1"}]}]
        "extensions":[{"object-type":"po-target-header", "comment":"comment_value", "entries":[{"key":"ht","value":"vt1"}]}]
        """
        entries = []
        metadatas = pofile.ordered_metadata()
        for item in metadatas:
            entry = {"key": item[0], "value": item[1]}
            entries.append(entry)

        if pofile.metadata.has_key('Content-Type'):
            self.validate_content_type(pofile.metadata['Content-Type'],
                                       object_type)

        extensions = [{
            "object-type": object_type,
            "comment": pofile.header,
            "entries": entries
        }]
        return extensions

    def create_pofile(self, path):
        """
        Convert the po file to a pofile object in polib.
        @return: pofile object
        """
        try:
            po = polib.pofile(path)
        except Exception, e:
            self.log.error(str(e))
            sys.exit(1)

        return po
Пример #12
0
class PublicanUtility:
    def __init__(self):
        self.log = Logger()

    def create_txtflow(self, pofile):
        """
        Convert the content of the pot file to a list of text flow.
        @return: the dictionary object of textflow
        """
        textflows = []
        for entry in pofile:
            reflist = []
            if entry.msgctxt:
                self.log.warn("encountered msgctxt; not currently supported")
            m = hashlib.md5()
            m.update(entry.msgid.encode('utf-8'))
            textflowId = m.hexdigest()
            """
            "extensions":[{"object-type":"pot-entry-header","context":"context",
            "references":["fff"],"extractedComment":"extractedComment",
            "flags":["java-format"]}]
            """
            extracted_comment = entry.comment
            references = entry.occurrences
            for ref in references:
                node = ref[0]+":"+ref[1]
                reflist.append(node)
            flags = entry.flags
            
            #extensions_single_comment = [{'object-type':'comment','value':'test','space':'preserve'}]
            #extensions_pot_entry_header = [{"object-type":"pot-entry-header","context":"context","references":["fff"],"extractedComment":"extractedComment","flags":["java-format"]}]

            extensions=[{'object-type':'comment','value':extracted_comment,'space':'preserve'}, {"object-type":"pot-entry-header","context":"","references":reflist,"extractedComment":'',"flags":flags}]

            textflow = {'id': textflowId, 'lang':'en-US', 'content':entry.msgid, 'extensions':extensions, 'revision':1}
            textflows.append(textflow)
        return textflows
    
    def create_txtflowtarget(self, pofile):
        """
        Convert the content of the po file to a list of textflowtarget.
        @return: the dictionary object of textflow
        """
        obs_list=pofile.obsolete_entries()
        textflowtargets = []
        
        for entry in pofile:
            if entry in obs_list:
                continue
            m = hashlib.md5()
            m.update(entry.msgid.encode('utf-8'))
            textflowId = m.hexdigest()
            comment = entry.comment
            
            if entry.msgstr:
                state = "Approved"
            else:
                state = "New"
            #need judge for fuzzy state
            
            #create extensions
            extensions = [{"object-type":"comment","value":comment,"space":"preserve"}]
            
            # {"resId":"782f49c4e93c32403ba0b51821b38b90","state":"Approved","translator":{"email":"id","name":"name"},"content":"title:
            # ttff","extensions":[{"object-type":"comment","value":"testcomment","space":"preserve"}]}
            # Diable the translator to avoid issues on server side
            textflowtarget = {'resId': textflowId, 'state': state, 'content':entry.msgstr,'extensions':extensions}
            
            #Temporary fill in the admin info for translator to pass the validation, waiting for server side change
            textflowtargets.append(textflowtarget)
        
        return textflowtargets

    def create_extensions(self, pofile, object_type):
        """
        "extensions":[{"object-type":"po-header","comment":"comment_value", "entries":[{"key":"h1","value":"v1"}]}]
        "extensions":[{"object-type":"po-target-header", "comment":"comment_value", "entries":[{"key":"ht","value":"vt1"}]}]
        """
        entries = []
        metadatas = pofile.ordered_metadata()
        for item in metadatas:
            entry = {"key":item[0], "value":item[1]}
            entries.append(entry)
       
        extensions = [{"object-type":object_type,"comment":pofile.header, "entries":entries}]
        return extensions

    def create_pofile(self, path):
        """
        Convert the po file to a pofile object in polib.
        @return: pofile object
        """
        try:
            po = polib.pofile(path)
        except Exception:
            self.log.error("Can not processing the po file")
            sys.exit()

        return po

    def get_file_list(self, path, file_type):
        final_file_list = []
        root_list = os.listdir(path)
        for item in root_list:
            if item == '.svn':
                continue
            full_path = os.path.join(path, item)
            if full_path.endswith(file_type):
                final_file_list.append(full_path)
            if os.path.isdir(full_path):
                final_file_list+=self.get_file_list(full_path, file_type)
        return final_file_list

    def hash_match(self, message, msgid):
        m = hashlib.md5()
        m.update(message.msgid.encode('utf-8'))
        if m.hexdigest() == msgid:
            return True
        else:
            return False 

    def strip_path(self, full_path, root_path):
        if root_path[-1] != "/":
            root_path = root_path+'/'

        filename = full_path.split(root_path)[1]

        if '.' in filename:
            # Strip the file name
            filename = filename.split('.')[0]

        return filename

    def potfile_to_json(self, filepath, root_path):
        """
        Parse the pot file, create the request body
        @param filepath: the path of the pot file
        """
        filename = self.strip_path(filepath, root_path)
        pofile = self.create_pofile(filepath)
        textflows = self.create_txtflow(pofile)
        extensions = self.create_extensions(pofile, "po-header")
        items = {'name':filename, 'contentType':'application/x-gettext', 'lang':'en-US', 'extensions':extensions, 'textFlows':textflows}
        
        return json.dumps(items), filename

    def pofile_to_json(self, filepath):
        """
        Parse the po file, create the request body
        @param filepath: the path of the po file
        """
        pofile = self.create_pofile(filepath)
        textflowtargets = self.create_txtflowtarget(pofile)
        #the function for extensions have not implemented yet
        extensions = self.create_extensions(pofile, "po-target-header")
        items = {'links':[],'extensions':extensions, 'textFlowTargets':textflowtargets}
        
        return json.dumps(items)

    def save_to_pofile(self, path, translations, pot):
        """
        Save PO file to path, based on json objects of pot and translations 
        @param translations: the json object of the content retrieved from server
        @param path: the po folder for output
        @param pot: the json object of the pot retrieved from server
        """
        po = polib.POFile(fpath=path)
        
        potcontent = json.loads(pot)
        # pylint: disable-msg=E1103
        textflows = potcontent.get('textFlows')
                
        if potcontent.get('extensions'):
            extensions = potcontent.get('extensions')[0]
            po.header = extensions.get('comment')     
            for item in extensions.get('entries'):
                po.metadata[item['key']]=item['value']                    
        else:
            raise InvalidPOTFileException("Error", "the extensions of Resource is empty")

        for textflow in textflows:
            if textflow.get('extensions'):
                poentry = polib.POEntry(occurrences=None)
                entry_list = textflow.get('extensions')
                for entry in entry_list:
                    if entry.get('object-type') == 'pot-entry-header':
                        #PotEntryHeader
                        #Check the references is not empty
                        if entry.get('references')!=[u'']:
                            for item in entry.get('references'):
                                #in some cases, entry contains more than one reference
                                if ' ' in item:
                                    reference = item.split(' ')
                                    ref_list = []
                                    for i in reference:
                                        ref = tuple(i.split(':'))
                                        ref_list.append(ref)
                                    poentry.occurrences= ref_list 
                                else:
                                    poentry.occurrences = [tuple(item.split(':'))]
                        else:
                            poentry.occurrences = None
                        #print poentry.occurrences
                        poentry.flags = entry.get('flags')  
                    
                    if entry.get('object-type') == 'comment':
                        #SimpleComment
                        poentry.comment = entry.get('value')
                         
                poentry.msgid = textflow.get('content')
                po.append(poentry)
            else:
                raise InvalidPOTFileException("Error", "the extensions of TextFlow is empty")
          
        #If the translation is exist, read the content of the po file
        if translations:
            content = json.loads(translations)
            """            
            "extensions":[{"object-type":"po-target-header", "comment":"comment_value", "entries":[{"key":"ht","value":"vt1"}]}]
            """
            if content.get('extensions'):
                ext = content.get('extensions')[0]
                header_comment = ext.get('comment')
                if header_comment:
                    po.header = header_comment
                for item in ext.get('entries'):
                    po.metadata[item['key']]=item['value']  
            
            targets = content.get('textFlowTargets')
                            
            """
            "extensions":[{"object-type":"comment","value":"testcomment","space":"preserve"}]
            """ 
            # copy any other stuff you need to transfer
            for message in po:
                for translation in targets:
                    if translation.get('extensions'):
                        extensions=translation.get('extensions')[0]
                        #if extensions:
                        #    ext_type = extensions.get('object-type')
                        #    comment = extensions.get('comment')
                        #    entries = extensions.get('value')
                    if self.hash_match(message, translation.get('resId')):
                        message.msgstr = translation.get('content')
                   
        # finally save resulting po to outpath as lang/myfile.po
       
        po.save()
        # pylint: disable-msg=E1103
        self.log.info("Writing po file to %s"%(path))
Пример #13
0
class ZanataCommand:
    def __init__(self, url, username=None, apikey=None, http_headers=None):
        self.log = Logger()
        self.zanata_resource = ZanataResource(url, username, apikey,
                                              http_headers)

    def disable_ssl_cert_validation(self):
        self.zanata_resource.disable_ssl_cert_validation()

    ##############################################
    #
    # Commands for interaction with zanata server
    #
    ##############################################
    def get_file_list(self, projectid, iterationid):
        return self.zanata_resource.documents.get_file_list(
            projectid, iterationid)

    def get_server_version(self, url):
        try:
            content = self.zanata_resource.version.get_server_version()
            if content:
                server_version = content['versionNo']
                return server_version
        except UnAvaliableResourceException:
            self.log.error(
                "Can not retrieve the server version, server may not support the version service"
            )
        except UnavailableServiceError:
            self.log.error("Service Temporarily Unavailable, stop processing!")
            sys.exit(1)

    """
    def check_project(self, command_options, project_config):
        project_id = ''
        iteration_id = ''
        if command_options.has_key('project_id'):
            project_id =  command_options['project_id'][0]['value']
        else:
            if project_config.has_key('project_id'):
                project_id = project_config['project_id']

        if command_options.has_key('project_version'):
            iteration_id = command_options['project_version'][0]['value']
        else:
            if project_config.has_key('project_version'):
                iteration_id = project_config['project_version']

        if not project_id:
            self.log.error("Please specify a valid project id in zanata.xml or with '--project-id' option")
            sys.exit(1)

        if not iteration_id:
            self.log.error("Please specify a valid version id in zanata.xml or with '--project-version' option")
            sys.exit(1)

        self.log.info("Project: %s"%project_id)
        self.log.info("Version: %s"%iteration_id)
        self.verify_project(project_id, iteration_id)
    """

    def verify_project(self, project_id, version_id):
        try:
            self.zanata_resource.projects.get(project_id)
        except NoSuchProjectException, e:
            self.log.error(str(e))
            sys.exit(1)

        try:
            self.zanata_resource.projects.iterations.get(
                project_id, version_id)
        except NoSuchProjectException, e:
            self.log.error(str(e))
            sys.exit(1)