root/galaxy-central/eggs/Babel-0.9.4-py2.6.egg/babel/messages/checkers.py

リビジョン 3, 6.4 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2007 Edgewall Software
4# All rights reserved.
5#
6# This software is licensed as described in the file COPYING, which
7# you should have received as part of this distribution. The terms
8# are also available at http://babel.edgewall.org/wiki/License.
9#
10# This software consists of voluntary contributions made by many
11# individuals. For the exact contribution history, see the revision
12# history and logs, available at http://babel.edgewall.org/log/.
13
14"""Various routines that help with validation of translations.
15
16:since: version 0.9
17"""
18
19from itertools import izip
20from babel.messages.catalog import TranslationError, PYTHON_FORMAT
21
22#: list of format chars that are compatible to each other
23_string_format_compatibilities = [
24    set(['i', 'd', 'u']),
25    set(['x', 'X']),
26    set(['f', 'F', 'g', 'G'])
27]
28
29
30def num_plurals(catalog, message):
31    """Verify the number of plurals in the translation."""
32    if not message.pluralizable:
33        if not isinstance(message.string, basestring):
34            raise TranslationError("Found plural forms for non-pluralizable "
35                                   "message")
36        return
37
38    # skip further tests if no catalog is provided.
39    elif catalog is None:
40        return
41
42    msgstrs = message.string
43    if not isinstance(msgstrs, (list, tuple)):
44        msgstrs = (msgstrs,)
45    if len(msgstrs) != catalog.num_plurals:
46        raise TranslationError("Wrong number of plural forms (expected %d)" %
47                               catalog.num_plurals)
48
49
50def python_format(catalog, message):
51    """Verify the format string placeholders in the translation."""
52    if 'python-format' not in message.flags:
53        return
54    msgids = message.id
55    if not isinstance(msgids, (list, tuple)):
56        msgids = (msgids,)
57    msgstrs = message.string
58    if not isinstance(msgstrs, (list, tuple)):
59        msgstrs = (msgstrs,)
60
61    for msgid, msgstr in izip(msgids, msgstrs):
62        if msgstr:
63            _validate_format(msgid, msgstr)
64
65
66def _validate_format(format, alternative):
67    """Test format string `alternative` against `format`.  `format` can be the
68    msgid of a message and `alternative` one of the `msgstr`\s.  The two
69    arguments are not interchangeable as `alternative` may contain less
70    placeholders if `format` uses named placeholders.
71
72    If `format` does not use string formatting a `ValueError` is raised.
73
74    If the string formatting of `alternative` is compatible to `format` the
75    function returns `None`, otherwise a `TranslationError` is raised.
76
77    Examples for compatible format strings:
78
79    >>> _validate_format('Hello %s!', 'Hallo %s!')
80    >>> _validate_format('Hello %i!', 'Hallo %d!')
81
82    Example for an incompatible format strings:
83
84    >>> _validate_format('Hello %(name)s!', 'Hallo %s!')
85    Traceback (most recent call last):
86      ...
87    TranslationError: the format strings are of different kinds
88
89    This function is used by the `python_format` checker.
90
91    :param format: The original format string
92    :param alternative: The alternative format string that should be checked
93                        against format
94    :return: None on success
95    :raises TranslationError: on formatting errors
96    """
97
98    def _parse(string):
99        result = []
100        for match in PYTHON_FORMAT.finditer(string):
101            name, format, typechar = match.groups()
102            if typechar == '%' and name is None:
103                continue
104            result.append((name, str(typechar)))
105        return result
106
107    def _compatible(a, b):
108        if a == b:
109            return True
110        for set in _string_format_compatibilities:
111            if a in set and b in set:
112                return True
113        return False
114
115    def _check_positional(results):
116        positional = None
117        for name, char in results:
118            if positional is None:
119                positional = name is None
120            else:
121                if (name is None) != positional:
122                    raise TranslationError('format string mixes positional '
123                                           'and named placeholders')
124        return bool(positional)
125
126    a, b = map(_parse, (format, alternative))
127
128    # if a does not use string formattings, we are dealing with invalid
129    # input data.  This function only works if the first string provided
130    # does contain string format chars
131    if not a:
132        raise ValueError('original string provided does not use string '
133                         'formatting.')
134
135    # now check if both strings are positional or named
136    a_positional, b_positional = map(_check_positional, (a, b))
137    if a_positional and not b_positional and not b:
138        raise TranslationError('placeholders are incompatible')
139    elif a_positional != b_positional:
140        raise TranslationError('the format strings are of different kinds')
141
142    # if we are operating on positional strings both must have the
143    # same number of format chars and those must be compatible
144    if a_positional:
145        if len(a) != len(b):
146            raise TranslationError('positional format placeholders are '
147                                   'unbalanced')
148        for idx, ((_, first), (_, second)) in enumerate(izip(a, b)):
149            if not _compatible(first, second):
150                raise TranslationError('incompatible format for placeholder '
151                                       '%d: %r and %r are not compatible' %
152                                       (idx + 1, first, second))
153
154    # otherwise the second string must not have names the first one
155    # doesn't have and the types of those included must be compatible
156    else:
157        type_map = dict(a)
158        for name, typechar in b:
159            if name not in type_map:
160                raise TranslationError('unknown named placeholder %r' % name)
161            elif not _compatible(typechar, type_map[name]):
162                raise TranslationError('incompatible format for '
163                                       'placeholder %r: '
164                                       '%r and %r are not compatible' %
165                                       (name, typechar, type_map[name]))
166
167
168def _find_checkers():
169    try:
170        from pkg_resources import working_set
171    except ImportError:
172        return [num_plurals, python_format]
173    checkers = []
174    for entry_point in working_set.iter_entry_points('babel.checkers'):
175        checkers.append(entry_point.load())
176    return checkers
177
178
179checkers = _find_checkers()
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。