[Zope3-checkins] SVN: Zope3/trunk/src/zope/ Changed the strategy
for handling fallback domains. We want fallback
Jim Fulton
jim at zope.com
Wed Nov 9 16:30:39 EST 2005
Log message for revision 40011:
Changed the strategy for handling fallback domains. We want fallback
domains to know what domain they fell back from to generate useful
"test" translations. Now, when we can't find a domain, we try to get
a fallback-domain factory which is used to compute a fallback domain
on the fly.
Also, the test language now shows default values in translations.
This is helpful for recognizing message ids and, in tests, for
verifying that the correct default was used.
Changed:
U Zope3/trunk/src/zope/app/i18n/tests/configure.zcml
D Zope3/trunk/src/zope/app/i18n/tests/locales/
U Zope3/trunk/src/zope/i18n/__init__.py
U Zope3/trunk/src/zope/i18n/interfaces/__init__.py
U Zope3/trunk/src/zope/i18n/testmessagecatalog.py
U Zope3/trunk/src/zope/i18n/testmessagecatalog.txt
U Zope3/trunk/src/zope/i18n/tests/test.py
U Zope3/trunk/src/zope/i18n/tests/test_translationdomain.py
U Zope3/trunk/src/zope/i18n/translationdomain.py
-=-
Modified: Zope3/trunk/src/zope/app/i18n/tests/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/i18n/tests/configure.zcml 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/app/i18n/tests/configure.zcml 2005-11-09 21:30:39 UTC (rev 40011)
@@ -1,9 +1,10 @@
<configure
xmlns="http://namespaces.zope.org/zope"
- xmlns:i18n="http://namespaces.zope.org/i18n"
>
<!-- Default (empty) Translations -->
- <i18n:registerTranslations directory="locales" />
+ <utility
+ component="zope.i18n.testmessagecatalog.TestMessageFallbackDomain"
+ />
</configure>
Modified: Zope3/trunk/src/zope/i18n/__init__.py
===================================================================
--- Zope3/trunk/src/zope/i18n/__init__.py 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/i18n/__init__.py 2005-11-09 21:30:39 UTC (rev 40011)
@@ -26,6 +26,7 @@
from zope.i18nmessageid import MessageFactory, Message
from zope.i18n.interfaces import ITranslationDomain
+from zope.i18n.interfaces import IFallbackTranslationDomainFactory
from zope.component import queryUtility
# Set up regular expressions for finding interpolation variables in text.
@@ -50,9 +51,13 @@
if domain:
util = queryUtility(ITranslationDomain, domain)
if util is None:
- util = queryUtility(ITranslationDomain)
+ util = queryUtility(IFallbackTranslationDomainFactory)
+ if util is not None:
+ util = util(domain)
else:
- util = queryUtility(ITranslationDomain)
+ util = queryUtility(IFallbackTranslationDomainFactory)
+ if util is not None:
+ util = util()
if util is None:
return interpolate(default, mapping)
Modified: Zope3/trunk/src/zope/i18n/interfaces/__init__.py
===================================================================
--- Zope3/trunk/src/zope/i18n/interfaces/__init__.py 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/i18n/interfaces/__init__.py 2005-11-09 21:30:39 UTC (rev 40011)
@@ -151,7 +151,17 @@
the simplifications.
"""
+class IFallbackTranslationDomainFactory(Interface):
+ """Factory for creating fallback translation domains
+ Fallback translation domains are primarily used for testing or
+ debugging i18n.
+ """
+
+ def __call__(domain_id=u''):
+ """Return a fallback translation domain for the given domain id.
+ """
+
class ITranslator(Interface):
"""A collaborative object which contains the domain, context, and locale.
Modified: Zope3/trunk/src/zope/i18n/testmessagecatalog.py
===================================================================
--- Zope3/trunk/src/zope/i18n/testmessagecatalog.py 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/i18n/testmessagecatalog.py 2005-11-09 21:30:39 UTC (rev 40011)
@@ -16,11 +16,12 @@
$Id$
"""
-from zope import interface
-from zope.i18n.interfaces import IGlobalMessageCatalog
+from zope import component, interface
+import zope.i18n.interfaces
+from zope.i18n.translationdomain import TranslationDomain
class TestMessageCatalog:
- interface.implements(IGlobalMessageCatalog)
+ interface.implements(zope.i18n.interfaces.IGlobalMessageCatalog)
language = 'test'
@@ -28,8 +29,13 @@
self.domain = domain
def queryMessage(self, msgid, default=None):
- return u'[[%s][%s]]' % (self.domain or getattr(msgid, 'domain', ''),
- msgid)
+ default = getattr(msgid, 'default', default)
+ if default != None and default != msgid:
+ msg = u"%s (%s)" % (msgid, default)
+ else:
+ msg = msgid
+
+ return u'[[%s][%s]]' % (self.domain, msg)
getMessage = queryMessage
@@ -39,4 +45,13 @@
def reload(self):
pass
-
+ at interface.implementer(zope.i18n.interfaces.ITranslationDomain)
+def TestMessageFallbackDomain(domain_id=u''):
+ domain = TranslationDomain(domain_id)
+ domain.addCatalog(TestMessageCatalog(domain_id))
+ return domain
+
+interface.directlyProvides(
+ TestMessageFallbackDomain,
+ zope.i18n.interfaces.IFallbackTranslationDomainFactory,
+ )
Modified: Zope3/trunk/src/zope/i18n/testmessagecatalog.txt
===================================================================
--- Zope3/trunk/src/zope/i18n/testmessagecatalog.txt 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/i18n/testmessagecatalog.txt 2005-11-09 21:30:39 UTC (rev 40011)
@@ -21,25 +21,46 @@
>>> cat.reload()
-Normally, the catalog's domain overrides the message id's domain:
+If a message id has a default, it will be included in the output:
- >>> import zope.i18nmessageid
- >>> id = zope.i18nmessageid.MessageFactory('baz.splat')('eek')
+ >>> id = zope.i18nmessageid.MessageFactory('foo.bar')('eek', default='Eek')
>>> cat.queryMessage(id)
- u'[[foo.bar][eek]]'
+ u'[[foo.bar][eek (Eek)]]'
>>> cat.getMessage(id)
- u'[[foo.bar][eek]]'
+ u'[[foo.bar][eek (Eek)]]'
-However, if the catalog's domain is '', indicating a fallback domain,
-then the id's domain is used:
+If a message doesn't have a default, but a default is passed in to
+queryMessage, the default will be used used:
- >>> cat = zope.i18n.testmessagecatalog.TestMessageCatalog('')
+ >>> cat.queryMessage('eek', default='Eek')
+ u'[[foo.bar][eek (Eek)]]'
- >>> cat.queryMessage(id)
- u'[[baz.splat][eek]]'
+ >>> cat.getMessage(id, default='Waaa')
+ u'[[foo.bar][eek (Eek)]]'
- >>> cat.getMessage(id)
- u'[[baz.splat][eek]]'
+Fallback domains
+----------------
+
+The testmessagecatalog module also provide a fallback domain factory
+that has the test catalog as it's only catalog:
+
+ >>> factory = zope.i18n.testmessagecatalog.TestMessageFallbackDomain
+ >>> import zope.i18n.interfaces
+ >>> zope.i18n.interfaces.IFallbackTranslationDomainFactory.providedBy(
+ ... factory)
+ True
+ >>> domain = factory('foo.bar')
+ >>> domain.translate(u'eek')
+ u'eek'
+
+ >>> domain.translate(u'eek', target_language='test')
+ u'[[foo.bar][eek]]'
+
+Note that if a default is padded in, it will be included in test
+output:
+
+ >>> domain.translate(u'eek', target_language='test', default=u'Eek')
+ u'[[foo.bar][eek (Eek)]]'
Modified: Zope3/trunk/src/zope/i18n/tests/test.py
===================================================================
--- Zope3/trunk/src/zope/i18n/tests/test.py 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/i18n/tests/test.py 2005-11-09 21:30:39 UTC (rev 40011)
@@ -49,15 +49,22 @@
>>> _translate(u'eek', 'your.domain')
u'eek'
-A fallback domain can be provided. This is normally used for testing:
+A fallback domain factory can be provided. This is normally used for testing:
- >>> component.provideUtility(TestDomain(eek=u'test'))
+ >>> def fallback(domain=u''):
+ ... return TestDomain(eek=u'test-from-' + domain)
+ >>> interface.directlyProvides(
+ ... fallback,
+ ... zope.i18n.interfaces.IFallbackTranslationDomainFactory,
+ ... )
+ >>> component.provideUtility(fallback)
+
>>> _translate(u'eek')
- u'test'
+ u'test-from-'
>>> _translate(u'eek', 'your.domain')
- u'test'
+ u'test-from-your.domain'
"""
Modified: Zope3/trunk/src/zope/i18n/tests/test_translationdomain.py
===================================================================
--- Zope3/trunk/src/zope/i18n/tests/test_translationdomain.py 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/i18n/tests/test_translationdomain.py 2005-11-09 21:30:39 UTC (rev 40011)
@@ -16,7 +16,6 @@
$Id$
"""
import unittest, os
-from zope.testing import doctest
from zope.i18n.translationdomain import TranslationDomain
from zope.i18n.gettextmessagecatalog import GettextMessageCatalog
from zope.i18n.tests.test_itranslationdomain import \
@@ -127,41 +126,9 @@
"this THAT the other")
-def test_message_domain_ignored_by_fallback_domain():
- """\
-
-Normally, a translation domain will try to lookup an alternative
-translation domain if a message's domain is different than it's own:
-
- >>> domain = TranslationDomain('mydomain')
- >>> msgid = MessageIDFactory('huh')(u'short_greeting', 'default')
- >>> domain.translate(msgid, target_language='en')
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError:
- (<InterfaceClass zope.i18n.interfaces.ITranslationDomain>, 'huh')
-
-
-However, fallback domains, which have an empty domain name, ignore
-message domains:
-
- >>> domain = TranslationDomain('')
- >>> path = testdir()
- >>> en_catalog = GettextMessageCatalog('en', 'other',
- ... os.path.join(path, 'en-default.mo'))
- >>> domain.addCatalog(en_catalog)
- >>> domain.translate(msgid, target_language='en')
- u'Hello!'
-
-Fallback domains are used mainly for testing.
-
-"""
-
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestGlobalTranslationDomain))
- suite.addTest(doctest.DocTestSuite())
return suite
if __name__ == '__main__':
Modified: Zope3/trunk/src/zope/i18n/translationdomain.py
===================================================================
--- Zope3/trunk/src/zope/i18n/translationdomain.py 2005-11-09 20:50:12 UTC (rev 40010)
+++ Zope3/trunk/src/zope/i18n/translationdomain.py 2005-11-09 21:30:39 UTC (rev 40011)
@@ -85,7 +85,7 @@
# MessageID attributes override arguments
if isinstance(msgid, (Message, MessageID)):
- if (msgid.domain != self.domain) and self.domain:
+ if msgid.domain != self.domain:
util = getUtility(ITranslationDomain, msgid.domain)
mapping = msgid.mapping
default = msgid.default
@@ -101,15 +101,22 @@
if catalog_names is not None:
break
- # Did the fallback fail? Sigh, return None
text = default
if catalog_names:
- for name in catalog_names:
- catalog = self._data[name]
- s = catalog.queryMessage(msgid)
- if s is not None:
- text = s
- break
+ if len(catalog_names) == 1:
+ # this is a slight optimization for the case when there is a
+ # single catalog. More importantly, it is extremely helpful
+ # when testing and the test language is used, because it
+ # allows the test language to get the default.
+ text = self._data[catalog_names[0]].queryMessage(
+ msgid, default)
+ else:
+ for name in catalog_names:
+ catalog = self._data[name]
+ s = catalog.queryMessage(msgid)
+ if s is not None:
+ text = s
+ break
# Now we need to do the interpolation
if text is not None:
More information about the Zope3-Checkins
mailing list