Commit 72c0de0c authored by Florent Guillaume's avatar Florent Guillaume

Merged changes from the Zope-2_6-branch:

Modified the translation service to return None if no translation exist.
So now using i18n tags without a translation service should give the
same behavior as before. The tests reflect that.
parent f2fc170b
...@@ -277,7 +277,9 @@ Zope Changes ...@@ -277,7 +277,9 @@ Zope Changes
- xmlrpclib has been updated to the Python 2.2 version, which includes - xmlrpclib has been updated to the Python 2.2 version, which includes
support for the Expat parser for unmarshalling data, which speeds up support for the Expat parser for unmarshalling data, which speeds up
things considerably. things considerably.
- Added i18n support in TAL processing
Zope 2.6.0 alpha 1 Zope 2.6.0 alpha 1
Features Added Features Added
......
...@@ -13,14 +13,14 @@ ...@@ -13,14 +13,14 @@
############################################################################## ##############################################################################
"""Global Translation Service for providing I18n to Page Templates. """Global Translation Service for providing I18n to Page Templates.
$Id: GlobalTranslationService.py,v 1.2 2002/09/18 15:12:46 efge Exp $ $Id: GlobalTranslationService.py,v 1.3 2002/10/06 17:21:07 efge Exp $
""" """
class DummyTranslationService: class DummyTranslationService:
"""Translation service that does nothing and returns the message id.""" """Translation service that doesn't know anything about translation."""
def translate(self, domain, msgid, mapping=None, def translate(self, domain, msgid, mapping=None,
context=None, target_language=None): context=None, target_language=None):
return msgid return None
# XXX Not all of Zope.I18n.ITranslationService is implemented. # XXX Not all of Zope.I18n.ITranslationService is implemented.
translationService = DummyTranslationService() translationService = DummyTranslationService()
......
<html> <html>
<body> <body>
<head> <head>
<p i18n:translate="foobar">baz</p> <p i18n:domain="foo" i18n:translate="bar">baz</p>
<a href="foo" alt="alttext" i18n:attributes="alt">link</a>
<p i18n:domain="dom" i18n:translate="">
<span tal:replace="string:Lomax" i18n:name="name" /> was born in
<span tal:replace="string:Antarctica" i18n:name="country" />.
</p>
</head> </head>
</body> </body>
</html> </html>
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
<body> <body>
<head> <head>
<p i18n:domain="foo" i18n:translate="bar">baz</p> <p i18n:domain="foo" i18n:translate="bar">baz</p>
<a href="foo" alt="alttext" i18n:attributes="alt">link</a>
<p i18n:domain="dom" i18n:translate="">
<span tal:replace="string:Lomax" i18n:name="name" /> was born in
<span tal:replace="string:Antarctica" i18n:name="country" />.
</p>
</head> </head>
</body> </body>
</html> </html>
<html> <html>
<body> <body>
<head> <head>
<p>foobar</p> <p>baz</p>
<a href="foo" alt="alttext">link</a>
<p>
Lomax was born in
Antarctica.
</p>
</head> </head>
</body> </body>
</html> </html>
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
<body> <body>
<head> <head>
<p>[foo](bar)</p> <p>[foo](bar)</p>
<a href="foo" alt="[default](alttext)">link</a>
<p>[dom](${name} was born in ${country}.)</p>
</head> </head>
</body> </body>
</html> </html>
...@@ -47,6 +47,23 @@ def normalize(text): ...@@ -47,6 +47,23 @@ def normalize(text):
return ' '.join(text.split()) return ' '.join(text.split())
NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
_interp_regex = re.compile(r'(?<!\$)(\$(?:%(n)s|{%(n)s}))' %({'n': NAME_RE}))
_get_var_regex = re.compile(r'%(n)s' %({'n': NAME_RE}))
def interpolate(text, mapping):
"""Interpolate ${keyword} substitutions."""
if not mapping:
return text
# Find all the spots we want to substitute.
to_replace = _interp_regex.findall(text)
# Now substitute with the variables in mapping.
for string in to_replace:
var = _get_var_regex.findall(string)[0]
text = text.replace(string, mapping.get(var))
return text
class AltTALGenerator(TALGenerator): class AltTALGenerator(TALGenerator):
def __init__(self, repldict, expressionCompiler=None, xml=0): def __init__(self, repldict, expressionCompiler=None, xml=0):
...@@ -348,7 +365,11 @@ class TALInterpreter: ...@@ -348,7 +365,11 @@ class TALInterpreter:
def i18n_attribute(self, s): def i18n_attribute(self, s):
# s is the value of an attribute before translation # s is the value of an attribute before translation
# it may have been computed # it may have been computed
return self.translate(s, {}) xlated = self.translate(s, {})
if xlated is None:
return s
else:
return xlated
def no_tag(self, start, program): def no_tag(self, start, program):
state = self.saveState() state = self.saveState()
...@@ -518,25 +539,35 @@ class TALInterpreter: ...@@ -518,25 +539,35 @@ class TALInterpreter:
# subnodes, which should /not/ go to the output stream. # subnodes, which should /not/ go to the output stream.
tmpstream = self.StringIO() tmpstream = self.StringIO()
self.interpretWithStream(stuff[1], tmpstream) self.interpretWithStream(stuff[1], tmpstream)
content = None
# We only care about the evaluated contents if we need an implicit # We only care about the evaluated contents if we need an implicit
# message id. All other useful information will be in the i18ndict on # message id. All other useful information will be in the i18ndict on
# the top of the i18nStack. # the top of the i18nStack.
if msgid == '': if msgid == '':
msgid = normalize(tmpstream.getvalue()) content = tmpstream.getvalue()
msgid = normalize(content)
self.i18nStack.pop() self.i18nStack.pop()
# See if there is was an i18n:data for msgid # See if there is was an i18n:data for msgid
if len(stuff) > 2: if len(stuff) > 2:
obj = self.engine.evaluate(stuff[2]) obj = self.engine.evaluate(stuff[2])
xlated_msgid = self.translate(msgid, i18ndict, obj) xlated_msgid = self.translate(msgid, i18ndict, obj)
# XXX I can't decide whether we want to cgi escape the translated # If there is no translation available, use evaluated content.
# string or not. OT1H not doing this could introduce a cross-site if xlated_msgid is None:
# scripting vector by allowing translators to sneak JavaScript into if content is None:
# translations. OTOH, for implicit interpolation values, we don't content = tmpstream.getvalue()
# want to escape stuff like ${name} <= "<b>Timmy</b>". # We must do potential substitutions "by hand".
#s = escape(xlated_msgid) s = interpolate(content, i18ndict)
s = xlated_msgid else:
# XXX I can't decide whether we want to cgi escape the translated
# string or not. OT1H not doing this could introduce a cross-site
# scripting vector by allowing translators to sneak JavaScript into
# translations. OTOH, for implicit interpolation values, we don't
# want to escape stuff like ${name} <= "<b>Timmy</b>".
#s = escape(xlated_msgid)
s = xlated_msgid
# If there are i18n variables to interpolate into this string, better # If there are i18n variables to interpolate into this string, better
# do it now. # do it now.
# XXX efge: actually, this is already done by the translation service.
self._stream_write(s) self._stream_write(s)
bytecode_handlers['insertTranslation'] = do_insertTranslation bytecode_handlers['insertTranslation'] = do_insertTranslation
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment