flufl.i18n-1.1.3/0000775000175000017500000000000012326554745013701 5ustar barrybarry00000000000000flufl.i18n-1.1.3/MANIFEST.in0000664000175000017500000000014312326544555015433 0ustar barrybarry00000000000000include *.py MANIFEST.in global-include *.txt *.rst *.po *.mo *.ini exclude .bzrignore prune build flufl.i18n-1.1.3/setup.py0000664000175000017500000000430112316276127015403 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . from setup_helpers import ( description, get_version, long_description, require_python) from setuptools import setup, find_packages require_python(0x20600f0) __version__ = get_version('flufl/i18n/__init__.py') setup( name='flufl.i18n', version=__version__, namespace_packages=['flufl'], packages=find_packages(), include_package_data=True, zip_safe=False, maintainer='Barry Warsaw', maintainer_email='barry@python.org', description=description('README.rst'), long_description=long_description('README.rst', 'flufl/i18n/NEWS.rst'), license='LGPLv3', url='https://launchpad.net/flufl.i18n', download_url='https://launchpad.net/flufl.i18n/+download', test_suite='flufl.i18n.tests', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: ' 'GNU Lesser General Public License v3 or later (LGPLv3+)', 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS :: MacOS X', 'Programming Language :: Python', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Internationalization', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Localization', ] ) flufl.i18n-1.1.3/setup.cfg0000664000175000017500000000022112326554745015515 0ustar barrybarry00000000000000[build_sphinx] source_dir = flufl/i18n [upload_docs] upload_dir = build/sphinx/html [egg_info] tag_date = 0 tag_build = tag_svn_revision = 0 flufl.i18n-1.1.3/setup_helpers.py0000664000175000017500000001204212316276127017126 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """setup.py helper functions.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'description', 'find_doctests', 'get_version', 'long_description', 'require_python', ] import os import re import sys DEFAULT_VERSION_RE = re.compile(r'(?P\d+\.\d+(?:\.\d+)?)') EMPTYSTRING = '' __version__ = '2.1' def require_python(minimum): """Require at least a minimum Python version. The version number is expressed in terms of `sys.hexversion`. E.g. to require a minimum of Python 2.6, use:: >>> require_python(0x206000f0) :param minimum: Minimum Python version supported. :type minimum: integer """ if sys.hexversion < minimum: hversion = hex(minimum)[2:] if len(hversion) % 2 != 0: hversion = '0' + hversion split = list(hversion) parts = [] while split: parts.append(int(''.join((split.pop(0), split.pop(0))), 16)) major, minor, micro, release = parts if release == 0xf0: print('Python {0}.{1}.{2} or better is required'.format( major, minor, micro)) else: print('Python {0}.{1}.{2} ({3}) or better is required'.format( major, minor, micro, hex(release)[2:])) sys.exit(1) def get_version(filename, pattern=None): """Extract the __version__ from a file without importing it. While you could get the __version__ by importing the module, the very act of importing can cause unintended consequences. For example, Distribute's automatic 2to3 support will break. Instead, this searches the file for a line that starts with __version__, and extract the version number by regular expression matching. By default, two or three dot-separated digits are recognized, but by passing a pattern parameter, you can recognize just about anything. Use the `version` group name to specify the match group. :param filename: The name of the file to search. :type filename: string :param pattern: Optional alternative regular expression pattern to use. :type pattern: string :return: The version that was extracted. :rtype: string """ if pattern is None: cre = DEFAULT_VERSION_RE else: cre = re.compile(pattern) with open(filename) as fp: for line in fp: if line.startswith('__version__'): mo = cre.search(line) assert mo, 'No valid __version__ string found' return mo.group('version') raise AssertionError('No __version__ assignment found') def find_doctests(start='.', extension='.rst'): """Find separate-file doctests in the package. This is useful for Distribute's automatic 2to3 conversion support. The `setup()` keyword argument `convert_2to3_doctests` requires file names, which may be difficult to track automatically as you add new doctests. :param start: Directory to start searching in (default is cwd) :type start: string :param extension: Doctest file extension (default is .txt) :type extension: string :return: The doctest files found. :rtype: list """ doctests = [] for dirpath, dirnames, filenames in os.walk(start): doctests.extend(os.path.join(dirpath, filename) for filename in filenames if filename.endswith(extension)) return doctests def long_description(*filenames): """Provide a long description.""" res = [''] for filename in filenames: with open(filename) as fp: for line in fp: res.append(' ' + line) res.append('') res.append('\n') return EMPTYSTRING.join(res) def description(filename): """Provide a short description.""" # This ends up in the Summary header for PKG-INFO and it should be a # one-liner. It will get rendered on the package page just below the # package version header but above the long_description, which ironically # gets stuff into the Description header. It should not include reST, so # pick out the first single line after the double header. with open(filename) as fp: for lineno, line in enumerate(fp): if lineno < 3: continue line = line.strip() if len(line) > 0: return line flufl.i18n-1.1.3/flufl/0000775000175000017500000000000012326554745015011 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/__init__.py0000664000175000017500000000156612316276127017124 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n. # # flufl.i18n is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . # this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) flufl.i18n-1.1.3/flufl/i18n/0000775000175000017500000000000012326554745015570 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/_registry.py0000664000175000017500000000316612316276127020151 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Translation registry.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'registry', ] from flufl.i18n._application import Application class Registry: """A registry of application translation lookup strategies.""" def __init__(self): # Map application names to Application instances. self._registry = {} def register(self, strategy): """Add an association between an application and a lookup strategy. :param strategy: An application translation lookup strategy. :type application: A callable object with a .name attribute :return: An application instance which can be used to access the language catalogs for the application. :rtype: `Application` """ application = Application(strategy) self._registry[strategy.name] = application return application registry = Registry() flufl.i18n-1.1.3/flufl/i18n/docs/0000775000175000017500000000000012326554745016520 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/docs/using.rst0000664000175000017500000001635612316276127020404 0ustar barrybarry00000000000000============================ Using the flufl.i18n library ============================ Set up ====== There are two basic ways that your application can set up translations using this library. The simple initialization will work for most applications, where there is only one language context for the entire run of the application. The more complex initialization works well for applications like servers that may want to use multiple language contexts during their execution. Single language contexts ------------------------ If your application only needs one language context for its entire execution, you can use the simple API to set things up. >>> from flufl.i18n import initialize The library by default uses the ``$LANG`` and ``$LOCPATH`` environment variables to set things up:: >>> # The testing 'xx' language rot13's the source string. The >>> # gettext catalogs are in this package directory. >>> import os >>> import flufl.i18n.testing.messages >>> os.environ['LANG'] = 'xx' >>> os.environ['LOCPATH'] = os.path.dirname( ... flufl.i18n.testing.messages.__file__) Now you just need to call the ``initialize()`` function with the application's name and you'll get an object back that you can assign to the ``_()`` function for run-time translations. >>> _ = initialize('flufl') >>> print(_('A test message')) N grfg zrffntr It's probably best to just share this function through imports, but it does no harm to call ``initialize()`` again. >>> _ = initialize('flufl') >>> print(_('A test message')) N grfg zrffntr .. >>> # Unregister the application domain used earlier. Also, clear the >>> # environment settings from above. >>> from flufl.i18n import registry >>> registry._registry.clear() >>> del os.environ['LANG'] >>> del os.environ['LOCPATH'] Multiple language contexts -------------------------- Some applications, such as servers, are more complex; they need multiple language contexts during their execution. To support this, there is a global registry of catalog look up :doc:`strategies `. When a particular language code is specified, the strategy is used to find the catalog that provides that language's translations. ``flufl.i18n`` comes with a couple of fairly simple strategies, but you can of course write your own. A convenient built-in strategy looks up catalogs from within the package directory using `GNU gettext`_'s convention, where the base directory for the catalogs is rooted in a subpackage. >>> from flufl.i18n import registry >>> from flufl.i18n import PackageStrategy >>> strategy = PackageStrategy('flufl', flufl.i18n.testing.messages) The first argument is the application name, which must be unique among all registered strategies. The second argument is the package where the translations can be found. Once you have the desired strategy, register this with the global registry. The registration process returns an application object which can be used to look up language codes. >>> application = registry.register(strategy) The application object keeps track of a current translation catalog, and exports a method which you can bind to the *underscore* function in your module globals for convenient gettext usage. By doing so, at run time, ``_()`` will always translate the string argument to the current catalog's language. >>> _ = application._ By default the application just translates the source string back into the source string. I.e. it is a null translator. >>> print(_('A test message')) A test message And it has no language code. >>> print(_.code) None You can temporarily push a new language context to the top of the stack, which automatically rebinds the underscore function to the language's catalog. >>> _.push('xx') >>> print(_.code) xx >>> print(_('A test message')) N grfg zrffntr Pop the current language to return to the default. Once you're at the bottom of the stack, more pops will just give you the default translation. >>> _.pop() >>> print(_.code) None >>> print(_('A test message')) A test message >>> _.pop() >>> print(_.code) None >>> print(_('A test message')) A test message The underscore method has a context manager called ``using`` which can be used to temporarily set a new language inside a ``with`` statement:: >>> with _.using('xx'): ... print(_('A test message')) N grfg zrffntr >>> print(_('A test message')) A test message These ``with`` statements are nestable:: >>> with _.using('xx'): ... print(_('A test message')) ... with _.using('yy'): ... print(_('A test message')) ... print(_('A test message')) N grfg zrffntr egassem tset A N grfg zrffntr >>> print(_('A test message')) A test message You can set the bottom language context, which replaces the default null translation:: >>> _.default = 'xx' >>> print(_('A test message')) N grfg zrffntr >>> _.pop() >>> print(_.code) xx >>> print(_('A test message')) N grfg zrffntr >>> with _.using('yy'): ... print(_('A test message')) egassem tset A >>> print(_('A test message')) N grfg zrffntr Substitutions and placeholders ============================== As you can see from the example above, using the library is very simple. You just put the string to translate inside the underscore function. What if your source strings need placeholders for other runtime information? In that case, you use `PEP 292`_ style substitution strings as arguments to the underscore function. Substitutions are taken from the locals and globals of the function doing the translation, so that you don't have to repeat yourself. >>> ordinal = 'first' >>> def print_it(name): ... print(_('The $ordinal test message $name')) In this example, when ``print_it()`` is called, the ``$ordinal`` placeholder is taken from globals, while the ``$name`` placeholder is taken from the function locals (i.e. the arguments). .. >>> # Reset the language context. >>> del _.default >>> print(_.code) None With no language context in place, the source string is printed unchanged, except that the substitutions are made. >>> print_it('Anne') The first test message Anne When a substitution is missing, rather than raise an exception, the ``$variable`` is used unchanged. >>> del ordinal >>> print_it('Bart') The $ordinal test message Bart When there is a language context in effect, the substitutions happen after translation. >>> ordinal = 'second' >>> with _.using('xx'): ... print_it('Cris') second si n grfg zrffntr Cris Some languages change the order of the substitution variables, but of course there is no problem with that. >>> ordinal = 'third' >>> with _.using('yy'): ... print_it('Dave') Dave egassem tset third eht Locals always take precedence over globals:: >>> def print_it(name, ordinal): ... print(_('The $ordinal test message $name')) >>> with _.using('yy'): ... print_it('Elle', 'fourth') Elle egassem tset fourth eht .. _`GNU gettext`: http://www.gnu.org/software/gettext/manual/gettext.html .. _`PEP 292`: http://www.python.org/dev/peps/pep-0292/ flufl.i18n-1.1.3/flufl/i18n/docs/__init__.py0000664000175000017500000000000012316276127020611 0ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/docs/expand.rst0000664000175000017500000000143412316276127020525 0ustar barrybarry00000000000000=================== Expanding templates =================== `PEP 292`_ defines a simplified string template, where substitution variables are identified by a leading ``$``-sign. The substitution dictionary names the keys and values that should be interpolated into the template:: >>> key_1 = 'key_1' >>> key_2 = 'key_2' >>> from flufl.i18n import expand >>> # This may fail for Python < 2.6.5 >>> print(expand( ... '$key_2 is different than $key_1', { ... key_1: 'the first key', ... key_2: 'the second key', ... })) the second key is different than the first key See `issue 4978`_ for Python 2.6.x compatibility. .. _`PEP 292`: http://www.python.org/dev/peps/pep-0292/ .. _`issue 4978`: http://bugs.python.org/issue4978 flufl.i18n-1.1.3/flufl/i18n/docs/strategies.rst0000664000175000017500000000611712316276127021423 0ustar barrybarry00000000000000================== Catalog strategies ================== The way ``flufl.i18n`` finds its catalog for an application is extensible. These are called *strategies*. ``flufl.i18n`` comes with a couple of fairly simple strategies. The first locates catalog files from within a package's directory. Inside the package directory, you still need the ``gettext`` standard layout of ``/LC_MESSAGES/.mo``. Python package strategies ========================= For example, to use the catalog in ``flufl.i18n``'s testing package, you would use the ``PackageStrategy``. >>> from flufl.i18n import PackageStrategy >>> import flufl.i18n.testing.messages By setting the ``$LANG`` environment variable, we can specify that the application translates into that language automatically. >>> # The testing 'xx' language rot13's the source string. >>> import os >>> os.environ['LANG'] = 'xx' The first argument is the application name, which must be unique among all registered strategies. The second argument is the package in which to search. >>> strategy = PackageStrategy('flufl', flufl.i18n.testing.messages) Once you have the desired strategy, register this with the global registry. The registration process returns an application object which can be used to look up language codes. >>> from flufl.i18n import registry >>> application = registry.register(strategy) The application object keeps track of a current translation catalog, and exports a method which you can bind to the 'underscore' function in your module globals for convenient gettext usage. >>> _ = application._ By doing so, at run time, ``_()`` will always translate the string argument to the current catalog's language. >>> print(_('A test message')) N grfg zrffntr .. >>> # Hack to unregister the previous strategy. >>> registry._registry.clear() Simple strategy =============== There is also a simpler strategy that uses both the ``$LANG`` environment variable, and the ``$LOCPATH`` environment variable to set things up:: >>> os.environ['LOCPATH'] = os.path.dirname( ... flufl.i18n.testing.messages.__file__) >>> from flufl.i18n import SimpleStrategy >>> strategy = SimpleStrategy('flufl') >>> application = registry.register(strategy) >>> _ = application._ >>> print(_('A test message')) N grfg zrffntr Calling with zero arguments =========================== Strategies should be prepared to accept zero arguments when called, to produce a *default* translation (usually the ``gettext.NullTranslator``). Here, we look for the `ugettext()` method for Python 2 and the `gettext()` method for Python 3:: >>> def get_ugettext(strategy): ... catalog = strategy() ... try: ... return catalog.ugettext ... except AttributeError: ... # Python 3 ... return catalog.gettext >>> print(get_ugettext(SimpleStrategy('example'))('A test message')) A test message >>> print(get_ugettext(PackageStrategy( ... 'example', flufl.i18n.testing.messages))('A test message')) A test message flufl.i18n-1.1.3/flufl/i18n/testing/0000775000175000017500000000000012326554745017245 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/testing/messages/0000775000175000017500000000000012326554745021054 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/testing/messages/__init__.py0000664000175000017500000000000012316276127023145 0ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/testing/messages/xx/0000775000175000017500000000000012326554745021513 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/testing/messages/xx/LC_MESSAGES/0000775000175000017500000000000012326554745023300 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/testing/messages/xx/LC_MESSAGES/flufl.mo0000664000175000017500000000077211624413310024731 0ustar barrybarry000000000000004L`ap9 A test messageThe $ordinal test message $nameProject-Id-Version: PACKAGE VERSION POT-Creation-Date: Sun Jan 8 15:53:47 2006 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language-Team: LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Generated-By: hand N grfg zrffntr$ordinal si n grfg zrffntr $nameflufl.i18n-1.1.3/flufl/i18n/testing/messages/xx/LC_MESSAGES/flufl.po0000664000175000017500000000124712316276127024746 0ustar barrybarry00000000000000# A testing catalog # Copyright (C) 2009-2014 by Barry A. Warsaw # Barry Warsaw , 2009, 2010. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: Sun Jan 8 15:53:47 2006\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: hand\n" #: flufl/i18n/docs/readme.txt:39 msgid "A test message" msgstr "N grfg zrffntr" #: flufl/i18n/docs/readme.txt:40 msgid "The $ordinal test message $name" msgstr "$ordinal si n grfg zrffntr $name" flufl.i18n-1.1.3/flufl/i18n/testing/messages/yy/0000775000175000017500000000000012326554745021515 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/testing/messages/yy/LC_MESSAGES/0000775000175000017500000000000012326554745023302 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/testing/messages/yy/LC_MESSAGES/flufl.mo0000664000175000017500000000077111624413325024740 0ustar barrybarry000000000000004L`ap9A test messageThe $ordinal test message $nameProject-Id-Version: PACKAGE VERSION POT-Creation-Date: Sun Jan 8 15:53:47 2006 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language-Team: LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Generated-By: hand egassem tset A$name egassem tset $ordinal ehtflufl.i18n-1.1.3/flufl/i18n/testing/messages/yy/LC_MESSAGES/flufl.po0000664000175000017500000000124612316276127024747 0ustar barrybarry00000000000000# A testing catalog # Copyright (C) 2009-2014 by Barry A. Warsaw # Barry Warsaw , 2009, 2010. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: Sun Jan 8 15:53:47 2006\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: hand\n" #: flufl/i18n/docs/readme.txt:39 msgid "A test message" msgstr "egassem tset A" #: flufl/i18n/docs/readme.txt:40 msgid "The $ordinal test message $name" msgstr "$name egassem tset $ordinal eht" flufl.i18n-1.1.3/flufl/i18n/testing/__init__.py0000664000175000017500000000000012316276127021336 0ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/_strategy.py0000664000175000017500000000610212316276127020134 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Catalog search strategies.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'PackageStrategy', 'SimpleStrategy', ] import os import gettext class _BaseStrategy: """Common code for strategies.""" def __init__(self, name): """Create a catalog lookup strategy. :param name: The application's name. :type name: string """ self.name = name self._messages_dir = None def __call__(self, language_code=None): """Find the catalog for the language. :param language_code: The language code to find. If None, then the default gettext language code lookup scheme is used. :type language_code: string :return: A `gettext` catalog. :rtype: `gettext.NullTranslations` or subclass """ # gettext.translation() requires None or a sequence. languages = (None if language_code is None else [language_code]) try: return gettext.translation( self.name, self._messages_dir, languages) except IOError: # Fall back to untranslated source language. return gettext.NullTranslations() class PackageStrategy(_BaseStrategy): """A strategy that finds catalogs based on package paths.""" def __init__(self, name, package): """Create a catalog lookup strategy. :param name: The application's name. :type name: string :param package: The package path to the message catalogs. This strategy uses the __file__ of the package path as the directory containing `gettext` messages. :type package_name: module """ super(PackageStrategy, self).__init__(name) self._messages_dir = os.path.dirname(package.__file__) class SimpleStrategy(_BaseStrategy): """A simpler strategy for getting translations.""" def __init__(self, name): """Create a catalog lookup strategy. :param name: The application's name. :type name: string :param package: The package path to the message catalogs. This strategy uses the __file__ of the package path as the directory containing `gettext` messages. :type package_name: module """ super(SimpleStrategy, self).__init__(name) self._messages_dir = os.environ.get('LOCPATH') flufl.i18n-1.1.3/flufl/i18n/_application.py0000664000175000017500000002052012316276127020575 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """An application.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'Application', ] from flufl.i18n._translator import Translator class _Using: """Context manager for _.using().""" def __init__(self, application, language_code): self._application = application self._language_code = language_code def __enter__(self): self._application.push(self._language_code) def __exit__(self, *exc_info): self._application.pop() # Do not suppress exceptions. return False class _Underscore: """The implementation of the _() function. This class is internal representation only and has an incestuous relationship with the Application class. """ def __init__(self, application): self._application = application def __call__(self, original, extras=None): """Translate the string into the language of the current context. :param original: The original string to translate. :type original: string :param extras: Extra substitution mapping, elements of which override the locals and globals. :return: The translated string. :rtype: string """ return self._application.current.translate(original, extras) def using(self, language_code): """Create a context manager for temporary translation. While in this context manager, translations use the given language code. When the with statement exits, the original language is restored. These are nestable. """ return _Using(self._application, language_code) def push(self, language_code): """Push a new catalog onto the stack. The translation catalog associated with the language code now becomes the currently active translation context. """ self._application.push(language_code) def pop(self): """Pop the current catalog off the translation stack. No exception is raised for under-runs. In that case, pop() just no-ops and the null translation becomes the current translation context. """ self._application.pop() @property def default(self): """Return the default language code. :return: The default language code. :rtype: string or None if there is no default language """ return self._application.default @default.setter def default(self, language_code): """Set the default language code. :param language_code: The language code for the default translator. :type language_code: string """ self._application.default = language_code @default.deleter def default(self): """Reset the default language to the null translator.""" del self._application.default @property def code(self): """Return the language code currently in effect.""" code = self._application.code if code is None: return self.default return code class Application: """Manage all the catalogs for a particular application. You can ask the application for a specific catalog based on the language code. The Application requires a strategy for finding catalog files. Attributes: * dedent (default True) - controls whether translated strings are dedented or not. This is passed through to the underlying `Translator` instance. * depth (default 2) - The number of stack frames to call sys._getframe() with in the underlying `Translator` instance. Passed through to that class's constructor. """ def __init__(self, strategy): """Create an `Application`. Use the `dedent` attribute on this instance to control whether translated strings are dedented or not. This is passed straight through to the `Translator` instance created in the _() method. :param strategy: A callable that can find catalog files for the application based on the language code. :type strategy: callable taking one string argument, the language code. """ self._strategy = strategy # A mapping from language codes to catalogs. self._catalogs = {} self._stack = [] # Arguments to the Translator constructor. self.dedent = True self.depth = 2 # By default, the baseline translator is the null translator. Use our # public API so that we share code. self._default_language = None self._default_translator = None # This sets the _default_translator. del self.default @property def name(self): """The application name. :return: The application name. :rtype: string """ return self._strategy.name @property def default(self): """Return the default language code. :return: The default language code. :rtype: string or None if there is no default language """ return self._default_language @default.setter def default(self, language_code): """Set the default language code. :param language_code: The language code for the default translator. :type language_code: string """ self._default_language = language_code catalog = self.get(language_code) self._default_translator = Translator(catalog, self.dedent, self.depth) @default.deleter def default(self): """Reset the default language to the null translator.""" self._default_language = None self._default_translator = Translator( self._strategy(), self.dedent, self.depth) def get(self, language_code): """Get the catalog associated with the language code. :param language_code: The language code. :type language_code: string :return: A `gettext` catalog. :rtype: `gettext.NullTranslations` or subclass. """ missing = object() catalog = self._catalogs.get(language_code, missing) if catalog is missing: catalog = self._strategy(language_code) self._catalogs[language_code] = catalog return catalog @property def _(self): """Return a translator object, tied to the current catalog. :return: A translator context object for the current active catalog. :rtype: `Translator` """ return _Underscore(self) def push(self, language_code): """Push a new catalog onto the stack. The translation catalog associated with the language code now becomes the currently active translation context. """ catalog = self.get(language_code) translator = Translator(catalog, self.dedent, self.depth) self._stack.append((language_code, translator)) def pop(self): """Pop the current catalog off the translation stack. No exception is raised for under-runs. In that case, pop() just no-ops and the null translation becomes the current translation context. """ if len(self._stack) > 0: self._stack.pop() @property def current(self): """Return the current translator. :return: The current translator. :rtype: `Translator` """ if len(self._stack) == 0: return self._default_translator return self._stack[-1][1] @property def code(self): """Return the current language code. :return: The current language code. :rtype: string """ if len(self._stack) == 0: return None return self._stack[-1][0] flufl.i18n-1.1.3/flufl/i18n/NEWS.rst0000664000175000017500000000377612326543735017110 0ustar barrybarry00000000000000===================== NEWS for flufl.i18n ===================== 1.1.3 (2014-04-25) ================== * Include MANIFEST.in in the sdist tarball, otherwise the Debian package won't built correctly. 1.1.2 (2014-03-31) ================== * Fix documentation bug. LP: #1026403 * Use modern setuptools rather than distutils. * Bump copyright years. 1.1.1 (2012-04-19) ================== * Add classifiers to setup.py and make the long description more compatible with the Cheeseshop. * Other changes to make the Cheeseshop page look nicer. (LP: #680136) * setup_helper.py version 2.1. 1.1 (2012-01-19) ================ * Support Python 3 without the need for 2to3. 1.0.4 (2010-12-06) ================== * Restore missing line from MANIFEST.in to fix distribution tarball. 1.0.3 (2010-12-01) ================== * Fix setup.py to not install myfixers artifact directory on install. * Remove pylint.rc; we'll use pyflakes instead. 1.0.2 (2010-06-23) ================== * Small documentation fix. 1.0.1 (2010-06-09) ================== * Ditch the use of zc.buildout. * Improved documentation. 1.0 (2010-04-24) ================ * Use Distribute instead of Setuptools. * Port to Python 3 when used with 2to3. * More documentation improvements. 0.6 (2010-04-21) ================ * Documentation and lint clean up. 0.5 (2010-04-20) ================ * Added a simplified initialization API for one-language-context applications. This works much better for non-server applications. * Added a SimpleStrategy which recognizes the $LOCPATH environment variable. * Show how PEP 292 strings are supported automatically. * When strategies are called with zero arguments, they supply the default translation context, which is usually a NullTranslation. This is better than hardcoding the NullTranslation in the Application. 0.4 (2010-03-04) ================ * Add the ability to get the current language code, via _.code 0.3 (2009-11-15) ================ * Initial release; refactored from Mailman 3. flufl.i18n-1.1.3/flufl/i18n/__init__.py0000664000175000017500000000217612326544030017671 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Expose sub-module names in the package namespace.""" __version__ = '1.1.3' from flufl.i18n._expand import expand from flufl.i18n._registry import registry from flufl.i18n._strategy import * def initialize(domain): """A convenience function for setting up translation. :param domain: The application's name. :type domain: string """ strategy = SimpleStrategy(domain) application = registry.register(strategy) return application._ flufl.i18n-1.1.3/flufl/i18n/conf.py0000664000175000017500000001533112316276230017057 0ustar barrybarry00000000000000# -*- coding: utf-8 -*- # # flufl.i18n documentation build configuration file, created by # sphinx-quickstart on Fri Apr 23 11:41:37 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. from __future__ import print_function import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.append(os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['../../_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'README' # General information about the project. project = 'flufl.i18n' copyright = '2009-2014, Barry A. Warsaw' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # from flufl.i18n import __version__ # The short X.Y version. version = __version__ # The full version, including alpha/beta/rc tags. release = __version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build', 'build', 'flufl.i18n.egg-info', 'distribute-0.6.10'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['../../_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'flufli18ndoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('README.rst', 'flufli18n.tex', 'flufl.i18n Documentation', 'Barry A. Warsaw', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True import errno def index_html(): cwd = os.getcwd() try: os.chdir('build/sphinx/html') try: os.symlink('README.html', 'index.html') except OSError as error: if error.errno != errno.EEXIST: raise print('index.html -> README.html') finally: os.chdir(cwd) import atexit atexit.register(index_html) flufl.i18n-1.1.3/flufl/i18n/_expand.py0000664000175000017500000000304412316276127017553 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """String interpolation.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'expand', ] import logging from string import Template log = logging.getLogger('flufl.i18n') def expand(template, substitutions, template_class=Template): """Expand string template with substitutions. :param template: A PEP 292 $-string template. :type template: string :param substitutions: The substitutions dictionary. :type substitutions: dict :param template_class: The template class to use. :type template_class: class :return: The substituted string. :rtype: string """ try: return template_class(template).safe_substitute(substitutions) except (TypeError, ValueError): # The template is really screwed up. log.exception('broken template: %s', template) flufl.i18n-1.1.3/flufl/i18n/_substitute.py0000664000175000017500000000251412316276127020510 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Substitutions.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'Template', 'attrdict', ] import string _missing = object() class Template(string.Template): """Match any attribute path.""" idpattern = r'[_a-z][_a-z0-9.]*' class attrdict(dict): """Follow attribute paths.""" def __getitem__(self, key): parts = key.split('.') value = super(attrdict, self).__getitem__(parts.pop(0)) while parts: value = getattr(value, parts.pop(0), _missing) if value is _missing: raise KeyError(key) return value flufl.i18n-1.1.3/flufl/i18n/README.rst0000664000175000017500000000542512316276247017262 0ustar barrybarry00000000000000====================================================== flufl.i18n - A high level API for internationalization ====================================================== This package provides a high level, convenient API for managing internationalization translation contexts in Python application. There is a simple API for single-context applications, such as command line scripts which only need to translate into one language during the entire course of their execution. There is a more flexible, but still convenient API for multi-context applications, such as servers, which may need to switch language contexts for different tasks. Requirements ============ ``flufl.i18n`` requires Python 2.6.5 or newer, and is compatible with Python 3. Documentation ============= A `simple guide`_ to using the library is available within this package, in the form of doctests. The manual is also available online in the Cheeseshop at: http://packages.python.org/flufl.i18n Project details =============== The project home page is: http://launchpad.net/flufl.i18n You should report bugs at: http://bugs.launchpad.net/flufl.i18n You can download the latest version of the package either from the Cheeseshop: http://pypi.python.org/pypi/flufl.i18n or from the Launchpad page above. Of course you can also just install it with ``pip`` or ``easy_install`` from the command line:: % sudo pip install flufl.i18n % sudo easy_install flufl.i18n You may want to use `virtualenv`_ instead of installing the package into the system Python. You can grab the latest development copy of the code using Bazaar, from the Launchpad home page above. See http://bazaar-vcs.org for details on the Bazaar distributed revision control system. If you have Bazaar installed, you can branch the code like this:: % bzr branch lp:flufl.i18n You may contact the author via barry@python.org. Copyright ========= Copyright (C) 2009-2014 Barry A. Warsaw This file is part of flufl.i18n flufl.i18n is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. flufl.i18n is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with flufl.i18n. If not, see . Table of Contents ================= .. toctree:: :glob: docs/using docs/* NEWS .. _`simple guide`: docs/using.html .. _`virtualenv`: http://www.virtualenv.org/en/latest/index.html flufl.i18n-1.1.3/flufl/i18n/tests/0000775000175000017500000000000012326554745016732 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/tests/test_translator.py0000664000175000017500000001042612316276127022531 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Tests for the Translator class. This cannot be a doctest because of the sys._getframe() manipulations. That does not play well with the way doctest executes Python code. But see translator.txt for a description of how this should work in real Python code. """ from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ ] import unittest from flufl.i18n._translator import Translator # Some globals for following tests. purple = 'porpoises' magenta = 'monkeys' green = 'gerbil' class Catalog: """Test catalog.""" def __init__(self): self.translation = None def ugettext(self, original): """Return the translation.""" return self.translation # For Python 3. gettext = ugettext def charset(self): """Return the encoding.""" # The default is ascii. return None class TranslatorTests(unittest.TestCase): """Tests of the Translator class.""" def setUp(self): self.catalog = Catalog() # We need depth=1 because we're calling the translation at the same # level as the locals we care about. self.translator = Translator(self.catalog, depth=1) def test_locals(self): # Test that locals get properly substituted. aqua = 'aardvarks' blue = 'badgers' cyan = 'cats' self.catalog.translation = '$blue and $cyan and $aqua' self.assertEqual(self.translator.translate('source string'), 'badgers and cats and aardvarks') def test_globals(self): # Test that globals get properly substituted. self.catalog.translation = '$purple and $magenta and $green' self.assertEqual(self.translator.translate('source string'), 'porpoises and monkeys and gerbil') def test_dict_overrides_locals(self): # Test that explicit mappings override locals. aqua = 'aardvarks' blue = 'badgers' cyan = 'cats' overrides = dict(blue='bats') self.catalog.translation = '$blue and $cyan and $aqua' self.assertEqual(self.translator.translate('source string', overrides), 'bats and cats and aardvarks') def test_globals_with_overrides(self): # Test that globals with overrides get properly substituted. self.catalog.translation = '$purple and $magenta and $green' overrides = dict(green='giraffe') self.assertEqual(self.translator.translate('source string', overrides), 'porpoises and monkeys and giraffe') def test_empty_string(self): # The empty string is always translated as the empty string. self.assertEqual(self.translator.translate(''), '') def test_dedent(self): # By default, the translated string is always dedented. aqua = 'aardvarks' blue = 'badgers' cyan = 'cats' self.catalog.translation = """\ These are the $blue These are the $cyan These are the $aqua """ for line in self.translator.translate('source string').splitlines(): self.assertTrue(line[:5], 'These') def test_no_dedent(self): # You can optionally suppress the dedent. aqua = 'aardvarks' blue = 'badgers' cyan = 'cats' self.catalog.translation = """\ These are the $blue These are the $cyan These are the $aqua """ translator = Translator(self.catalog, dedent=False) for line in translator.translate('source string').splitlines(): self.assertTrue(line[:9], ' These') flufl.i18n-1.1.3/flufl/i18n/tests/__init__.py0000664000175000017500000000000012316276127021023 0ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl/i18n/tests/test_documentation.py0000664000175000017500000000471512316276127023215 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Test harness for doctests.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'additional_tests', ] import os import atexit import doctest import unittest from pkg_resources import ( resource_filename, resource_exists, resource_listdir, cleanup_resources) DOCTEST_FLAGS = ( doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | doctest.REPORT_NDIFF) def setup(testobj): """Test setup.""" # Make sure future statements in our doctests match the Python code. When # run with 2to3, the future import gets removed and these names are not # defined. try: testobj.globs['absolute_import'] = absolute_import testobj.globs['print_function'] = print_function testobj.globs['unicode_literals'] = unicode_literals except NameError: pass # Ensure that environment variables affecting translation are neutralized. for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): if envar in os.environ: del os.environ[envar] def additional_tests(): "Run the doc tests (README.txt and docs/*, if any exist)" doctest_files = [ os.path.abspath(resource_filename('flufl.i18n', 'README.rst'))] if resource_exists('flufl.i18n', 'docs'): for name in resource_listdir('flufl.i18n', 'docs'): if name.endswith('.rst'): doctest_files.append( os.path.abspath( resource_filename('flufl.i18n', 'docs/%s' % name))) kwargs = dict(module_relative=False, optionflags=DOCTEST_FLAGS, setUp=setup, ) atexit.register(cleanup_resources) return unittest.TestSuite(( doctest.DocFileSuite(*doctest_files, **kwargs))) flufl.i18n-1.1.3/flufl/i18n/_translator.py0000664000175000017500000001037012316276127020465 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Basic translation context class.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ 'Translator', ] import sys import textwrap from flufl.i18n._substitute import attrdict, Template from flufl.i18n._expand import expand try: unicode_type = unicode except NameError: # Python 3 unicode_type = str class Translator: """A translation context.""" def __init__(self, catalog, dedent=True, depth=2): """Create a translation context. :param catalog: The translation catalog. :type catalog: `gettext.NullTranslations` or subclass :param dedent: Whether the input string should be dedented. :type dedent: bool :param depth: Number of stack frames to call sys._getframe() with. :type depth: int """ self._catalog = catalog self.dedent = dedent self.depth = depth # Python 3's .gettext() returns unicodes. try: self._gettext = self._catalog.ugettext except AttributeError: # Must be Python 3, right? self._gettext = self._catalog.gettext def translate(self, original, extras=None): """Translate the string. :param original: The original string to translate. :type original: string :param extras: Extra substitution mapping, elements of which override the locals and globals. :return: The translated string. :rtype: string """ if original == '': return '' assert original, 'Cannot translate: {0}'.format(original) # Because the original string is what the text extractors put into the # catalog, we must first look up the original unadulterated string in # the catalog. Use the global translation context for this. # # Translations must be unicode safe internally. The translation # service is one boundary to the outside world, so to honor this # constraint, make sure that all strings to come out of this are # unicodes, even if the translated string or dictionary values are # 8-bit strings. tns = self._gettext(original) charset = self._catalog.charset() or 'us-ascii' # Do PEP 292 style $-string interpolation into the resulting string. # # This lets you write something like: # # now = time.ctime(time.time()) # print _('The current time is: $now') # # and have it Just Work. Key precedence is: # # extras > locals > globals # # Get the frame of the caller. frame = sys._getframe(self.depth) # Create the raw dictionary of substitutions. raw_dict = frame.f_globals.copy() raw_dict.update(frame.f_locals) if extras is not None: raw_dict.update(extras) # Python 2 requires ** dictionaries to have str, not unicode keys. # For our purposes, keys should always be ascii. Values though should # be unicode. translated_string = expand(tns, attrdict(raw_dict), Template) # Use the bytes type here instead of str for better compatibility with # 2to3, which transforms this code into trying to decode a unicode to # a unicode. if isinstance(translated_string, bytes): translated_string = unicode_type(translated_string, charset) # Dedent the string if so desired. if self.dedent: translated_string = textwrap.dedent(translated_string) return translated_string flufl.i18n-1.1.3/tox.ini0000664000175000017500000000012412316276657015213 0ustar barrybarry00000000000000[tox] envlist = py26,py27,py32,py33,py34 [testenv] commands = python setup.py test flufl.i18n-1.1.3/flufl.i18n.egg-info/0000775000175000017500000000000012326554745017261 5ustar barrybarry00000000000000flufl.i18n-1.1.3/flufl.i18n.egg-info/SOURCES.txt0000664000175000017500000000203712326554745021147 0ustar barrybarry00000000000000COPYING-LESSER.txt MANIFEST.in README.rst setup.cfg setup.py setup_helpers.py template.py tox.ini flufl/__init__.py flufl.i18n.egg-info/PKG-INFO flufl.i18n.egg-info/SOURCES.txt flufl.i18n.egg-info/dependency_links.txt flufl.i18n.egg-info/namespace_packages.txt flufl.i18n.egg-info/not-zip-safe flufl.i18n.egg-info/top_level.txt flufl/i18n/NEWS.rst flufl/i18n/README.rst flufl/i18n/__init__.py flufl/i18n/_application.py flufl/i18n/_expand.py flufl/i18n/_registry.py flufl/i18n/_strategy.py flufl/i18n/_substitute.py flufl/i18n/_translator.py flufl/i18n/conf.py flufl/i18n/docs/__init__.py flufl/i18n/docs/expand.rst flufl/i18n/docs/strategies.rst flufl/i18n/docs/using.rst flufl/i18n/testing/__init__.py flufl/i18n/testing/messages/__init__.py flufl/i18n/testing/messages/xx/LC_MESSAGES/flufl.mo flufl/i18n/testing/messages/xx/LC_MESSAGES/flufl.po flufl/i18n/testing/messages/yy/LC_MESSAGES/flufl.mo flufl/i18n/testing/messages/yy/LC_MESSAGES/flufl.po flufl/i18n/tests/__init__.py flufl/i18n/tests/test_documentation.py flufl/i18n/tests/test_translator.pyflufl.i18n-1.1.3/flufl.i18n.egg-info/top_level.txt0000664000175000017500000000000612326554745022007 0ustar barrybarry00000000000000flufl flufl.i18n-1.1.3/flufl.i18n.egg-info/dependency_links.txt0000664000175000017500000000000112326554745023327 0ustar barrybarry00000000000000 flufl.i18n-1.1.3/flufl.i18n.egg-info/namespace_packages.txt0000664000175000017500000000000612326554745023610 0ustar barrybarry00000000000000flufl flufl.i18n-1.1.3/flufl.i18n.egg-info/not-zip-safe0000664000175000017500000000000112326554605021502 0ustar barrybarry00000000000000 flufl.i18n-1.1.3/flufl.i18n.egg-info/PKG-INFO0000664000175000017500000001242512326554745020362 0ustar barrybarry00000000000000Metadata-Version: 1.1 Name: flufl.i18n Version: 1.1.3 Summary: A high level API for Python internationalization. Home-page: https://launchpad.net/flufl.i18n Author: Barry Warsaw Author-email: barry@python.org License: LGPLv3 Download-URL: https://launchpad.net/flufl.i18n/+download Description: ========== flufl.i18n ========== A high level API for Python internationalization. The ``flufl.i18n`` library provides a convenient API for managing translation contexts in Python applications. It provides facilities not only for single-context applications like command line scripts, but also more sophisticated management of multiple-context applications such as Internet servers. License ======= This file is part of flufl.i18n. flufl.i18n is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 3 of the License. flufl.i18n is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with flufl.i18n. If not, see . ===================== NEWS for flufl.i18n ===================== 1.1.3 (2014-04-25) ================== * Include MANIFEST.in in the sdist tarball, otherwise the Debian package won't built correctly. 1.1.2 (2014-03-31) ================== * Fix documentation bug. LP: #1026403 * Use modern setuptools rather than distutils. * Bump copyright years. 1.1.1 (2012-04-19) ================== * Add classifiers to setup.py and make the long description more compatible with the Cheeseshop. * Other changes to make the Cheeseshop page look nicer. (LP: #680136) * setup_helper.py version 2.1. 1.1 (2012-01-19) ================ * Support Python 3 without the need for 2to3. 1.0.4 (2010-12-06) ================== * Restore missing line from MANIFEST.in to fix distribution tarball. 1.0.3 (2010-12-01) ================== * Fix setup.py to not install myfixers artifact directory on install. * Remove pylint.rc; we'll use pyflakes instead. 1.0.2 (2010-06-23) ================== * Small documentation fix. 1.0.1 (2010-06-09) ================== * Ditch the use of zc.buildout. * Improved documentation. 1.0 (2010-04-24) ================ * Use Distribute instead of Setuptools. * Port to Python 3 when used with 2to3. * More documentation improvements. 0.6 (2010-04-21) ================ * Documentation and lint clean up. 0.5 (2010-04-20) ================ * Added a simplified initialization API for one-language-context applications. This works much better for non-server applications. * Added a SimpleStrategy which recognizes the $LOCPATH environment variable. * Show how PEP 292 strings are supported automatically. * When strategies are called with zero arguments, they supply the default translation context, which is usually a NullTranslation. This is better than hardcoding the NullTranslation in the Application. 0.4 (2010-03-04) ================ * Add the ability to get the current language code, via _.code 0.3 (2009-11-15) ================ * Initial release; refactored from Mailman 3. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+) Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: MacOS :: MacOS X Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Internationalization Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Localization flufl.i18n-1.1.3/COPYING-LESSER.txt0000664000175000017500000001672512316276127016552 0ustar barrybarry00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. flufl.i18n-1.1.3/PKG-INFO0000664000175000017500000001242512326554745015002 0ustar barrybarry00000000000000Metadata-Version: 1.1 Name: flufl.i18n Version: 1.1.3 Summary: A high level API for Python internationalization. Home-page: https://launchpad.net/flufl.i18n Author: Barry Warsaw Author-email: barry@python.org License: LGPLv3 Download-URL: https://launchpad.net/flufl.i18n/+download Description: ========== flufl.i18n ========== A high level API for Python internationalization. The ``flufl.i18n`` library provides a convenient API for managing translation contexts in Python applications. It provides facilities not only for single-context applications like command line scripts, but also more sophisticated management of multiple-context applications such as Internet servers. License ======= This file is part of flufl.i18n. flufl.i18n is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 3 of the License. flufl.i18n is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with flufl.i18n. If not, see . ===================== NEWS for flufl.i18n ===================== 1.1.3 (2014-04-25) ================== * Include MANIFEST.in in the sdist tarball, otherwise the Debian package won't built correctly. 1.1.2 (2014-03-31) ================== * Fix documentation bug. LP: #1026403 * Use modern setuptools rather than distutils. * Bump copyright years. 1.1.1 (2012-04-19) ================== * Add classifiers to setup.py and make the long description more compatible with the Cheeseshop. * Other changes to make the Cheeseshop page look nicer. (LP: #680136) * setup_helper.py version 2.1. 1.1 (2012-01-19) ================ * Support Python 3 without the need for 2to3. 1.0.4 (2010-12-06) ================== * Restore missing line from MANIFEST.in to fix distribution tarball. 1.0.3 (2010-12-01) ================== * Fix setup.py to not install myfixers artifact directory on install. * Remove pylint.rc; we'll use pyflakes instead. 1.0.2 (2010-06-23) ================== * Small documentation fix. 1.0.1 (2010-06-09) ================== * Ditch the use of zc.buildout. * Improved documentation. 1.0 (2010-04-24) ================ * Use Distribute instead of Setuptools. * Port to Python 3 when used with 2to3. * More documentation improvements. 0.6 (2010-04-21) ================ * Documentation and lint clean up. 0.5 (2010-04-20) ================ * Added a simplified initialization API for one-language-context applications. This works much better for non-server applications. * Added a SimpleStrategy which recognizes the $LOCPATH environment variable. * Show how PEP 292 strings are supported automatically. * When strategies are called with zero arguments, they supply the default translation context, which is usually a NullTranslation. This is better than hardcoding the NullTranslation in the Application. 0.4 (2010-03-04) ================ * Add the ability to get the current language code, via _.code 0.3 (2009-11-15) ================ * Initial release; refactored from Mailman 3. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+) Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: MacOS :: MacOS X Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Internationalization Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Localization flufl.i18n-1.1.3/template.py0000664000175000017500000000146612316276127016067 0ustar barrybarry00000000000000# Copyright (C) 2009-2014 by Barry A. Warsaw # # This file is part of flufl.i18n # # flufl.i18n is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, version 3 of the License. # # flufl.i18n is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License # for more details. # # You should have received a copy of the GNU Lesser General Public License # along with flufl.i18n. If not, see . """Module contents.""" from __future__ import absolute_import, print_function, unicode_literals __metaclass__ = type __all__ = [ ] flufl.i18n-1.1.3/README.rst0000664000175000017500000000177412316276127015373 0ustar barrybarry00000000000000========== flufl.i18n ========== A high level API for Python internationalization. The ``flufl.i18n`` library provides a convenient API for managing translation contexts in Python applications. It provides facilities not only for single-context applications like command line scripts, but also more sophisticated management of multiple-context applications such as Internet servers. License ======= This file is part of flufl.i18n. flufl.i18n is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, version 3 of the License. flufl.i18n is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with flufl.i18n. If not, see .