From 642146b3d17249a2904f441d7270fa036c85d4f4 Mon Sep 17 00:00:00 2001 From: Amit Srivastava Date: Tue, 7 Jan 2025 16:02:52 -0800 Subject: [PATCH] Moved django-babel into hue repo django-babel has been out of maintenance for a while. We forked it several years ago and have been updating it to support newer and newer django versions. This commit brings the whole django-babel code into our repo and makes it simpler to maintain it in future. This will also allow us to make django upgrade changes in lock-step with the hue app. --- desktop/core/base_requirements.txt | 2 +- desktop/core/ext-py3/django-babel/.travis.yml | 42 +++ desktop/core/ext-py3/django-babel/AUTHORS | 16 + .../core/ext-py3/django-babel/CHANGELOG.rst | 114 ++++++ desktop/core/ext-py3/django-babel/COPYING | 28 ++ desktop/core/ext-py3/django-babel/MANIFEST.in | 6 + desktop/core/ext-py3/django-babel/README.rst | 350 ++++++++++++++++++ .../django-babel/django_babel/__init__.py | 4 + .../django-babel/django_babel/extract.py | 178 +++++++++ .../django_babel/management/__init__.py | 0 .../management/commands/__init__.py | 0 .../django_babel/management/commands/babel.py | 117 ++++++ .../django-babel/django_babel/middleware.py | 42 +++ .../django_babel/templatetags/__init__.py | 12 + .../django_babel/templatetags/babel.py | 72 ++++ .../core/ext-py3/django-babel/docs/Makefile | 177 +++++++++ .../core/ext-py3/django-babel/docs/conf.py | 276 ++++++++++++++ .../ext-py3/django-babel/docs/extract.rst | 5 + .../core/ext-py3/django-babel/docs/index.rst | 29 ++ .../core/ext-py3/django-babel/docs/make.bat | 242 ++++++++++++ .../django-babel/docs/management-commands.rst | 5 + .../ext-py3/django-babel/docs/middleware.rst | 5 + .../django-babel/docs/template-tags.rst | 5 + desktop/core/ext-py3/django-babel/setup.cfg | 2 + desktop/core/ext-py3/django-babel/setup.py | 53 +++ .../core/ext-py3/django-babel/tests/babel.cfg | 1 + .../ext-py3/django-babel/tests/conftest.py | 7 + .../django-babel/tests/test_command.py | 37 ++ .../django-babel/tests/test_extract.py | 220 +++++++++++ .../ext-py3/django-babel/tests/test_render.py | 26 ++ .../tests/testproject/__init__.py | 0 .../locale/en/LC_MESSAGES/.gitkeep | 0 .../locale/fi/LC_MESSAGES/django.po | 8 + .../tests/testproject/settings.py | 29 ++ .../tests/testproject/templates/test.txt | 12 + .../django-babel/tests/testproject/urls.py | 18 + desktop/core/ext-py3/django-babel/tox.ini | 34 ++ 37 files changed, 2173 insertions(+), 1 deletion(-) create mode 100644 desktop/core/ext-py3/django-babel/.travis.yml create mode 100644 desktop/core/ext-py3/django-babel/AUTHORS create mode 100644 desktop/core/ext-py3/django-babel/CHANGELOG.rst create mode 100644 desktop/core/ext-py3/django-babel/COPYING create mode 100644 desktop/core/ext-py3/django-babel/MANIFEST.in create mode 100644 desktop/core/ext-py3/django-babel/README.rst create mode 100644 desktop/core/ext-py3/django-babel/django_babel/__init__.py create mode 100644 desktop/core/ext-py3/django-babel/django_babel/extract.py create mode 100644 desktop/core/ext-py3/django-babel/django_babel/management/__init__.py create mode 100644 desktop/core/ext-py3/django-babel/django_babel/management/commands/__init__.py create mode 100644 desktop/core/ext-py3/django-babel/django_babel/management/commands/babel.py create mode 100644 desktop/core/ext-py3/django-babel/django_babel/middleware.py create mode 100644 desktop/core/ext-py3/django-babel/django_babel/templatetags/__init__.py create mode 100644 desktop/core/ext-py3/django-babel/django_babel/templatetags/babel.py create mode 100644 desktop/core/ext-py3/django-babel/docs/Makefile create mode 100644 desktop/core/ext-py3/django-babel/docs/conf.py create mode 100644 desktop/core/ext-py3/django-babel/docs/extract.rst create mode 100644 desktop/core/ext-py3/django-babel/docs/index.rst create mode 100644 desktop/core/ext-py3/django-babel/docs/make.bat create mode 100644 desktop/core/ext-py3/django-babel/docs/management-commands.rst create mode 100644 desktop/core/ext-py3/django-babel/docs/middleware.rst create mode 100644 desktop/core/ext-py3/django-babel/docs/template-tags.rst create mode 100644 desktop/core/ext-py3/django-babel/setup.cfg create mode 100755 desktop/core/ext-py3/django-babel/setup.py create mode 100644 desktop/core/ext-py3/django-babel/tests/babel.cfg create mode 100644 desktop/core/ext-py3/django-babel/tests/conftest.py create mode 100644 desktop/core/ext-py3/django-babel/tests/test_command.py create mode 100644 desktop/core/ext-py3/django-babel/tests/test_extract.py create mode 100644 desktop/core/ext-py3/django-babel/tests/test_render.py create mode 100644 desktop/core/ext-py3/django-babel/tests/testproject/__init__.py create mode 100644 desktop/core/ext-py3/django-babel/tests/testproject/locale/en/LC_MESSAGES/.gitkeep create mode 100644 desktop/core/ext-py3/django-babel/tests/testproject/locale/fi/LC_MESSAGES/django.po create mode 100644 desktop/core/ext-py3/django-babel/tests/testproject/settings.py create mode 100644 desktop/core/ext-py3/django-babel/tests/testproject/templates/test.txt create mode 100644 desktop/core/ext-py3/django-babel/tests/testproject/urls.py create mode 100644 desktop/core/ext-py3/django-babel/tox.ini diff --git a/desktop/core/base_requirements.txt b/desktop/core/base_requirements.txt index 016671d738a..13069cb1112 100644 --- a/desktop/core/base_requirements.txt +++ b/desktop/core/base_requirements.txt @@ -71,7 +71,6 @@ tabulate==0.8.9 trino==0.329.0 git+https://github.com/gethue/thrift.git thrift-sasl==0.4.3 -git+https://github.com/gethue/django-babel.git django-utils-six==2.0 six==1.16.0 psutil==5.8.0 @@ -81,3 +80,4 @@ drf-spectacular[sidecar]==0.27.2 -e file://${ROOT}/desktop/core/ext-py3/djangosaml2-0.18.0 -e file://${ROOT}/desktop/core/ext-py3/pysaml2-7.3.1 -e file://${ROOT}/desktop/core/ext-py3/python-sasl-0.3.1 +-e file://${ROOT}/desktop/core/ext-py3/django-babel diff --git a/desktop/core/ext-py3/django-babel/.travis.yml b/desktop/core/ext-py3/django-babel/.travis.yml new file mode 100644 index 00000000000..517512faefc --- /dev/null +++ b/desktop/core/ext-py3/django-babel/.travis.yml @@ -0,0 +1,42 @@ +language: python +python: 3.5 +sudo: false +env: + - TOX_ENV=docs + - TOX_ENV=lint + - TOX_ENV=py27-django18 + - TOX_ENV=py27-django111 + - TOX_ENV=py34-django18 + - TOX_ENV=py34-django111 + - TOX_ENV=py34-django20 + - TOX_ENV=py35-django18 + - TOX_ENV=py35-django111 + - TOX_ENV=py35-django20 + - TOX_ENV=py35-django21 + - TOX_ENV=py35-django22 + - TOX_ENV=py35-django30 + - TOX_ENV=py35-django31 + - TOX_ENV=py35-django32 +matrix: + include: + - env: TOX_ENV=py36-django18 + python: "3.6" + - env: TOX_ENV=py36-django111 + python: "3.6" + - env: TOX_ENV=py36-django20 + python: "3.6" + - env: TOX_ENV=py36-django21 + python: "3.6" + - env: TOX_ENV=py36-django22 + python: "3.6" + - env: TOX_ENV=py36-django30 + python: "3.6" + - env: TOX_ENV=py36-django31 + python: "3.6" + - env: TOX_ENV=py36-django32 + python: "3.6" + - env: TOX_ENV=py36-djangomaster + python: "3.6" +install: pip install tox +script: tox -e $TOX_ENV +cache: pip diff --git a/desktop/core/ext-py3/django-babel/AUTHORS b/desktop/core/ext-py3/django-babel/AUTHORS new file mode 100644 index 00000000000..4ea0210b9b6 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/AUTHORS @@ -0,0 +1,16 @@ +django-babel is written and maintained by the django-babel team and various +contributors: + +Contributors: + +- Christopher Lenz +- Felix Schwarz +- Jeroen Ruigrok van der Werven +- Ramiro Morales +- Thomas Grainger +- Christopher Grebs + + +django-babel was previously developed under the Copyright of Edgewall Software. +The following copyright notice holds true for releases before 2013: "Copyright +(c) 2007 - 2011 by Edgewall Software" diff --git a/desktop/core/ext-py3/django-babel/CHANGELOG.rst b/desktop/core/ext-py3/django-babel/CHANGELOG.rst new file mode 100644 index 00000000000..068a482f43e --- /dev/null +++ b/desktop/core/ext-py3/django-babel/CHANGELOG.rst @@ -0,0 +1,114 @@ +Changelog +========= + +0.6.3 (unreleased) +------------------ + +- Nothing changed yet. + + +0.6.2 (2017-12-18) +------------------ + +- compatibility with Django 2.0 added + + +0.6.1 (2017-12-18) +------------------ + +* compatibility with Django 1.11 added + +0.6.0 - 2017-04-25 +------------------ + +* compatibility with unsupported Django versions (<1.8) is dropped +* compatibility with Django 1.10+ middlewares was added + +0.5.1 - 2016-03-30 +------------------ + +* make imports absolute in babel templatetags +* strip quotes from translations via _() +* fix links in docs +* Add support for "trimmed" blocktrans content + +0.5.0 - 2016-02-29 +------------------ + +* Add compatibility for Django-1.9 + +0.4.0 - 2015-04-22 +------------------ + +* Add compatibility for Django 1.8 +* Add compatibility for latest django master +* Various python 3 fixes + + +0.3.9 - 2014-12-24 +------------------ + +* Fix dependencies on Django/Babel to use lower-case egg names. + +0.3.8 - 2014-10-14 +------------------ + +* Fix old reference to `babeldjango` module in entry points. + +0.3.7 - 2014-10-14 +------------------ + +* Fix Python 3.x compatibility in `babel makemessages` command. + +0.3.6 - 2014-10-05 +------------------ + +* Django 1.7 compatibility + + +0.3.5 - 2014-09-10 +------------------ + +* Create .po and .pot files if not existing, plus it's specific base directories. + + +0.3.4 - 2014-05-25 +------------------ + +* Fixed django compatibility + +0.3.3 - 2014-04-22 +------------------ + +* Fixed release builds + + +0.3.2 - 2014-04-22 +------------------ + +* Initial testing infrastructure +* Add management command `babel` with `makemessages` and `compilemessages` + labels. Mimics django's `makemessages` and `compilemessages` commands. +* Various unicode fixes + + +0.3.1 - 2013-12-11 +------------------ + +* fix relative import in template tags + + +0.3.0 - 2013-12-11 +------------------ + +* Rename package to django_babel + + +0.2.3 - 2013-12-11 +------------------ + +* Rename package on PyPI +* Use GitHub as source control + + +.. _`master`: https://github.com/python-babel/django-babel diff --git a/desktop/core/ext-py3/django-babel/COPYING b/desktop/core/ext-py3/django-babel/COPYING new file mode 100644 index 00000000000..364e7b0a5b2 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/COPYING @@ -0,0 +1,28 @@ +Copyright (C) 2013-2014 django-babel Team +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/desktop/core/ext-py3/django-babel/MANIFEST.in b/desktop/core/ext-py3/django-babel/MANIFEST.in new file mode 100644 index 00000000000..64b45b63d7d --- /dev/null +++ b/desktop/core/ext-py3/django-babel/MANIFEST.in @@ -0,0 +1,6 @@ +include CHANGELOG.rst README.rst COPYING +recursive-include tests * +recursive-include docs * +global-exclude *.pyc +global-exclude *.pyo +prune docs/_build diff --git a/desktop/core/ext-py3/django-babel/README.rst b/desktop/core/ext-py3/django-babel/README.rst new file mode 100644 index 00000000000..aed8ab85980 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/README.rst @@ -0,0 +1,350 @@ +Tools for using Babel with Django +================================= + +This package contains various utilities for integration of `Babel`_ into the +`Django`_ web framework: + + * A message extraction plugin for Django templates. + * A middleware class that adds the Babel `Locale`_ object to requests. + * A set of template tags for date and number formatting. + + +Extracting Messages +------------------- + +Babel provides a message extraction framework similar to GNU ``xgettext``, but +more extensible and geared towards Python applications. While Django does +provide `wrapper scripts`_ for making the use of ``xgettext`` more +convenient, the extraction functionality is rather limited. For example, you +can't use template files with an extension other than ``.html``, and everything +needs to be in your project package directory. + +Extraction Method Mapping +^^^^^^^^^^^^^^^^^^^^^^^^^ + +So django-babel comes with an extraction method plugin that can extract +localizable messages from Django template files. Python is supported out of the +box by Babel. To use this extraction functionality, create a file called +``babel.cfg`` in your project directory (the directory above your project +package), with the content: + +.. code-block:: ini + + [django: templates/**.*] + [django: mypkg/*/templates/**.*] + [python: mypkg/**.py] + +This instructs Babel to look for any files in the top-level ``templates`` +directory, or any files in application ``templates`` directories, and use the +extraction method named “django” to extract messages from those template files. +You'll need to adjust those glob patterns to wherever you my be storing your +templates. + +Also, any files with the extension ``.py`` inside your package directory (replace +“mypkg” with the actual name of your Django project package) are processed by +the “python” extraction method. + +If you don't use setuptools, or for some reason haven't installed django-babel +using setuptools/pip, you'll need to define what function the extraction method +“django” maps to. This is done in an extra section at the top of the +configuration file: + +.. code-block:: ini + + [extractors] + django = django_babel.extract:extract_django + +The encoding of the templates is assumed to be UTF-8. If you are using a +different encoding, you will need to specify it in the configuration. For +example: + +.. code-block:: ini + + [django: templates/**.*] + encoding = iso-8859-1 + + +Running the Extraction Process +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Once you've set up the configuration file, the actual extraction is performed +by executing the command-line program ``pybabel`` which is installed alongside +the Babel package: + +.. code-block:: bash + + $ cd projectdir + $ pybabel extract -F babel.cfg -o mypkg/locale/django.pot . + +This creates the PO file template in ``mypkg/locale/django.pot``. + + +Creating and Updating Translations Catalogs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you don't already have translation catalogs, you need to create them. This +is done using the ``pybabel init`` command: + +.. code-block:: bash + + $ pybabel init -D django -i mypkg/locale/django.pot -d mypkg/locale -l en_US + $ pybabel init -D django -i mypkg/locale/django.pot -d mypkg/locale -l de_DE + +This should create two files: ``mypkg/locale/en_US/django.po`` and +``mypkg/locale/de_DE/django.po``. These files are where you put the actual +translations. + +When you modify your Python source files or your templates, you genereally need +to sync the translation catalogs. For that, you first perform a fresh +extraction as described in the previous section, so that the ``django.pot`` file +gets updated. + +Then, you run the ``pybabel update`` command to merge the changes into the +translation catalogs: + +```bash +$ pybabel update -D django -i mypkg/locale/django.pot -d mypkg/locale +``` + +This will update all the ``.po`` files found in the ``mypkg/locale`` directory. + + +Compiling Translations Catalogs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Finally, you need to compile those ``.po`` files to binary ``.mo`` files. Use the +`pybabel compile` command for that: + +.. code-block:: bash + + $ pybabel compile -D django -d mypkg/locale + +Add the ``--statistics`` option to get information about the completeness of your +translations: + +.. code-block:: bash + + $ pybabel compile -D django -d mypkg/locale --statistics + + +Using ``setup.py`` +^^^^^^^^^^^^^^^^^^ + +Much of the above process can be automated if you add a ``setup.py`` script to +your project and use the distutils/setuptools commands that come with Babel. +This is described at `Distutils/Setuptools Integration`_. + + +Using the Middleware +-------------------- + +To use the Babel middleware, add it to the list of ``MIDDLEWARE_CLASSES`` in your +settings module. If you're also using Django's own ``LocaleMiddleware`` to vary +the locale based on user preference, the Babel middleware must be inserted +after the Django one: + +.. code-block:: python + + MIDDLEWARE_CLASSES = ( + ... + 'django.middleware.locale.LocaleMiddleware', + 'django_babel.middleware.LocaleMiddleware', + ... + ) + +This adds a ``locale`` attribute to the request object, which is an instance of +the Babel ``Locale`` class. You can access the locale via ``request.locale`` when +the request object is available, or otherwise use the +``django_babel.middleware.get_current_locale()`` function to get the current +locale from a thread-local cache. + + +Using the Template Tags +----------------------- + +The template filters provided by django-babel allow formatting of date/time and +number values in a locale-sensitive manner, providing much more powerful +alternatives to the ``date``, ``time``, and ``floatformat`` filters that come with +Django. + +To make the template filters/tags available, you need to add django-babel to +the list of ``INSTALLED_APPS`` in your settings module: + +.. code-block:: python + + INSTALLED_APPS = ( + ... + 'django_babel', + ... + ) + +And in every template you want to use the filters, you need to explicitly load +the django-babel library: + +.. code-block:: django + + {% load babel %} + +General information on date/time and number formatting can be found at +`Date Formatting`_ and `Number Formatting`_. + +The following filters are made available. The examples assume a locale of +``en_US``. + + +``datefmt`` +^^^^^^^^^^^ + +Renders a string representation of a date. + +* **Input**: ``datetime.date``, ``datetime.datetime``, or a float/int timestamp +* **Parameters**: the format name or pattern (optional) + +Assuming that ``book.pubdate`` returns a ``datetime.date`` or +``datetime.datetime`` object: + +.. code-block:: django + + {{ book.pubdate|datefmt:"short" }} + +would render: **4/1/07**, and + +.. code-block:: django + + {{ book.pubdate|datefmt:"E, MMM dd yyyy GGG" }} + +would render: **Sun, Apr 01 2007 AD** + +``datetimefmt`` +^^^^^^^^^^^^^^^ + +Renders a string representation of a date and time. + +* **Input**: ``datetime.datetime``, or a float/int timestamp +* **Parameters**: the format name or pattern (optional) + +Examples: + +.. code-block:: django + + {{ book.pubdate|datetimefmt:"short" }} + +would render: **4/1/07 3:30 PM**, and + +.. code-block:: django + + {{ book.pubdate|datetimefmt:"E, MMM dd yyyy GGG' - 'HH:mm:ss'" }} + +would render: **Sun, Apr 01 2007 AD - 15:30:00** + +``timefmt`` +^^^^^^^^^^^ + +Renders a string representation of a time. + +* **Input**: ``datetime.datetime``, ``datetime.time``, or a float/int timestamp +* **Parameters**: the format name or pattern (optional) + +Examples: + +.. code-block:: django + + {{ book.pubdate|timefmt:"short" }} + +would render: **3:30 PM**, and + +.. code-block:: django + + {{ book.pubdate|timefmt:"h 'o''clock' a'" }} + +would render: **3 o'clock PM** + +``decimalfmt`` +^^^^^^^^^^^^^^ + +Renders a string representation of a decimal number. + +* **Input**: a `Decimal` object, or a float/int/long value +* **Parameters**: the format name or pattern (optional) + +Examples: + +.. code-block:: django + + {{ book.pagecount|decimalfmt }} + +would render: **1,234**, and + +.. code-block:: django + + {{ book.pagecount|decimalfmt:"#,##0.00" }} + +would render: **1,234.00** + +``currencyfmt`` +^^^^^^^^^^^^^^^ + +Renders a number formatted as a currency value. + +* **Input**: a ``Decimal`` object, or a float/int/long value +* **Parameters**: the currency code + +Examples: + +.. code-block:: django + + {{ book.price|currencyfmt:"USD" }} + +would render: **$49.90** + +``percentfmt`` +^^^^^^^^^^^^^^ + +Renders a string representation of a number as a percentage. + +* **Input**: a ``Decimal`` object, or a float/int/long value +* **Parameters**: the format name or pattern (optional) + +Examples: + +Assuming ``book.rebate`` would return ``0.15``, + +.. code-block:: django + + {{ book.rebate|percentfmt }} + +would render **15%**, and + +.. code-block:: django + + {{ book.rebate|percentfmt:"#,##0.00%" }} + +would render **15.00%**. + +``scientificfmt`` +^^^^^^^^^^^^^^^^^ + +Renders a string representation of a number using scientific notation. + +* **Input**: a ``Decimal`` object, or a float/int/long value +* **Parameters**: none + +Examples: + +Assuming ``book.numsold`` would return 1.000.000, + +.. code-block:: django + + {{ book.numsold|scientificfmt }} + +would render **10E5**. + + + +.. _Babel: http://babel.pocoo.org/ +.. _Django: https://www.djangoproject.com/ +.. _wrapper scripts: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#localization-how-to-create-language-files +.. _Distutils/Setuptools Integration: http://babel.pocoo.org/en/stable/setup.html +.. _Date Formatting: http://babel.pocoo.org/en/stable/dates.html +.. _Number Formatting: http://babel.pocoo.org/en/stable/numbers.html +.. _Locale: http://babel.pocoo.org/en/stable/api/core.html#babel.core.Locale diff --git a/desktop/core/ext-py3/django-babel/django_babel/__init__.py b/desktop/core/ext-py3/django-babel/django_babel/__init__.py new file mode 100644 index 00000000000..74f9c0cf622 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/django_babel/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +from pkg_resources import get_distribution + +__version__ = get_distribution('django-babel').version diff --git a/desktop/core/ext-py3/django-babel/django_babel/extract.py b/desktop/core/ext-py3/django-babel/django_babel/extract.py new file mode 100644 index 00000000000..e664a161fd5 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/django_babel/extract.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- +try: + from django.template.base import Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK +except ImportError: + # Django 2.1+ + from django.template.base import Lexer, TokenType + + TOKEN_TEXT = TokenType.TEXT + TOKEN_VAR = TokenType.VAR + TOKEN_BLOCK = TokenType.BLOCK + +from django.utils.translation import trim_whitespace +from django.utils.encoding import smart_text + +try: + from django.utils.translation.trans_real import ( + inline_re, block_re, endblock_re, plural_re, constant_re) +except ImportError: + # Django 1.11+ + from django.utils.translation.template import ( + inline_re, block_re, endblock_re, plural_re, constant_re) + + +def join_tokens(tokens, trim=False): + message = ''.join(tokens) + if trim: + message = trim_whitespace(message) + return message + + +def strip_quotes(s): + if (s[0] == s[-1]) and s.startswith(("'", '"')): + return s[1:-1] + return s + + +def extract_django(fileobj, keywords, comment_tags, options): + """Extract messages from Django template files. + + :param fileobj: the file-like object the messages should be extracted from + :param keywords: a list of keywords (i.e. function names) that should + be recognized as translation functions + :param comment_tags: a list of translator tags to search for and + include in the results + :param options: a dictionary of additional options (optional) + :return: an iterator over ``(lineno, funcname, message, comments)`` + tuples + :rtype: ``iterator`` + """ + intrans = False + inplural = False + trimmed = False + message_context = None + singular = [] + plural = [] + lineno = 1 + + encoding = options.get('encoding', 'utf8') + text = fileobj.read().decode(encoding) + + try: + text_lexer = Lexer(text) + except TypeError: + # Django 1.9 changed the way we invoke Lexer; older versions + # require two parameters. + text_lexer = Lexer(text, None) + + for t in text_lexer.tokenize(): + lineno += t.contents.count('\n') + if intrans: + if t.token_type == TOKEN_BLOCK: + endbmatch = endblock_re.match(t.contents) + pluralmatch = plural_re.match(t.contents) + if endbmatch: + if inplural: + if message_context: + yield ( + lineno, + 'npgettext', + [smart_text(message_context), + smart_text(join_tokens(singular, trimmed)), + smart_text(join_tokens(plural, trimmed))], + [], + ) + else: + yield ( + lineno, + 'ngettext', + (smart_text(join_tokens(singular, trimmed)), + smart_text(join_tokens(plural, trimmed))), + []) + else: + if message_context: + yield ( + lineno, + 'pgettext', + [smart_text(message_context), + smart_text(join_tokens(singular, trimmed))], + [], + ) + else: + yield ( + lineno, + None, + smart_text(join_tokens(singular, trimmed)), + []) + + intrans = False + inplural = False + message_context = None + singular = [] + plural = [] + elif pluralmatch: + inplural = True + else: + raise SyntaxError('Translation blocks must not include ' + 'other block tags: %s' % t.contents) + elif t.token_type == TOKEN_VAR: + if inplural: + plural.append('%%(%s)s' % t.contents) + else: + singular.append('%%(%s)s' % t.contents) + elif t.token_type == TOKEN_TEXT: + if inplural: + plural.append(t.contents) + else: + singular.append(t.contents) + else: + if t.token_type == TOKEN_BLOCK: + imatch = inline_re.match(t.contents) + bmatch = block_re.match(t.contents) + cmatches = constant_re.findall(t.contents) + if imatch: + g = imatch.group(1) + g = strip_quotes(g) + message_context = imatch.group(3) + if message_context: + # strip quotes + message_context = message_context[1:-1] + yield ( + lineno, + 'pgettext', + [smart_text(message_context), smart_text(g)], + [], + ) + message_context = None + else: + yield lineno, None, smart_text(g), [] + elif bmatch: + if bmatch.group(2): + message_context = bmatch.group(2)[1:-1] + for fmatch in constant_re.findall(t.contents): + stripped_fmatch = strip_quotes(fmatch) + yield lineno, None, smart_text(stripped_fmatch), [] + intrans = True + inplural = False + trimmed = 'trimmed' in t.split_contents() + singular = [] + plural = [] + elif cmatches: + for cmatch in cmatches: + stripped_cmatch = strip_quotes(cmatch) + yield lineno, None, smart_text(stripped_cmatch), [] + elif t.token_type == TOKEN_VAR: + parts = t.contents.split('|') + cmatch = constant_re.match(parts[0]) + if cmatch: + stripped_cmatch = strip_quotes(cmatch.group(1)) + yield lineno, None, smart_text(stripped_cmatch), [] + for p in parts[1:]: + if p.find(':_(') >= 0: + p1 = p.split(':', 1)[1] + if p1[0] == '_': + p1 = p1[1:] + if p1[0] == '(': + p1 = p1.strip('()') + p1 = strip_quotes(p1) + yield lineno, None, smart_text(p1), [] diff --git a/desktop/core/ext-py3/django-babel/django_babel/management/__init__.py b/desktop/core/ext-py3/django-babel/django_babel/management/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/desktop/core/ext-py3/django-babel/django_babel/management/commands/__init__.py b/desktop/core/ext-py3/django-babel/django_babel/management/commands/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/desktop/core/ext-py3/django-babel/django_babel/management/commands/babel.py b/desktop/core/ext-py3/django-babel/django_babel/management/commands/babel.py new file mode 100644 index 00000000000..a616bd4a96e --- /dev/null +++ b/desktop/core/ext-py3/django-babel/django_babel/management/commands/babel.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +import os +from distutils.dist import Distribution +from subprocess import call + +from django.core.management.base import LabelCommand, CommandError +from django.conf import settings + + +__all__ = ['Command'] + + +class Command(LabelCommand): + + args = '[makemessages] [compilemessages]' + + def add_arguments(self, parser): + super(Command, self).add_arguments(parser) + parser.add_argument( + '--locale', '-l', default=[], dest='locale', action='append', + help=( + 'Creates or updates the message files for the given locale(s)' + ' (e.g pt_BR). Can be used multiple times.' + ), + ) + parser.add_argument( + '--domain', '-d', default='django', dest='domain', + help='The domain of the message files (default: "django").', + ), + parser.add_argument( + '--mapping-file', '-F', default=None, dest='mapping_file', + help='Mapping file', + ) + + def handle_label(self, command, **options): + if command not in ('makemessages', 'compilemessages'): + raise CommandError( + "You must either apply 'makemessages' or 'compilemessages'" + ) + + if command == 'makemessages': + self.handle_makemessages(**options) + if command == 'compilemessages': + self.handle_compilemessages(**options) + + def handle_makemessages(self, **options): + locale_paths = list(settings.LOCALE_PATHS) + domain = options.pop('domain') + locales = options.pop('locale') + + # support for mapping file specification via setup.cfg + # TODO: Try to support all possible options. + distribution = Distribution() + distribution.parse_config_files(distribution.find_config_files()) + + mapping_file = options.pop('mapping_file', None) + has_extract = 'extract_messages' in distribution.command_options + if mapping_file is None and has_extract: + opts = distribution.command_options['extract_messages'] + try: + mapping_file = opts['mapping_file'][1] + except (IndexError, KeyError): + mapping_file = None + + for path in locale_paths: + potfile = os.path.join(path, '%s.pot' % domain) + + if not os.path.exists(path): + os.makedirs(path) + + if not os.path.exists(potfile): + with open(potfile, 'wb') as fobj: + fobj.write(b'') + + cmd = ['pybabel', 'extract', '-o', potfile] + + if mapping_file is not None: + cmd.extend(['-F', mapping_file]) + + cmd.append(os.path.dirname(os.path.relpath(path))) + + call(cmd) + + for locale in locales: + pofile = os.path.join( + os.path.dirname(potfile), + locale, + 'LC_MESSAGES', + '%s.po' % domain) + + if not os.path.isdir(os.path.dirname(pofile)): + os.makedirs(os.path.dirname(pofile)) + + if not os.path.exists(pofile): + with open(pofile, 'wb') as fobj: + fobj.write(b'') + + cmd = ['pybabel', 'update', '-D', domain, + '-i', potfile, + '-d', os.path.relpath(path), + '-l', locale] + call(cmd) + + def handle_compilemessages(self, **options): + locale_paths = list(settings.LOCALE_PATHS) + domain = options.pop('domain') + locales = options.pop('locale') + + for path in locale_paths: + for locale in locales: + po_file = os.path.join( + path, locale, 'LC_MESSAGES', domain + '.po' + ) + if os.path.exists(po_file): + cmd = ['pybabel', 'compile', '-D', domain, + '-d', path, '-l', locale] + call(cmd) diff --git a/desktop/core/ext-py3/django-babel/django_babel/middleware.py b/desktop/core/ext-py3/django-babel/django_babel/middleware.py new file mode 100644 index 00000000000..8ad5b38c4bb --- /dev/null +++ b/desktop/core/ext-py3/django-babel/django_babel/middleware.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +from babel import Locale, UnknownLocaleError +from django.utils.translation import get_language +from threading import local + +try: + from django.utils.deprecation import MiddlewareMixin +except ImportError: + # Not required for Django <= 1.9, see: + # https://docs.djangoproject.com/en/1.10/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware + MiddlewareMixin = object + + +__all__ = ['get_current_locale', 'LocaleMiddleware'] + +_thread_locals = local() + + +def get_current_locale(): + """Get current locale data outside views. + + See http://babel.pocoo.org/en/stable/api/core.html#babel.core.Locale + for Locale objects documentation + """ + return getattr(_thread_locals, 'locale', None) + + +class LocaleMiddleware(MiddlewareMixin): + + """Simple Django middleware that makes available a Babel `Locale` object + via the `request.locale` attribute. + """ + + def process_request(self, request): + try: + code = getattr(request, 'LANGUAGE_CODE', get_language()) + locale = Locale.parse(code, sep='-') + except (ValueError, UnknownLocaleError): + pass + else: + _thread_locals.locale = request.locale = locale diff --git a/desktop/core/ext-py3/django-babel/django_babel/templatetags/__init__.py b/desktop/core/ext-py3/django-babel/django_babel/templatetags/__init__.py new file mode 100644 index 00000000000..0d752c62486 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/django_babel/templatetags/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://babel.edgewall.org/wiki/License. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://babel.edgewall.org/log/. diff --git a/desktop/core/ext-py3/django-babel/django_babel/templatetags/babel.py b/desktop/core/ext-py3/django-babel/django_babel/templatetags/babel.py new file mode 100644 index 00000000000..85f5f6ef6aa --- /dev/null +++ b/desktop/core/ext-py3/django-babel/django_babel/templatetags/babel.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +from babel import support as babel_support +from babel import core as babel_core +from django.conf import settings +from django.template import Library +from django.utils.translation import to_locale, get_language +try: + from pytz import timezone +except ImportError: + timezone = None + +from django_babel.middleware import get_current_locale + +__all__ = [ + 'datefmt', 'datetimefmt', 'timefmt', 'numberfmt', 'decimalfmt', + 'currencyfmt', 'percentfmt', 'scientificfmt', +] + +register = Library() + + +def _get_format(): + locale = get_current_locale() + if not locale: + locale = babel_core.Locale.parse(to_locale(get_language())) + if timezone: + tzinfo = timezone(settings.TIME_ZONE) + else: + tzinfo = None + return babel_support.Format(locale, tzinfo) + + +@register.filter +def datefmt(date=None, format='medium'): + return _get_format().date(date, format=format) + + +@register.filter +def datetimefmt(datetime=None, format='medium'): + return _get_format().datetime(datetime, format=format) + + +@register.filter +def timefmt(time=None, format='medium'): + return _get_format().time(time, format=format) + + +@register.filter +def numberfmt(number): + return _get_format().number(number) + + +@register.filter +def decimalfmt(number, format=None): + return _get_format().decimal(number, format=format) + + +@register.filter +def currencyfmt(number, currency): + return _get_format().currency(number, currency) + + +@register.filter +def percentfmt(number, format=None): + return _get_format().percent(number, format=format) + + +@register.filter +def scientificfmt(number): + return _get_format().scientific(number) diff --git a/desktop/core/ext-py3/django-babel/docs/Makefile b/desktop/core/ext-py3/django-babel/docs/Makefile new file mode 100644 index 00000000000..9136ea67127 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-babel.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-babel.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/django-babel" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-babel" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/desktop/core/ext-py3/django-babel/docs/conf.py b/desktop/core/ext-py3/django-babel/docs/conf.py new file mode 100644 index 00000000000..82a550e238d --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/conf.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# django-babel documentation build configuration file, created by +# sphinx-quickstart on Sat Feb 22 14:40:46 2014. +# +# 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. + +import sys +import os + +import django_babel + + +def _short_version(release): + parts = release.split('.') + return '.'.join(parts[:2]) + + +# 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.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# 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', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.viewcode', +] + +# 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-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'django-babel' +copyright = '2014, Christopher Grebs' + +# 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. + +# The full version, including alpha/beta/rc tags. +release = django_babel.__version__ +# The short X.Y version. +version = _short_version(release) + +# 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 patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# 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 = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# 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". + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# 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_domain_indices = 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, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = 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 = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'django-babeldoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'django-babel.tex', 'django-babel Documentation', + 'Christopher Grebs', '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 + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'django-babel', 'django-babel Documentation', + ['Christopher Grebs'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'django-babel', 'django-babel Documentation', + 'Christopher Grebs', 'django-babel', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/desktop/core/ext-py3/django-babel/docs/extract.rst b/desktop/core/ext-py3/django-babel/docs/extract.rst new file mode 100644 index 00000000000..9402e261428 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/extract.rst @@ -0,0 +1,5 @@ +Extract +======= + +.. automodule:: django_babel.extract + :members: diff --git a/desktop/core/ext-py3/django-babel/docs/index.rst b/desktop/core/ext-py3/django-babel/docs/index.rst new file mode 100644 index 00000000000..880b41ac0ef --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/index.rst @@ -0,0 +1,29 @@ +.. django-babel documentation master file, created by + sphinx-quickstart on Sat Feb 22 14:40:46 2014. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +======================================== +Welcome to django-babel's documentation! +======================================== + +.. include:: ../README.rst +.. include:: ../CHANGELOG.rst + +Contents: + +.. toctree:: + :maxdepth: 2 + + extract + management-commands + middleware + template-tags + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/desktop/core/ext-py3/django-babel/docs/make.bat b/desktop/core/ext-py3/django-babel/docs/make.bat new file mode 100644 index 00000000000..844b82b8966 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/make.bat @@ -0,0 +1,242 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-babel.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-babel.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/desktop/core/ext-py3/django-babel/docs/management-commands.rst b/desktop/core/ext-py3/django-babel/docs/management-commands.rst new file mode 100644 index 00000000000..b2e1c49aba1 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/management-commands.rst @@ -0,0 +1,5 @@ +Management Commands +=================== + +.. automodule:: django_babel.management.commands.babel + :members: diff --git a/desktop/core/ext-py3/django-babel/docs/middleware.rst b/desktop/core/ext-py3/django-babel/docs/middleware.rst new file mode 100644 index 00000000000..4d5f60a6985 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/middleware.rst @@ -0,0 +1,5 @@ +Middleware +========== + +.. automodule:: django_babel.middleware + :members: diff --git a/desktop/core/ext-py3/django-babel/docs/template-tags.rst b/desktop/core/ext-py3/django-babel/docs/template-tags.rst new file mode 100644 index 00000000000..7ca38c0770b --- /dev/null +++ b/desktop/core/ext-py3/django-babel/docs/template-tags.rst @@ -0,0 +1,5 @@ +Template Tags +============= + +.. automodule:: django_babel.templatetags.babel + :members: diff --git a/desktop/core/ext-py3/django-babel/setup.cfg b/desktop/core/ext-py3/django-babel/setup.cfg new file mode 100644 index 00000000000..5e4090017a9 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/setup.cfg @@ -0,0 +1,2 @@ +[wheel] +universal = 1 diff --git a/desktop/core/ext-py3/django-babel/setup.py b/desktop/core/ext-py3/django-babel/setup.py new file mode 100755 index 00000000000..361e14ad36f --- /dev/null +++ b/desktop/core/ext-py3/django-babel/setup.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import os +import codecs +from setuptools import setup, find_packages + + +def read(*parts): + filename = os.path.join(os.path.dirname(__file__), *parts) + with codecs.open(filename, encoding='utf-8') as fp: + return fp.read() + + +setup( + name='django-babel', + description='Utilities for using Babel in Django', + long_description=read('README.rst') + u'\n\n' + read('CHANGELOG.rst'), + version='0.6.3.dev0', + license='BSD', + author='Christopher Grebs', + author_email='cg@webshox.org', + maintainer='Thomas Grainger', + maintainer_email='django-babel@graingert.co.uk', + url='https://github.com/python-babel/django-babel/', + packages=find_packages(exclude=('tests',)), + install_requires=[ + 'django>=1.8,<3.3', + 'babel>=1.3', + ], + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: Web Environment', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Framework :: Django', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: Implementation :: PyPy', + 'Programming Language :: Python :: Implementation :: CPython', + ], + entry_points={ + 'babel.extractors': [ + 'django = django_babel.extract:extract_django', + ] + } +) diff --git a/desktop/core/ext-py3/django-babel/tests/babel.cfg b/desktop/core/ext-py3/django-babel/tests/babel.cfg new file mode 100644 index 00000000000..71fb8763d2a --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/babel.cfg @@ -0,0 +1 @@ +[django: **/templates/**.*] diff --git a/desktop/core/ext-py3/django-babel/tests/conftest.py b/desktop/core/ext-py3/django-babel/tests/conftest.py new file mode 100644 index 00000000000..49cfd8ebc2b --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/conftest.py @@ -0,0 +1,7 @@ +from django.conf import settings + +from testproject import settings as testproject_settings + + +def pytest_configure(): + settings.configure(**vars(testproject_settings)) diff --git a/desktop/core/ext-py3/django-babel/tests/test_command.py b/desktop/core/ext-py3/django-babel/tests/test_command.py new file mode 100644 index 00000000000..d68516094ee --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/test_command.py @@ -0,0 +1,37 @@ +import os + +import pkg_resources +from django.core.management import call_command + +TEST_LOCALE_DIR = pkg_resources.resource_filename( + 'testproject', 'locale' +) + + +def test_babel_compilemessages(): + call_command( + 'babel', + 'compilemessages', + '-l', 'fi', + ) + # Assert that the .mo file was created by attempting to delete it. + os.unlink( + os.path.join(TEST_LOCALE_DIR, 'fi', 'LC_MESSAGES', 'django.mo') + ) + + +def test_babel_makemessages(): + call_command( + 'babel', + 'makemessages', + '-l', 'en', + '-F', pkg_resources.resource_filename(__name__, 'babel.cfg'), + ) + # See that the expected files get populated with the discovered message + for path in [ + os.path.join(TEST_LOCALE_DIR, 'django.pot'), + os.path.join(TEST_LOCALE_DIR, 'en', 'LC_MESSAGES', 'django.po'), + ]: + with open(path) as infp: + assert '"This could be translated."' in infp.read() + os.unlink(path) # clean up diff --git a/desktop/core/ext-py3/django-babel/tests/test_extract.py b/desktop/core/ext-py3/django-babel/tests/test_extract.py new file mode 100644 index 00000000000..aca1a583890 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/test_extract.py @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- +import unittest + +import pytest + +from babel.messages import extract +from babel._compat import BytesIO + +import django +from django_babel.extract import extract_django + + +default_keys = extract.DEFAULT_KEYWORDS.keys() + + +class ExtractDjangoTestCase(unittest.TestCase): + # TODO: translator comments are not yet supported! + + def test_extract_no_tags(self): + buf = BytesIO(b'nothing') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([], messages) + + def test_extract_simple_double_quotes(self): + buf = BytesIO(b'{% trans "Bunny" %}') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'Bunny', [])], messages) + + def test_extract_simple_single_quotes(self): + buf = BytesIO(b"{% trans 'Bunny' %}") + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'Bunny', [])], messages) + + def test_extract_simple_with_context_single_quotes(self): + buf = BytesIO(b"{% trans 'Bunny' context 'carrot' %}") + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, 'pgettext', + [u'carrot', u'Bunny'], [])], messages) + + def test_extract_simple_with_context_double_quotes(self): + buf = BytesIO(b"{% trans 'Bunny' context \"carrot\" %}") + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, 'pgettext', + [u'carrot', u'Bunny'], [])], messages) + + def test_extract_simple_with_context_with_single_quotes(self): + buf = BytesIO(b"{% trans 'Bunny' context \"'carrot'\" %}") + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, 'pgettext', + [u'\'carrot\'', u'Bunny'], [])], messages) + + def test_extract_simple_with_context_with_double_quotes(self): + buf = BytesIO(b"{% trans 'Bunny' context '\"carrot\"' %}") + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, 'pgettext', + [u'"carrot"', u'Bunny'], [])], messages) + + def test_extract_var(self): + buf = BytesIO(b'{% blocktrans %}{{ anton }}{% endblocktrans %}') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'%(anton)s', [])], messages) + + def test_extract_filter_with_filter(self): + test_tmpl = ( + b'{% blocktrans with berta=anton|lower %}' + b'{{ berta }}{% endblocktrans %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'%(berta)s', [])], messages) + + def test_extract_with_interpolation(self): + buf = BytesIO(b'{% blocktrans %}xxx{{ anton }}xxx{% endblocktrans %}') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'xxx%(anton)sxxx', [])], messages) + + def test_extract_unicode(self): + buf = BytesIO(u'{% trans "@ſðæ314“ſſ¶ÐĐÞ→SÆ^ĸŁ" %}'.encode('utf8')) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'@ſðæ314“ſſ¶ÐĐÞ→SÆ^ĸŁ', [])], messages) + + def test_extract_unicode_blocktrans(self): + test_tmpl = u'{% blocktrans %}@ſðæ314“ſſ¶ÐĐÞ→SÆ^ĸŁ{% endblocktrans %}' + buf = BytesIO(test_tmpl.encode('utf8')) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'@ſðæ314“ſſ¶ÐĐÞ→SÆ^ĸŁ', [])], messages) + + # TODO: Yet expected to not extract the comments. + def test_extract_ignored_comment(self): + buf = BytesIO( + b'{# ignored comment #1 #}{% trans "Translatable literal #9a" %}', + ) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual( + [(1, None, u'Translatable literal #9a', [])], messages + ) + + def test_extract_ignored_comment2(self): + test_tmpl = ( + b'{# Translators: ignored i18n comment #1 #}' + b'{% trans "Translatable literal #9a" %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual( + [(1, None, u'Translatable literal #9a', [])], messages + ) + + def test_extract_valid_comment(self): + test_tmpl = ( + b'{# ignored comment #6 #}' + b'{% trans "Translatable literal #9h" %}' + b'{# Translators: valid i18n comment #7 #}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual( + [(1, None, u'Translatable literal #9h', [])], messages + ) + + def test_extract_singular_form(self): + test_tmpl = ( + b'{% blocktrans count counter=number %}' + b'singular{% plural %}{{ counter }} plural' + b'{% endblocktrans %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual( + [(1, 'ngettext', (u'singular', u'%(counter)s plural'), [])], + messages + ) + + def test_trans_blocks_must_not_include_other_block_tags(self): + buf = BytesIO(b'{% blocktrans %}{% other_tag %}{% endblocktrans %}') + gen = extract_django(buf, default_keys, [], {}) + with pytest.raises(SyntaxError): + next(gen) + + def test_extract_var_other(self): + buf = BytesIO(b'{{ book }}') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([], messages) + + def test_extract_filters_default_translatable(self): + buf = BytesIO(b'{{ book.author|default:_("Unknown") }}') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'Unknown', [])], messages) + + def test_extract_filters_default_translatable_single_quotes(self): + buf = BytesIO(b"{{ book.author|default:_('Unknown') }}") + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'Unknown', [])], messages) + + def test_extract_constant_single_quotes(self): + buf = BytesIO(b"{{ _('constant') }}") + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'constant', [])], messages) + + def test_extract_constant_double_quotes(self): + buf = BytesIO(b'{{ _("constant") }}') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'constant', [])], messages) + + def test_extract_constant_block(self): + buf = BytesIO(b'{% _("constant") %}') + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(1, None, u'constant', [])], messages) + + def test_extract_constant_in_block(self): + test_tmpl = ( + b'{% blocktrans foo=_("constant") %}{{ foo }}{% endblocktrans %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual( + [(1, None, u'constant', []), (1, None, u'%(foo)s', [])], + messages, + ) + + def test_extract_context_in_block(self): + test_tmpl = ( + b'{% blocktrans context "banana" %}{{ foo }}{% endblocktrans %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual( + [(1, 'pgettext', [u'banana', u'%(foo)s'], [])], + messages, + ) + + def test_extract_context_in_plural_block(self): + test_tmpl = ( + b'{% blocktrans context "banana" %}{{ foo }}' + b'{% plural %}{{ bar }}{% endblocktrans %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual( + [(1, 'npgettext', [u'banana', u'%(foo)s', u'%(bar)s'], [])], + messages, + ) + + def test_blocktrans_with_whitespace_not_trimmed(self): + test_tmpl = ( + b'{% blocktrans %}\n\tfoo\n\tbar\n{% endblocktrans %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(4, None, u'\n\tfoo\n\tbar\n', [])], messages) + + @pytest.mark.skipif(django.VERSION < (1, 7), + reason='Trimmed whitespace is a Django >= 1.7 feature') + def test_blocktrans_with_whitespace_trimmed(self): + test_tmpl = ( + b'{% blocktrans trimmed %}\n\tfoo\n\tbar\n{% endblocktrans %}' + ) + buf = BytesIO(test_tmpl) + messages = list(extract_django(buf, default_keys, [], {})) + self.assertEqual([(4, None, u'foo bar', [])], messages) diff --git a/desktop/core/ext-py3/django-babel/tests/test_render.py b/desktop/core/ext-py3/django-babel/tests/test_render.py new file mode 100644 index 00000000000..61d8ddb1d38 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/test_render.py @@ -0,0 +1,26 @@ +# -- encoding: utf-8 -- +from __future__ import unicode_literals + +import pytest + + +@pytest.mark.parametrize('locale', ('en', 'fi', 'sv', 'pt-BR')) +def test_babel_render(client, locale): + """ + Test the middleware and the rendery bits. + """ + response = client.get('/', HTTP_ACCEPT_LANGUAGE=locale) + # "Parse" the key-value format + lines = response.content.decode('utf-8').strip().splitlines() + content = dict(kv.split('=', 1) for kv in lines) + # See that we're rendering in the locale we expect + assert content['language_code'] == locale.lower() + # check that we could access `babel.Locale.language_name` + assert content['language_name'] == { + 'en': 'English', + 'fi': 'suomi', + 'sv': 'svenska', + 'pt-BR': 'português', + }[locale] + # The rest are not really tested (aside from smoke tests) further; + # the Babel test suite has taken care of that. diff --git a/desktop/core/ext-py3/django-babel/tests/testproject/__init__.py b/desktop/core/ext-py3/django-babel/tests/testproject/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/desktop/core/ext-py3/django-babel/tests/testproject/locale/en/LC_MESSAGES/.gitkeep b/desktop/core/ext-py3/django-babel/tests/testproject/locale/en/LC_MESSAGES/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/desktop/core/ext-py3/django-babel/tests/testproject/locale/fi/LC_MESSAGES/django.po b/desktop/core/ext-py3/django-babel/tests/testproject/locale/fi/LC_MESSAGES/django.po new file mode 100644 index 00000000000..94c72441bd9 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/testproject/locale/fi/LC_MESSAGES/django.po @@ -0,0 +1,8 @@ +# the header message is required to turn off the fuzzy bit for the catalog +msgid "" +msgstr "" + +#: tests/templates/test.txt:2 +msgid "This could be translated." +msgstr "Tämän voisi kääntää." + diff --git a/desktop/core/ext-py3/django-babel/tests/testproject/settings.py b/desktop/core/ext-py3/django-babel/tests/testproject/settings.py new file mode 100644 index 00000000000..50071adc2d6 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/testproject/settings.py @@ -0,0 +1,29 @@ +import pkg_resources + +SECRET_KEY = 'x' +USE_I18N = True +ROOT_URLCONF = 'testproject.urls' +INSTALLED_APPS = [ + 'django_babel', + 'testproject', +] +MIDDLEWARE = [ + 'django.middleware.locale.LocaleMiddleware', + 'django_babel.middleware.LocaleMiddleware', +] +MIDDLEWARE_CLASSES = MIDDLEWARE # backwards compat +TEMPLATES = [ + { + 'NAME': 'default', + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.i18n', + ], + }, + }, +] +LOCALE_PATHS = [ + pkg_resources.resource_filename(__name__, 'locale'), +] diff --git a/desktop/core/ext-py3/django-babel/tests/testproject/templates/test.txt b/desktop/core/ext-py3/django-babel/tests/testproject/templates/test.txt new file mode 100644 index 00000000000..25996885b12 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/testproject/templates/test.txt @@ -0,0 +1,12 @@ +{% load i18n babel %} +text={% trans "This could be translated." %} +language_code={{ LANGUAGE_CODE }} +language_name={{ locale.language_name }} +date={{ date|datefmt }} +datetime={{ date|datetimefmt }} +time={{ date|timefmt }} +number={{ number|numberfmt }} +decimal={{ number|decimalfmt }} +currency={{ number|currencyfmt:"EUR" }} +percent={{ number|percentfmt }} +scientificfmt={{ number|scientificfmt }} diff --git a/desktop/core/ext-py3/django-babel/tests/testproject/urls.py b/desktop/core/ext-py3/django-babel/tests/testproject/urls.py new file mode 100644 index 00000000000..2bf25018f35 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tests/testproject/urls.py @@ -0,0 +1,18 @@ +import time + +from django.conf.urls import url +from django.shortcuts import render +from django.utils.timezone import now + + +def test_view(request): + return render(request, 'test.txt', { + 'date': now(), + 'number': time.time(), + 'locale': request.locale, + }) + + +urlpatterns = [ + url('^$', test_view), +] diff --git a/desktop/core/ext-py3/django-babel/tox.ini b/desktop/core/ext-py3/django-babel/tox.ini new file mode 100644 index 00000000000..d322cc2a556 --- /dev/null +++ b/desktop/core/ext-py3/django-babel/tox.ini @@ -0,0 +1,34 @@ +[tox] +envlist = py{27,34,35,36}-django{18,111}, + py{35,36,37}-django{20,21,22,30,31,32}, + py{36,37}-django{master}, + lint, docs + +[testenv] +deps = + coverage + pytest + pytest-cov + pytest-django + python-coveralls + django18: Django>=1.8,<1.9 + django111: Django>=1.11,<2.0 + django20: Django>=2.0,<2.1 + django21: Django>=2.1,<2.2 + django22: Django>=2.2,<3 + django30: Django>=3.0,<3.1 + django31: Django>=3.1,<3.2 + django32: Django>=3.2,<3.3 + djangomaster: https://github.com/django/django/archive/master.tar.gz#egg=Django +commands = py.test {posargs} + +[testenv:docs] +deps = sphinx +commands = + sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/_build/html + sphinx-build -W -b linkcheck docs {envtmpdir}/_build/html + +[testenv:lint] +deps = + flake8==3.3.0 +commands=flake8 django_babel tests