summaryrefslogtreecommitdiff
path: root/repoze/bfg/i18n.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2010-10-25 10:29:31 -0400
committerChris McDonough <chrism@plope.com>2010-10-25 10:29:31 -0400
commit64372401084889a440c9d990a0febc221e3e4b5c (patch)
treec8939a341505d19f19fa6918d264b4e1d95326f8 /repoze/bfg/i18n.py
parentc8e78c2037806f3e5dab57de635bf80865b7061d (diff)
downloadpyramid-64372401084889a440c9d990a0febc221e3e4b5c.tar.gz
pyramid-64372401084889a440c9d990a0febc221e3e4b5c.tar.bz2
pyramid-64372401084889a440c9d990a0febc221e3e4b5c.zip
first pass at converting bfg to pyramid namespace
Diffstat (limited to 'repoze/bfg/i18n.py')
-rw-r--r--repoze/bfg/i18n.py322
1 files changed, 0 insertions, 322 deletions
diff --git a/repoze/bfg/i18n.py b/repoze/bfg/i18n.py
deleted file mode 100644
index c3ba7efad..000000000
--- a/repoze/bfg/i18n.py
+++ /dev/null
@@ -1,322 +0,0 @@
-import gettext
-import os
-
-from translationstring import Translator
-from translationstring import Pluralizer
-from translationstring import TranslationString # API
-from translationstring import TranslationStringFactory # API
-
-TranslationString = TranslationString # PyFlakes
-TranslationStringFactory = TranslationStringFactory # PyFlakes
-
-from repoze.bfg.interfaces import ILocalizer
-from repoze.bfg.interfaces import ITranslationDirectories
-from repoze.bfg.interfaces import ILocaleNegotiator
-
-from repoze.bfg.settings import get_settings
-from repoze.bfg.threadlocal import get_current_registry
-
-class Localizer(object):
- """
- An object providing translation and pluralizations related to
- the current request's locale name. A
- :class:`repoze.bfg.i18n.Localizer` object is created using the
- :func:`repoze.bfg.i18n.get_localizer` function.
- """
- def __init__(self, locale_name, translations):
- self.locale_name = locale_name
- self.translations = translations
- self.pluralizer = None
- self.translator = None
-
- def translate(self, tstring, domain=None, mapping=None):
- """
- Translate a :term:`translation string` to the current language
- and interpolate any *replacement markers* in the result. The
- ``translate`` method accepts three arguments: ``tstring``
- (required), ``domain`` (optional) and ``mapping`` (optional).
- When called, it will translate the ``tstring`` translation
- string to a ``unicode`` object using the current locale. If
- the current locale could not be determined, the result of
- interpolation of the default value is returned. The optional
- ``domain`` argument can be used to specify or override the
- domain of the ``tstring`` (useful when ``tstring`` is a normal
- string rather than a translation string). The optional
- ``mapping`` argument can specify or override the ``tstring``
- interpolation mapping, useful when the ``tstring`` argument is
- a simple string instead of a translation string.
-
- Example::
-
- from repoze.bfg.18n import TranslationString
- ts = TranslationString('Add ${item}', domain='mypackage',
- mapping={'item':'Item'})
- translated = localizer.translate(ts)
-
- Example::
-
- translated = localizer.translate('Add ${item}', domain='mypackage',
- mapping={'item':'Item'})
-
- """
- if self.translator is None:
- self.translator = Translator(self.translations)
- return self.translator(tstring, domain=domain, mapping=mapping)
-
- def pluralize(self, singular, plural, n, domain=None, mapping=None):
- """
- Return a Unicode string translation by using two
- :term:`message identifier` objects as a singular/plural pair
- and an ``n`` value representing the number that appears in the
- message using gettext plural forms support. The ``singular``
- and ``plural`` objects passed may be translation strings or
- unicode strings. ``n`` represents the number of elements.
- ``domain`` is the translation domain to use to do the
- pluralization, and ``mapping`` is the interpolation mapping
- that should be used on the result. Note that if the objects
- passed are translation strings, their domains and mappings are
- ignored. The domain and mapping arguments must be used
- instead. If the ``domain`` is not supplied, a default domain
- is used (usually ``messages``).
-
- Example::
-
- num = 1
- translated = localizer.pluralize('Add ${num} item',
- 'Add ${num} items',
- num,
- mapping={'num':num})
-
-
- """
- if self.pluralizer is None:
- self.pluralizer = Pluralizer(self.translations)
- return self.pluralizer(singular, plural, n, domain=domain,
- mapping=mapping)
-
-
-def default_locale_negotiator(request):
- """ The default :term:`locale negotiator`. Returns a locale name
- or ``None``.
-
- - First, the negotiator looks for the ``_LOCALE_`` attribute of
- the request object (possibly set by a view or a listener for an
- :term:`event`).
-
- - Then it looks for the ``request.params['_LOCALE_']`` value.
-
- - Then it looks for the ``request.cookies['_LOCALE_']`` value.
-
- - Finally, the negotiator returns ``None`` if the locale could not
- be determined via any of the previous checks (when a locale
- negotiator returns ``None``, it signifies that the
- :term:`default locale name` should be used.)
- """
- name = '_LOCALE_'
- locale_name = getattr(request, name, None)
- if locale_name is None:
- locale_name = request.params.get(name)
- if locale_name is None:
- locale_name = request.cookies.get(name)
- return locale_name
-
-def negotiate_locale_name(request):
- """ Negotiate and return the :term:`locale name` associated with
- the current request (never cached)."""
- try:
- registry = request.registry
- except AttributeError:
- registry = get_current_registry()
- negotiator = registry.queryUtility(ILocaleNegotiator,
- default=default_locale_negotiator)
- locale_name = negotiator(request)
-
- if locale_name is None:
- settings = get_settings() or {}
- locale_name = settings.get('default_locale_name', 'en')
-
- return locale_name
-
-def get_locale_name(request):
- """ Return the :term:`locale name` associated with the current
- request (possibly cached)."""
- locale_name = getattr(request, 'bfg_locale_name', None)
- if locale_name is None:
- locale_name = negotiate_locale_name(request)
- request.bfg_locale_name = locale_name
- return locale_name
-
-def get_localizer(request):
- """ Retrieve a :class:`repoze.bfg.i18n.Localizer` object
- corresponding to the current request's locale name. """
- localizer = getattr(request, 'bfg_localizer', None)
-
- if localizer is None:
- # no locale object cached on request
- try:
- registry = request.registry
- except AttributeError:
- registry = get_current_registry()
-
- current_locale_name = get_locale_name(request)
- localizer = registry.queryUtility(ILocalizer, name=current_locale_name)
-
- if localizer is None:
- # no localizer utility registered yet
- translations = Translations()
- translations._catalog = {}
- tdirs = registry.queryUtility(ITranslationDirectories, default=[])
- for tdir in tdirs:
- locale_dirs = [ (lname, os.path.join(tdir, lname)) for lname in
- os.listdir(tdir) ]
- for locale_name, locale_dir in locale_dirs:
- if locale_name != current_locale_name:
- continue
- messages_dir = os.path.join(locale_dir, 'LC_MESSAGES')
- if not os.path.isdir(os.path.realpath(messages_dir)):
- continue
- for mofile in os.listdir(messages_dir):
- mopath = os.path.realpath(os.path.join(messages_dir,
- mofile))
- if mofile.endswith('.mo') and os.path.isfile(mopath):
- mofp = open(mopath, 'rb')
- domain = mofile[:-3]
- dtrans = Translations(mofp, domain)
- translations.add(dtrans)
-
- localizer = Localizer(locale_name=current_locale_name,
- translations=translations)
- registry.registerUtility(localizer, ILocalizer,
- name=current_locale_name)
- request.bfg_localizer = localizer
-
- return localizer
-
-class Translations(gettext.GNUTranslations, object):
- """An extended translation catalog class (ripped off from Babel) """
-
- DEFAULT_DOMAIN = 'messages'
-
- def __init__(self, fileobj=None, domain=DEFAULT_DOMAIN):
- """Initialize the translations catalog.
-
- :param fileobj: the file-like object the translation should be read
- from
- """
- gettext.GNUTranslations.__init__(self, fp=fileobj)
- self.files = filter(None, [getattr(fileobj, 'name', None)])
- self.domain = domain
- self._domains = {}
-
- @classmethod
- 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 locales is not None:
- if not isinstance(locales, (list, tuple)):
- locales = [locales]
- locales = [str(l) for l in locales]
- if not domain:
- domain = cls.DEFAULT_DOMAIN
- filename = gettext.find(domain, dirname, locales)
- if not filename:
- return gettext.NullTranslations()
- return cls(fileobj=open(filename, 'rb'), domain=domain)
-
- def __repr__(self):
- return '<%s: "%s">' % (type(self).__name__,
- self._info.get('project-id-version'))
-
- def add(self, translations, merge=True):
- """Add the given translations to the catalog.
-
- If the domain of the translations is different than that of the
- current catalog, they are added as a catalog that is only accessible
- by the various ``d*gettext`` functions.
-
- :param translations: the `Translations` instance with the messages to
- add
- :param merge: whether translations for message domains that have
- already been added should be merged with the existing
- translations
- :return: the `Translations` instance (``self``) so that `merge` calls
- can be easily chained
- :rtype: `Translations`
- """
- domain = getattr(translations, 'domain', self.DEFAULT_DOMAIN)
- if merge and domain == self.domain:
- return self.merge(translations)
-
- existing = self._domains.get(domain)
- if merge and existing is not None:
- existing.merge(translations)
- else:
- translations.add_fallback(self)
- self._domains[domain] = translations
-
- return self
-
- def merge(self, translations):
- """Merge the given translations into the catalog.
-
- Message translations in the specified 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, gettext.GNUTranslations):
- self._catalog.update(translations._catalog)
- if isinstance(translations, Translations):
- self.files.extend(translations.files)
-
- return self
-
- def dgettext(self, domain, message):
- """Like ``gettext()``, but look the message up in the specified
- domain.
- """
- return self._domains.get(domain, self).gettext(message)
-
- def ldgettext(self, domain, message):
- """Like ``lgettext()``, but look the message up in the specified
- domain.
- """
- return self._domains.get(domain, self).lgettext(message)
-
- def dugettext(self, domain, message):
- """Like ``ugettext()``, but look the message up in the specified
- domain.
- """
- return self._domains.get(domain, self).ugettext(message)
-
- def dngettext(self, domain, singular, plural, num):
- """Like ``ngettext()``, but look the message up in the specified
- domain.
- """
- return self._domains.get(domain, self).ngettext(singular, plural, num)
-
- def ldngettext(self, domain, singular, plural, num):
- """Like ``lngettext()``, but look the message up in the specified
- domain.
- """
- return self._domains.get(domain, self).lngettext(singular, plural, num)
-
- def dungettext(self, domain, singular, plural, num):
- """Like ``ungettext()`` but look the message up in the specified
- domain.
- """
- return self._domains.get(domain, self).ungettext(singular, plural, num)
-