summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2010-04-21 10:35:07 +0000
committerChris McDonough <chrism@agendaless.com>2010-04-21 10:35:07 +0000
commit51981a128c7ed05e51938a3f358c0970dcc33a6f (patch)
tree60b8b1cde60e28ea2d1bc6139dab47de444b0ed6
parent1c7039e337401ceb7eb16040234dcf9da8335f55 (diff)
downloadpyramid-51981a128c7ed05e51938a3f358c0970dcc33a6f.tar.gz
pyramid-51981a128c7ed05e51938a3f358c0970dcc33a6f.tar.bz2
pyramid-51981a128c7ed05e51938a3f358c0970dcc33a6f.zip
Moved i18n work to a branch and revert to pre-i18n-feature state via svn merge -r9054:9030 svn+ssh://repoze@svn.repoze.org/svn/repoze.bfg/trunk
-rw-r--r--CHANGES.txt9
-rw-r--r--TODO.txt2
-rw-r--r--docs/api.rst1
-rw-r--r--docs/api/i18n.rst23
-rw-r--r--docs/glossary.rst24
-rw-r--r--docs/index.rst1
-rw-r--r--docs/latexindex.rst1
-rw-r--r--docs/narr/i18n.rst265
-rw-r--r--docs/narr/views.rst5
-rw-r--r--repoze/bfg/chameleon_text.py8
-rw-r--r--repoze/bfg/chameleon_zpt.py8
-rw-r--r--repoze/bfg/configuration.py35
-rw-r--r--repoze/bfg/i18n.py202
-rw-r--r--repoze/bfg/interfaces.py16
-rw-r--r--repoze/bfg/tests/test_chameleon_text.py20
-rw-r--r--repoze/bfg/tests/test_chameleon_zpt.py20
-rw-r--r--repoze/bfg/tests/test_configuration.py21
-rw-r--r--repoze/bfg/tests/test_i18n.py219
-rw-r--r--setup.py3
19 files changed, 12 insertions, 871 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index ea6e17f90..fdc67b191 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -22,7 +22,7 @@ Features
returned.
Other normal view predicates can also be used in combination with an
- exception view registration::
+ exception view registration:
from repoze.bfg.view import bfg_view
from repoze.bfg.exceptions import NotFound
@@ -74,13 +74,6 @@ Dependencies
- A new install-time dependency on the ``venusian`` distribution was
added.
-- Chameleon 1.2.3 or better is now required (internationalization and
- per-template debug settings).
-
-- Add an explicit direct dependency on ``zope.i18nmessageid``. This
- distribution was already a transitive dependency, but now we're
- relying on it directly within ``repoze.bfg.i18n``.
-
Internal
--------
diff --git a/TODO.txt b/TODO.txt
index 0d19e8273..b16d806b2 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -17,5 +17,3 @@
- Provide a webob.Response class facade for forward compat.
-- Replace default_notfound_view and default_forbidden_view with better
- exception view candidates.
diff --git a/docs/api.rst b/docs/api.rst
index a97c79fa9..2bd5fca01 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -15,7 +15,6 @@ documentation is organized alphabetically by module name.
api/configuration
api/events
api/exceptions
- api/i18n
api/interfaces
api/location
api/paster
diff --git a/docs/api/i18n.rst b/docs/api/i18n.rst
deleted file mode 100644
index a67350b64..000000000
--- a/docs/api/i18n.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-.. _i18n_module:
-
-:mod:`repoze.bfg.i18n`
-----------------------
-
-.. automodule:: repoze.bfg.i18n
-
- .. autoclass:: TranslationString
-
- .. autoclass:: TranslationStringFactory
-
- .. autoinstance:: bfg_tstr
-
- .. autofunction:: get_translator(request)
-
- .. autofunction:: interpolate
-
- .. autoclass:: InterpolationOnlyTranslator
-
-See :ref:`i18n_chapter` for more information about using
-:mod:`repoze.bfg` internationalization services within an application.
-
-
diff --git a/docs/glossary.rst b/docs/glossary.rst
index 537af06b9..14bd4fc44 100644
--- a/docs/glossary.rst
+++ b/docs/glossary.rst
@@ -667,27 +667,3 @@ Glossary
at import time, the action usually taken by the decorator is
deferred until a separate "scan" phase. :mod:`repoze.bfg` relies
on Venusian to provide a basis for its :term:`scan` feature.
-
- Translation String
- An instance of the :class:`repoze.bfg.i18n.TranslationString`,
- which is a class that behaves like a Unicode string, but has
- several extra attributes such as ``domain``, ``msgid``, and
- ``mapping`` for use during translation. Translation strings are
- usually created by hand within software, but are sometimes
- created on the behalf of the system for automatic template
- translation. For more information, see :ref:`i18n_chapter`.
-
- Translator
- A callable which receives a :term:`translation string` and
- returns a translated Unicode object for the purposes of
- internationalization. A translator may be suppled to a
- :mod:`repoze.bfg` application at startup time indirectly via the
- ``translator_factory`` function, which is a :term:`translator
- factory`.
-
- Translator Factory
- A callable which receives a :term:`request` and returns a
- :term:`translator` for the purposes of internationalization. A
- translator factory may be suppled to a :mod:`repoze.bfg`
- application at startup time via the ``translator_factory``
- function.
diff --git a/docs/index.rst b/docs/index.rst
index c1b185352..ee32cf691 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -53,7 +53,6 @@ Narrative documentation in chapter form explaining how to use
narr/templates
narr/models
narr/security
- narr/i18n
narr/vhosting
narr/events
narr/environment
diff --git a/docs/latexindex.rst b/docs/latexindex.rst
index 5850ee06c..45438e939 100644
--- a/docs/latexindex.rst
+++ b/docs/latexindex.rst
@@ -42,7 +42,6 @@ Narrative Documentation
narr/templates
narr/models
narr/security
- narr/i18n
narr/vhosting
narr/events
narr/environment
diff --git a/docs/narr/i18n.rst b/docs/narr/i18n.rst
deleted file mode 100644
index 45bbab342..000000000
--- a/docs/narr/i18n.rst
+++ /dev/null
@@ -1,265 +0,0 @@
-.. index::
- single: i18n
- single: internationalization
-
-.. _i18n_chapter:
-
-Using Internationalization
-==========================
-
-:mod:`repoze.bfg` offers an internationalization (i18n) subsystem that
-can be used to translate the text of buttons, the text of error
-messages and other software-defined values into the native language of
-aq user of your :mod:`repoze-bfg` driven website.
-
-Activating Translation
-----------------------
-
-By default, a :mod:`repoze.bfg` application performs no translation
-without explicitly configuring a :term:`translator factory`. To make
-any translation at all happen, you must pass a translator factory
-object to your application's
-:mod:`repoze.bfg.configuration.Configurator` by supplying it with a
-``translator_factory`` argument. For example:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.configuration import Configurator
- from repoze.bfg.i18n import InterpolationOnlyTranslator
- config = Configurator(translator_factory=InterpolationOnlyTranslator)
-
-.. note:: At the time of this writing, only one (very weak) translator
- factory named :class:`repoze.bfg.i18n.InterpolationOnlyTranslator`
- ships as part of the :mod:`repoze.bfg` software. This class only
- does basic interpolation of mapping values; it does not actually do
- any language translation.
-
-Creating a Translation String
------------------------------
-
-While you write your software, you can insert specialized markup into
-your Python code that makes it possible for the system to translate
-text values into the languages used by your application's users. This
-markup generates a :term:`translation string`. A translation string
-is an object that behave mostly like a normal Unicode object, except
-that it also carries around extra information related to its job as
-part of :mod:`repoze.bfg` the translation machinery.
-
-Using The ``TranslationString`` Class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-One way to create a translation string is to use the
-:class:`repoze.bfg.i18n.TranslationString` callable:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import TranslationString
- ts = TranslationString('Add')
-
-This creates a Unicode-like object that is a TranslationString.
-
-The first argument to :class:`repoze.bfg.i18n.TranslationString` is
-the ``text``; it is required. The ``text`` value acts as a default
-value for the translation string if a translation to the user's
-language cannot be found at translation time. The ``text`` argument
-must be a Unicode object or an ASCII string. The text may optionally
-contain *replacement markers*. For instance:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import TranslationString
- ts = TranslationString('Add ${number}')
-
-Within the string above, ``${stuff}`` is a replacement marker. It
-will be replaced by whatever is in the *mapping* for a translation
-string. The mapping may be supplied at the same time as the
-replacement marker:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import TranslationString
- ts = TranslationString('Add ${number}', mapping={'number':1})
-
-Any number of replacement markers can be present in th text value, any
-number of times. Only markers which can be replaced by the values in
-the *mapping* will be replaced at translation time. The others will
-not be interpolated and will be output literally.
-
-A translation string should also usually carry a *domain*. The domain
-represents a translation category to disambiguate it from other
-translations of the same msgid, in case they conflict.
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import TranslationString
- ts = TranslationString('Add ${number}', mapping={'number':1},
- domain='form')
-
-The above translation string named a domain of "form". A
-:term:`translator` function will often use the domain to locate a file
-on the filesystem which contains translations for a given context. In
-this case, if it were trying to translate to our msgid to German, it
-might try to find a translation from a :term:`gettext` file like this
-one::
-
- locale/de/LC_MESSAGES/form.mo
-
-In other words, it would want to take translations from the "form.mo"
-translation file in the German language.
-
-Domain translation support is dependent upon the :term:`translator
-factory` in use. Not all translator factories use domain information
-that is associated with a translation string. However, it is always
-safe to associate a given translation string with a domain; the
-information is ignored by translators that don't support it.
-
-Finally, the TranslationString constructor accepts a ``msgid``
-argument. If a ``msgid`` argument is supplied, it is used as the
-*message identifier* for the translation string. When ``msgid`` is
-``None``, the ``text`` value passed to a TranslationString is used as
-an implicit message identifier. Message identifiers are matched with
-translations in translation files, so it is often useful to create
-translation strings with "opaque" message identifiers unrelated to
-their default text:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import TranslationString
- ts = TranslationString('Add ${number}', msgid='add-number',
- domain='form', mapping={'number':1})
-
-Using the ``bfg_tstr`` Translation String Factory
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Another way to generate a translation string is to use the
-:attr:`repoze.bfg.i18n.bfg_tstr` object. This object is a
-*translation string factory*. Basically a translation string factory
-presets the ``domain`` value of any :term:`translation string`
-generated by using it. For example:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import bfg_tstr as _
- ts = _('Add ${number}', msgid='add-number', mapping={'number':1})
-
-.. note:: We imported ``bfg_tstr`` as the name ``_``. This is a
- convention which will be supported by translation file generation
- tools.
-
-The result of calling ``bfg_tstr`` is a
-:class:`repoze.bfg.i18n.TranslationString` instance. Even though a
-``domain`` value was not passed to bfg_tstr (as would have been
-necessary if the :class:`repoze.bfg.i18n.TranslationString`
-constructor were used instead of a translation string factory), the
-``domain`` attribute of the resulting translation string will be
-``bfg``. As a result, the previous code example is completely
-equivalent (except for spelling) to:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import TranslationString as _
- ts = _('Add ${number}', msgid='add-number', mapping={'number':1},
- domain='form')
-
-Using the ``TranslationStringFactory`` Class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can set up your own translation string factory much like the one
-provided as :mod:`repoze.bfg.i18n.bfg_tstr` by using the
-:class:`repoze.bfg.i18n.TranslationStringFactory` class. For example,
-if you'd like to create a translation string factory which presets the
-``domain`` value of generated translation strings to ``form``, you'd
-do something like this:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import TranslationStringFactory
- _ = TranslationStringFactory('form')
- ts = _('Add ${number}', msgid='add-number', mapping={'number':1})
-
-.. note:: We created this factory with the name ``_``. This is a
- convention which will be supported by translation file generation
- tools.
-
-Performing a Translation by Hand
---------------------------------
-
-If you need to perform translation "by hand" in an application, use
-the :func:`repoze.bfg.i18n.get_translator` function to obtain a
-:term:`translator` . :func:`repoze.bfg.i18n.get_translator` will
-return either the current translator defined by the
-``translator_factory`` passed to the Configurator at startup or a
-default translator if no explicit translator factory has been
-registered.
-
-Remember that a translator is a callable which accepts either a
-:term:`translation string` and which returns a Unicode object
-representing the translation. So, generating a translation in a view
-component of your application might look like so:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import get_translator
-
- from repoze.bfg.i18n import bfg_tstr as _
- ts = _('Add ${number}', mapping={'number':1})
-
- def aview(request):
- translator = get_translator(request)
- translated = translator(ts)
-
-A translator may be called any number of times after being retrieved
-from the ``get_translator`` function.
-
-Defining A Translator Factory
------------------------------
-
-A translator factory is an object which accepts a :term:`request` and
-which returns a :term:`translator` callable.
-
-The :term:`translator` callable returned by a translator factory must
-accept a single positional argument which represents a
-:term:`translation string` and should return a fully localized and
-expanded translation of the translation string.
-
-A simplistic implementation of both a translator factory and a
-translator (via its constructor and ``__call__`` methods respecively)
-named :class:`repoze.bfg.i18n.InterpolationOnlyTranslator` is defined.
-Here it is:
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.i18n import interpolate
-
- class InterpolationOnlyTranslator(object):
- def __init__(self, request):
- self.request = request
-
- def __call__(self, message):
- mapping = getattr(message, 'mapping', None)
- return interpolate(message, mapping)
-
-The exact operation of a translator is left to the implementor of a
-particular translator factory. You can define and use your own
-translator factory by passing it as the ``translator_factory``
-argument to the :class:`repoze.bfg.configuration.Configurator`
-constructor.
-
-.. code-block:: python
- :linenos:
-
- from repoze.bfg.configuration import Configurator
- from repoze.bfg.i18n import InterpolationOnlyTranslator
- config = Configurator(translator_factory=InterpolationOnlyTranslator, ...)
-
diff --git a/docs/narr/views.rst b/docs/narr/views.rst
index eebaa63de..a24e4b7b5 100644
--- a/docs/narr/views.rst
+++ b/docs/narr/views.rst
@@ -840,11 +840,6 @@ In all cases, the message provided to the exception constructor is
made available to the view which :mod:`repoze.bfg` invokes as
``request.exception.args[0]``.
-.. index::
- single: exception views
-
-.. _exception_views:
-
Exception Views
~~~~~~~~~~~~~~~~
diff --git a/repoze/bfg/chameleon_text.py b/repoze/bfg/chameleon_text.py
index deb1cc43d..f1dc8e3aa 100644
--- a/repoze/bfg/chameleon_text.py
+++ b/repoze/bfg/chameleon_text.py
@@ -22,7 +22,6 @@ except ImportError: # pragma: no cover
from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ITemplateRenderer
-from repoze.bfg.interfaces import IChameleonTranslate
from repoze.bfg.decorator import reify
from repoze.bfg.renderers import template_renderer_factory
@@ -51,12 +50,7 @@ class TextTemplateRenderer(object):
def template(self):
settings = get_settings()
auto_reload = settings and settings['reload_templates']
- reg = get_current_registry()
- translate = None
- if reg is not None:
- translate = reg.queryUtility(IChameleonTranslate)
- return TextTemplateFile(self.path, auto_reload=auto_reload,
- translate=translate)
+ return TextTemplateFile(self.path, auto_reload=auto_reload)
def implementation(self):
return self.template
diff --git a/repoze/bfg/chameleon_zpt.py b/repoze/bfg/chameleon_zpt.py
index 687a11305..f597ebd5f 100644
--- a/repoze/bfg/chameleon_zpt.py
+++ b/repoze/bfg/chameleon_zpt.py
@@ -13,7 +13,6 @@ except ImportError: # pragma: no cover
def __init__(self, *arg, **kw):
raise ImportError, exc, tb
-from repoze.bfg.interfaces import IChameleonTranslate
from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ITemplateRenderer
@@ -34,12 +33,7 @@ class ZPTTemplateRenderer(object):
def template(self):
settings = get_settings()
auto_reload = settings and settings['reload_templates']
- reg = get_current_registry()
- translate = None
- if reg is not None:
- translate = reg.queryUtility(IChameleonTranslate)
- return PageTemplateFile(self.path, auto_reload=auto_reload,
- translate=translate)
+ return PageTemplateFile(self.path, auto_reload=auto_reload)
def implementation(self):
return self.template
diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py
index a98b3e7d6..4673479da 100644
--- a/repoze/bfg/configuration.py
+++ b/repoze/bfg/configuration.py
@@ -17,7 +17,6 @@ from zope.interface import implements
from repoze.bfg.interfaces import IAuthenticationPolicy
from repoze.bfg.interfaces import IAuthorizationPolicy
-from repoze.bfg.interfaces import IChameleonTranslate
from repoze.bfg.interfaces import IDebugLogger
from repoze.bfg.interfaces import IDefaultRootFactory
from repoze.bfg.interfaces import IExceptionViewClassifier
@@ -32,7 +31,6 @@ from repoze.bfg.interfaces import IRoutesMapper
from repoze.bfg.interfaces import ISecuredView
from repoze.bfg.interfaces import ISettings
from repoze.bfg.interfaces import ITemplateRenderer
-from repoze.bfg.interfaces import ITranslatorFactory
from repoze.bfg.interfaces import ITraverser
from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import IViewClassifier
@@ -47,7 +45,6 @@ from repoze.bfg.events import WSGIApplicationCreatedEvent
from repoze.bfg.exceptions import Forbidden
from repoze.bfg.exceptions import NotFound
from repoze.bfg.exceptions import ConfigurationError
-from repoze.bfg.i18n import ChameleonTranslate
from repoze.bfg.log import make_stream_logger
from repoze.bfg.path import caller_package
from repoze.bfg.registry import Registry
@@ -138,23 +135,14 @@ class Configurator(object):
logs to stderr will be used. If it is passed, it should be an
instance of the :class:`logging.Logger` (PEP 282) standard library
class. The debug logger is used by :mod:`repoze.bfg` itself to
- log warnings and authorization debugging information.
-
- If ``translator_factory`` is passed, it should be a
- :term:`translator factory` object. A translator factory is an
- object which accepts a request and which returns a translation
- function. The translation function accepts a :term:`translation
- string` and returns a Unicode object representing the translated
- string. The default for ``translator_factory`` is ``None``,
- meaning that no translation is performed during template
- rendering. """
+ log warnings and authorization debugging information. """
manager = manager # for testing injection
venusian = venusian # for testing injection
def __init__(self, registry=None, package=None, settings=None,
root_factory=None, authentication_policy=None,
authorization_policy=None, renderers=DEFAULT_RENDERERS,
- debug_logger=None, translator_factory=None):
+ debug_logger=None):
self.package = package or caller_package()
self.registry = registry
if registry is None:
@@ -166,8 +154,7 @@ class Configurator(object):
authentication_policy=authentication_policy,
authorization_policy=authorization_policy,
renderers=renderers,
- debug_logger=debug_logger,
- translator_factory=translator_factory)
+ debug_logger=debug_logger)
def _set_settings(self, mapping):
settings = Settings(mapping or {})
@@ -283,8 +270,7 @@ class Configurator(object):
def setup_registry(self, settings=None, root_factory=None,
authentication_policy=None, authorization_policy=None,
- renderers=DEFAULT_RENDERERS, debug_logger=None,
- translator_factory=None):
+ renderers=DEFAULT_RENDERERS, debug_logger=None):
""" When you pass a non-``None`` ``registry`` argument to the
:term:`Configurator` constructor, no initial 'setup' is
performed against the registry. This is because the registry
@@ -318,8 +304,6 @@ class Configurator(object):
self.add_renderer(name, renderer)
self.set_notfound_view(default_notfound_view)
self.set_forbidden_view(default_forbidden_view)
- if translator_factory is not None:
- self.set_translator_factory(translator_factory)
# getSiteManager is a unit testing dep injection
def hook_zca(self, getSiteManager=None):
@@ -1241,6 +1225,10 @@ class Configurator(object):
found via context-finding or ``None`` if no context could
be found. The exception causing the registered view to be
called is however still available as ``request.exception``.
+ .. warning:: This method has been deprecated in
+ :mod:`repoze.bfg` 1.3. See
+ :ref:`changing_the_forbidden_view` to see how a not found
+ view should be registered in :mod:`repoze.bfg` 1.3+.
The ``view`` argument should be a :term:`view callable`.
@@ -1311,13 +1299,6 @@ class Configurator(object):
return self.add_view(bwcompat_view, context=NotFound,
wrapper=wrapper, _info=_info)
- def set_translator_factory(self, factory):
- """ Set ``factory`` up as the current application
- :term:`translator factory` (for internationalization)"""
- self.registry.registerUtility(factory, ITranslatorFactory)
- ctranslate = ChameleonTranslate(factory)
- self.registry.registerUtility(ctranslate, IChameleonTranslate)
-
def add_static_view(self, name, path, cache_max_age=3600, _info=u''):
""" Add a view used to render static resources to the current
configuration state.
diff --git a/repoze/bfg/i18n.py b/repoze/bfg/i18n.py
deleted file mode 100644
index adbdb1db6..000000000
--- a/repoze/bfg/i18n.py
+++ /dev/null
@@ -1,202 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-
-import re
-
-from zope.interface import implements
-from zope.interface import classProvides
-
-from zope.i18nmessageid import Message
-
-from repoze.bfg.interfaces import ITranslator
-from repoze.bfg.interfaces import ITranslatorFactory
-from repoze.bfg.interfaces import IChameleonTranslate
-
-from repoze.bfg.threadlocal import get_current_registry
-from repoze.bfg.threadlocal import get_current_request
-
-class TranslationString(Message):
- """ The constructor for a :term:`translation string`. This
- constructor accepts one required argument named ``text``.
- ``text`` must be the default text of the translation string,
- optionally including replacement markers such as ``${foo}``.
-
- Optional keyword arguments to the TranslationString constructor
- include ``msgid``, ``mapping`` and ``domain``.
-
- ``mapping``, if supplied, must be a dictionarylike object which
- represents the replacement values for any replacement markers
- found within the ``text`` value of this
-
- ``msgid`` represents an explicit :term:`message identifier` for
- this translation string. Usually, the ``text`` of a translation
- string serves as its message identifier. However, using this
- option you can pass an explicit message identifier, usually a
- simple string. This is useful when the ``text`` of a translation
- string is too complicated or too long to be used as a translation
- key. If ``msgid`` is ``None`` (the default), the ``msgid`` value
- used by this translation string will be assumed to be the value of
- ``text``.
-
- ``domain`` represents the :term:`translation domain`. By default,
- the translation domain is ``None``, indicating that this
- translation string is associated with no translation domain.
-
- After a translation string is constructed, its ``text`` value is
- available as the ``default`` attribute of the object, the
- ``msgid`` is available as the ``msgid`` attribute of the object,
- the ``domain`` is available as the ``domain`` attribute, and the
- ``mapping`` is available as the ``mapping`` attribute.
- """
- def __new__(cls, text, mapping=None, msgid=None, domain=None):
- if msgid is None:
- msgid = text
- return Message.__new__(cls, msgid, domain=domain, default=text,
- mapping=mapping)
-
-class TranslationStringFactory(object):
- """ Create a factory which will generate translation strings
- without requiring that each call to the factory be passed a
- ``domain`` value. The ``domain`` value passed to this class'
- constructor will be used as the ``domain`` values of
- :class:`repoze.bfg.i18n.TranslationString` objects generated by
- the ``__call__`` of this class. The ``text``, ``mapping``, and
- ``msgid`` values provided to ``__call__`` have the meaning as
- described by the constructor of the
- :class:`repoze.bfg.i18n.TranslationString`"""
- def __init__(self, domain):
- self.domain = domain
-
- def __call__(self, text, mapping=None, msgid=None):
- return TranslationString(text, mapping=mapping, msgid=msgid,
- domain=self.domain)
-
-bfg_tstr = TranslationStringFactory('bfg')
-bfg_tstr.__doc__ = """\
- A :class:`repoze.bfg.i18n.TranslationStringFactory` instance with
- a default ``domain`` value of ``bfg``. This object may be called
- with the values ``text``, ``mapping``, and ``msgid`` as per the
- documentation of the
- :class:`repoze.bfg.i18n.TranslationStringFactory` class."""
-
-def get_translator(request, translator_factory=None):
- """ Return a :term:`translator` for the given request based on the
- :term:`translator factory` registered for the current application
- and the :term:`request` passed in as the request object. If no
- translator factory was sent to the
- :class:`repoze.bfg.configuration.Configurator` constructor at
- application startup, this function will return a very simple
- default 'interpolation only' translator.
-
- Note that the translation factory will only be constructed once
- per request instance.
- """
-
- translator = getattr(request, '_bfg_translator', None)
-
- if translator is None:
-
- if translator_factory is None:
- try:
- reg = request.registry
- except AttributeError:
- reg = get_current_registry()
- translator_factory = reg.queryUtility(
- ITranslatorFactory,
- default=InterpolationOnlyTranslator)
-
- translator = translator_factory(request)
-
- try:
- request._bfg_translator = translator
- except AttributeError: # pragma: no cover
- pass # it's only a cache
-
- return translator
-
-class InterpolationOnlyTranslator(object):
-
- """ A class implementing the :term:`translator factory` interface
- as its constructor and the :term:`translator` interface as its
- ``__call__`` method. Useful as a minimal translator factory, this
- class only does basic interpolation of mapping values; it does not
- actually do any language translations and ignores all
- :term:`translation domain` information. To use it explicitly::
-
- from repoze.bfg.configuration import Configurator
- from repoze.bfg.i18n import InterpolationOnlyTranslator
- config = Configurator(translator_factory=InterpolationOnlyTranslator)
-
- An instance of this class is returned by
- :func:`repoze.bfg.i18n.get_translator` if no explicit translator
- factory is registered.
- """
- classProvides(ITranslatorFactory)
- implements(ITranslator)
- def __init__(self, request):
- self.request = request
-
- def __call__(self, message):
- mapping = getattr(message, 'mapping', None)
- return interpolate(message, mapping)
-
-class ChameleonTranslate(object):
- """ Registered as a Chameleon translate function 'under the hood'
- to allow our ITranslator and ITranslatorFactory to drive template
- translation."""
- implements(IChameleonTranslate)
- def __init__(self, translator_factory):
- self.translator_factory = translator_factory
-
- def __call__(self, text, domain=None, mapping=None, context=None,
- target_language=None, default=None):
- if text is None:
- return None
- if default is None:
- default = text
- if mapping is None:
- mapping = {}
- if not hasattr(text, 'mapping'):
- text = TranslationString(default, mapping=mapping, msgid=text,
- domain=domain)
- translator = self.make_translator(target_language)
- return translator(text)
-
- def make_translator(self, target_language):
- translator = None
- request = get_current_request()
- if request is not None:
- translator = get_translator(request, self.translator_factory)
- if translator is None:
- translator = InterpolationOnlyTranslator(request)
- return translator
-
-NAME_RE = r"[a-zA-Z][-a-zA-Z0-9_]*"
-
-_interp_regex = re.compile(r'(?<!\$)(\$(?:(%(n)s)|{(%(n)s)}))'
- % ({'n': NAME_RE}))
-
-def interpolate(text, mapping=None):
- """ Interpolate a string with one or more *replacement markers*
- (``${foo}`` or ``${bar}``). Note that if a :term:`translation
- string` is passed to this function, it will be implicitly
- converted back to the Unicode object."""
- def replace(match):
- whole, param1, param2 = match.groups()
- return unicode(mapping.get(param1 or param2, whole))
-
- if not text or not mapping:
- return text
-
- return _interp_regex.sub(replace, text)
diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py
index f09ad7e36..40d29348c 100644
--- a/repoze/bfg/interfaces.py
+++ b/repoze/bfg/interfaces.py
@@ -229,19 +229,3 @@ class IPackageOverrides(Interface):
# VH_ROOT_KEY is an interface; its imported from other packages (e.g.
# traversalwrapper)
VH_ROOT_KEY = 'HTTP_X_VHM_ROOT'
-
-class ITranslatorFactory(Interface):
- """ Internal interface representing an i18n translator factory """
- def __call__(request):
- """ Return a translator """
-
-class ITranslator(Interface):
- def __call__(tstr):
- """ Return a translation based on the translation string tstr """
-
-class IChameleonTranslate(Interface):
- """ Internal interface representing a chameleon translate function """
- def __call__(msgid, domain=None, mapping=None, context=None,
- target_language=None, default=None):
- """ Translate a mess of arguments to a Unicode object """
-
diff --git a/repoze/bfg/tests/test_chameleon_text.py b/repoze/bfg/tests/test_chameleon_text.py
index 204805adb..007c102e3 100644
--- a/repoze/bfg/tests/test_chameleon_text.py
+++ b/repoze/bfg/tests/test_chameleon_text.py
@@ -28,16 +28,6 @@ class Base:
class TextTemplateRendererTests(Base, unittest.TestCase):
- def setUp(self):
- from repoze.bfg.configuration import Configurator
- from repoze.bfg.registry import Registry
- registry = Registry()
- self.config = Configurator(registry=registry)
- self.config.begin()
-
- def tearDown(self):
- self.config.end()
-
def _getTargetClass(self):
from repoze.bfg.chameleon_text import TextTemplateRenderer
return TextTemplateRenderer
@@ -64,16 +54,6 @@ class TextTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template, instance.__dict__['template'])
- def test_template_with_ichameleon_translate(self):
- from repoze.bfg.interfaces import IChameleonTranslate
- def ct(): pass
- self.config.registry.registerUtility(ct, IChameleonTranslate)
- minimal = self._getTemplatePath('minimal.txt')
- instance = self._makeOne(minimal)
- self.failIf('template' in instance.__dict__)
- template = instance.template
- self.assertEqual(template.translate, ct)
-
def test_call(self):
minimal = self._getTemplatePath('minimal.txt')
instance = self._makeOne(minimal)
diff --git a/repoze/bfg/tests/test_chameleon_zpt.py b/repoze/bfg/tests/test_chameleon_zpt.py
index cbf9dd10b..e4bf8f766 100644
--- a/repoze/bfg/tests/test_chameleon_zpt.py
+++ b/repoze/bfg/tests/test_chameleon_zpt.py
@@ -21,16 +21,6 @@ class Base(object):
return reg
class ZPTTemplateRendererTests(Base, unittest.TestCase):
- def setUp(self):
- from repoze.bfg.configuration import Configurator
- from repoze.bfg.registry import Registry
- registry = Registry()
- self.config = Configurator(registry=registry)
- self.config.begin()
-
- def tearDown(self):
- self.config.end()
-
def _getTargetClass(self):
from repoze.bfg.chameleon_zpt import ZPTTemplateRenderer
return ZPTTemplateRenderer
@@ -65,16 +55,6 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase):
template = instance.template
self.assertEqual(template, instance.__dict__['template'])
- def test_template_with_ichameleon_translate(self):
- from repoze.bfg.interfaces import IChameleonTranslate
- def ct(): pass
- self.config.registry.registerUtility(ct, IChameleonTranslate)
- minimal = self._getTemplatePath('minimal.pt')
- instance = self._makeOne(minimal)
- self.failIf('template' in instance.__dict__)
- template = instance.template
- self.assertEqual(template.translate, ct)
-
def test_call_with_nondict_value(self):
minimal = self._getTemplatePath('minimal.pt')
instance = self._makeOne(minimal)
diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py
index efd58139f..99d564b91 100644
--- a/repoze/bfg/tests/test_configuration.py
+++ b/repoze/bfg/tests/test_configuration.py
@@ -265,15 +265,6 @@ class ConfiguratorTests(unittest.TestCase):
self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'),
renderer)
- def test_setup_registry_translator_factory(self):
- from repoze.bfg.registry import Registry
- from repoze.bfg.interfaces import ITranslatorFactory
- factory = object()
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(translator_factory=factory)
- self.assertEqual(reg.getUtility(ITranslatorFactory), factory)
-
def test_add_settings_settings_already_registered(self):
from repoze.bfg.registry import Registry
from repoze.bfg.interfaces import ISettings
@@ -1736,18 +1727,6 @@ class ConfiguratorTests(unittest.TestCase):
request = self._makeRequest(config)
self.assertEqual(wrapped(None, request).__class__, StaticURLParser)
- def test_set_translator_factory(self):
- from repoze.bfg.interfaces import ITranslatorFactory
- from repoze.bfg.interfaces import IChameleonTranslate
- def factory(): pass
- config = self._makeOne()
- config.set_translator_factory(factory)
- self.assertEqual(config.registry.getUtility(ITranslatorFactory),
- factory)
- self.assertEqual(
- config.registry.getUtility(IChameleonTranslate).translator_factory,
- factory)
-
def test_set_notfound_view(self):
from zope.interface import implementedBy
from repoze.bfg.interfaces import IRequest
diff --git a/repoze/bfg/tests/test_i18n.py b/repoze/bfg/tests/test_i18n.py
deleted file mode 100644
index 7d17b4551..000000000
--- a/repoze/bfg/tests/test_i18n.py
+++ /dev/null
@@ -1,219 +0,0 @@
-import unittest
-
-class TestTranslationString(unittest.TestCase):
- def _makeOne(self, text, **kw):
- from repoze.bfg.i18n import TranslationString
- return TranslationString(text, **kw)
-
- def test_msgid_None(self):
- inst = self._makeOne('text')
- self.assertEqual(inst, 'text')
- self.assertEqual(inst.default, 'text')
-
- def test_msgid_not_None(self):
- inst = self._makeOne('text', msgid='msgid')
- self.assertEqual(inst, 'msgid')
- self.assertEqual(inst.default, 'text')
-
- def test_allargs(self):
- inst = self._makeOne('text', msgid='msgid', mapping='mapping',
- domain='domain')
- self.assertEqual(inst, 'msgid')
- self.assertEqual(inst.default, 'text')
- self.assertEqual(inst.mapping, 'mapping')
- self.assertEqual(inst.domain, 'domain')
-
-class TestTranslationStringFactory(unittest.TestCase):
- def _makeOne(self, domain):
- from repoze.bfg.i18n import TranslationStringFactory
- return TranslationStringFactory(domain)
-
- def test_allargs(self):
- factory = self._makeOne('budge')
- inst = factory('text', mapping='mapping', msgid='msgid')
- self.assertEqual(inst, 'msgid')
- self.assertEqual(inst.domain, 'budge')
- self.assertEqual(inst.mapping, 'mapping')
- self.assertEqual(inst.default, 'text')
-
-class Test_bfg_tstr(unittest.TestCase):
- def _callFUT(self, text, **kw):
- from repoze.bfg.i18n import bfg_tstr
- return bfg_tstr(text, **kw)
-
- def test_allargs(self):
- inst = self._callFUT('text', mapping='mapping', msgid='msgid')
- self.assertEqual(inst, 'msgid')
- self.assertEqual(inst.domain, 'bfg')
- self.assertEqual(inst.mapping, 'mapping')
- self.assertEqual(inst.default, 'text')
-
-class Test_get_translator(unittest.TestCase):
- def _callFUT(self, request):
- from repoze.bfg.i18n import get_translator
- return get_translator(request)
-
- def test_no_ITranslatorFactory(self):
- from repoze.bfg.i18n import InterpolationOnlyTranslator
- request = DummyRequest()
- request.registry = DummyRegistry()
- translator = self._callFUT(request)
- self.assertEqual(translator.__class__, InterpolationOnlyTranslator)
-
- def test_no_registry_on_request(self):
- from repoze.bfg.i18n import InterpolationOnlyTranslator
- request = DummyRequest()
- translator = self._callFUT(request)
- self.assertEqual(translator.__class__, InterpolationOnlyTranslator)
-
- def test_with_ITranslatorFactory_from_registry(self):
- request = DummyRequest()
- tfactory = DummyTranslatorFactory()
- request.registry = DummyRegistry(tfactory)
- translator = self._callFUT(request)
- self.assertEqual(translator.request, request)
-
- def test_with_ITranslatorFactory_from_request_cache(self):
- request = DummyRequest()
- request.registry = DummyRegistry()
- request._bfg_translator = 'abc'
- translator = self._callFUT(request)
- self.assertEqual(translator, 'abc')
-
-class TestInterpolationOnlyTranslator(unittest.TestCase):
- def _makeOne(self, request):
- from repoze.bfg.i18n import InterpolationOnlyTranslator
- return InterpolationOnlyTranslator(request)
-
- def test_it(self):
- message = DummyMessage('text ${a}', mapping={'a':'1'})
- translator = self._makeOne(None)
- result = translator(message)
- self.assertEqual(result, u'text 1')
-
-class TestChameleonTranslate(unittest.TestCase):
- def setUp(self):
- request = DummyRequest()
- from repoze.bfg.configuration import Configurator
- self.config = Configurator()
- self.config.begin(request=request)
- self.request = request
-
- def tearDown(self):
- self.config.end()
-
- def _makeOne(self, factory):
- from repoze.bfg.i18n import ChameleonTranslate
- return ChameleonTranslate(factory)
-
- def test_text_None(self):
- trans = self._makeOne(None)
- result = trans(None)
- self.assertEqual(result, None)
-
- def test_no_current_request(self):
- self.config.manager.pop()
- trans = self._makeOne(None)
- result = trans('text')
- self.assertEqual(result, 'text')
-
- def test_with_current_request_no_translator(self):
- trans = self._makeOne(None)
- result = trans('text')
- self.assertEqual(result, 'text')
-
- def test_with_current_request_and_translator(self):
- from repoze.bfg.interfaces import ITranslatorFactory
- translator = DummyTranslator()
- factory = DummyTranslatorFactory(translator)
- self.config.registry.registerUtility(factory, ITranslatorFactory)
- trans = self._makeOne(None)
- result = trans('text')
- self.assertEqual(result, 'text')
- self.assertEqual(result.domain, None)
- self.assertEqual(result.default, 'text')
- self.assertEqual(result.mapping, {})
-
- def test_with_allargs(self):
- from repoze.bfg.interfaces import ITranslatorFactory
- translator = DummyTranslator()
- factory = DummyTranslatorFactory(translator)
- self.config.registry.registerUtility(factory, ITranslatorFactory)
- trans = self._makeOne(None)
- result = trans('text', domain='domain', mapping={'a':'1'},
- context=None, target_language='lang',
- default='default')
- self.assertEqual(result, 'text')
- self.assertEqual(result.domain, 'domain')
- self.assertEqual(result.default, 'default')
- self.assertEqual(result.mapping, {'a':'1'})
-
-class Test_interpolate(unittest.TestCase):
- def _callFUT(self, text, mapping=None):
- from repoze.bfg.i18n import interpolate
- return interpolate(text, mapping)
-
- def test_substitution(self):
- mapping = {"name": "Zope", "version": 3}
- result = self._callFUT(u"This is $name version ${version}.", mapping)
- self.assertEqual(result, u'This is Zope version 3.')
-
- def test_subsitution_more_than_once(self):
- mapping = {"name": "Zope", "version": 3}
- result = self._callFUT(
- u"This is $name version ${version}. ${name} $version!",
- mapping)
- self.assertEqual(result, u'This is Zope version 3. Zope 3!')
-
- def test_double_dollar_escape(self):
- mapping = {"name": "Zope", "version": 3}
- result = self._callFUT('$$name', mapping)
- self.assertEqual(result, u'$$name')
-
- def test_missing_not_interpolated(self):
- mapping = {"name": "Zope", "version": 3}
- result = self._callFUT(
- u"This is $name $version. $unknown $$name $${version}.",
- mapping)
- self.assertEqual(result,
- u'This is Zope 3. $unknown $$name $${version}.')
-
- def test_missing_mapping(self):
- result = self._callFUT(u"This is ${name}")
- self.assertEqual(result, u'This is ${name}')
-
-class DummyMessage(unicode):
- def __new__(cls, text, msgid=None, domain=None, mapping=None):
- self = unicode.__new__(cls, text)
- if msgid is None:
- msgid = unicode(text)
- self.msgid = msgid
- self.domain = domain
- self.mapping = mapping or {}
- return self
-
-class DummyRequest(object):
- pass
-
-class DummyRegistry(object):
- def __init__(self, tfactory=None):
- self.tfactory = tfactory
-
- def queryUtility(self, iface, default=None):
- return self.tfactory or default
-
-class DummyTranslator(object):
- def __call__(self, message):
- return message
-
-class DummyTranslatorFactory(object):
- def __init__(self, translator=None):
- self.translator = translator
-
- def __call__(self, request):
- self.request = request
- if self.translator is None:
- return self
- return self.translator
-
-
diff --git a/setup.py b/setup.py
index cae2656eb..3dbed2c2a 100644
--- a/setup.py
+++ b/setup.py
@@ -27,7 +27,7 @@ except IOError:
README = CHANGES = ''
install_requires=[
- 'Chameleon >= 1.2.3',
+ 'Chameleon',
'Paste > 1.7', # temp version pin to prevent PyPi install failure :-(
'PasteDeploy',
'PasteScript',
@@ -39,7 +39,6 @@ install_requires=[
'zope.deprecation',
'zope.interface >= 3.5.1', # 3.5.0 comment: "allow to bootstrap on jython"
'venusian >= 0.2',
- 'zope.i18nmessageid',
]
if sys.version_info[:2] < (2, 6):