'dngettext': (2, 3),
}
-DEFAULT_MAPPING = {'**.py': 'python'}
+DEFAULT_MAPPING = [('**.py', 'python')]
def extract_from_dir(dirname=os.getcwd(), method_map=DEFAULT_MAPPING,
options_map=None, keywords=DEFAULT_KEYWORDS,
parameter, which maps extended glob patterns to extraction method names.
For example, the following is the default mapping:
- >>> method_map = {
- ... '**.py': 'python'
- ... }
+ >>> method_map = [
+ ... ('**.py', 'python')
+ ... ]
This basically says that files with the filename extension ".py" at any
level inside the directory should be processed by the "python" extraction
the documentation of the `pathmatch` function for details on the pattern
syntax.
- The following extended mapping would also use the "genshi" extraction method
- on any file in "templates" subdirectory:
+ The following extended mapping would also use the "genshi" extraction
+ method on any file in "templates" subdirectory:
- >>> method_map = {
- ... '**/templates/**.*': 'genshi',
- ... '**.py': 'python'
- ... }
+ >>> method_map = [
+ ... ('**/templates/**.*', 'genshi'),
+ ... ('**.py', 'python')
+ ... ]
The dictionary provided by the optional `options_map` parameter augments
- the mapping data. It too uses extended glob patterns as keys, but the values
- are dictionaries mapping options names to option values (both strings).
+ these mappings. It uses extended glob patterns as keys, and the values are
+ dictionaries mapping options names to option values (both strings).
The glob patterns of the `options_map` do not necessarily need to be the
- same as those used in the pattern. For example, while all files in the
- ``templates`` folders in an application may be Genshi applications, the
+ same as those used in the method mapping. For example, while all files in
+ the ``templates`` folders in an application may be Genshi applications, the
options for those files may differ based on extension:
>>> options_map = {
... }
:param dirname: the path to the directory to extract messages from
- :param method_map: a mapping of extraction method names to extended glob
- patterns
+ :param method_map: a list of ``(pattern, method)`` tuples that maps of
+ extraction method names to extended glob patterns
:param options_map: a dictionary of additional options (optional)
:param keywords: a dictionary mapping keywords (i.e. names of functions
that should be recognized as translation functions) to
if options_map is None:
options_map = {}
- # Sort methods by pattern length
- # FIXME: we'll probably need to preserve the user-supplied order in the
- # frontends
- methods = method_map.items()
- methods.sort(lambda a,b: -cmp(len(a[0]), len(b[0])))
-
absname = os.path.abspath(dirname)
for root, dirnames, filenames in os.walk(absname):
for subdir in dirnames:
os.path.join(root, filename).replace(os.sep, '/'),
dirname
)
- for pattern, method in methods:
+ for pattern, method in method_map:
if pathmatch(pattern, filename):
filepath = os.path.join(absname, filename)
options = {}
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2007 Edgewall Software
DEFAULT_MAPPING
from babel.messages.pofile import write_po, write_pot
from babel.messages.plurals import PLURALS
+from babel.util import odict
__all__ = ['CommandLineInterface', 'extract_messages',
'check_message_extractors', 'main']
]).keys()
def run(self):
- if self.mapping_file:
- fileobj = open(self.mapping_file, 'U')
- try:
- method_map, options_map = parse_mapping(fileobj)
- finally:
- fileobj.close()
- elif self.distribution.message_extractors:
- message_extractors = self.distribution.message_extractors
- if isinstance(message_extractors, basestring):
- method_map, options_map = parse_mapping(StringIO(
- message_extractors
- ))
- else:
- method_map = {}
- options_map = {}
- for pattern, (method, options) in message_extractors.items():
- method_map[pattern] = method
- options_map[pattern] = options
- else:
- method_map = DEFAULT_MAPPING
- options_map = {}
-
+ mappings = self._get_mappings()
outfile = open(self.output_file, 'w')
try:
catalog = Catalog()
- for dirname in self.input_dirs:
+ for dirname, (method_map, options_map) in mappings.items():
def callback(filename, method, options):
if method == 'ignore':
return
finally:
outfile.close()
+ def _get_mappings(self):
+ mappings = {}
+
+ if self.mapping_file:
+ fileobj = open(self.mapping_file, 'U')
+ try:
+ method_map, options_map = parse_mapping(fileobj)
+ for dirname in self.input_dirs:
+ mappings[dirname] = method_map, options_map
+ finally:
+ fileobj.close()
+
+ elif self.distribution.message_extractors:
+ message_extractors = self.distribution.message_extractors
+ for dirname, mapping in message_extractors.items():
+ if isinstance(mapping, basestring):
+ method_map, options_map = parse_mapping(StringIO(mapping))
+ else:
+ method_map, options_map = [], {}
+ for pattern, method, options in mapping:
+ method_map.append((pattern, method))
+ options_map[pattern] = options or {}
+ mappings[dirname] = method_map, options_map
+
+ else:
+ for dirname in self.input_dirs:
+ mappings[dirname] = DEFAULT_MAPPING, {}
+
+ return mappings
+
def check_message_extractors(dist, name, value):
"""Validate the ``message_extractors`` keyword argument to ``setup()``.
<http://peak.telecommunity.com/DevCenter/setuptools#adding-setup-arguments>`_
"""
assert name == 'message_extractors'
- if not isinstance(value, (basestring, dict)):
- raise DistutilsSetupError('the value of the "extract_messages" '
- 'parameter must be a string or dictionary')
+ if not isinstance(value, dict):
+ raise DistutilsSetupError('the value of the "message_extractors" '
+ 'parameter must be a dictionary')
class new_catalog(Command):
>>> buf = StringIO('''
... # Python source files
- ... [python: foobar/**.py]
+ ... [python: **.py]
...
... # Genshi templates
- ... [genshi: foobar/**/templates/**.html]
+ ... [genshi: **/templates/**.html]
... include_attrs =
- ... [genshi: foobar/**/templates/**.txt]
+ ... [genshi: **/templates/**.txt]
... template_class = genshi.template.text.TextTemplate
... encoding = latin-1
... ''')
>>> method_map, options_map = parse_mapping(buf)
- >>> method_map['foobar/**.py']
- 'python'
- >>> options_map['foobar/**.py']
+ >>> method_map[0]
+ ('**.py', 'python')
+ >>> options_map['**.py']
{}
- >>> method_map['foobar/**/templates/**.html']
- 'genshi'
- >>> options_map['foobar/**/templates/**.html']['include_attrs']
+ >>> method_map[1]
+ ('**/templates/**.html', 'genshi')
+ >>> options_map['**/templates/**.html']['include_attrs']
''
- >>> method_map['foobar/**/templates/**.txt']
- 'genshi'
- >>> options_map['foobar/**/templates/**.txt']['template_class']
+ >>> method_map[2]
+ ('**/templates/**.txt', 'genshi')
+ >>> options_map['**/templates/**.txt']['template_class']
'genshi.template.text.TextTemplate'
- >>> options_map['foobar/**/templates/**.txt']['encoding']
+ >>> options_map['**/templates/**.txt']['encoding']
'latin-1'
:param fileobj: a readable file-like object containing the configuration
:rtype: `tuple`
:see: `extract_from_directory`
"""
- method_map = {}
+ method_map = []
options_map = {}
parser = RawConfigParser()
+ parser._sections = odict(parser._sections) # We need ordered sections
parser.readfp(fileobj, filename)
for section in parser.sections():
method, pattern = [part.strip() for part in section.split(':', 1)]
- method_map[pattern] = method
+ method_map.append((pattern, method))
options_map[pattern] = dict(parser.items(section))
return (method_map, options_map)
locale='en_US'), '(12,345)')
def test_default_rounding(self):
- """Testing Round-Half-Even (Banker's rounding)
+ """
+ Testing Round-Half-Even (Banker's rounding)
A '5' is rounded to the closest 'even' number
"""
self.assertEqual(numbers.format_decimal(5.5, '0', locale='sv'), '6')
self.assertEqual(numbers.format_decimal(6.5, '0', locale='sv'), '6')
self.assertEqual(numbers.format_decimal(1.2325, locale='sv'), '1,232')
- self.assertEqual(numbers.format_decimal(1.2325, locale='sv'), '1,232')
self.assertEqual(numbers.format_decimal(1.2335, locale='sv'), '1,234')
:see: `http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747`
"""
- def __init__(self, dict=None):
- dict.__init__(self, dict)
+ def __init__(self, data=None):
+ dict.__init__(self, data or {})
self._keys = []
def __delitem__(self, key):
--width (-w) set output line width (default 76)
--no-wrap do not break long message lines, longer than the
output line width, into several lines
+ --input-dirs directories that should be scanned for messages
Running the command will produce a PO template file::
setup(...
message_extractors = {
- 'foobar/**.py': ('python', None),
- 'foobar/**/templates/**.html': ('genshi', None),
- 'foobar/**/templates/**.txt': ('genshi', {
- 'template_class': 'genshi.template.text.TextTemplate'
- })
+ 'foobar': [
+ ('**.py', ('python', None),
+ ('**/templates/**.html', ('genshi', None),
+ ('**/templates/**.txt', ('genshi', {
+ 'template_class': 'genshi.template.text.TextTemplate'
+ })
+ ],
},
...
| ``--no-wrap`` | do not break long message lines, longer than |
| | the output line width, into several lines |
+-----------------------------+----------------------------------------------+
+ | ``--input-dirs`` | directories that should be scanned for |
+ | | messages |
+ +-----------------------------+----------------------------------------------+