Exemple #1
0
    def __call__(self, stream, directives, ctxt, **vars):
        ctxt.push({"_i18n.choose.params": self.params, "_i18n.choose.singular": None, "_i18n.choose.plural": None})

        ngettext = ctxt.get("_i18n.ngettext")
        assert hasattr(ngettext, "__call__"), "No ngettext function available"
        dngettext = ctxt.get("_i18n.dngettext")
        if not dngettext:
            dngettext = lambda d, s, p, n: ngettext(s, p, n)

        new_stream = []
        singular_stream = None
        singular_msgbuf = None
        plural_stream = None
        plural_msgbuf = None

        numeral = self.numeral.evaluate(ctxt)
        is_plural = self._is_plural(numeral, ngettext)

        for event in stream:
            if event[0] is SUB and any(isinstance(d, ChooseBranchDirective) for d in event[1][0]):
                subdirectives, substream = event[1]

                if isinstance(subdirectives[0], SingularDirective):
                    singular_stream = list(_apply_directives(substream, subdirectives, ctxt, vars))
                    new_stream.append((MSGBUF, None, (None, -1, -1)))

                elif isinstance(subdirectives[0], PluralDirective):
                    if is_plural:
                        plural_stream = list(_apply_directives(substream, subdirectives, ctxt, vars))

            else:
                new_stream.append(event)

        if ctxt.get("_i18n.domain"):
            ngettext = lambda s, p, n: dngettext(ctxt.get("_i18n.domain"), s, p, n)

        singular_msgbuf = ctxt.get("_i18n.choose.singular")
        if is_plural:
            plural_msgbuf = ctxt.get("_i18n.choose.plural")
            msgbuf, choice = plural_msgbuf, plural_stream
        else:
            msgbuf, choice = singular_msgbuf, singular_stream
            plural_msgbuf = MessageBuffer(self)

        for kind, data, pos in new_stream:
            if kind is MSGBUF:
                for event in choice:
                    if event[0] is MSGBUF:
                        translation = ngettext(singular_msgbuf.format(), plural_msgbuf.format(), numeral)
                        for subevent in msgbuf.translate(translation):
                            yield subevent
                    else:
                        yield event
            else:
                yield kind, data, pos

        ctxt.pop()
