[Checkins] SVN: zope.i18n/branches/lazy-tds/ The ZCML directive handler for a translation domain registration now

Hanno Schlichting hanno at hannosch.eu
Wed Oct 10 10:47:39 UTC 2012


Nice work!

Did you look at the hacky way I used in PlacelessTranslationService to
make catalog lazy?

> Modified: zope.i18n/branches/lazy-tds/src/zope/i18n/tests/test_zcml.py
> ===================================================================
> --- zope.i18n/branches/lazy-tds/src/zope/i18n/tests/test_zcml.py        2012-10-10 08:02:21 UTC (rev 127956)
> +++ zope.i18n/branches/lazy-tds/src/zope/i18n/tests/test_zcml.py        2012-10-10 09:25:17 UTC (rev 127957)
> @@ -43,13 +43,7 @@
>          from zope.configuration import xmlconfig
>          super(DirectivesTest, self).setUp()
>          self.context = xmlconfig.file('meta.zcml', zope.i18n)
> -        self.allowed = config.ALLOWED_LANGUAGES
> -        config.ALLOWED_LANGUAGES = None
>
> -    def tearDown(self):
> -        super(DirectivesTest, self).tearDown()
> -        config.ALLOWED_LANGUAGES = self.allowed
> -
>      def testRegisterTranslations(self):
>          from zope.configuration import xmlconfig
>          self.assert_(queryUtility(ITranslationDomain) is None)
> @@ -59,27 +53,13 @@
>              <i18n:registerTranslations directory="locale" />
>              </configure>
>              ''', self.context)
> -        path = os.path.join(os.path.dirname(zope.i18n.tests.__file__),
> -                            'locale', 'en', 'LC_MESSAGES', 'zope-i18n.mo')
>          util = getUtility(ITranslationDomain, 'zope-i18n')
> -        self.assertEquals(util._catalogs.get('test'), ['test'])
> -        self.assertEquals(util._catalogs.get('en'), [unicode(path)])
>
> -    def testAllowedTranslations(self):
> -        from zope.configuration import xmlconfig
> -        self.assert_(queryUtility(ITranslationDomain) is None)
> -        config.ALLOWED_LANGUAGES = ('de', 'fr')
> -        xmlconfig.string(
> -            template % '''
> -            <configure package="zope.i18n.tests">
> -            <i18n:registerTranslations directory="locale" />
> -            </configure>
> -            ''', self.context)
> -        path = os.path.join(os.path.dirname(zope.i18n.tests.__file__),
> -                            'locale', 'de', 'LC_MESSAGES', 'zope-i18n.mo')
> -        util = getUtility(ITranslationDomain, 'zope-i18n')
> -        self.assertEquals(util._catalogs,
> -                          {'test': ['test'], 'de': [unicode(path)]})
> +        self.assertEquals(util.translate('test', target_language='test'),
> +                          u'[[zope-i18n][test]]')
> +        self.assertEquals(util.translate('test', target_language='en'), u'test')
> +        self.assertEquals(util.translate('New Domain', target_language='en'),
> +                          u'New Domain translated')
>
>      def testRegisterDistributedTranslations(self):
>          from zope.configuration import xmlconfig
> @@ -96,14 +76,7 @@
>              <i18n:registerTranslations directory="locale2" />
>              </configure>
>              ''', self.context)
> -        path1 = os.path.join(os.path.dirname(zope.i18n.tests.__file__),
> -                             'locale', 'en', 'LC_MESSAGES', 'zope-i18n.mo')
> -        path2 = os.path.join(os.path.dirname(zope.i18n.tests.__file__),
> -                             'locale2', 'en', 'LC_MESSAGES', 'zope-i18n.mo')
>          util = getUtility(ITranslationDomain, 'zope-i18n')
> -        self.assertEquals(util._catalogs.get('test'), ['test', 'test'])
> -        self.assertEquals(util._catalogs.get('en'),
> -                          [unicode(path1), unicode(path2)])
>
>          msg = util.translate(u'Additional message', target_language='en')
>          self.assertEquals(msg, u'Additional message translated')
> @@ -140,8 +113,6 @@
>              </configure>
>              ''', self.context)
>          util = getUtility(ITranslationDomain, 'zope-i18n')
> -        self.assertEquals(util._catalogs,
> -                          {'test': ['test'], 'en': [unicode(path)]})
>
>          msg = util.translate(u"I'm a newer file", target_language='en')
>          self.assertEquals(msg, u"I'm a newer file translated")
> @@ -163,12 +134,9 @@
>              <i18n:registerTranslations directory="locale3" domain="zope-i18n" />
>              </configure>
>              ''', self.context)
> -        path = os.path.join(os.path.dirname(zope.i18n.tests.__file__),
> -                            'locale3', 'en', 'LC_MESSAGES', 'zope-i18n.mo')
>          util = getUtility(ITranslationDomain, 'zope-i18n')
> -        self.assertEquals(util._catalogs,
> -                          {'test': ['test'], 'en': [unicode(path)]})
> -
> +        self.assertEquals(util.translate('test', target_language='test'),
> +                          u'[[zope-i18n][test]]')
>          self.assert_(queryUtility(ITranslationDomain, 'zope-i18n2') is None)

