BuildL10n.py :  » XML » 4Suite » 4Suite-XML-1.0.2 » Ft » Lib » DistExt » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » XML » 4Suite 
4Suite » 4Suite XML 1.0.2 » Ft » Lib » DistExt » BuildL10n.py
import os, glob, struct, array
from distutils import dep_util
from distutils.core import Command
from distutils.errors import DistutilsFileError

class BuildL10n(Command):

    command_name = 'build_l10n'

    description = "compile message catalog to binary format"

    user_options = [
        ('build-dir=', 'd', "directory to \"build\" (copy) to"),
        ('force', 'f', "forcibly build everything (ignore file timestamps"),
        ]

    def initialize_options(self):
        self.build_dir = None
        self.force = None
        return

    def finalize_options(self):
        self.set_undefined_options('build',
                                   ('build_l10n', 'build_dir'),
                                   ('force', 'force'))
        self.localizations = self.distribution.l10n
        return

    def run(self):
        domain = self.distribution.get_name()
        for loc in self.localizations:
            # Create the build directory for this language
            build_dir = os.path.join(self.build_dir, loc.language,
                                     'LC_MESSAGES')
            self.mkpath(build_dir)

            pofile = loc.source
            mofile = os.path.join(build_dir, domain + '.mo')

            if not (self.force or dep_util.newer(pofile, mofile)):
                self.announce("not compiling %s (up-to-date)" % pofile, 1)
                continue

            self.announce("compiling %s -> %s" % (pofile, mofile), 2)

            # Parse the catalog
            msgfmt = MsgFmt()
            msgfmt.parse(pofile)

            # Compute output
            if not self.dry_run:
                fp = open(mofile, "wb")
                try:
                    msgfmt.generate(fp)
                finally:
                    fp.close()
        return

    # -- external interfaces ------------------------------------------

    def get_outputs(self):
        outputs = []
        domain = self.distribution.get_name()
        for loc in self.localizations:
            # Create the build directory for this language
            build_dir = os.path.join(self.build_dir, loc.language,
                                     'LC_MESSAGES')
            mofile = os.path.join(build_dir, domain + '.mo')
            outputs.append(mofile)
        return outputs

    def get_source_files(self):
        return [ loc.source for loc in self.localizations ]


class MsgFmt:

    def __init__(self):
        self.__messages = {}
        return

    def add(self, id, str, fuzzy):
        "Add a non-fuzzy translation to the dictionary."
        if not fuzzy and str:
            self.__messages[id] = str

    def generate(self, fp):
        "Return the generated output."
        keys = self.__messages.keys()
        # the keys are sorted in the .mo file
        keys.sort()
        offsets = []
        ids = strs = ''
        for id in keys:
            # For each string, we need size and file offset.  Each string is
            # NUL terminated; the NUL does not count into the size.
            msgstr = self.__messages[id]
            offsets.append((len(ids), len(id), len(strs), len(msgstr)))
            ids += id + '\0'
            strs += msgstr + '\0'

        # The header is 7 32-bit unsigned integers.  We don't use hash tables,
        # so the keys start right after the index tables.
        # translated string.
        keystart = 7*4+16*len(keys)
        # and the values start after the keys
        valuestart = keystart + len(ids)
        koffsets = []
        voffsets = []
        # The string table first has the list of keys, then the list of values.
        # Each entry has first the size of the string, then the file offset.
        for o1, l1, o2, l2 in offsets:
            koffsets += [l1, o1+keystart]
            voffsets += [l2, o2+valuestart]
        offsets = koffsets + voffsets
        fp.write(struct.pack("Iiiiiii",
                             0x950412deL,       # Magic
                             0,                 # Version
                             len(keys),         # # of entries
                             7*4,               # start of key index
                             7*4+len(keys)*8,   # start of value index
                             0, 0))             # size and offset of hash table
        fp.write(array.array("i", offsets).tostring())
        fp.write(ids)
        fp.write(strs)
        return

    def parse(self, pofile):
        ID = 1
        STR = 2

        try:
            lines = open(pofile).readlines()
        except IOError, (errno, errstr):
            raise DistutilsFileError("could not read from '%s': %s" % (
                pofile, errstr))
        section = None
        fuzzy = 0

        # Parse the catalog
        lno = 0
        for l in lines:
            lno += 1
            # If we get a comment line after a msgstr, this is a new entry
            if l[0] == '#' and section == STR:
                self.add(msgid, msgstr, fuzzy)
                section = None
                fuzzy = 0
            # Record a fuzzy mark
            if l[:2] == '#,' and l.find('fuzzy'):
                fuzzy = 1
            # Skip comments
            if l[0] == '#':
                continue
            # Now we are in a msgid section, output previous section
            if l.startswith('msgid'):
                if section == STR:
                    self.add(msgid, msgstr, fuzzy)
                section = ID
                l = l[5:]
                msgid = msgstr = ''
            # Now we are in a msgstr section
            elif l.startswith('msgstr'):
                section = STR
                l = l[6:]
            # Skip empty lines
            l = l.strip()
            if not l:
                continue
            # XXX: Does this always follow Python escape semantics?
            l = eval(l)
            if section == ID:
                msgid += l
            elif section == STR:
                msgstr += l
            else:
                self.warn('Syntax error on %s:%d before: %s ' % (
                    pofile, lno, l))
                return

        # Add last entry
        if section == STR:
            self.add(msgid, msgstr, fuzzy)
        return

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.