Exemple #2
0
    def __call__(self, stream):
        """Apply the filter to the given stream.
        
        :param stream: the markup event stream to filter
        """
        in_form = in_select = in_option = in_textarea = False
        select_value = option_value = textarea_value = None
        option_start = None
        option_text = []
        no_option_value = False

        for kind, data, pos in stream:

            if kind is START:
                tag, attrs = data
                tagname = tag.localname

                if tagname == 'form' and (
                        self.name and attrs.get('name') == self.name
                        or self.id and attrs.get('id') == self.id
                        or not (self.id or self.name)):
                    in_form = True

                elif in_form:
                    if tagname == 'input':
                        type = attrs.get('type', '').lower()
                        if type in ('checkbox', 'radio'):
                            name = attrs.get('name')
                            if name and name in self.data:
                                value = self.data[name]
                                declval = attrs.get('value')
                                checked = False
                                if isinstance(value, (list, tuple)):
                                    if declval is not None:
                                        checked = declval in [
                                            str(v) for v in value
                                        ]
                                    else:
                                        checked = any(value)
                                else:
                                    if declval is not None:
                                        checked = declval == str(value)
                                    elif type == 'checkbox':
                                        checked = bool(value)
                                if checked:
                                    attrs |= [(QName('checked'), 'checked')]
                                elif 'checked' in attrs:
                                    attrs -= 'checked'
                        elif type in ('', 'hidden', 'text') \
                                or type == 'password' and self.passwords:
                            name = attrs.get('name')
                            if name and name in self.data:
                                value = self.data[name]
                                if isinstance(value, (list, tuple)):
                                    value = value[0]
                                if value is not None:
                                    attrs |= [(QName('value'), str(value))]
                    elif tagname == 'select':
                        name = attrs.get('name')
                        if name in self.data:
                            select_value = self.data[name]
                            in_select = True
                    elif tagname == 'textarea':
                        name = attrs.get('name')
                        if name in self.data:
                            textarea_value = self.data.get(name)
                            if isinstance(textarea_value, (list, tuple)):
                                textarea_value = textarea_value[0]
                            in_textarea = True
                    elif in_select and tagname == 'option':
                        option_start = kind, data, pos
                        option_value = attrs.get('value')
                        if option_value is None:
                            no_option_value = True
                            option_value = ''
                        in_option = True
                        continue
                yield kind, (tag, attrs), pos

            elif in_form and kind is TEXT:
                if in_select and in_option:
                    if no_option_value:
                        option_value += data
                    option_text.append((kind, data, pos))
                    continue
                elif in_textarea:
                    continue
                yield kind, data, pos

            elif in_form and kind is END:
                tagname = data.localname
                if tagname == 'form':
                    in_form = False
                elif tagname == 'select':
                    in_select = False
                    select_value = None
                elif in_select and tagname == 'option':
                    if isinstance(select_value, (tuple, list)):
                        selected = option_value in [
                            str(v) for v in select_value
                        ]
                    else:
                        selected = option_value == str(select_value)
                    okind, (tag, attrs), opos = option_start
                    if selected:
                        attrs |= [(QName('selected'), 'selected')]
                    elif 'selected' in attrs:
                        attrs -= 'selected'
                    yield okind, (tag, attrs), opos
                    if option_text:
                        for event in option_text:
                            yield event
                    in_option = False
                    no_option_value = False
                    option_start = option_value = None
                    option_text = []
                elif in_textarea and tagname == 'textarea':
                    if textarea_value:
                        yield TEXT, str(textarea_value), pos
                        textarea_value = None
                    in_textarea = False
                yield kind, data, pos

            else:
                yield kind, data, pos
