diff options
author | Godefroid Chapelle <gotcha@bubblenet.be> | 2005-09-24 20:51:36 +0000 |
---|---|---|
committer | Godefroid Chapelle <gotcha@bubblenet.be> | 2005-09-24 20:51:36 +0000 |
commit | 3ea3d8f217c85720ad8976da55d6e6f17967bd49 (patch) | |
tree | 5104cbf872443d8b81c4f5573b20a07e8d44d47c | |
parent | b0b9d011f3d12438e8f6f612fd754c58b461891c (diff) | |
download | zope-tal-3ea3d8f217c85720ad8976da55d6e6f17967bd49.tar.gz |
improve multiple domains i18n tests; fix tests; then fix interpreter
-rw-r--r-- | dummyengine.py | 100 | ||||
-rw-r--r-- | talinterpreter.py | 4 | ||||
-rw-r--r-- | tests/test_talinterpreter.py | 112 |
3 files changed, 97 insertions, 119 deletions
diff --git a/dummyengine.py b/dummyengine.py index aa76c62..4dbe489 100644 --- a/dummyengine.py +++ b/dummyengine.py @@ -265,6 +265,19 @@ class DummyTranslationDomain(object): domain = '' + msgids = {} + + def appendMsgid(self, domain, data): + if not self.msgids.has_key(domain): + self.msgids[domain] = [] + self.msgids[domain].append(data) + + def getMsgids(self, domain): + return self.msgids[domain] + + def clearMsgids(self): + self.msgids = {} + def translate(self, msgid, mapping=None, context=None, target_language=None, default=None): @@ -293,94 +306,27 @@ class DummyTranslationDomain(object): elif domain and hasattr('', domain): text = getattr(msgid, domain)() else: + domain = 'default' text = msgid.upper() + self.appendMsgid(domain, (msgid, mapping)) + def repl(m): return unicode(mapping[m.group(m.lastindex).lower()]) cre = re.compile(r'\$(?:([_A-Za-z][-\w]*)|\{([_A-Za-z][-\w]*)\})') return cre.sub(repl, text) - class MultipleDomainsDummyEngine(DummyEngine): - def __init__(self, macros=None): - if macros is None: - macros = {} - self.macros = macros - dict = {'nothing': None, 'default': Default} - self.locals = self.globals = dict - self.stack = [dict] - self.translationDomain = DummyTranslationDomain() - self.lowerDomain = LowerDummyDomain() - self.useEngineAttrDicts = False - def translate(self, msgid, domain=None, mapping=None, default=None): + if isinstance(msgid, (MessageID, Message)): domain = msgid.domain - if domain in ['lower', 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine']: - translationDomain = self.lowerDomain - else: - translationDomain = self.translationDomain - translationDomain.domain = domain - return translationDomain.translate( + + if domain == 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine': + domain = 'lower' + + self.translationDomain.domain = domain + return self.translationDomain.translate( msgid, mapping, default=default) -class LowerDummyDomain(object): - implements(ITranslationDomain) - - domain = '' - - def translate(self, msgid, mapping=None, context=None, - target_language=None, default=None): - - domain = self.domain - # This is a fake translation service which simply uppercases non - # ${name} placeholder text in the message id. - # - # First, transform a string with ${name} placeholders into a list of - # substrings. Then lowcase everything but the placeholders, then glue - # things back together. - - # If the domain is a string method, then transform the string - # by calling that method. - - # MessageID attributes override arguments - if isinstance(msgid, (MessageID, Message)): - domain = msgid.domain - mapping = msgid.mapping - default = msgid.default - if default is None: # Message doesn't substitute itself for - default = msgid # missing default - - # simulate an unknown msgid by returning None - if msgid == "don't translate me": - text = default - elif domain and hasattr('', domain): - text = getattr(msgid, domain)() - else: - text = msgid.lower() - - def repl(m): - return unicode(mapping[m.group(m.lastindex).lower()]) - cre = re.compile(r'\$(?:([_A-Za-z][-\w]*)|\{([_A-Za-z][-\w]*)\})') - return cre.sub(repl, text) - - def translate(self, msgid, mapping=None, context=None, - target_language=None, default=None): - # This is a fake translation service which simply lowercases non - # ${name} placeholder text in the message id. - # - # First, transform a string with ${name} placeholders into a list of - # substrings. Then upcase everything but the placeholders, then glue - # things back together. - - # simulate an unknown msgid by returning None - if msgid == "don't translate me": - text = default - else: - text = msgid.lower() - - def repl(m, mapping=mapping): - return ustr(mapping[m.group(m.lastindex).lower()]) - cre = re.compile(r'\$(?:(%s)|\{(%s)\})' % (NAME_RE, NAME_RE)) - return cre.sub(repl, text) diff --git a/talinterpreter.py b/talinterpreter.py index d4f16d4..3d09b34 100644 --- a/talinterpreter.py +++ b/talinterpreter.py @@ -19,6 +19,8 @@ import cgi import operator import sys +from types import StringType, UnicodeType + # Do not use cStringIO here! It's not unicode aware. :( from StringIO import StringIO @@ -651,6 +653,8 @@ class TALInterpreter(object): return if isinstance(text, I18nMessageTypes): text = self.engine.translate(text) + elif isinstance(text, (StringType, UnicodeType)): + text = self.engine.translate(text, domain=self.i18nContext.domain) self._writeText(text) def do_i18nVariable(self, stuff): diff --git a/tests/test_talinterpreter.py b/tests/test_talinterpreter.py index 270e17b..8f31958 100644 --- a/tests/test_talinterpreter.py +++ b/tests/test_talinterpreter.py @@ -22,9 +22,6 @@ import unittest from StringIO import StringIO -from zope.interface import implements -from zope.i18n.interfaces import ITranslationDomain - from zope.tal.taldefs import METALError, I18NError, TAL_VERSION from zope.tal.htmltalparser import HTMLTALParser from zope.tal.talparser import TALParser @@ -127,10 +124,6 @@ class MacroExtendTestCase(TestCaseBase): self.assertEqual(actual, expected) - - - - class I18NCornerTestCaseBase(TestCaseBase): def factory(self, msgid, default, mapping={}): @@ -221,10 +214,16 @@ class I18NCornerTestCaseBase(TestCaseBase): def test_translate_static_text_as_dynamic(self): program, macros = self._compile( '<div i18n:translate="">This is text for ' - '<span i18n:translate="" tal:content="bar" i18n:name="bar_name"/>.' + '<span tal:content="bar" i18n:name="bar_name"/>.' '</div>') self._check(program, '<div>THIS IS TEXT FOR <span>BaRvAlUe</span>.</div>\n') + program, macros = self._compile( + '<div i18n:translate="">This is text for ' + '<span i18n:translate="" tal:content="bar" i18n:name="bar_name"/>.' + '</div>') + self._check(program, + '<div>THIS IS TEXT FOR <span>BARVALUE</span>.</div>\n') def test_translate_static_text_as_dynamic_from_bytecode(self): program = [('version', TAL_VERSION), @@ -259,32 +258,24 @@ class I18NCornerTestCaseBase(TestCaseBase): self._check(program, '<div>THIS IS TEXT FOR <span>BARVALUE</span>.</div>\n') - def _getCollectingTranslationDomain(self): - class CollectingTranslationDomain(DummyTranslationDomain): - data = [] - - def translate(self, msgid, mapping=None, - context=None, target_language=None, default=None): - self.data.append((msgid, mapping)) - return DummyTranslationDomain.translate( - self, - msgid, mapping, context, target_language, default) - - xlatdmn = CollectingTranslationDomain() - self.engine.translationDomain = xlatdmn - return xlatdmn - def test_for_correct_msgids(self): - xlatdmn = self._getCollectingTranslationDomain() + self.engine.translationDomain.clearMsgids() result = StringIO() + #GChapelle: + #I have the feeling the i18n:translate with the i18n:name is wrong + # + #program, macros = self._compile( + # '<div i18n:translate="">This is text for ' + # '<span i18n:translate="" tal:content="bar" ' + # 'i18n:name="bar_name"/>.</div>') program, macros = self._compile( '<div i18n:translate="">This is text for ' - '<span i18n:translate="" tal:content="bar" ' + '<span tal:content="bar" ' 'i18n:name="bar_name"/>.</div>') self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() - msgids = list(xlatdmn.data) + msgids = self.engine.translationDomain.getMsgids('default') msgids.sort() self.assertEqual(1, len(msgids)) self.assertEqual('This is text for ${bar_name}.', msgids[0][0]) @@ -293,10 +284,29 @@ class I18NCornerTestCaseBase(TestCaseBase): '<div>THIS IS TEXT FOR <span>BaRvAlUe</span>.</div>\n', result.getvalue()) + def test_for_correct_msgids_translate_name(self): + self.engine.translationDomain.clearMsgids() + result = StringIO() + program, macros = self._compile( + '<div i18n:translate="">This is text for ' + '<span i18n:translate="" tal:content="bar" ' + 'i18n:name="bar_name"/>.</div>') + self.interpreter = TALInterpreter(program, {}, self.engine, + stream=result) + self.interpreter() + msgids = self.engine.translationDomain.getMsgids('default') + msgids.sort() + self.assertEqual(2, len(msgids)) + self.assertEqual('This is text for ${bar_name}.', msgids[1][0]) + self.assertEqual({'bar_name': '<span>BARVALUE</span>'}, msgids[1][1]) + self.assertEqual( + '<div>THIS IS TEXT FOR <span>BARVALUE</span>.</div>\n', + result.getvalue()) + def test_i18ntranslate_i18nname_and_attributes(self): # Test for Issue 301: Bug with i18n:name and i18n:translate # on the same element - xlatdmn = self._getCollectingTranslationDomain() + self.engine.translationDomain.clearMsgids() result = StringIO() program, macros = self._compile( '<p i18n:translate="">' @@ -305,7 +315,7 @@ class I18NCornerTestCaseBase(TestCaseBase): self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() - msgids = list(xlatdmn.data) + msgids = self.engine.translationDomain.getMsgids('default') msgids.sort() self.assertEqual(2, len(msgids)) self.assertEqual('Some static text and a ${link}.', msgids[0][0]) @@ -319,7 +329,7 @@ class I18NCornerTestCaseBase(TestCaseBase): # Test for Issue 314: i18n:translate removes line breaks from # <pre>...</pre> contents # HTML mode - xlatdmn = self._getCollectingTranslationDomain() + self.engine.translationDomain.clearMsgids() result = StringIO() program, macros = self._compile( '<div i18n:translate=""> This is text\n' @@ -329,7 +339,7 @@ class I18NCornerTestCaseBase(TestCaseBase): self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() - msgids = list(xlatdmn.data) + msgids = self.engine.translationDomain.getMsgids('default') msgids.sort() self.assertEqual(2, len(msgids)) self.assertEqual(' This is text\n <b>\tfor</b>\n pre. ', msgids[0][0]) @@ -340,7 +350,7 @@ class I18NCornerTestCaseBase(TestCaseBase): result.getvalue()) # XML mode - xlatdmn = self._getCollectingTranslationDomain() + self.engine.translationDomain.clearMsgids() result = StringIO() parser = TALParser() parser.parseString( @@ -352,7 +362,7 @@ class I18NCornerTestCaseBase(TestCaseBase): self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() - msgids = list(xlatdmn.data) + msgids = self.engine.translationDomain.getMsgids('default') msgids.sort() self.assertEqual(1, len(msgids)) self.assertEqual('This is text <b> for</b> barvalue.', msgids[0][0]) @@ -362,7 +372,7 @@ class I18NCornerTestCaseBase(TestCaseBase): result.getvalue()) def test_raw_msgids_and_i18ntranslate_i18nname(self): - xlatdmn = self._getCollectingTranslationDomain() + self.engine.translationDomain.clearMsgids() result = StringIO() program, macros = self._compile( '<div i18n:translate=""> This is text\n \tfor\n' @@ -370,7 +380,7 @@ class I18NCornerTestCaseBase(TestCaseBase): self.interpreter = TALInterpreter(program, {}, self.engine, stream=result) self.interpreter() - msgids = list(xlatdmn.data) + msgids = self.engine.translationDomain.getMsgids('default') msgids.sort() self.assertEqual(2, len(msgids)) self.assertEqual(' \tbar\n ', msgids[0][0]) @@ -405,20 +415,19 @@ class UnusedExplicitDomainTestCase(I18NCornerTestCaseMessageID): def setUp(self): + # MultipleDomainsDummyEngine is a Engine + # where default domain transforms to uppercase self.engine = MultipleDomainsDummyEngine() - # Make sure we'll translate the msgid not its unicode representation self.engine.setLocal('foo', self.factory('FoOvAlUe${empty}', 'default', {'empty': ''})) self.engine.setLocal('bar', 'BaRvAlUe') self.engine.setLocal('baz', self.factory('BaZvAlUe', 'default', {})) # Message ids with different domains - self.engine.setLocal('tolower', - self.factory('ToLower', 'default', {}, domain='lower')) self.engine.setLocal('toupper', self.factory('ToUpper', 'default', {})) - self.engine.setLocal('othertolower', - self.factory('OtherToLower', 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine', {}, domain='lower')) + self.engine.setLocal('tolower', + self.factory('ToLower', 'default', {}, domain='lower')) def test_multiple_domains(self): program, macros = self._compile( @@ -431,11 +440,30 @@ class UnusedExplicitDomainTestCase(I18NCornerTestCaseMessageID): self._check(program, '<div>tolower</div>\n') program, macros = self._compile( '<div i18n:translate=""' - ' tal:content="othertolower" />') - self._check(program, '<div>othertolower</div>\n') - + ' tal:content="string:ToUpper" />') + self._check(program, '<div>TOUPPER</div>\n') + program, macros = self._compile( + '<div i18n:translate=""' + ' i18n:domain="lower"' + ' tal:content="string:ToLower" />') + self._check(program, '<div>tolower</div>\n') def test_unused_explicit_domain(self): + #a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine + #is a domain that transforms to lowercase + self.engine.setLocal('othertolower', + self.factory('OtherToLower', 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine', {}, domain='lower')) + program, macros = self._compile( + '<div i18n:translate=""' + ' tal:content="othertolower" />') + self._check(program, '<div>othertolower</div>\n') + #takes domain into account for strings + program, macros = self._compile( + '<div i18n:translate=""' + ' i18n:domain="a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine"' + ' tal:content="string:ToLower" />') + self._check(program, '<div>tolower</div>\n') + #but not for messageids program, macros = self._compile( '<div i18n:translate=""' ' i18n:domain="a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine"' |