changeset 61:9d13b9a5d727 trunk

Move `Translations` and `LazyProxy` to new `babel.support` module, which should contain any convenience code that is useful for applications using Babel/I18n, but not used by Babel itself. ''(Note that [61] was an accidential check in of part of this change)''
author cmlenz
date Fri, 08 Jun 2007 11:54:01 +0000
parents f088d3518283
children 2df27f49c320
files babel/messages/catalog.py babel/support.py babel/tests/__init__.py babel/tests/support.py
diffstat 4 files changed, 237 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/babel/messages/catalog.py
+++ b/babel/messages/catalog.py
@@ -62,7 +62,7 @@
         >>> Message(('foo', 'bar')).pluralizable
         True
         
-        :rtype:  `bool`
+        :type:  `bool`
         """)
 
     def python_format(self):
@@ -78,7 +78,7 @@
         >>> Message(('foo %(name)s', 'foo %(name)s')).python_format
         True
         
-        :rtype:  `bool`
+        :type:  `bool`
         """)
 
 
new file mode 100644
--- /dev/null
+++ b/babel/support.py
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://babel.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://babel.edgewall.org/log/.
+
+"""Several classes and functions that help with integrating and using Babel
+in applications.
+
+.. note: the code in this module is not used by Babel itself
+"""
+
+import gettext
+
+__all__ = ['LazyProxy', 'Translations']
+__docformat__ = 'restructuredtext en'
+
+
+class LazyProxy(object):
+    """Class for proxy objects that delegate to a specified function to evaluate
+    the actual object.
+    
+    >>> def greeting(name='world'):
+    ...     return 'Hello, %s!' % name
+    >>> lazy_greeting = LazyProxy(greeting, name='Joe')
+    >>> print lazy_greeting
+    Hello, Joe!
+    >>> u'  ' + lazy_greeting
+    u'  Hello, Joe!'
+    >>> u'(%s)' % lazy_greeting
+    u'(Hello, Joe!)'
+    
+    This can be used, for example, to implement lazy translation functions that
+    delay the actual translation until the string is actually used. The
+    rationale for such behavior is that the locale of the user may not always
+    be available. In web applications, you only know the locale when processing
+    a request.
+    
+    The proxy implementation attempts to be as complete as possible, so that
+    the lazy objects should mostly work as expected, for example for sorting:
+    
+    >>> greetings = [
+    ...     LazyProxy(greeting, 'world'),
+    ...     LazyProxy(greeting, 'Joe'),
+    ...     LazyProxy(greeting, 'universe'),
+    ... ]
+    >>> greetings.sort()
+    >>> for greeting in greetings:
+    ...     print greeting
+    Hello, Joe!
+    Hello, universe!
+    Hello, world!
+    """
+    __slots__ = ['_func', '_args', '_kwargs', '_value']
+
+    def __init__(self, func, *args, **kwargs):
+        # Avoid triggering our own __setattr__ implementation
+        object.__setattr__(self, '_func', func)
+        object.__setattr__(self, '_args', args)
+        object.__setattr__(self, '_kwargs', kwargs)
+        object.__setattr__(self, '_value', None)
+
+    def value(self):
+        if self._value is None:
+            value = self._func(*self._args, **self._kwargs)
+            object.__setattr__(self, '_value', value)
+        return self._value
+    value = property(value)
+
+    def __contains__(self, key):
+        return key in self.value
+
+    def __nonzero__(self):
+        return bool(self.value)
+
+    def __dir__(self):
+        return dir(self.value)
+
+    def __iter__(self):
+        return iter(self.value)
+
+    def __len__(self):
+        return len(self.value)
+
+    def __str__(self):
+        return str(self.value)
+
+    def __unicode__(self):
+        return unicode(self.value)
+
+    def __add__(self, other):
+        return self.value + other
+
+    def __radd__(self, other):
+        return other + self.value
+
+    def __mod__(self, other):
+        return self.value % other
+
+    def __rmod__(self, other):
+        return other % self.value
+
+    def __mul__(self, other):
+        return self.value * other
+
+    def __rmul__(self, other):
+        return other * self.value
+
+    def __call__(self, *args, **kwargs):
+        return self.value(*args, **kwargs)
+
+    def __lt__(self, other):
+        return self.value < other
+
+    def __le__(self, other):
+        return self.value <= other
+
+    def __eq__(self, other):
+        return self.value == other
+
+    def __ne__(self, other):
+        return self.value != other
+
+    def __gt__(self, other):
+        return self.value > other
+
+    def __ge__(self, other):
+        return self.value >= other
+
+    def __delattr__(self, name):
+        delattr(self.value, name)
+
+    def __getattr__(self, name):
+        return getattr(self.value, name)
+
+    def __setattr__(self, key, value):
+        setattr(self.value, name, value)
+
+    def __delitem__(self, key):
+        del self.value[key]
+
+    def __getitem__(self, key):
+        return self.value[key]
+
+    def __setitem__(self, key, value):
+        self.value[name] = value
+
+
+class Translations(gettext.GNUTranslations):
+    """An extended translation catalog class."""
+
+    DEFAULT_DOMAIN = 'messages'
+
+    def __init__(self, fileobj=None):
+        """Initialize the translations catalog.
+        
+        :param fileobj: the file-like object the translation should be read
+                        from
+        """
+        gettext.GNUTranslations.__init__(self, fp=fileobj)
+        self.files = [getattr(fileobj, 'name')]
+
+    def load(cls, dirname=None, locales=None, domain=DEFAULT_DOMAIN):
+        """Load translations from the given directory.
+        
+        :param dirname: the directory containing the ``MO`` files
+        :param locales: the list of locales in order of preference (items in
+                        this list can be either `Locale` objects or locale
+                        strings)
+        :param domain: the message domain
+        :return: the loaded catalog, or a ``NullTranslations`` instance if no
+                 matching translations were found
+        :rtype: `Translations`
+        """
+        if not isinstance(locales, (list, tuple)):
+            locales = [locales]
+        locales = [str(locale) for locale in locales]
+        filename = gettext.find(domain or self.DEFAULT_DOMAIN, dirname, locales)
+        if not filename:
+            return gettext.NullTranslations()
+        return cls(fileobj=open(filename, 'rb'))
+    load = classmethod(load)
+
+    def merge(self, translations):
+        """Merge the given translations into the catalog.
+        
+        Message translations in the specfied catalog override any messages with
+        the same identifier in the existing catalog.
+        
+        :param translations: the `Translations` instance with the messages to
+                             merge
+        :return: the `Translations` instance (``self``) so that `merge` calls
+                 can be easily chained
+        :rtype: `Translations`
+        """
+        if isinstance(translations, Translations):
+            self._catalog.update(translations._catalog)
+            self.files.extend(translations.files)
+        return self
+
+    def __repr__(self):
+        return "<%s %r>" % (type(self).__name__)
--- a/babel/tests/__init__.py
+++ b/babel/tests/__init__.py
@@ -14,7 +14,7 @@
 import unittest
 
 def suite():
-    from babel.tests import core, dates, localedata, numbers, util
+    from babel.tests import core, dates, localedata, numbers, support, util
     from babel.messages import tests as messages
     suite = unittest.TestSuite()
     suite.addTest(core.suite())
new file mode 100644
--- /dev/null
+++ b/babel/tests/support.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2007 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://babel.edgewall.org/wiki/License.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://babel.edgewall.org/log/.
+
+import doctest
+import unittest
+
+from babel import support
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocTestSuite(support))
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')
Copyright (C) 2012-2017 Edgewall Software