Exemple #3
0
    def __call__(self,
                 stream,
                 ctxt=None,
                 translate_text=True,
                 translate_attrs=True):
        """Translate any localizable strings in the given stream.
        
        This function shouldn't be called directly. Instead, an instance of
        the `Translator` class should be registered as a filter with the
        `Template` or the `TemplateLoader`, or applied as a regular stream
        filter. If used as a template filter, it should be inserted in front of
        all the default filters.
        
        :param stream: the markup event stream
        :param ctxt: the template context (not used)
        :param translate_text: whether text nodes should be translated (used
                               internally)
        :param translate_attrs: whether attribute values should be translated
                                (used internally)
        :return: the localized stream
        """
        ignore_tags = self.ignore_tags
        include_attrs = self.include_attrs
        skip = 0
        xml_lang = XML_NAMESPACE['lang']
        if not self.extract_text:
            translate_text = False
            translate_attrs = False

        if type(self.translate) is FunctionType:
            gettext = self.translate
            if ctxt:
                ctxt['_i18n.gettext'] = gettext
        else:
            if IS_PYTHON2:
                gettext = self.translate.ugettext
                ngettext = self.translate.ungettext
            else:
                gettext = self.translate.gettext
                ngettext = self.translate.ngettext
            try:
                if IS_PYTHON2:
                    dgettext = self.translate.dugettext
                    dngettext = self.translate.dungettext
                else:
                    dgettext = self.translate.dgettext
                    dngettext = self.translate.dngettext
            except AttributeError:
                dgettext = lambda _, y: gettext(y)
                dngettext = lambda _, s, p, n: ngettext(s, p, n)
            if ctxt:
                ctxt['_i18n.gettext'] = gettext
                ctxt['_i18n.ngettext'] = ngettext
                ctxt['_i18n.dgettext'] = dgettext
                ctxt['_i18n.dngettext'] = dngettext

        if ctxt and ctxt.get('_i18n.domain'):
            # TODO: This can cause infinite recursion if dgettext is defined
            #       via the AttributeError case above!
            gettext = lambda msg: dgettext(ctxt.get('_i18n.domain'), msg)

        for kind, data, pos in stream:

            # skip chunks that should not be localized
            if skip:
                if kind is START:
                    skip += 1
                elif kind is END:
                    skip -= 1
                yield kind, data, pos
                continue

            # handle different events that can be localized
            if kind is START:
                tag, attrs = data
                if tag in self.ignore_tags or \
                        isinstance(attrs.get(xml_lang), basestring):
                    skip += 1
                    yield kind, data, pos
                    continue

                new_attrs = []
                changed = False

                for name, value in attrs:
                    newval = value
                    if isinstance(value, basestring):
                        if translate_attrs and name in include_attrs:
                            newval = gettext(value)
                    else:
                        newval = list(
                            self(_ensure(value), ctxt, translate_text=False))
                    if newval != value:
                        value = newval
                        changed = True
                    new_attrs.append((name, value))
                if changed:
                    attrs = Attrs(new_attrs)

                yield kind, (tag, attrs), pos

            elif translate_text and kind is TEXT:
                text = data.strip()
                if text:
                    data = data.replace(text, unicode(gettext(text)))
                yield kind, data, pos

            elif kind is SUB:
                directives, substream = data
                current_domain = None
                for idx, directive in enumerate(directives):
                    # Organize directives to make everything work
                    # FIXME: There's got to be a better way to do this!
                    if isinstance(directive, DomainDirective):
                        # Grab current domain and update context
                        current_domain = directive.domain
                        ctxt.push({'_i18n.domain': current_domain})
                        # Put domain directive as the first one in order to
                        # update context before any other directives evaluation
                        directives.insert(0, directives.pop(idx))

                # If this is an i18n directive, no need to translate text
                # nodes here
                is_i18n_directive = any([
                    isinstance(d, ExtractableI18NDirective) for d in directives
                ])
                substream = list(
                    self(substream,
                         ctxt,
                         translate_text=not is_i18n_directive,
                         translate_attrs=translate_attrs))
                yield kind, (directives, substream), pos

                if current_domain:
                    ctxt.pop()
            else:
                yield kind, data, pos
Exemple #4
0
    def __call__(self, stream, directives, ctxt, **vars):
        ctxt.push({
            '_i18n.choose.params': self.params,
            '_i18n.choose.singular': None,
            '_i18n.choose.plural': None
        })

        ngettext = ctxt.get('_i18n.ngettext')
        assert hasattr(ngettext, '__call__'), 'No ngettext function available'
        dngettext = ctxt.get('_i18n.dngettext')
        if not dngettext:
            dngettext = lambda d, s, p, n: ngettext(s, p, n)

        new_stream = []
        singular_stream = None
        singular_msgbuf = None
        plural_stream = None
        plural_msgbuf = None

        numeral = self.numeral.evaluate(ctxt)
        is_plural = self._is_plural(numeral, ngettext)

        for event in stream:
            if event[0] is SUB and any(
                    isinstance(d, ChooseBranchDirective) for d in event[1][0]):
                subdirectives, substream = event[1]

                if isinstance(subdirectives[0], SingularDirective):
                    singular_stream = list(
                        _apply_directives(substream, subdirectives, ctxt,
                                          vars))
                    new_stream.append((MSGBUF, None, (None, -1, -1)))

                elif isinstance(subdirectives[0], PluralDirective):
                    if is_plural:
                        plural_stream = list(
                            _apply_directives(substream, subdirectives, ctxt,
                                              vars))

            else:
                new_stream.append(event)

        if ctxt.get('_i18n.domain'):
            ngettext = lambda s, p, n: dngettext(ctxt.get('_i18n.domain'), s,
                                                 p, n)

        singular_msgbuf = ctxt.get('_i18n.choose.singular')
        if is_plural:
            plural_msgbuf = ctxt.get('_i18n.choose.plural')
            msgbuf, choice = plural_msgbuf, plural_stream
        else:
            msgbuf, choice = singular_msgbuf, singular_stream
            plural_msgbuf = MessageBuffer(self)

        for kind, data, pos in new_stream:
            if kind is MSGBUF:
                for event in choice:
                    if event[0] is MSGBUF:
                        translation = ngettext(singular_msgbuf.format(),
                                               plural_msgbuf.format(), numeral)
                        for subevent in msgbuf.translate(translation):
                            yield subevent
                    else:
                        yield event
            else:
                yield kind, data, pos

        ctxt.pop()