Why did you remove those tests? They look like they are testing
internals, but was that the only reason?

> Modified: zope.i18n/branches/lazy-tds/src/zope/i18n/translationdomain.py
> ===================================================================
> --- zope.i18n/branches/lazy-tds/src/zope/i18n/translationdomain.py      2012-10-10 08:02:21 UTC (rev 127956)
> +++ zope.i18n/branches/lazy-tds/src/zope/i18n/translationdomain.py      2012-10-10 09:25:17 UTC (rev 127957)
> @@ -17,7 +17,9 @@
>  from zope.i18nmessageid import Message
>  from zope.i18n import translate, interpolate
>  from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
> -from zope.i18n.interfaces import ITranslationDomain, INegotiator
> +from zope.i18n.interfaces import INegotiator
> +from zope.i18n.compile import compile_mo_file
> +from zope.i18n.gettextmessagecatalog import GettextMessageCatalog
>
>  # The configuration should specify a list of fallback languages for the
>  # site.  If a particular catalog for a negotiated language is not available,
> @@ -31,6 +33,7 @@
>
>
>  class TranslationDomain(SimpleTranslationDomain):
> +    languages = ()

You are setting self.languages to an empty set in the init. Why use a
tuple here?

>      def __init__(self, domain, fallbacks=None):
>          self.domain = domain
> @@ -43,22 +46,34 @@
>          if fallbacks is None:
>              fallbacks = LANGUAGE_FALLBACKS
>          self._fallbacks = fallbacks
> +        self._pending = {}
> +        self.languages = set()
>
>      def _registerMessageCatalog(self, language, catalog_name):
>          key = language
>          mc = self._catalogs.setdefault(key, [])
>          mc.append(catalog_name)
> +        self.languages.add(language)
>
>      def addCatalog(self, catalog):
>          self._data[catalog.getIdentifier()] = catalog
>          self._registerMessageCatalog(catalog.language,
>                                       catalog.getIdentifier())
>
> +    def addLanguage(self, lang, path):
> +        self._pending.setdefault(lang, []).append(path)
> +        self.languages.add(lang)
> +
>      def setLanguageFallbacks(self, fallbacks=None):
>          if fallbacks is None:
>              fallbacks = LANGUAGE_FALLBACKS
>          self._fallbacks = fallbacks
>
> +    def importCatalog(self, lang, lc_messages_path):
> +        path = compile_mo_file(self.domain, lc_messages_path)

The compile_mo_file should be conditional on the
config.COMPILE_MO_FILES flag. The automatic mo file compilation is an
optional feature and not everyone wants it. Especially in environments
where the application process doesn't have write permissions to the
file system.

