Mercurial > genshi > mirror
diff genshi/filters/i18n.py @ 790:da90cee22560 trunk
Merged the custom-directives branch back into trunk.
author | cmlenz |
---|---|
date | Wed, 10 Sep 2008 20:53:09 +0000 |
parents | 31432f30a6fb |
children | f9e23d472a6e |
line wrap: on
line diff
--- a/genshi/filters/i18n.py +++ b/genshi/filters/i18n.py @@ -23,7 +23,8 @@ from genshi.core import Attrs, Namespace, QName, START, END, TEXT, START_NS, \ END_NS, XML_NAMESPACE, _ensure -from genshi.template.base import Template, EXPR, SUB +from genshi.template.base import DirectiveFactory, EXPR, SUB, _apply_directives +from genshi.template.directives import Directive from genshi.template.markup import MarkupTemplate, EXEC __all__ = ['Translator', 'extract'] @@ -32,7 +33,42 @@ I18N_NAMESPACE = Namespace('http://genshi.edgewall.org/i18n') -class Translator(object): +class CommentDirective(Directive): + + __slots__ = [] + + @classmethod + def attach(cls, template, stream, value, namespaces, pos): + return None, stream + + +class MsgDirective(Directive): + + __slots__ = ['params'] + + def __init__(self, value, template, hints=None, namespaces=None, + lineno=-1, offset=-1): + Directive.__init__(self, None, template, namespaces, lineno, offset) + self.params = [name.strip() for name in value.split(',')] + + def __call__(self, stream, directives, ctxt, **vars): + msgbuf = MessageBuffer(self.params) + + stream = iter(stream) + yield stream.next() # the outer start tag + previous = stream.next() + for event in stream: + msgbuf.append(*previous) + previous = event + + gettext = ctxt.get('_i18n.gettext') + for event in msgbuf.translate(gettext(msgbuf.format())): + yield event + + yield previous # the outer end tag + + +class Translator(DirectiveFactory): """Can extract and translate localizable strings from markup streams and templates. @@ -85,12 +121,18 @@ exclude specific parts of a template from being extracted and translated. """ + directives = [ + ('comment', CommentDirective), + ('msg', MsgDirective) + ] + IGNORE_TAGS = frozenset([ QName('script'), QName('http://www.w3.org/1999/xhtml}script'), QName('style'), QName('http://www.w3.org/1999/xhtml}style') ]) INCLUDE_ATTRS = frozenset(['abbr', 'alt', 'label', 'prompt', 'standby', 'summary', 'title']) + NAMESPACE = I18N_NAMESPACE def __init__(self, translate=NullTranslations(), ignore_tags=IGNORE_TAGS, include_attrs=INCLUDE_ATTRS, extract_text=True): @@ -113,7 +155,7 @@ self.include_attrs = include_attrs self.extract_text = extract_text - def __call__(self, stream, ctxt=None, search_text=True, msgbuf=None): + def __call__(self, stream, ctxt=None, search_text=True): """Translate any localizable strings in the given stream. This function shouldn't be called directly. Instead, an instance of @@ -126,23 +168,23 @@ :param ctxt: the template context (not used) :param search_text: whether text nodes should be translated (used internally) - :param msgbuf: a `MessageBuffer` object or `None` (used internally) :return: the localized stream """ ignore_tags = self.ignore_tags include_attrs = self.include_attrs + skip = 0 + xml_lang = XML_NAMESPACE['lang'] + if type(self.translate) is FunctionType: gettext = self.translate else: gettext = self.translate.ugettext - if not self.extract_text: - search_text = False + if ctxt: + ctxt['_i18n.gettext'] = gettext - ns_prefixes = [] - skip = 0 - i18n_comment = I18N_NAMESPACE['comment'] - i18n_msg = I18N_NAMESPACE['msg'] - xml_lang = XML_NAMESPACE['lang'] + extract_text = self.extract_text + if not extract_text: + search_text = False for kind, data, pos in stream: @@ -168,7 +210,7 @@ changed = False for name, value in attrs: newval = value - if search_text and isinstance(value, basestring): + if extract_text and isinstance(value, basestring): if name in include_attrs: newval = gettext(value) else: @@ -182,48 +224,23 @@ if changed: attrs = Attrs(new_attrs) - if msgbuf: - msgbuf.append(kind, data, pos) - continue - elif i18n_msg in attrs: - params = attrs.get(i18n_msg) - if params and type(params) is list: # event tuple - params = params[0][1] - msgbuf = MessageBuffer(params) - attrs -= (i18n_comment, i18n_msg) - yield kind, (tag, attrs), pos elif search_text and kind is TEXT: - if not msgbuf: - text = data.strip() - if text: - data = data.replace(text, unicode(gettext(text))) - yield kind, data, pos - else: - msgbuf.append(kind, data, pos) - - elif msgbuf and kind is EXPR: - msgbuf.append(kind, data, pos) - - elif not skip and msgbuf and kind is END: - msgbuf.append(kind, data, pos) - if not msgbuf.depth: - for event in msgbuf.translate(gettext(msgbuf.format())): - yield event - msgbuf = None - yield kind, data, pos + text = data.strip() + if text: + data = data.replace(text, unicode(gettext(text))) + yield kind, data, pos elif kind is SUB: - subkind, substream = data - new_substream = list(self(substream, ctxt, msgbuf=msgbuf)) - yield kind, (subkind, new_substream), pos - - elif kind is START_NS and data[1] == I18N_NAMESPACE: - ns_prefixes.append(data[0]) - - elif kind is END_NS and data in ns_prefixes: - ns_prefixes.remove(data) + directives, substream = data + # If this is an i18n:msg directive, no need to translate text + # nodes here + is_msg = filter(None, [isinstance(d, MsgDirective) + for d in directives]) + substream = list(self(substream, ctxt, + search_text=not is_msg)) + yield kind, (directives, substream), pos else: yield kind, data, pos @@ -372,7 +389,9 @@ :param lineno: the line number on which the first stream event belonging to the message was found """ - self.params = [name.strip() for name in params.split(',')] + if isinstance(params, basestring): + params = [name.strip() for name in params.split(',')] + self.params = params self.comment = comment self.lineno = lineno self.string = []