Exemple #5
0
    def __call__(self, stream):
        """Apply the filter to the given stream.
        
        :param stream: the markup event stream to filter
        """
        in_form = in_select = in_option = in_textarea = False
        select_value = option_value = textarea_value = None
        option_start = None
        option_text = []
        no_option_value = False

        for kind, data, pos in stream:

            if kind is START:
                tag, attrs = data
                tagname = tag.localname

                if tagname == 'form' and (
                        self.name and attrs.get('name') == self.name or
                        self.id and attrs.get('id') == self.id or
                        not (self.id or self.name)):
                    in_form = True

                elif in_form:
                    if tagname == 'input':
                        type = attrs.get('type', '').lower()
                        if type in ('checkbox', 'radio'):
                            name = attrs.get('name')
                            if name and name in self.data:
                                value = self.data[name]
                                declval = attrs.get('value')
                                checked = False
                                if isinstance(value, (list, tuple)):
                                    if declval is not None:
                                        checked = declval in [unicode(v) for v
                                                              in value]
                                    else:
                                        checked = any(value)
                                else:
                                    if declval is not None:
                                        checked = declval == unicode(value)
                                    elif type == 'checkbox':
                                        checked = bool(value)
                                if checked:
                                    attrs |= [(QName('checked'), 'checked')]
                                elif 'checked' in attrs:
                                    attrs -= 'checked'
                        elif type in ('', 'hidden', 'text') \
                                or type == 'password' and self.passwords:
                            name = attrs.get('name')
                            if name and name in self.data:
                                value = self.data[name]
                                if isinstance(value, (list, tuple)):
                                    value = value[0]
                                if value is not None:
                                    attrs |= [
                                        (QName('value'), unicode(value))
                                    ]
                    elif tagname == 'select':
                        name = attrs.get('name')
                        if name in self.data:
                            select_value = self.data[name]
                            in_select = True
                    elif tagname == 'textarea':
                        name = attrs.get('name')
                        if name in self.data:
                            textarea_value = self.data.get(name)
                            if isinstance(textarea_value, (list, tuple)):
                                textarea_value = textarea_value[0]
                            in_textarea = True
                    elif in_select and tagname == 'option':
                        option_start = kind, data, pos
                        option_value = attrs.get('value')
                        if option_value is None:
                            no_option_value = True
                            option_value = ''
                        in_option = True
                        continue
                yield kind, (tag, attrs), pos

            elif in_form and kind is TEXT:
                if in_select and in_option:
                    if no_option_value:
                        option_value += data
                    option_text.append((kind, data, pos))
                    continue
                elif in_textarea:
                    continue
                yield kind, data, pos

            elif in_form and kind is END:
                tagname = data.localname
                if tagname == 'form':
                    in_form = False
                elif tagname == 'select':
                    in_select = False
                    select_value = None
                elif in_select and tagname == 'option':
                    if isinstance(select_value, (tuple, list)):
                        selected = option_value in [unicode(v) for v
                                                    in select_value]
                    else:
                        selected = option_value == unicode(select_value)
                    okind, (tag, attrs), opos = option_start
                    if selected:
                        attrs |= [(QName('selected'), 'selected')]
                    elif 'selected' in attrs:
                        attrs -= 'selected'
                    yield okind, (tag, attrs), opos
                    if option_text:
                        for event in option_text:
                            yield event
                    in_option = False
                    no_option_value = False
                    option_start = option_value = None
                    option_text = []
                elif in_textarea and tagname == 'textarea':
                    if textarea_value:
                        yield TEXT, unicode(textarea_value), pos
                        textarea_value = None
                    in_textarea = False
                yield kind, data, pos

            else:
                yield kind, data, pos