> +        catalog = GettextMessageCatalog(lang, self.domain, path)
> +        self.addCatalog(catalog)
> +
>      def translate(self, msgid, mapping=None, context=None,
>                    target_language=None, default=None):
>          """See zope.i18n.interfaces.ITranslationDomain"""
> @@ -74,6 +89,10 @@
>              # try to determine target language from negotiator utility
>              target_language = negotiator.getLanguage(langs, context)
>
> +        paths = self._pending.pop(target_language, ())
> +        for path in paths:
> +            self.importCatalog(target_language, path)
> +
>          return self._recursive_translate(
>              msgid, mapping, target_language, default, context)
>
> @@ -124,7 +143,7 @@
>                  # 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.
> +                # allows the test language to get the default.
>                  text = self._data[catalog_names[0]].queryMessage(
>                      msgid, default)
>              else:
>
> Modified: zope.i18n/branches/lazy-tds/src/zope/i18n/zcml.py
> ===================================================================
> --- zope.i18n/branches/lazy-tds/src/zope/i18n/zcml.py   2012-10-10 08:02:21 UTC (rev 127956)
> +++ zope.i18n/branches/lazy-tds/src/zope/i18n/zcml.py   2012-10-10 09:25:17 UTC (rev 127957)
> @@ -28,8 +28,6 @@
>  from zope.schema import TextLine
>
>  from zope.i18n import config
> -from zope.i18n.compile import compile_mo_file
> -from zope.i18n.gettextmessagecatalog import GettextMessageCatalog
>  from zope.i18n.testmessagecatalog import TestMessageCatalog
>  from zope.i18n.translationdomain import TranslationDomain
>  from zope.i18n.interfaces import ITranslationDomain
> @@ -61,7 +59,7 @@
>      return lang in config.ALLOWED_LANGUAGES
>
>
> -def handler(catalogs, name):
> +def handler(name, langs):
>      """ special handler handling the merging of two message catalogs """
>      gsm = getSiteManager()
>      # Try to get an existing domain and add the given catalogs to it
> @@ -69,8 +67,8 @@
>      if domain is None:
>          domain = TranslationDomain(name)
>          gsm.registerUtility(domain, ITranslationDomain, name=name)
> -    for catalog in catalogs:
> -        domain.addCatalog(catalog)
> +    for lang, path in langs.items():
> +        domain.addLanguage(lang, path)
>      # make sure we have a TEST catalog for each domain:
>      domain.addCatalog(TestMessageCatalog(name))
>
> @@ -86,38 +84,29 @@
>      for language in os.listdir(path):
>          if not allow_language(language):
>              continue
> +
>          lc_messages_path = os.path.join(path, language, 'LC_MESSAGES')
>          if os.path.isdir(lc_messages_path):
> -            # Preprocess files and update or compile the mo files
> -            if config.COMPILE_MO_FILES:
> -                for domain_path in glob(os.path.join(lc_messages_path,
> -                                                     '%s.po' % domain)):
> -                    domain_file = os.path.basename(domain_path)
> -                    name = domain_file[:-3]
> -                    compile_mo_file(name, lc_messages_path)
> -            for domain_path in glob(os.path.join(lc_messages_path,
> -                                                 '%s.mo' % domain)):
> +            query = os.path.join(lc_messages_path, '%s.[pm]o' % domain)
> +            for domain_path in glob(query):
>                  loaded = True
> -                domain_file = os.path.basename(domain_path)
> -                name = domain_file[:-3]
> +                base, ext = os.path.splitext(domain_path)
> +                name = os.path.basename(base)
>                  if not name in domains:
>                      domains[name] = {}
> -                domains[name][language] = domain_path
> +                domains[name][language] = lc_messages_path
>      if loaded:
>          logger.debug('register directory %s' % directory)
>
>      # Now create TranslationDomain objects and add them as utilities
>      for name, langs in domains.items():
> -        catalogs = []
> -        for lang, file in langs.items():
> -            catalogs.append(GettextMessageCatalog(lang, name, file))
>          # register the necessary actions directly (as opposed to using
>          # `zope.component.zcml.utility`) since we need the actual utilities
>          # in place before the merging can be done...
>          _context.action(
>              discriminator = None,
>              callable = handler,
> -            args = (catalogs, name))
> +            args = (name, langs))
>
>      # also register the interface for the translation utilities
>      provides = ITranslationDomain


More information about the checkins mailing list