[Zope3-checkins] CVS: Zope3/src/zope/app/translation_files - extract.py:1.15

Philipp von Weitershausen philikon at philikon.de
Wed Dec 17 09:07:24 EST 2003


Update of /cvs-repository/Zope3/src/zope/app/translation_files
In directory cvs.zope.org:/tmp/cvs-serv8554/src/zope/app/translation_files

Modified Files:
	extract.py 
Log Message:
Divided the message id extraction machinery up into two files. The
extract module contains classes and functions and the i18nextract script
is the command utility using them.


=== Zope3/src/zope/app/translation_files/extract.py 1.14 => 1.15 ===
--- Zope3/src/zope/app/translation_files/extract.py:1.14	Wed Dec 17 05:06:12 2003
+++ Zope3/src/zope/app/translation_files/extract.py	Wed Dec 17 09:06:54 2003
@@ -1,3 +1,4 @@
+#!/usr/bin/env python2.3
 ##############################################################################
 #
 # Copyright (c) 2003 Zope Corporation and Contributors.
@@ -11,41 +12,22 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-"""Program to extract internationalization markup from Python Code,
-Page Templates and ZCML.
+"""Extract message strings from python modules, page template files
+and ZCML files.
 
-This tool will extract all findable message strings from all
-internationalizable files in your Zope 3 product. It only extracts message ids
-of the specified domain. It defaults to the 'zope' domain and the zope.app
-package.
-
-Note: The Python Code extraction tool does not support domain registration, so
-      that all message strings are returned for Python code.
-
-Usage: extract.py [options]
-Options:
-    -h / --help
-        Print this message and exit.
-    -d / --domain <domain>
-        Specifies the domain that is supposed to be extracted (i.e. 'zope')
-    -p / --path <path>
-        Specifies the package that is supposed to be searched
-        (i.e. 'zope/app')
-    -o dir
-        Specifies a directory, relative to the package in which to put the
-        output translation template.
+$Id$
 """
-__id__ = "$Id$"
 
 import os, sys, fnmatch
-import getopt
 import time
 import tokenize
 import traceback
 from pygettext import safe_eval, normalize, make_escapes
 
-__meta_class__ = type
+from interfaces import IPOTEntry, IPOTMaker, ITokenEater
+from zope.interface import implements
 
+__meta_class__ = type
 
 pot_header = '''\
 ##############################################################################
@@ -75,15 +57,10 @@
 
 '''
 
-def usage(code, msg=''):
-    # Python 2.1 required
-    print >> sys.stderr, __doc__
-    if msg:
-        print >> sys.stderr, msg
-    sys.exit(code)
-
 class POTEntry:
-    """This class represents a single message entry in the POT file."""
+    """This class represents a single message entry in the POT file.
+    """
+    implements(IPOTEntry)
 
     def __init__(self, msgid, comments=None):
         self.msgid = msgid
@@ -109,16 +86,16 @@
     def __cmp__(self, other):
         return cmp(self.comments, other.comments)
 
-
 class POTMaker:
-    """This class inserts sets of strings into a POT file."""
+    """This class inserts sets of strings into a POT file.
+    """
+    implements(IPOTMaker)
     
     def __init__ (self, output_fn, path):
         self._output_filename = output_fn
         self.path = path
         self.catalog = {}
 
-
     def add(self, strings, base_dir=None):
         for msgid, locations in strings.items():
             if msgid == '':
@@ -130,7 +107,6 @@
                 if base_dir is not None:
                     filename = filename.replace(base_dir, '')
                 self.catalog[msgid].addLocationComment(filename, lineno)
-                
 
     def _getProductVersion(self):
         # First, try to get the product version
@@ -145,13 +121,11 @@
         else:
             return 'Zope 3 (unknown version)'
 
-
     def write(self):
-        
         file = open(self._output_filename, 'w')
-        file.write(pot_header % {'time': time.ctime(),
+        file.write(pot_header % {'time':    time.ctime(),
                                  'version': self._getProductVersion()})
-        
+
         # Sort the catalog entries by filename
         catalog = self.catalog.values()
         catalog.sort()
@@ -162,10 +136,42 @@
             
         file.close()
 
-
 class TokenEater:
-    """This is almost 100% taken from pygettext.py, except that I removed all
-    option handling and output a dictionary."""
+    """This is almost 100% taken from pygettext.py, except that I
+    removed all option handling and output a dictionary.
+
+    >>> eater = TokenEater()
+    >>> make_escapes(0)
+
+    TokenEater eats tokens generated by the standard python module
+    tokenize.
+
+    >>> import tokenize
+    >>> from StringIO import StringIO
+
+    We feed it a (fake) file:
+
+    >>> file = StringIO("_('hello', 'buenos dias')")
+    >>> tokenize.tokenize(file.readline, eater)
+
+    The catalog of collected message ids contains our example
+
+    >>> catalog = eater.getCatalog()
+    >>> catalog
+    {u'hello': [(None, 1)]}
+
+    The key in the catalog is not a unicode string, it's a real
+    message id with a default value:
+
+    >>> msgid = catalog.keys()[0]
+    >>> msgid
+    u'hello'
+    >>> msgid.default
+    u'buenos dias'
+
+    Note that everything gets converted to unicode.
+    """
+    implements(ITokenEater)
     
     def __init__(self):
         self.__messages = {}
@@ -267,27 +273,6 @@
 
         return catalog
 
-                    
-def app_dir():
-    try:
-        import zope.app
-    except ImportError:
-        # Couldn't import zope.app, need to add something to the Python
-        # path
-
-        # Get the path of the src
-        path = os.path.abspath(os.path.dirname(sys.argv[0]))
-        while not path.endswith('src'):
-            path = os.path.dirname(path)
-        sys.path.insert(0, path)
-
-        import zope.app
-
-    dir = os.path.dirname(zope.app.__file__)
-
-    return dir
-
-
 def find_files(dir, pattern, exclude=()):
     files = []
 
@@ -297,12 +282,11 @@
                   if name not in exclude]
         
     os.path.walk(dir, visit, files)
-
     return files
 
-
 def py_strings(dir, domain="zope"):
-    """Retrieve all Python messages from dir that are in the domain."""
+    """Retrieve all Python messages from dir that are in the domain.
+    """
     eater = TokenEater()
     make_escapes(0)
     for filename in find_files(dir, '*.py', 
@@ -320,9 +304,9 @@
     # XXX: No support for domains yet :(
     return eater.getCatalog()
 
-
 def zcml_strings(dir, domain="zope"):
-    """Retrieve all ZCML messages from dir that are in the domain."""
+    """Retrieve all ZCML messages from dir that are in the domain.
+    """
     from zope.app._app import config
     import zope
     dirname = os.path.dirname
@@ -331,9 +315,9 @@
     context = config(site_zcml, execute=False)
     return context.i18n_strings.get(domain, {})
 
-
 def tal_strings(dir, domain="zope", include_default_domain=False):
-    """Retrieve all TAL messages from dir that are in the domain."""
+    """Retrieve all TAL messages from dir that are in the domain.
+    """
     # We import zope.tal.talgettext here because we can't rely on the
     # right sys path until app_dir has run
     from zope.tal.talgettext import POEngine, POTALInterpreter
@@ -368,60 +352,3 @@
     for msgid, locations in catalog.items():
         catalog[msgid] = map(lambda l: (l[0], l[1][0]), locations)
     return catalog
-
-
-def main(argv=sys.argv):
-    try:
-        opts, args = getopt.getopt(
-            sys.argv[1:],
-            'hd:p:o:',
-            ['help', 'domain=', 'path='])
-    except getopt.error, msg:
-        usage(1, msg)
-
-    domain = 'zope'
-    path = app_dir()
-    include_default_domain = True
-    output_dir = None
-    for opt, arg in opts:
-        if opt in ('-h', '--help'):
-            usage(0)
-        elif opt in ('-d', '--domain'):
-            domain = arg
-            include_default_domain = False
-        elif opt in ('-o', ):
-            output_dir = arg
-        elif opt in ('-p', '--path'):
-            if not os.path.exists(arg):
-                usage(1, 'The specified path does not exist.')
-            path = arg
-            # We might not have an absolute path passed in.
-            if not path == os.path.abspath(path):
-                cwd = os.getcwd()
-                # This is for symlinks. Thanks to Fred for this trick.
-                if os.environ.has_key('PWD'):
-                    cwd = os.environ['PWD']
-                path = os.path.normpath(os.path.join(cwd, arg))
-
-    # When generating the comments, we will not need the base directory info,
-    # since it is specific to everyone's installation
-    src_start = path.find('src')
-    base_dir = path[:src_start]
-
-    output_file = domain+'.pot'
-    if output_dir:
-        output_dir = os.path.join(path, output_dir)
-        if not os.path.exists(output_dir):
-            os.mkdir(output_dir)
-        output_file = os.path.join(output_dir, output_file)
-        
-
-    maker = POTMaker(output_file, path)
-    maker.add(py_strings(path, domain), base_dir)
-    maker.add(zcml_strings(path, domain), base_dir)
-    maker.add(tal_strings(path, domain, include_default_domain), base_dir)
-    maker.write()
-
-
-if __name__ == '__main__':
-    main()




More information about the Zope3-Checkins mailing list