Exemple #6
0
    def __call__(self, stream, ctxt=None, translate_text=True,
                 translate_attrs=True):
        """Translate any localizable strings in the given stream.
        
        This function shouldn't be called directly. Instead, an instance of
        the `Translator` class should be registered as a filter with the
        `Template` or the `TemplateLoader`, or applied as a regular stream
        filter. If used as a template filter, it should be inserted in front of
        all the default filters.
        
        :param stream: the markup event stream
        :param ctxt: the template context (not used)
        :param translate_text: whether text nodes should be translated (used
                               internally)
        :param translate_attrs: whether attribute values should be translated
                                (used internally)
        :return: the localized stream
        """
        ignore_tags = self.ignore_tags
        include_attrs = self.include_attrs
        skip = 0
        xml_lang = XML_NAMESPACE['lang']
        if not self.extract_text:
            translate_text = False
            translate_attrs = False

        if type(self.translate) is FunctionType:
            gettext = self.translate
            if ctxt:
                ctxt['_i18n.gettext'] = gettext
        else:
            if IS_PYTHON2:
                gettext = self.translate.ugettext
                ngettext = self.translate.ungettext
            else:
                gettext = self.translate.gettext
                ngettext = self.translate.ngettext
            try:
                if IS_PYTHON2:
                    dgettext = self.translate.dugettext
                    dngettext = self.translate.dungettext
                else:
                    dgettext = self.translate.dgettext
                    dngettext = self.translate.dngettext
            except AttributeError:
                dgettext = lambda _, y: gettext(y)
                dngettext = lambda _, s, p, n: ngettext(s, p, n)
            if ctxt:
                ctxt['_i18n.gettext'] = gettext
                ctxt['_i18n.ngettext'] = ngettext
                ctxt['_i18n.dgettext'] = dgettext
                ctxt['_i18n.dngettext'] = dngettext

        if ctxt and ctxt.get('_i18n.domain'):
            # TODO: This can cause infinite recursion if dgettext is defined
            #       via the AttributeError case above!
            gettext = lambda msg: dgettext(ctxt.get('_i18n.domain'), msg)

        for kind, data, pos in stream:

            # skip chunks that should not be localized
            if skip:
                if kind is START:
                    skip += 1
                elif kind is END:
                    skip -= 1
                yield kind, data, pos
                continue

            # handle different events that can be localized
            if kind is START:
                tag, attrs = data
                if tag in self.ignore_tags or \
                        isinstance(attrs.get(xml_lang), basestring):
                    skip += 1
                    yield kind, data, pos
                    continue

                new_attrs = []
                changed = False

                for name, value in attrs:
                    newval = value
                    if isinstance(value, basestring):
                        if translate_attrs and name in include_attrs:
                            newval = gettext(value)
                    else:
                        newval = list(
                            self(_ensure(value), ctxt, translate_text=False)
                        )
                    if newval != value:
                        value = newval
                        changed = True
                    new_attrs.append((name, value))
                if changed:
                    attrs = Attrs(new_attrs)

                yield kind, (tag, attrs), pos

            elif translate_text and kind is TEXT:
                text = data.strip()
                if text:
                    data = data.replace(text, unicode(gettext(text)))
                yield kind, data, pos

            elif kind is SUB:
                directives, substream = data
                current_domain = None
                for idx, directive in enumerate(directives):
                    # Organize directives to make everything work
                    # FIXME: There's got to be a better way to do this!
                    if isinstance(directive, DomainDirective):
                        # Grab current domain and update context
                        current_domain = directive.domain
                        ctxt.push({'_i18n.domain': current_domain})
                        # Put domain directive as the first one in order to
                        # update context before any other directives evaluation
                        directives.insert(0, directives.pop(idx))

                # If this is an i18n directive, no need to translate text
                # nodes here
                is_i18n_directive = any([
                    isinstance(d, ExtractableI18NDirective)
                    for d in directives
                ])
                substream = list(self(substream, ctxt,
                                      translate_text=not is_i18n_directive,
                                      translate_attrs=translate_attrs))
                yield kind, (directives, substream), pos

                if current_domain:
                    ctxt.pop()
            else:
                yield kind, data, pos
Exemple #7
0
    def __call__(self, stream):
        """Apply the filter to the given stream.
        
        :param stream: the markup event stream to filter
        """
        in_form = in_select = in_option = in_textarea = False
        select_value = option_value = textarea_value = None
        option_start = None
        option_text = []
        no_option_value = False

        for kind, data, pos in stream:

            if kind is START:
                tag, attrs = data
                tagname = tag.localname

                if tagname == "form" and (
                    self.name
                    and attrs.get("name") == self.name
                    or self.id
                    and attrs.get("id") == self.id
                    or not (self.id or self.name)
                ):
                    in_form = True

                elif in_form:
                    if tagname == "input":
                        type = attrs.get("type", "").lower()
                        if type in ("checkbox", "radio"):
                            name = attrs.get("name")
                            if name and name in self.data:
                                value = self.data[name]
                                declval = attrs.get("value")
                                checked = False
                                if isinstance(value, (list, tuple)):
                                    if declval:
                                        checked = declval in [unicode(v) for v in value]
                                    else:
                                        checked = any(value)
                                else:
                                    if declval:
                                        checked = declval == unicode(value)
                                    elif type == "checkbox":
                                        checked = bool(value)
                                if checked:
                                    attrs |= [(QName("checked"), "checked")]
                                elif "checked" in attrs:
                                    attrs -= "checked"
                        elif type in ("", "hidden", "text") or type == "password" and self.passwords:
                            name = attrs.get("name")
                            if name and name in self.data:
                                value = self.data[name]
                                if isinstance(value, (list, tuple)):
                                    value = value[0]
                                if value is not None:
                                    attrs |= [(QName("value"), unicode(value))]
                    elif tagname == "select":
                        name = attrs.get("name")
                        if name in self.data:
                            select_value = self.data[name]
                            in_select = True
                    elif tagname == "textarea":
                        name = attrs.get("name")
                        if name in self.data:
                            textarea_value = self.data.get(name)
                            if isinstance(textarea_value, (list, tuple)):
                                textarea_value = textarea_value[0]
                            in_textarea = True
                    elif in_select and tagname == "option":
                        option_start = kind, data, pos
                        option_value = attrs.get("value")
                        if option_value is None:
                            no_option_value = True
                            option_value = ""
                        in_option = True
                        continue
                yield kind, (tag, attrs), pos

            elif in_form and kind is TEXT:
                if in_select and in_option:
                    if no_option_value:
                        option_value += data
                    option_text.append((kind, data, pos))
                    continue
                elif in_textarea:
                    continue
                yield kind, data, pos

            elif in_form and kind is END:
                tagname = data.localname
                if tagname == "form":
                    in_form = False
                elif tagname == "select":
                    in_select = False
                    select_value = None
                elif in_select and tagname == "option":
                    if isinstance(select_value, (tuple, list)):
                        selected = option_value in [unicode(v) for v in select_value]
                    else:
                        selected = option_value == unicode(select_value)
                    okind, (tag, attrs), opos = option_start
                    if selected:
                        attrs |= [(QName("selected"), "selected")]
                    elif "selected" in attrs:
                        attrs -= "selected"
                    yield okind, (tag, attrs), opos
                    if option_text:
                        for event in option_text:
                            yield event
                    in_option = False
                    no_option_value = False
                    option_start = option_value = None
                    option_text = []
                elif tagname == "textarea":
                    if textarea_value:
                        yield TEXT, unicode(textarea_value), pos
                    in_textarea = False
                yield kind, data, pos

            else:
                yield kind, data, pos