New upstream version 2.0.0
intrigeri
2 years ago
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: Flask-Babel |
2 | Version: 0.12.2 | |
2 | Version: 2.0.0 | |
3 | 3 | Summary: Adds i18n/l10n support to Flask applications |
4 | 4 | Home-page: http://github.com/python-babel/flask-babel |
5 | 5 | Author: Armin Ronacher |
6 | 6 | Author-email: armin.ronacher@active-4.com |
7 | Maintainer: Tyler Kennedy | |
8 | Maintainer-email: tk@tkte.ch | |
7 | 9 | License: BSD |
8 | Description: # Flask Babel - 0.12.2 | |
10 | Description: # Flask Babel | |
9 | 11 | |
10 | [![Build Status](https://travis-ci.org/python-babel/flask-babel.svg?branch=master)](https://travis-ci.org/python-babel/flask-babel) | |
12 | ![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master) | |
11 | 13 | [![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel) |
12 | ![license](https://img.shields.io/github/license/python-babel/flask-babel.svg?maxAge=2592000) | |
13 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/flask-babel.svg) | |
14 | 14 | |
15 | 15 | Implements i18n and l10n support for Flask. This is based on the Python |
16 | 16 | [babel][] module as well as [pytz][] both of which are installed automatically |
22 | 22 | |
23 | 23 | [babel]: https://github.com/python-babel/babel |
24 | 24 | [pytz]: https://pypi.python.org/pypi/pytz/ |
25 | [docs]: https://pythonhosted.org/Flask-Babel/ | |
25 | [docs]: https://flask-babel.tkte.ch/ | |
26 | [semver]: https://semver.org/ | |
26 | 27 | |
27 | Platform: any | |
28 | Classifier: Development Status :: 4 - Beta | |
28 | Platform: UNKNOWN | |
29 | Classifier: Development Status :: 5 - Production/Stable | |
29 | 30 | Classifier: Environment :: Web Environment |
30 | 31 | Classifier: Intended Audience :: Developers |
31 | 32 | Classifier: License :: OSI Approved :: BSD License |
32 | 33 | Classifier: Operating System :: OS Independent |
33 | Classifier: Programming Language :: Python :: 2.7 | |
34 | Classifier: Programming Language :: Python :: 3.5 | |
34 | 35 | Classifier: Programming Language :: Python :: 3.6 |
36 | Classifier: Programming Language :: Python :: 3.7 | |
37 | Classifier: Programming Language :: Python :: 3.8 | |
38 | Classifier: Programming Language :: Python :: 3.9 | |
35 | 39 | Classifier: Programming Language :: Python :: Implementation :: CPython |
36 | 40 | Classifier: Programming Language :: Python :: Implementation :: PyPy |
37 | 41 | Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |
38 | 42 | Classifier: Topic :: Software Development :: Libraries :: Python Modules |
39 | 43 | Description-Content-Type: text/markdown |
44 | Provides-Extra: dev |
0 | 0 | LICENSE |
1 | 1 | MANIFEST.in |
2 | Makefile | |
3 | 2 | README.md |
4 | setup.cfg | |
5 | 3 | setup.py |
6 | 4 | Flask_Babel.egg-info/PKG-INFO |
7 | 5 | Flask_Babel.egg-info/SOURCES.txt |
13 | 11 | docs/conf.py |
14 | 12 | docs/index.rst |
15 | 13 | docs/make.bat |
16 | docs/_static/flask-babel.png | |
17 | 14 | flask_babel/__init__.py |
18 | flask_babel/_compat.py | |
19 | 15 | flask_babel/speaklater.py |
20 | 16 | tests/babel.cfg |
21 | tests/tests.py | |
17 | tests/test_date_formatting.py | |
18 | tests/test_gettext.py | |
19 | tests/test_integration.py | |
20 | tests/test_number_formatting.py | |
22 | 21 | tests/renamed_translations/messages.pot |
23 | 22 | tests/renamed_translations/de/LC_MESSAGES/messages.mo |
24 | 23 | tests/renamed_translations/de/LC_MESSAGES/messages.po |
24 | tests/renamed_translations/de/LC_MESSAGES/myapp.mo | |
25 | tests/renamed_translations/de/LC_MESSAGES/myapp.po | |
25 | 26 | tests/translations/messages.pot |
26 | 27 | tests/translations/de/LC_MESSAGES/messages.mo |
27 | 28 | tests/translations/de/LC_MESSAGES/messages.po |
29 | tests/translations/de/LC_MESSAGES/test.mo | |
30 | tests/translations/de/LC_MESSAGES/test.po | |
28 | 31 | tests/translations_different_domain/myapp.pot |
29 | 32 | tests/translations_different_domain/de/LC_MESSAGES/myapp.mo |
30 | 33 | tests/translations_different_domain/de/LC_MESSAGES/myapp.po⏎ |
0 | pytz | |
0 | 1 | Flask |
1 | 2 | Babel>=2.3 |
2 | 3 | Jinja2>=2.5 |
4 | ||
5 | [dev] | |
6 | pytest | |
7 | pytest-mock | |
8 | bumpversion | |
9 | ghp-import | |
10 | sphinx | |
11 | Pallets-Sphinx-Themes |
0 | .PHONY: clean-pyc test upload-docs | |
1 | ||
2 | all: clean-pyc test | |
3 | ||
4 | test: | |
5 | @cd tests; python tests.py | |
6 | ||
7 | tox-test: | |
8 | @tox | |
9 | ||
10 | clean-pyc: | |
11 | find . -name '*.pyc' -exec rm -f {} + | |
12 | find . -name '*.pyo' -exec rm -f {} + | |
13 | find . -name '*~' -exec rm -f {} + | |
14 | ||
15 | clean: clean-pyc | |
16 | ||
17 | upload-docs: | |
18 | $(MAKE) -C docs html | |
19 | python setup.py upload_docs | |
20 | ||
21 | .PHONY: upload-docs clean-pyc clean tox-test test all |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: Flask-Babel |
2 | Version: 0.12.2 | |
2 | Version: 2.0.0 | |
3 | 3 | Summary: Adds i18n/l10n support to Flask applications |
4 | 4 | Home-page: http://github.com/python-babel/flask-babel |
5 | 5 | Author: Armin Ronacher |
6 | 6 | Author-email: armin.ronacher@active-4.com |
7 | Maintainer: Tyler Kennedy | |
8 | Maintainer-email: tk@tkte.ch | |
7 | 9 | License: BSD |
8 | Description: # Flask Babel - 0.12.2 | |
10 | Description: # Flask Babel | |
9 | 11 | |
10 | [![Build Status](https://travis-ci.org/python-babel/flask-babel.svg?branch=master)](https://travis-ci.org/python-babel/flask-babel) | |
12 | ![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master) | |
11 | 13 | [![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel) |
12 | ![license](https://img.shields.io/github/license/python-babel/flask-babel.svg?maxAge=2592000) | |
13 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/flask-babel.svg) | |
14 | 14 | |
15 | 15 | Implements i18n and l10n support for Flask. This is based on the Python |
16 | 16 | [babel][] module as well as [pytz][] both of which are installed automatically |
22 | 22 | |
23 | 23 | [babel]: https://github.com/python-babel/babel |
24 | 24 | [pytz]: https://pypi.python.org/pypi/pytz/ |
25 | [docs]: https://pythonhosted.org/Flask-Babel/ | |
25 | [docs]: https://flask-babel.tkte.ch/ | |
26 | [semver]: https://semver.org/ | |
26 | 27 | |
27 | Platform: any | |
28 | Classifier: Development Status :: 4 - Beta | |
28 | Platform: UNKNOWN | |
29 | Classifier: Development Status :: 5 - Production/Stable | |
29 | 30 | Classifier: Environment :: Web Environment |
30 | 31 | Classifier: Intended Audience :: Developers |
31 | 32 | Classifier: License :: OSI Approved :: BSD License |
32 | 33 | Classifier: Operating System :: OS Independent |
33 | Classifier: Programming Language :: Python :: 2.7 | |
34 | Classifier: Programming Language :: Python :: 3.5 | |
34 | 35 | Classifier: Programming Language :: Python :: 3.6 |
36 | Classifier: Programming Language :: Python :: 3.7 | |
37 | Classifier: Programming Language :: Python :: 3.8 | |
38 | Classifier: Programming Language :: Python :: 3.9 | |
35 | 39 | Classifier: Programming Language :: Python :: Implementation :: CPython |
36 | 40 | Classifier: Programming Language :: Python :: Implementation :: PyPy |
37 | 41 | Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content |
38 | 42 | Classifier: Topic :: Software Development :: Libraries :: Python Modules |
39 | 43 | Description-Content-Type: text/markdown |
44 | Provides-Extra: dev |
0 | # Flask Babel - 0.12.2 | |
0 | # Flask Babel | |
1 | 1 | |
2 | [![Build Status](https://travis-ci.org/python-babel/flask-babel.svg?branch=master)](https://travis-ci.org/python-babel/flask-babel) | |
2 | ![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master) | |
3 | 3 | [![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel) |
4 | ![license](https://img.shields.io/github/license/python-babel/flask-babel.svg?maxAge=2592000) | |
5 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/flask-babel.svg) | |
6 | 4 | |
7 | 5 | Implements i18n and l10n support for Flask. This is based on the Python |
8 | 6 | [babel][] module as well as [pytz][] both of which are installed automatically |
14 | 12 | |
15 | 13 | [babel]: https://github.com/python-babel/babel |
16 | 14 | [pytz]: https://pypi.python.org/pypi/pytz/ |
17 | [docs]: https://pythonhosted.org/Flask-Babel/ | |
15 | [docs]: https://flask-babel.tkte.ch/ | |
16 | [semver]: https://semver.org/ |
0 | # Makefile for Sphinx documentation | |
0 | # Minimal makefile for Sphinx documentation | |
1 | 1 | # |
2 | 2 | |
3 | # You can set these variables from the command line. | |
4 | SPHINXOPTS = | |
5 | SPHINXBUILD = sphinx-build | |
6 | PAPER = | |
3 | # You can set these variables from the command line, and also | |
4 | # from the environment for the first two. | |
5 | SPHINXOPTS ?= | |
6 | SPHINXBUILD ?= sphinx-build | |
7 | SOURCEDIR = . | |
7 | 8 | BUILDDIR = _build |
8 | 9 | |
9 | # Internal variables. | |
10 | PAPEROPT_a4 = -D latex_paper_size=a4 | |
11 | PAPEROPT_letter = -D latex_paper_size=letter | |
12 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . | |
10 | # Put it first so that "make" without argument is like "make help". | |
11 | help: | |
12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | |
13 | 13 | |
14 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest | |
14 | import: | |
15 | ghp-import -n -c flask-babel.tkte.ch "$(BUILDDIR)/html" | |
15 | 16 | |
16 | help: | |
17 | @echo "Please use \`make <target>' where <target> is one of" | |
18 | @echo " html to make standalone HTML files" | |
19 | @echo " dirhtml to make HTML files named index.html in directories" | |
20 | @echo " singlehtml to make a single large HTML file" | |
21 | @echo " pickle to make pickle files" | |
22 | @echo " json to make JSON files" | |
23 | @echo " htmlhelp to make HTML files and a HTML help project" | |
24 | @echo " qthelp to make HTML files and a qthelp project" | |
25 | @echo " devhelp to make HTML files and a Devhelp project" | |
26 | @echo " epub to make an epub" | |
27 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" | |
28 | @echo " latexpdf to make LaTeX files and run them through pdflatex" | |
29 | @echo " text to make text files" | |
30 | @echo " man to make manual pages" | |
31 | @echo " changes to make an overview of all changed/added/deprecated items" | |
32 | @echo " linkcheck to check all external links for integrity" | |
33 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" | |
17 | .PHONY: help Makefile | |
34 | 18 | |
35 | clean: | |
36 | -rm -rf $(BUILDDIR)/* | |
37 | ||
38 | html: | |
39 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html | |
40 | @echo | |
41 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." | |
42 | ||
43 | dirhtml: | |
44 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml | |
45 | @echo | |
46 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." | |
47 | ||
48 | singlehtml: | |
49 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml | |
50 | @echo | |
51 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." | |
52 | ||
53 | pickle: | |
54 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle | |
55 | @echo | |
56 | @echo "Build finished; now you can process the pickle files." | |
57 | ||
58 | json: | |
59 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json | |
60 | @echo | |
61 | @echo "Build finished; now you can process the JSON files." | |
62 | ||
63 | htmlhelp: | |
64 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp | |
65 | @echo | |
66 | @echo "Build finished; now you can run HTML Help Workshop with the" \ | |
67 | ".hhp project file in $(BUILDDIR)/htmlhelp." | |
68 | ||
69 | qthelp: | |
70 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp | |
71 | @echo | |
72 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ | |
73 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" | |
74 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FlaskBabel.qhcp" | |
75 | @echo "To view the help file:" | |
76 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FlaskBabel.qhc" | |
77 | ||
78 | devhelp: | |
79 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp | |
80 | @echo | |
81 | @echo "Build finished." | |
82 | @echo "To view the help file:" | |
83 | @echo "# mkdir -p $$HOME/.local/share/devhelp/FlaskBabel" | |
84 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FlaskBabel" | |
85 | @echo "# devhelp" | |
86 | ||
87 | epub: | |
88 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub | |
89 | @echo | |
90 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." | |
91 | ||
92 | latex: | |
93 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |
94 | @echo | |
95 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." | |
96 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ | |
97 | "(use \`make latexpdf' here to do that automatically)." | |
98 | ||
99 | latexpdf: latex | |
100 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex | |
101 | @echo "Running LaTeX files through pdflatex..." | |
102 | make -C $(BUILDDIR)/latex all-pdf | |
103 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." | |
104 | ||
105 | text: | |
106 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text | |
107 | @echo | |
108 | @echo "Build finished. The text files are in $(BUILDDIR)/text." | |
109 | ||
110 | man: | |
111 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man | |
112 | @echo | |
113 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." | |
114 | ||
115 | changes: | |
116 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes | |
117 | @echo | |
118 | @echo "The overview file is in $(BUILDDIR)/changes." | |
119 | ||
120 | linkcheck: | |
121 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck | |
122 | @echo | |
123 | @echo "Link check complete; look for any errors in the above output " \ | |
124 | "or in $(BUILDDIR)/linkcheck/output.txt." | |
125 | ||
126 | doctest: | |
127 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest | |
128 | @echo "Testing of doctests in the sources finished, look at the " \ | |
129 | "results in $(BUILDDIR)/doctest/output.txt." | |
19 | # Catch-all target: route all unknown targets to Sphinx using the new | |
20 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). | |
21 | %: Makefile | |
22 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
0 | # -*- coding: utf-8 -*- | |
0 | # Configuration file for the Sphinx documentation builder. | |
1 | 1 | # |
2 | # Flask Babel documentation build configuration file, created by | |
3 | # sphinx-quickstart on Sat May 29 13:52:12 2010. | |
4 | # | |
5 | # This file is execfile()d with the current directory set to its containing dir. | |
6 | # | |
7 | # Note that not all possible configuration values are present in this | |
8 | # autogenerated file. | |
9 | # | |
10 | # All configuration values have a default; values that are commented out | |
11 | # serve to show the default. | |
2 | # This file only contains a selection of the most common options. For a full | |
3 | # list see the documentation: | |
4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html | |
12 | 5 | |
13 | import sys, os | |
6 | # -- Path setup -------------------------------------------------------------- | |
14 | 7 | |
15 | 8 | # If extensions (or modules to document with autodoc) are in another directory, |
16 | 9 | # add these directories to sys.path here. If the directory is relative to the |
17 | 10 | # documentation root, use os.path.abspath to make it absolute, like shown here. |
18 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) | |
19 | sys.path.append(os.path.abspath('_themes')) | |
11 | # | |
12 | # import os | |
13 | # import sys | |
14 | # sys.path.insert(0, os.path.abspath('.')) | |
20 | 15 | |
21 | # -- General configuration ----------------------------------------------------- | |
22 | 16 | |
23 | # If your documentation needs a minimal Sphinx version, state it here. | |
24 | #needs_sphinx = '1.0' | |
17 | # -- Project information ----------------------------------------------------- | |
25 | 18 | |
26 | # Add any Sphinx extension module names here, as strings. They can be extensions | |
27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. | |
28 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] | |
19 | project = 'Flask-Babel' | |
20 | copyright = '2020, Armin Ronacher' | |
21 | author = 'Armin Ronacher' | |
22 | ||
23 | # The full version, including alpha/beta/rc tags | |
24 | release = '2.0.0' | |
25 | ||
26 | ||
27 | # -- General configuration --------------------------------------------------- | |
28 | ||
29 | # Add any Sphinx extension module names here, as strings. They can be | |
30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom | |
31 | # ones. | |
32 | extensions = [ | |
33 | 'sphinx.ext.autodoc', | |
34 | 'sphinx.ext.viewcode', | |
35 | 'pallets_sphinx_themes' | |
36 | ] | |
29 | 37 | |
30 | 38 | # Add any paths that contain templates here, relative to this directory. |
31 | 39 | templates_path = ['_templates'] |
32 | 40 | |
33 | # The suffix of source filenames. | |
34 | source_suffix = '.rst' | |
35 | ||
36 | # The encoding of source files. | |
37 | #source_encoding = 'utf-8-sig' | |
38 | ||
39 | # The master toctree document. | |
40 | master_doc = 'index' | |
41 | ||
42 | # General information about the project. | |
43 | project = u'Flask Babel' | |
44 | copyright = u'2010, Armin Ronacher' | |
45 | ||
46 | # The version info for the project you're documenting, acts as replacement for | |
47 | # |version| and |release|, also used in various other places throughout the | |
48 | # built documents. | |
49 | # | |
50 | # The short X.Y version. | |
51 | version = '0.12.2' | |
52 | # The full version, including alpha/beta/rc tags. | |
53 | release = '0.12.2' | |
54 | ||
55 | # The language for content autogenerated by Sphinx. Refer to documentation | |
56 | # for a list of supported languages. | |
57 | #language = None | |
58 | ||
59 | # There are two options for replacing |today|: either, you set today to some | |
60 | # non-false value, then it is used: | |
61 | #today = '' | |
62 | # Else, today_fmt is used as the format for a strftime call. | |
63 | #today_fmt = '%B %d, %Y' | |
64 | ||
65 | 41 | # List of patterns, relative to source directory, that match files and |
66 | 42 | # directories to ignore when looking for source files. |
67 | exclude_patterns = ['_build'] | |
68 | ||
69 | # The reST default role (used for this markup: `text`) to use for all documents. | |
70 | #default_role = None | |
71 | ||
72 | # If true, '()' will be appended to :func: etc. cross-reference text. | |
73 | #add_function_parentheses = True | |
74 | ||
75 | # If true, the current module name will be prepended to all description | |
76 | # unit titles (such as .. function::). | |
77 | #add_module_names = True | |
78 | ||
79 | # If true, sectionauthor and moduleauthor directives will be shown in the | |
80 | # output. They are ignored by default. | |
81 | #show_authors = False | |
82 | ||
83 | # The name of the Pygments (syntax highlighting) style to use. | |
84 | #pygments_style = 'sphinx' | |
85 | ||
86 | # A list of ignored prefixes for module index sorting. | |
87 | #modindex_common_prefix = [] | |
43 | # This pattern also affects html_static_path and html_extra_path. | |
44 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] | |
88 | 45 | |
89 | 46 | |
90 | # -- Options for HTML output --------------------------------------------------- | |
47 | # -- Options for HTML output ------------------------------------------------- | |
91 | 48 | |
92 | # The theme to use for HTML and HTML Help pages. Major themes that come with | |
93 | # Sphinx are currently 'default' and 'sphinxdoc'. | |
94 | html_theme = 'flask_small' | |
95 | ||
96 | # Theme options are theme-specific and customize the look and feel of a theme | |
97 | # further. For a list of options available for each theme, see the | |
98 | # documentation. | |
99 | html_theme_options = { | |
100 | 'index_logo': 'flask-babel.png', | |
101 | 'github_fork': 'mitsuhiko/flask-babel' | |
102 | } | |
103 | ||
104 | # Add any paths that contain custom themes here, relative to this directory. | |
105 | html_theme_path = ['_themes'] | |
106 | ||
107 | # The name for this set of Sphinx documents. If None, it defaults to | |
108 | # "<project> v<release> documentation". | |
109 | #html_title = None | |
110 | ||
111 | # A shorter title for the navigation bar. Default is the same as html_title. | |
112 | #html_short_title = None | |
113 | ||
114 | # The name of an image file (relative to this directory) to place at the top | |
115 | # of the sidebar. | |
116 | #html_logo = None | |
117 | ||
118 | # The name of an image file (within the static path) to use as favicon of the | |
119 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 | |
120 | # pixels large. | |
121 | #html_favicon = None | |
49 | # The theme to use for HTML and HTML Help pages. See the documentation for | |
50 | # a list of builtin themes. | |
51 | # | |
52 | html_theme = 'flask' | |
122 | 53 | |
123 | 54 | # Add any paths that contain custom static files (such as style sheets) here, |
124 | 55 | # relative to this directory. They are copied after the builtin static files, |
125 | 56 | # so a file named "default.css" will overwrite the builtin "default.css". |
126 | 57 | html_static_path = ['_static'] |
127 | ||
128 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, | |
129 | # using the given strftime format. | |
130 | #html_last_updated_fmt = '%b %d, %Y' | |
131 | ||
132 | # If true, SmartyPants will be used to convert quotes and dashes to | |
133 | # typographically correct entities. | |
134 | #html_use_smartypants = True | |
135 | ||
136 | # Custom sidebar templates, maps document names to template names. | |
137 | #html_sidebars = {} | |
138 | ||
139 | # Additional templates that should be rendered to pages, maps page names to | |
140 | # template names. | |
141 | #html_additional_pages = {} | |
142 | ||
143 | # If false, no module index is generated. | |
144 | #html_domain_indices = True | |
145 | ||
146 | # If false, no index is generated. | |
147 | #html_use_index = True | |
148 | ||
149 | # If true, the index is split into individual pages for each letter. | |
150 | #html_split_index = False | |
151 | ||
152 | # If true, links to the reST sources are added to the pages. | |
153 | #html_show_sourcelink = True | |
154 | ||
155 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. | |
156 | #html_show_sphinx = True | |
157 | ||
158 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. | |
159 | #html_show_copyright = True | |
160 | ||
161 | # If true, an OpenSearch description file will be output, and all pages will | |
162 | # contain a <link> tag referring to it. The value of this option must be the | |
163 | # base URL from which the finished HTML is served. | |
164 | #html_use_opensearch = '' | |
165 | ||
166 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). | |
167 | #html_file_suffix = '' | |
168 | ||
169 | # Output file base name for HTML help builder. | |
170 | htmlhelp_basename = 'FlaskBabeldoc' | |
171 | ||
172 | ||
173 | # -- Options for LaTeX output -------------------------------------------------- | |
174 | ||
175 | # The paper size ('letter' or 'a4'). | |
176 | #latex_paper_size = 'letter' | |
177 | ||
178 | # The font size ('10pt', '11pt' or '12pt'). | |
179 | #latex_font_size = '10pt' | |
180 | ||
181 | # Grouping the document tree into LaTeX files. List of tuples | |
182 | # (source start file, target name, title, author, documentclass [howto/manual]). | |
183 | latex_documents = [ | |
184 | ('index', 'FlaskBabel.tex', u'Flask Babel Documentation', | |
185 | u'Armin Ronacher', 'manual'), | |
186 | ] | |
187 | ||
188 | # The name of an image file (relative to this directory) to place at the top of | |
189 | # the title page. | |
190 | #latex_logo = None | |
191 | ||
192 | # For "manual" documents, if this is true, then toplevel headings are parts, | |
193 | # not chapters. | |
194 | #latex_use_parts = False | |
195 | ||
196 | # If true, show page references after internal links. | |
197 | #latex_show_pagerefs = False | |
198 | ||
199 | # If true, show URL addresses after external links. | |
200 | #latex_show_urls = False | |
201 | ||
202 | # Additional stuff for the LaTeX preamble. | |
203 | #latex_preamble = '' | |
204 | ||
205 | # Documents to append as an appendix to all manuals. | |
206 | #latex_appendices = [] | |
207 | ||
208 | # If false, no module index is generated. | |
209 | #latex_domain_indices = True | |
210 | ||
211 | ||
212 | # -- Options for manual page output -------------------------------------------- | |
213 | ||
214 | # One entry per manual page. List of tuples | |
215 | # (source start file, name, description, authors, manual section). | |
216 | man_pages = [ | |
217 | ('index', 'flaskbabel', u'Flask Babel Documentation', | |
218 | [u'Armin Ronacher'], 1) | |
219 | ] | |
220 | ||
221 | intersphinx_mapping = {'http://docs.python.org/': None, | |
222 | 'http://flask.pocoo.org/docs/': None} |
11 | 11 | Installation |
12 | 12 | ------------ |
13 | 13 | |
14 | Install the extension with one of the following commands:: | |
15 | ||
16 | $ easy_install Flask-Babel | |
17 | ||
18 | or alternatively if you have pip installed:: | |
14 | Install the extension from PyPi:: | |
19 | 15 | |
20 | 16 | $ pip install Flask-Babel |
21 | 17 | |
22 | Please note that Flask-Babel requires Jinja 2.5. If you are using an | |
18 | Please note that Flask-Babel requires Jinja >=2.5. If you are using an | |
23 | 19 | older version you will have to upgrade or disable the Jinja support |
24 | 20 | (see configuration). |
25 | 21 | |
27 | 23 | Configuration |
28 | 24 | ------------- |
29 | 25 | |
30 | To get started all you need to do is to instanciate a :class:`Babel` | |
26 | To get started all you need to do is to instantiate a :class:`Babel` | |
31 | 27 | object after configuring the application:: |
32 | 28 | |
33 | 29 | from flask import Flask |
50 | 46 | This defaults to ``'UTC'`` which also is the |
51 | 47 | timezone your application must use internally. |
52 | 48 | `BABEL_TRANSLATION_DIRECTORIES` A semi-colon (``;``) separated string of |
53 | absolute and relative (to the app root) paths | |
54 | to translation folders. Defaults to | |
55 | ``translations``. | |
49 | absolute and relative (to the `root_path` of | |
50 | the application object) paths to translation | |
51 | folders. Defaults to ``translations``. | |
56 | 52 | `BABEL_DOMAIN` The message domain used by the application. |
57 | 53 | Defaults to ``messages``. |
58 | 54 | =============================== ============================================= |
59 | 55 | |
60 | 56 | For more complex applications you might want to have multiple applications |
61 | 57 | for different users which is where selector functions come in handy. The |
62 | first time the babel extension needs the locale (language code) of the | |
58 | first time the babel extension needs the locale (locale code/ID) of the | |
63 | 59 | current user it will call a :meth:`~Babel.localeselector` function, and |
64 | 60 | the first time the timezone is needed it will call a |
65 | 61 | :meth:`~Babel.timezoneselector` function. |
93 | 89 | |
94 | 90 | The example above assumes that the current user is stored on the |
95 | 91 | :data:`flask.g` object. |
92 | ||
93 | Jinja Filters | |
94 | ------------- | |
95 | ||
96 | Several commonly used formatters are added as jinja template filters after | |
97 | calling `init_app().` For dates and times, these are: | |
98 | ||
99 | - `<datetime>|datetimeformat` -> `format_datetime` | |
100 | - `<date>|dateformat` -> `format_date` | |
101 | - `<time>|timeformat` -> `format_time` | |
102 | - `<timedelta>|timedeltaformat` -> `format_timedelta` | |
103 | ||
104 | And for numbers, these are: | |
105 | ||
106 | - `<number>|numberformat` -> `format_number` | |
107 | - `<number>|decimalformat` -> `format_decimal` | |
108 | - `<number>|currencyformat` -> `format_currency` | |
109 | - `<number>|percentformat` -> `format_percent` | |
110 | - `<number>|scientificformat` -> `format_scientific` | |
96 | 111 | |
97 | 112 | Formatting Dates |
98 | 113 | ---------------- |
233 | 248 | and is the template for a ``.po`` file which contains the translated |
234 | 249 | strings. Babel can do all that for you. |
235 | 250 | |
236 | First of all you have to get into the folder where you have your | |
237 | application and create a mapping file. For typical Flask applications, this | |
238 | is what you want in there: | |
251 | First of all you have to create a mapping file. For typical Flask applications, | |
252 | this is what you want in there: | |
239 | 253 | |
240 | 254 | .. sourcecode:: ini |
241 | 255 | |
260 | 274 | |
261 | 275 | $ pybabel init -i messages.pot -d translations -l de |
262 | 276 | |
263 | ``-d translations`` tells pybabel to store the translations in this | |
264 | folder. This is where Flask-Babel will look for translations. Put it | |
265 | next to your template folder. | |
277 | ``-d translations`` tells pybabel to store the translations in a directory | |
278 | called "translations". This is the default folder where Flask-Babel will look | |
279 | for translations unless you changed `BABEL_TRANSLATION_DIRECTORIES` and should | |
280 | be at the root of your application. | |
266 | 281 | |
267 | 282 | Now edit the ``translations/de/LC_MESSAGES/messages.po`` file as needed. |
268 | 283 | Check out some gettext tutorials if you feel lost. |
0 | @ECHO OFF | |
1 | ||
2 | REM Command file for Sphinx documentation | |
3 | ||
4 | if "%SPHINXBUILD%" == "" ( | |
5 | set SPHINXBUILD=sphinx-build | |
6 | ) | |
7 | set BUILDDIR=_build | |
8 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . | |
9 | if NOT "%PAPER%" == "" ( | |
10 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% | |
11 | ) | |
12 | ||
13 | if "%1" == "" goto help | |
14 | ||
15 | if "%1" == "help" ( | |
16 | :help | |
17 | echo.Please use `make ^<target^>` where ^<target^> is one of | |
18 | echo. html to make standalone HTML files | |
19 | echo. dirhtml to make HTML files named index.html in directories | |
20 | echo. singlehtml to make a single large HTML file | |
21 | echo. pickle to make pickle files | |
22 | echo. json to make JSON files | |
23 | echo. htmlhelp to make HTML files and a HTML help project | |
24 | echo. qthelp to make HTML files and a qthelp project | |
25 | echo. devhelp to make HTML files and a Devhelp project | |
26 | echo. epub to make an epub | |
27 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter | |
28 | echo. text to make text files | |
29 | echo. man to make manual pages | |
30 | echo. changes to make an overview over all changed/added/deprecated items | |
31 | echo. linkcheck to check all external links for integrity | |
32 | echo. doctest to run all doctests embedded in the documentation if enabled | |
33 | goto end | |
34 | ) | |
35 | ||
36 | if "%1" == "clean" ( | |
37 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i | |
38 | del /q /s %BUILDDIR%\* | |
39 | goto end | |
40 | ) | |
41 | ||
42 | if "%1" == "html" ( | |
43 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html | |
44 | echo. | |
45 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. | |
46 | goto end | |
47 | ) | |
48 | ||
49 | if "%1" == "dirhtml" ( | |
50 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml | |
51 | echo. | |
52 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. | |
53 | goto end | |
54 | ) | |
55 | ||
56 | if "%1" == "singlehtml" ( | |
57 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml | |
58 | echo. | |
59 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. | |
60 | goto end | |
61 | ) | |
62 | ||
63 | if "%1" == "pickle" ( | |
64 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle | |
65 | echo. | |
66 | echo.Build finished; now you can process the pickle files. | |
67 | goto end | |
68 | ) | |
69 | ||
70 | if "%1" == "json" ( | |
71 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json | |
72 | echo. | |
73 | echo.Build finished; now you can process the JSON files. | |
74 | goto end | |
75 | ) | |
76 | ||
77 | if "%1" == "htmlhelp" ( | |
78 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp | |
79 | echo. | |
80 | echo.Build finished; now you can run HTML Help Workshop with the ^ | |
81 | .hhp project file in %BUILDDIR%/htmlhelp. | |
82 | goto end | |
83 | ) | |
84 | ||
85 | if "%1" == "qthelp" ( | |
86 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp | |
87 | echo. | |
88 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ | |
89 | .qhcp project file in %BUILDDIR%/qthelp, like this: | |
90 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\FlaskBabel.qhcp | |
91 | echo.To view the help file: | |
92 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\FlaskBabel.ghc | |
93 | goto end | |
94 | ) | |
95 | ||
96 | if "%1" == "devhelp" ( | |
97 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp | |
98 | echo. | |
99 | echo.Build finished. | |
100 | goto end | |
101 | ) | |
102 | ||
103 | if "%1" == "epub" ( | |
104 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub | |
105 | echo. | |
106 | echo.Build finished. The epub file is in %BUILDDIR%/epub. | |
107 | goto end | |
108 | ) | |
109 | ||
110 | if "%1" == "latex" ( | |
111 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex | |
112 | echo. | |
113 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. | |
114 | goto end | |
115 | ) | |
116 | ||
117 | if "%1" == "text" ( | |
118 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text | |
119 | echo. | |
120 | echo.Build finished. The text files are in %BUILDDIR%/text. | |
121 | goto end | |
122 | ) | |
123 | ||
124 | if "%1" == "man" ( | |
125 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man | |
126 | echo. | |
127 | echo.Build finished. The manual pages are in %BUILDDIR%/man. | |
128 | goto end | |
129 | ) | |
130 | ||
131 | if "%1" == "changes" ( | |
132 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes | |
133 | echo. | |
134 | echo.The overview file is in %BUILDDIR%/changes. | |
135 | goto end | |
136 | ) | |
137 | ||
138 | if "%1" == "linkcheck" ( | |
139 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck | |
140 | echo. | |
141 | echo.Link check complete; look for any errors in the above output ^ | |
142 | or in %BUILDDIR%/linkcheck/output.txt. | |
143 | goto end | |
144 | ) | |
145 | ||
146 | if "%1" == "doctest" ( | |
147 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest | |
148 | echo. | |
149 | echo.Testing of doctests in the sources finished, look at the ^ | |
150 | results in %BUILDDIR%/doctest/output.txt. | |
151 | goto end | |
152 | ) | |
153 | ||
154 | :end | |
0 | @ECHO OFF | |
1 | ||
2 | pushd %~dp0 | |
3 | ||
4 | REM Command file for Sphinx documentation | |
5 | ||
6 | if "%SPHINXBUILD%" == "" ( | |
7 | set SPHINXBUILD=sphinx-build | |
8 | ) | |
9 | set SOURCEDIR=. | |
10 | set BUILDDIR=_build | |
11 | ||
12 | if "%1" == "" goto help | |
13 | ||
14 | %SPHINXBUILD% >NUL 2>NUL | |
15 | if errorlevel 9009 ( | |
16 | echo. | |
17 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx | |
18 | echo.installed, then set the SPHINXBUILD environment variable to point | |
19 | echo.to the full path of the 'sphinx-build' executable. Alternatively you | |
20 | echo.may add the Sphinx directory to PATH. | |
21 | echo. | |
22 | echo.If you don't have Sphinx installed, grab it from | |
23 | echo.http://sphinx-doc.org/ | |
24 | exit /b 1 | |
25 | ) | |
26 | ||
27 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | |
28 | goto end | |
29 | ||
30 | :help | |
31 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | |
32 | ||
33 | :end | |
34 | popd |
0 | # -*- coding: utf-8 -*- | |
1 | 0 | """ |
2 | 1 | flaskext.babel |
3 | 2 | ~~~~~~~~~~~~~~ |
14 | 13 | from contextlib import contextmanager |
15 | 14 | from flask import current_app, request |
16 | 15 | from flask.ctx import has_request_context |
16 | from flask.helpers import locked_cached_property | |
17 | 17 | from babel import dates, numbers, support, Locale |
18 | from werkzeug import ImmutableDict | |
19 | try: | |
20 | from pytz.gae import pytz | |
21 | except ImportError: | |
22 | from pytz import timezone, UTC | |
23 | else: | |
24 | timezone = pytz.timezone | |
25 | UTC = pytz.UTC | |
26 | ||
27 | from flask_babel._compat import string_types | |
18 | from pytz import timezone, UTC | |
19 | from werkzeug.datastructures import ImmutableDict | |
20 | ||
28 | 21 | from flask_babel.speaklater import LazyString |
29 | 22 | |
30 | 23 | |
125 | 118 | |
126 | 119 | This has to return the locale as string (eg: ``'de_AT'``, ``'en_US'``) |
127 | 120 | """ |
128 | assert self.locale_selector_func is None, \ | |
129 | 'a localeselector function is already registered' | |
130 | 121 | self.locale_selector_func = f |
131 | 122 | return f |
132 | 123 | |
138 | 129 | |
139 | 130 | This has to return the timezone as string (eg: ``'Europe/Vienna'``) |
140 | 131 | """ |
141 | assert self.timezone_selector_func is None, \ | |
142 | 'a timezoneselector function is already registered' | |
143 | 132 | self.timezone_selector_func = f |
144 | 133 | return f |
145 | 134 | |
189 | 178 | """The message domain for the translations as a string. |
190 | 179 | """ |
191 | 180 | return self.app.config['BABEL_DOMAIN'] |
181 | ||
182 | @locked_cached_property | |
183 | def domain_instance(self): | |
184 | """The message domain for the translations. | |
185 | """ | |
186 | return Domain(domain=self.app.config['BABEL_DOMAIN']) | |
192 | 187 | |
193 | 188 | @property |
194 | 189 | def translation_directories(self): |
210 | 205 | object if used outside of the request or if a translation cannot be |
211 | 206 | found. |
212 | 207 | """ |
213 | ctx = _get_current_context() | |
214 | ||
215 | if ctx is None: | |
216 | return support.NullTranslations() | |
217 | ||
218 | translations = getattr(ctx, 'babel_translations', None) | |
219 | if translations is None: | |
220 | translations = support.Translations() | |
221 | ||
222 | babel = current_app.extensions['babel'] | |
223 | for dirname in babel.translation_directories: | |
224 | catalog = support.Translations.load( | |
225 | dirname, | |
226 | [get_locale()], | |
227 | babel.domain | |
228 | ) | |
229 | translations.merge(catalog) | |
230 | # FIXME: Workaround for merge() being really, really stupid. It | |
231 | # does not copy _info, plural(), or any other instance variables | |
232 | # populated by GNUTranslations. We probably want to stop using | |
233 | # `support.Translations.merge` entirely. | |
234 | if hasattr(catalog, 'plural'): | |
235 | translations.plural = catalog.plural | |
236 | ||
237 | ctx.babel_translations = translations | |
238 | ||
239 | return translations | |
208 | return get_domain().get_translations() | |
240 | 209 | |
241 | 210 | |
242 | 211 | def get_locale(): |
278 | 247 | if rv is None: |
279 | 248 | tzinfo = babel.default_timezone |
280 | 249 | else: |
281 | if isinstance(rv, string_types): | |
282 | tzinfo = timezone(rv) | |
283 | else: | |
284 | tzinfo = rv | |
250 | tzinfo = timezone(rv) if isinstance(rv, str) else rv | |
285 | 251 | ctx.babel_tzinfo = tzinfo |
286 | 252 | return tzinfo |
287 | 253 | |
304 | 270 | if hasattr(ctx, key): |
305 | 271 | delattr(ctx, key) |
306 | 272 | |
273 | if hasattr(ctx, 'forced_babel_locale'): | |
274 | ctx.babel_locale = ctx.forced_babel_locale | |
275 | ||
307 | 276 | |
308 | 277 | @contextmanager |
309 | 278 | def force_locale(locale): |
324 | 293 | yield |
325 | 294 | return |
326 | 295 | |
327 | babel = current_app.extensions['babel'] | |
328 | ||
329 | orig_locale_selector_func = babel.locale_selector_func | |
330 | 296 | orig_attrs = {} |
331 | 297 | for key in ('babel_translations', 'babel_locale'): |
332 | 298 | orig_attrs[key] = getattr(ctx, key, None) |
333 | 299 | |
334 | 300 | try: |
335 | babel.locale_selector_func = lambda: locale | |
336 | for key in orig_attrs: | |
337 | setattr(ctx, key, None) | |
301 | ctx.babel_locale = Locale.parse(locale) | |
302 | ctx.forced_babel_locale = ctx.babel_locale | |
303 | ctx.babel_translations = None | |
338 | 304 | yield |
339 | 305 | finally: |
340 | babel.locale_selector_func = orig_locale_selector_func | |
306 | if hasattr(ctx, 'forced_babel_locale'): | |
307 | del ctx.forced_babel_locale | |
308 | ||
341 | 309 | for key, value in orig_attrs.items(): |
342 | 310 | setattr(ctx, key, value) |
343 | 311 | |
475 | 443 | :rtype: unicode |
476 | 444 | """ |
477 | 445 | locale = get_locale() |
478 | return numbers.format_number(number, locale=locale) | |
446 | return numbers.format_decimal(number, locale=locale) | |
479 | 447 | |
480 | 448 | |
481 | 449 | def format_decimal(number, format=None): |
539 | 507 | return numbers.format_scientific(number, format=format, locale=locale) |
540 | 508 | |
541 | 509 | |
542 | def gettext(string, **variables): | |
543 | """Translates a string with the current locale and passes in the | |
544 | given keyword arguments as mapping to a string formatting string. | |
545 | ||
546 | :: | |
547 | ||
548 | gettext(u'Hello World!') | |
549 | gettext(u'Hello %(name)s!', name='World') | |
550 | """ | |
551 | t = get_translations() | |
552 | if t is None: | |
553 | return string if not variables else string % variables | |
554 | s = t.ugettext(string) | |
555 | return s if not variables else s % variables | |
556 | _ = gettext | |
557 | ||
558 | ||
559 | def ngettext(singular, plural, num, **variables): | |
560 | """Translates a string with the current locale and passes in the | |
561 | given keyword arguments as mapping to a string formatting string. | |
562 | The `num` parameter is used to dispatch between singular and various | |
563 | plural forms of the message. It is available in the format string | |
564 | as ``%(num)d`` or ``%(num)s``. The source language should be | |
565 | English or a similar language which only has one plural form. | |
566 | ||
567 | :: | |
568 | ||
569 | ngettext(u'%(num)d Apple', u'%(num)d Apples', num=len(apples)) | |
570 | """ | |
571 | variables.setdefault('num', num) | |
572 | t = get_translations() | |
573 | if t is None: | |
574 | s = singular if num == 1 else plural | |
510 | class Domain(object): | |
511 | """Localization domain. By default will use look for tranlations in Flask | |
512 | application directory and "messages" domain - all message catalogs should | |
513 | be called ``messages.mo``. | |
514 | """ | |
515 | ||
516 | def __init__(self, translation_directories=None, domain='messages'): | |
517 | if isinstance(translation_directories, str): | |
518 | translation_directories = [translation_directories] | |
519 | self._translation_directories = translation_directories | |
520 | self.domain = domain | |
521 | self.cache = {} | |
522 | ||
523 | def __repr__(self): | |
524 | return '<Domain({!r}, {!r})>'.format(self._translation_directories, self.domain) | |
525 | ||
526 | @property | |
527 | def translation_directories(self): | |
528 | if self._translation_directories is not None: | |
529 | return self._translation_directories | |
530 | babel = current_app.extensions['babel'] | |
531 | return babel.translation_directories | |
532 | ||
533 | def as_default(self): | |
534 | """Set this domain as default for the current request""" | |
535 | ctx = _get_current_context() | |
536 | ||
537 | if ctx is None: | |
538 | raise RuntimeError("No request context") | |
539 | ||
540 | ctx.babel_domain = self | |
541 | ||
542 | def get_translations_cache(self, ctx): | |
543 | """Returns dictionary-like object for translation caching""" | |
544 | return self.cache | |
545 | ||
546 | def get_translations(self): | |
547 | ctx = _get_current_context() | |
548 | ||
549 | if ctx is None: | |
550 | return support.NullTranslations() | |
551 | ||
552 | cache = self.get_translations_cache(ctx) | |
553 | locale = get_locale() | |
554 | try: | |
555 | return cache[str(locale), self.domain] | |
556 | except KeyError: | |
557 | translations = support.Translations() | |
558 | ||
559 | for dirname in self.translation_directories: | |
560 | catalog = support.Translations.load( | |
561 | dirname, | |
562 | [locale], | |
563 | self.domain | |
564 | ) | |
565 | translations.merge(catalog) | |
566 | # FIXME: Workaround for merge() being really, really stupid. It | |
567 | # does not copy _info, plural(), or any other instance variables | |
568 | # populated by GNUTranslations. We probably want to stop using | |
569 | # `support.Translations.merge` entirely. | |
570 | if hasattr(catalog, 'plural'): | |
571 | translations.plural = catalog.plural | |
572 | ||
573 | cache[str(locale), self.domain] = translations | |
574 | return translations | |
575 | ||
576 | def gettext(self, string, **variables): | |
577 | """Translates a string with the current locale and passes in the | |
578 | given keyword arguments as mapping to a string formatting string. | |
579 | ||
580 | :: | |
581 | ||
582 | gettext(u'Hello World!') | |
583 | gettext(u'Hello %(name)s!', name='World') | |
584 | """ | |
585 | t = self.get_translations() | |
586 | s = t.ugettext(string) | |
575 | 587 | return s if not variables else s % variables |
576 | 588 | |
577 | s = t.ungettext(singular, plural, num) | |
578 | return s if not variables else s % variables | |
579 | ||
580 | ||
581 | def pgettext(context, string, **variables): | |
582 | """Like :func:`gettext` but with a context. | |
583 | ||
584 | .. versionadded:: 0.7 | |
585 | """ | |
586 | t = get_translations() | |
587 | if t is None: | |
588 | return string if not variables else string % variables | |
589 | s = t.upgettext(context, string) | |
590 | return s if not variables else s % variables | |
591 | ||
592 | ||
593 | def npgettext(context, singular, plural, num, **variables): | |
594 | """Like :func:`ngettext` but with a context. | |
595 | ||
596 | .. versionadded:: 0.7 | |
597 | """ | |
598 | variables.setdefault('num', num) | |
599 | t = get_translations() | |
600 | if t is None: | |
601 | s = singular if num == 1 else plural | |
589 | def ngettext(self, singular, plural, num, **variables): | |
590 | """Translates a string with the current locale and passes in the | |
591 | given keyword arguments as mapping to a string formatting string. | |
592 | The `num` parameter is used to dispatch between singular and various | |
593 | plural forms of the message. It is available in the format string | |
594 | as ``%(num)d`` or ``%(num)s``. The source language should be | |
595 | English or a similar language which only has one plural form. | |
596 | ||
597 | :: | |
598 | ||
599 | ngettext(u'%(num)d Apple', u'%(num)d Apples', num=len(apples)) | |
600 | """ | |
601 | variables.setdefault('num', num) | |
602 | t = self.get_translations() | |
603 | s = t.ungettext(singular, plural, num) | |
602 | 604 | return s if not variables else s % variables |
603 | s = t.unpgettext(context, singular, plural, num) | |
604 | return s if not variables else s % variables | |
605 | ||
606 | ||
607 | def lazy_gettext(string, **variables): | |
608 | """Like :func:`gettext` but the string returned is lazy which means | |
609 | it will be translated when it is used as an actual string. | |
610 | ||
611 | Example:: | |
612 | ||
613 | hello = lazy_gettext(u'Hello World') | |
614 | ||
615 | @app.route('/') | |
616 | def index(): | |
617 | return unicode(hello) | |
618 | """ | |
619 | return LazyString(gettext, string, **variables) | |
620 | ||
621 | ||
622 | def lazy_pgettext(context, string, **variables): | |
623 | """Like :func:`pgettext` but the string returned is lazy which means | |
624 | it will be translated when it is used as an actual string. | |
625 | ||
626 | .. versionadded:: 0.7 | |
627 | """ | |
628 | return LazyString(pgettext, context, string, **variables) | |
605 | ||
606 | def pgettext(self, context, string, **variables): | |
607 | """Like :func:`gettext` but with a context. | |
608 | ||
609 | .. versionadded:: 0.7 | |
610 | """ | |
611 | t = self.get_translations() | |
612 | s = t.upgettext(context, string) | |
613 | return s if not variables else s % variables | |
614 | ||
615 | def npgettext(self, context, singular, plural, num, **variables): | |
616 | """Like :func:`ngettext` but with a context. | |
617 | ||
618 | .. versionadded:: 0.7 | |
619 | """ | |
620 | variables.setdefault('num', num) | |
621 | t = self.get_translations() | |
622 | s = t.unpgettext(context, singular, plural, num) | |
623 | return s if not variables else s % variables | |
624 | ||
625 | def lazy_gettext(self, string, **variables): | |
626 | """Like :func:`gettext` but the string returned is lazy which means | |
627 | it will be translated when it is used as an actual string. | |
628 | ||
629 | Example:: | |
630 | ||
631 | hello = lazy_gettext(u'Hello World') | |
632 | ||
633 | @app.route('/') | |
634 | def index(): | |
635 | return unicode(hello) | |
636 | """ | |
637 | return LazyString(self.gettext, string, **variables) | |
638 | ||
639 | def lazy_ngettext(self, singular, plural, num, **variables): | |
640 | """Like :func:`ngettext` but the string returned is lazy which means | |
641 | it will be translated when it is used as an actual string. | |
642 | ||
643 | Example:: | |
644 | ||
645 | apples = lazy_ngettext(u'%(num)d Apple', u'%(num)d Apples', num=len(apples)) | |
646 | ||
647 | @app.route('/') | |
648 | def index(): | |
649 | return unicode(apples) | |
650 | """ | |
651 | return LazyString(self.ngettext, singular, plural, num, **variables) | |
652 | ||
653 | def lazy_pgettext(self, context, string, **variables): | |
654 | """Like :func:`pgettext` but the string returned is lazy which means | |
655 | it will be translated when it is used as an actual string. | |
656 | ||
657 | .. versionadded:: 0.7 | |
658 | """ | |
659 | return LazyString(self.pgettext, context, string, **variables) | |
629 | 660 | |
630 | 661 | |
631 | 662 | def _get_current_context(): |
634 | 665 | |
635 | 666 | if current_app: |
636 | 667 | return current_app |
668 | ||
669 | ||
670 | def get_domain(): | |
671 | ctx = _get_current_context() | |
672 | if ctx is None: | |
673 | # this will use NullTranslations | |
674 | return Domain() | |
675 | ||
676 | try: | |
677 | return ctx.babel_domain | |
678 | except AttributeError: | |
679 | pass | |
680 | ||
681 | babel = current_app.extensions['babel'] | |
682 | ctx.babel_domain = babel.domain_instance | |
683 | return ctx.babel_domain | |
684 | ||
685 | ||
686 | # Create shortcuts for the default Flask domain | |
687 | def gettext(*args, **kwargs): | |
688 | return get_domain().gettext(*args, **kwargs) | |
689 | _ = gettext | |
690 | ||
691 | ||
692 | def ngettext(*args, **kwargs): | |
693 | return get_domain().ngettext(*args, **kwargs) | |
694 | ||
695 | ||
696 | def pgettext(*args, **kwargs): | |
697 | return get_domain().pgettext(*args, **kwargs) | |
698 | ||
699 | ||
700 | def npgettext(*args, **kwargs): | |
701 | return get_domain().npgettext(*args, **kwargs) | |
702 | ||
703 | ||
704 | def lazy_gettext(*args, **kwargs): | |
705 | return LazyString(gettext, *args, **kwargs) | |
706 | ||
707 | ||
708 | def lazy_pgettext(*args, **kwargs): | |
709 | return LazyString(pgettext, *args, **kwargs) | |
710 | ||
711 | ||
712 | def lazy_ngettext(*args, **kwargs): | |
713 | return LazyString(ngettext, *args, **kwargs) |
0 | # -*- coding: utf-8 -*- | |
1 | """ | |
2 | flask.ext.babel._compat | |
3 | ~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | ||
5 | :copyright: (c) 2013 by Armin Ronacher, Daniel Neuhäuser. | |
6 | :license: BSD, see LICENSE for more details. | |
7 | """ | |
8 | import sys | |
9 | ||
10 | ||
11 | PY2 = sys.version_info[0] == 2 | |
12 | ||
13 | ||
14 | if PY2: | |
15 | text_type = unicode | |
16 | string_types = (str, unicode) | |
17 | else: | |
18 | text_type = str | |
19 | string_types = (str, ) |
0 | # -*- coding: utf-8 -*- | |
1 | from flask_babel._compat import text_type | |
2 | ||
3 | ||
4 | 0 | class LazyString(object): |
5 | 1 | def __init__(self, func, *args, **kwargs): |
6 | 2 | self._func = func |
10 | 6 | def __getattr__(self, attr): |
11 | 7 | if attr == "__setstate__": |
12 | 8 | raise AttributeError(attr) |
13 | string = text_type(self) | |
9 | ||
10 | string = str(self) | |
14 | 11 | if hasattr(string, attr): |
15 | 12 | return getattr(string, attr) |
13 | ||
16 | 14 | raise AttributeError(attr) |
17 | 15 | |
18 | 16 | def __repr__(self): |
19 | return "l'{0}'".format(text_type(self)) | |
17 | return "l'{0}'".format(str(self)) | |
20 | 18 | |
21 | 19 | def __str__(self): |
22 | return text_type(self._func(*self._args, **self._kwargs)) | |
20 | return str(self._func(*self._args, **self._kwargs)) | |
23 | 21 | |
24 | 22 | def __len__(self): |
25 | return len(text_type(self)) | |
23 | return len(str(self)) | |
26 | 24 | |
27 | 25 | def __getitem__(self, key): |
28 | return text_type(self)[key] | |
26 | return str(self)[key] | |
29 | 27 | |
30 | 28 | def __iter__(self): |
31 | return iter(text_type(self)) | |
29 | return iter(str(self)) | |
32 | 30 | |
33 | 31 | def __contains__(self, item): |
34 | return item in text_type(self) | |
32 | return item in str(self) | |
35 | 33 | |
36 | 34 | def __add__(self, other): |
37 | return text_type(self) + other | |
35 | return str(self) + other | |
38 | 36 | |
39 | 37 | def __radd__(self, other): |
40 | return other + text_type(self) | |
38 | return other + str(self) | |
41 | 39 | |
42 | 40 | def __mul__(self, other): |
43 | return text_type(self) * other | |
41 | return str(self) * other | |
44 | 42 | |
45 | 43 | def __rmul__(self, other): |
46 | return other * text_type(self) | |
44 | return other * str(self) | |
47 | 45 | |
48 | 46 | def __lt__(self, other): |
49 | return text_type(self) < other | |
47 | return str(self) < other | |
50 | 48 | |
51 | 49 | def __le__(self, other): |
52 | return text_type(self) <= other | |
50 | return str(self) <= other | |
53 | 51 | |
54 | 52 | def __eq__(self, other): |
55 | return text_type(self) == other | |
53 | return str(self) == other | |
56 | 54 | |
57 | 55 | def __ne__(self, other): |
58 | return text_type(self) != other | |
56 | return str(self) != other | |
59 | 57 | |
60 | 58 | def __gt__(self, other): |
61 | return text_type(self) > other | |
59 | return str(self) > other | |
62 | 60 | |
63 | 61 | def __ge__(self, other): |
64 | return text_type(self) >= other | |
62 | return str(self) >= other | |
65 | 63 | |
66 | 64 | def __html__(self): |
67 | return text_type(self) | |
65 | return str(self) | |
68 | 66 | |
69 | 67 | def __hash__(self): |
70 | return hash(text_type(self)) | |
68 | return hash(str(self)) | |
71 | 69 | |
72 | 70 | def __mod__(self, other): |
73 | return text_type(self) % other | |
71 | return str(self) % other | |
74 | 72 | |
75 | 73 | def __rmod__(self, other): |
76 | return other + text_type(self)⏎ | |
74 | return other + str(self) |
7 | 7 | |
8 | 8 | setup( |
9 | 9 | name='Flask-Babel', |
10 | version='0.12.2', | |
10 | version='2.0.0', | |
11 | 11 | url='http://github.com/python-babel/flask-babel', |
12 | 12 | license='BSD', |
13 | 13 | author='Armin Ronacher', |
14 | 14 | author_email='armin.ronacher@active-4.com', |
15 | maintainer='Tyler Kennedy', | |
16 | maintainer_email='tk@tkte.ch', | |
15 | 17 | description='Adds i18n/l10n support to Flask applications', |
16 | 18 | long_description=long_description, |
17 | 19 | long_description_content_type='text/markdown', |
18 | 20 | packages=['flask_babel'], |
19 | 21 | zip_safe=False, |
20 | platforms='any', | |
21 | 22 | install_requires=[ |
23 | 'pytz', | |
22 | 24 | 'Flask', |
23 | 25 | 'Babel>=2.3', |
24 | 26 | 'Jinja2>=2.5' |
25 | 27 | ], |
26 | 28 | classifiers=[ |
27 | 'Development Status :: 4 - Beta', | |
29 | 'Development Status :: 5 - Production/Stable', | |
28 | 30 | 'Environment :: Web Environment', |
29 | 31 | 'Intended Audience :: Developers', |
30 | 32 | 'License :: OSI Approved :: BSD License', |
31 | 33 | 'Operating System :: OS Independent', |
32 | 'Programming Language :: Python :: 2.7', | |
34 | 'Programming Language :: Python :: 3.5', | |
33 | 35 | 'Programming Language :: Python :: 3.6', |
36 | 'Programming Language :: Python :: 3.7', | |
37 | 'Programming Language :: Python :: 3.8', | |
38 | 'Programming Language :: Python :: 3.9', | |
34 | 39 | 'Programming Language :: Python :: Implementation :: CPython', |
35 | 40 | 'Programming Language :: Python :: Implementation :: PyPy', |
36 | 41 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', |
37 | 42 | 'Topic :: Software Development :: Libraries :: Python Modules' |
38 | ] | |
43 | ], | |
44 | extras_require={ | |
45 | 'dev': [ | |
46 | 'pytest', | |
47 | 'pytest-mock', | |
48 | 'bumpversion', | |
49 | 'ghp-import', | |
50 | 'sphinx', | |
51 | 'Pallets-Sphinx-Themes' | |
52 | ] | |
53 | } | |
39 | 54 | ) |
Binary diff not shown
0 | # German translations for PROJECT. | |
1 | # Copyright (C) 2010 ORGANIZATION | |
2 | # This file is distributed under the same license as the PROJECT project. | |
3 | # FIRST AUTHOR <EMAIL@ADDRESS>, 2010. | |
4 | # | |
5 | msgid "" | |
6 | msgstr "" | |
7 | "Project-Id-Version: PROJECT VERSION\n" | |
8 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | |
9 | "POT-Creation-Date: 2010-05-29 17:00+0200\n" | |
10 | "PO-Revision-Date: 2010-05-30 12:56+0200\n" | |
11 | "Last-Translator: Armin Ronacher <armin.ronacher@active-4.com>\n" | |
12 | "Language-Team: de <LL@li.org>\n" | |
13 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" | |
14 | "MIME-Version: 1.0\n" | |
15 | "Content-Type: text/plain; charset=utf-8\n" | |
16 | "Content-Transfer-Encoding: 8bit\n" | |
17 | "Generated-By: Babel 0.9.5\n" | |
18 | ||
19 | #: tests.py:94 | |
20 | #, python-format | |
21 | msgid "Hello %(name)s!" | |
22 | msgstr "Hallo %(name)s!" | |
23 | ||
24 | #: tests.py:95 tests.py:96 | |
25 | #, python-format | |
26 | msgid "%(num)s Apple" | |
27 | msgid_plural "%(num)s Apples" | |
28 | msgstr[0] "%(num)s Apfel" | |
29 | msgstr[1] "%(num)s Äpfel" | |
30 | ||
31 | #: tests.py:119 | |
32 | msgid "Yes" | |
33 | msgstr "Ja" | |
34 |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import with_statement | |
2 | ||
3 | from datetime import datetime, timedelta | |
4 | from threading import Semaphore, Thread | |
5 | ||
6 | import flask | |
7 | ||
8 | import flask_babel as babel | |
9 | ||
10 | ||
11 | def test_basics(): | |
12 | app = flask.Flask(__name__) | |
13 | babel.Babel(app) | |
14 | d = datetime(2010, 4, 12, 13, 46) | |
15 | delta = timedelta(days=6) | |
16 | ||
17 | with app.test_request_context(): | |
18 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
19 | assert babel.format_date(d) == 'Apr 12, 2010' | |
20 | assert babel.format_time(d) == '1:46:00 PM' | |
21 | assert babel.format_timedelta(delta) == '1 week' | |
22 | assert babel.format_timedelta(delta, threshold=1) == '6 days' | |
23 | ||
24 | with app.test_request_context(): | |
25 | app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna' | |
26 | assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM' | |
27 | assert babel.format_date(d) == 'Apr 12, 2010' | |
28 | assert babel.format_time(d) == '3:46:00 PM' | |
29 | ||
30 | with app.test_request_context(): | |
31 | app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE' | |
32 | assert babel.format_datetime(d, 'long') == \ | |
33 | '12. April 2010 um 15:46:00 MESZ' | |
34 | ||
35 | ||
36 | def test_init_app(): | |
37 | b = babel.Babel() | |
38 | app = flask.Flask(__name__) | |
39 | b.init_app(app) | |
40 | d = datetime(2010, 4, 12, 13, 46) | |
41 | ||
42 | with app.test_request_context(): | |
43 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
44 | assert babel.format_date(d) == 'Apr 12, 2010' | |
45 | assert babel.format_time(d) == '1:46:00 PM' | |
46 | ||
47 | with app.test_request_context(): | |
48 | app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna' | |
49 | assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM' | |
50 | assert babel.format_date(d) == 'Apr 12, 2010' | |
51 | assert babel.format_time(d) == '3:46:00 PM' | |
52 | ||
53 | with app.test_request_context(): | |
54 | app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE' | |
55 | assert babel.format_datetime(d, 'long') == \ | |
56 | '12. April 2010 um 15:46:00 MESZ' | |
57 | ||
58 | ||
59 | def test_custom_formats(): | |
60 | app = flask.Flask(__name__) | |
61 | app.config.update( | |
62 | BABEL_DEFAULT_LOCALE='en_US', | |
63 | BABEL_DEFAULT_TIMEZONE='Pacific/Johnston' | |
64 | ) | |
65 | b = babel.Babel(app) | |
66 | b.date_formats['datetime'] = 'long' | |
67 | b.date_formats['datetime.long'] = 'MMMM d, yyyy h:mm:ss a' | |
68 | d = datetime(2010, 4, 12, 13, 46) | |
69 | ||
70 | with app.test_request_context(): | |
71 | assert babel.format_datetime(d) == 'April 12, 2010 3:46:00 AM' | |
72 | ||
73 | ||
74 | def test_custom_locale_selector(): | |
75 | app = flask.Flask(__name__) | |
76 | b = babel.Babel(app) | |
77 | d = datetime(2010, 4, 12, 13, 46) | |
78 | ||
79 | the_timezone = 'UTC' | |
80 | the_locale = 'en_US' | |
81 | ||
82 | @b.localeselector | |
83 | def select_locale(): | |
84 | return the_locale | |
85 | ||
86 | @b.timezoneselector | |
87 | def select_timezone(): | |
88 | return the_timezone | |
89 | ||
90 | with app.test_request_context(): | |
91 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
92 | ||
93 | the_locale = 'de_DE' | |
94 | the_timezone = 'Europe/Vienna' | |
95 | ||
96 | with app.test_request_context(): | |
97 | assert babel.format_datetime(d) == '12.04.2010, 15:46:00' | |
98 | ||
99 | ||
100 | def test_refreshing(): | |
101 | app = flask.Flask(__name__) | |
102 | babel.Babel(app) | |
103 | d = datetime(2010, 4, 12, 13, 46) | |
104 | with app.test_request_context(): | |
105 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
106 | app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna' | |
107 | babel.refresh() | |
108 | assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM' | |
109 | ||
110 | ||
111 | def test_force_locale(): | |
112 | app = flask.Flask(__name__) | |
113 | b = babel.Babel(app) | |
114 | ||
115 | @b.localeselector | |
116 | def select_locale(): | |
117 | return 'de_DE' | |
118 | ||
119 | with app.test_request_context(): | |
120 | assert str(babel.get_locale()) == 'de_DE' | |
121 | with babel.force_locale('en_US'): | |
122 | assert str(babel.get_locale()) == 'en_US' | |
123 | assert str(babel.get_locale()) == 'de_DE' | |
124 | ||
125 | ||
126 | def test_force_locale_with_threading(): | |
127 | app = flask.Flask(__name__) | |
128 | b = babel.Babel(app) | |
129 | ||
130 | @b.localeselector | |
131 | def select_locale(): | |
132 | return 'de_DE' | |
133 | ||
134 | semaphore = Semaphore(value=0) | |
135 | ||
136 | def first_request(): | |
137 | with app.test_request_context(): | |
138 | with babel.force_locale('en_US'): | |
139 | assert str(babel.get_locale()) == 'en_US' | |
140 | semaphore.acquire() | |
141 | ||
142 | thread = Thread(target=first_request) | |
143 | thread.start() | |
144 | ||
145 | try: | |
146 | with app.test_request_context(): | |
147 | assert str(babel.get_locale()) == 'de_DE' | |
148 | finally: | |
149 | semaphore.release() | |
150 | thread.join() | |
151 | ||
152 | ||
153 | def test_refresh_during_force_locale(): | |
154 | app = flask.Flask(__name__) | |
155 | b = babel.Babel(app) | |
156 | ||
157 | @b.localeselector | |
158 | def select_locale(): | |
159 | return 'de_DE' | |
160 | ||
161 | with app.test_request_context(): | |
162 | with babel.force_locale('en_US'): | |
163 | assert str(babel.get_locale()) == 'en_US' | |
164 | babel.refresh() | |
165 | assert str(babel.get_locale()) == 'en_US' |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import with_statement | |
2 | ||
3 | import flask | |
4 | ||
5 | import flask_babel as babel | |
6 | from flask_babel import gettext, lazy_gettext, lazy_ngettext, ngettext | |
7 | ||
8 | ||
9 | def test_basics(): | |
10 | app = flask.Flask(__name__) | |
11 | babel.Babel(app, default_locale='de_DE') | |
12 | ||
13 | with app.test_request_context(): | |
14 | assert gettext(u'Hello %(name)s!', name='Peter') == 'Hallo Peter!' | |
15 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 3) == \ | |
16 | u'3 Äpfel' | |
17 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 1) == \ | |
18 | u'1 Apfel' | |
19 | ||
20 | ||
21 | def test_template_basics(): | |
22 | app = flask.Flask(__name__) | |
23 | babel.Babel(app, default_locale='de_DE') | |
24 | ||
25 | t = lambda x: flask.render_template_string('{{ %s }}' % x) | |
26 | ||
27 | with app.test_request_context(): | |
28 | assert t("gettext('Hello %(name)s!', name='Peter')") == \ | |
29 | u'Hallo Peter!' | |
30 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 3)") == \ | |
31 | u'3 Äpfel' | |
32 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 1)") == \ | |
33 | u'1 Apfel' | |
34 | assert flask.render_template_string(''' | |
35 | {% trans %}Hello {{ name }}!{% endtrans %} | |
36 | ''', name='Peter').strip() == 'Hallo Peter!' | |
37 | assert flask.render_template_string(''' | |
38 | {% trans num=3 %}{{ num }} Apple | |
39 | {%- pluralize %}{{ num }} Apples{% endtrans %} | |
40 | ''', name='Peter').strip() == u'3 Äpfel' | |
41 | ||
42 | ||
43 | def test_lazy_gettext(): | |
44 | app = flask.Flask(__name__) | |
45 | babel.Babel(app, default_locale='de_DE') | |
46 | yes = lazy_gettext(u'Yes') | |
47 | with app.test_request_context(): | |
48 | assert str(yes) == 'Ja' | |
49 | assert yes.__html__() == 'Ja' | |
50 | ||
51 | app.config['BABEL_DEFAULT_LOCALE'] = 'en_US' | |
52 | with app.test_request_context(): | |
53 | assert str(yes) == 'Yes' | |
54 | assert yes.__html__() == 'Yes' | |
55 | ||
56 | ||
57 | def test_lazy_ngettext(): | |
58 | app = flask.Flask(__name__) | |
59 | babel.Babel(app, default_locale='de_DE') | |
60 | one_apple = lazy_ngettext(u'%(num)s Apple', u'%(num)s Apples', 1) | |
61 | with app.test_request_context(): | |
62 | assert str(one_apple) == '1 Apfel' | |
63 | assert one_apple.__html__() == '1 Apfel' | |
64 | two_apples = lazy_ngettext(u'%(num)s Apple', u'%(num)s Apples', 2) | |
65 | with app.test_request_context(): | |
66 | assert str(two_apples) == u'2 Äpfel' | |
67 | assert two_apples.__html__() == u'2 Äpfel' | |
68 | ||
69 | ||
70 | def test_lazy_gettext_defaultdomain(): | |
71 | app = flask.Flask(__name__) | |
72 | b = babel.Babel(app, default_locale='de_DE', default_domain='test') | |
73 | first = lazy_gettext('first') | |
74 | with app.test_request_context(): | |
75 | assert str(first) == 'erste' | |
76 | app.config['BABEL_DEFAULT_LOCALE'] = 'en_US' | |
77 | with app.test_request_context(): | |
78 | assert str(first) == 'first' | |
79 | ||
80 | ||
81 | def test_list_translations(): | |
82 | app = flask.Flask(__name__) | |
83 | b = babel.Babel(app, default_locale='de_DE') | |
84 | translations = b.list_translations() | |
85 | assert len(translations) == 1 | |
86 | assert str(translations[0]) == 'de' | |
87 | ||
88 | ||
89 | def test_no_formatting(): | |
90 | """ | |
91 | Ensure we don't format strings unless a variable is passed. | |
92 | """ | |
93 | app = flask.Flask(__name__) | |
94 | babel.Babel(app) | |
95 | ||
96 | with app.test_request_context(): | |
97 | assert gettext(u'Test %s') == u'Test %s' | |
98 | assert gettext(u'Test %(name)s', name=u'test') == u'Test test' | |
99 | assert gettext(u'Test %s') % 'test' == u'Test test' | |
100 | ||
101 | ||
102 | def test_domain(): | |
103 | app = flask.Flask(__name__) | |
104 | b = babel.Babel(app, default_locale='de_DE') | |
105 | domain = babel.Domain(domain='test') | |
106 | ||
107 | with app.test_request_context(): | |
108 | assert domain.gettext('first') == 'erste' | |
109 | assert babel.gettext('first') == 'first' | |
110 | ||
111 | ||
112 | def test_as_default(): | |
113 | app = flask.Flask(__name__) | |
114 | b = babel.Babel(app, default_locale='de_DE') | |
115 | domain = babel.Domain(domain='test') | |
116 | ||
117 | with app.test_request_context(): | |
118 | assert babel.gettext('first') == 'first' | |
119 | domain.as_default() | |
120 | assert babel.gettext('first') == 'erste' | |
121 | ||
122 | ||
123 | def test_default_domain(): | |
124 | app = flask.Flask(__name__) | |
125 | b = babel.Babel(app, default_locale='de_DE', default_domain='test') | |
126 | ||
127 | with app.test_request_context(): | |
128 | assert babel.gettext('first') == 'erste' | |
129 | ||
130 | ||
131 | def test_multiple_apps(): | |
132 | app1 = flask.Flask(__name__) | |
133 | b1 = babel.Babel(app1, default_locale='de_DE') | |
134 | ||
135 | app2 = flask.Flask(__name__) | |
136 | b2 = babel.Babel(app2, default_locale='de_DE') | |
137 | ||
138 | with app1.test_request_context() as ctx: | |
139 | assert babel.gettext('Yes') == 'Ja' | |
140 | ||
141 | assert ('de_DE', 'messages') in b1.domain_instance.get_translations_cache(ctx) | |
142 | ||
143 | with app2.test_request_context() as ctx: | |
144 | assert 'de_DE', 'messages' not in b2.domain_instance.get_translations_cache(ctx) | |
145 | ||
146 | ||
147 | def test_cache(mocker): | |
148 | load_mock = mocker.patch( | |
149 | "babel.support.Translations.load", side_effect=babel.support.Translations.load | |
150 | ) | |
151 | ||
152 | app = flask.Flask(__name__) | |
153 | b = babel.Babel(app, default_locale="de_DE") | |
154 | ||
155 | @b.localeselector | |
156 | def select_locale(): | |
157 | return the_locale | |
158 | ||
159 | # first request, should load en_US | |
160 | the_locale = "en_US" | |
161 | with app.test_request_context() as ctx: | |
162 | assert b.domain_instance.get_translations_cache(ctx) == {} | |
163 | assert babel.gettext("Yes") == "Yes" | |
164 | assert load_mock.call_count == 1 | |
165 | ||
166 | # second request, should use en_US from cache | |
167 | with app.test_request_context() as ctx: | |
168 | assert set(b.domain_instance.get_translations_cache(ctx)) == { | |
169 | ("en_US", "messages") | |
170 | } | |
171 | assert babel.gettext("Yes") == "Yes" | |
172 | assert load_mock.call_count == 1 | |
173 | ||
174 | # third request, should load de_DE from cache | |
175 | the_locale = "de_DE" | |
176 | with app.test_request_context() as ctx: | |
177 | assert set(b.domain_instance.get_translations_cache(ctx)) == { | |
178 | ("en_US", "messages") | |
179 | } | |
180 | assert babel.gettext("Yes") == "Ja" | |
181 | assert load_mock.call_count == 2 | |
182 | ||
183 | # now everything is cached, so no more loads should happen! | |
184 | the_locale = "en_US" | |
185 | with app.test_request_context() as ctx: | |
186 | assert set(b.domain_instance.get_translations_cache(ctx)) == { | |
187 | ("en_US", "messages"), | |
188 | ("de_DE", "messages"), | |
189 | } | |
190 | assert babel.gettext("Yes") == "Yes" | |
191 | assert load_mock.call_count == 2 | |
192 | ||
193 | the_locale = "de_DE" | |
194 | with app.test_request_context() as ctx: | |
195 | assert set(b.domain_instance.get_translations_cache(ctx)) == { | |
196 | ("en_US", "messages"), | |
197 | ("de_DE", "messages"), | |
198 | } | |
199 | assert babel.gettext("Yes") == "Ja" | |
200 | assert load_mock.call_count == 2 |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import with_statement | |
2 | ||
3 | import pickle | |
4 | ||
5 | import flask | |
6 | from babel.support import NullTranslations | |
7 | ||
8 | import flask_babel as babel | |
9 | from flask_babel import get_translations, gettext, lazy_gettext | |
10 | ||
11 | ||
12 | def test_no_request_context(): | |
13 | b = babel.Babel() | |
14 | app = flask.Flask(__name__) | |
15 | b.init_app(app) | |
16 | ||
17 | with app.app_context(): | |
18 | assert isinstance(get_translations(), NullTranslations) | |
19 | ||
20 | ||
21 | def test_multiple_directories(): | |
22 | """ | |
23 | Ensure we can load translations from multiple directories. | |
24 | """ | |
25 | b = babel.Babel() | |
26 | app = flask.Flask(__name__) | |
27 | ||
28 | app.config.update({ | |
29 | 'BABEL_TRANSLATION_DIRECTORIES': ';'.join(( | |
30 | 'translations', | |
31 | 'renamed_translations' | |
32 | )), | |
33 | 'BABEL_DEFAULT_LOCALE': 'de_DE' | |
34 | }) | |
35 | ||
36 | b.init_app(app) | |
37 | ||
38 | with app.test_request_context(): | |
39 | translations = b.list_translations() | |
40 | ||
41 | assert(len(translations) == 2) | |
42 | assert(str(translations[0]) == 'de') | |
43 | assert(str(translations[1]) == 'de') | |
44 | ||
45 | assert gettext( | |
46 | u'Hello %(name)s!', | |
47 | name='Peter' | |
48 | ) == 'Hallo Peter!' | |
49 | ||
50 | ||
51 | def test_multiple_directories_different_domain(): | |
52 | """ | |
53 | Ensure we can load translations from multiple directories with a | |
54 | custom domain. | |
55 | """ | |
56 | b = babel.Babel() | |
57 | app = flask.Flask(__name__) | |
58 | ||
59 | app.config.update({ | |
60 | 'BABEL_TRANSLATION_DIRECTORIES': ';'.join(( | |
61 | 'translations_different_domain', | |
62 | 'renamed_translations' | |
63 | )), | |
64 | 'BABEL_DEFAULT_LOCALE': 'de_DE', | |
65 | 'BABEL_DOMAIN': 'myapp' | |
66 | }) | |
67 | ||
68 | b.init_app(app) | |
69 | ||
70 | with app.test_request_context(): | |
71 | translations = b.list_translations() | |
72 | ||
73 | assert(len(translations) == 2) | |
74 | assert(str(translations[0]) == 'de') | |
75 | assert(str(translations[1]) == 'de') | |
76 | ||
77 | assert gettext( | |
78 | u'Hello %(name)s!', | |
79 | name='Peter' | |
80 | ) == 'Hallo Peter!' | |
81 | assert gettext(u'Good bye') == 'Auf Wiedersehen' | |
82 | ||
83 | ||
84 | def test_different_domain(): | |
85 | """ | |
86 | Ensure we can load translations from multiple directories. | |
87 | """ | |
88 | b = babel.Babel() | |
89 | app = flask.Flask(__name__) | |
90 | ||
91 | app.config.update({ | |
92 | 'BABEL_TRANSLATION_DIRECTORIES': 'translations_different_domain', | |
93 | 'BABEL_DEFAULT_LOCALE': 'de_DE', | |
94 | 'BABEL_DOMAIN': 'myapp' | |
95 | }) | |
96 | ||
97 | b.init_app(app) | |
98 | ||
99 | with app.test_request_context(): | |
100 | translations = b.list_translations() | |
101 | ||
102 | assert(len(translations) == 1) | |
103 | assert(str(translations[0]) == 'de') | |
104 | ||
105 | assert gettext(u'Good bye') == 'Auf Wiedersehen' | |
106 | ||
107 | ||
108 | def test_lazy_old_style_formatting(): | |
109 | lazy_string = lazy_gettext(u'Hello %(name)s') | |
110 | assert lazy_string % {u'name': u'test'} == u'Hello test' | |
111 | ||
112 | lazy_string = lazy_gettext(u'test') | |
113 | assert u'Hello %s' % lazy_string == u'Hello test' | |
114 | ||
115 | ||
116 | def test_lazy_pickling(): | |
117 | lazy_string = lazy_gettext(u'Foo') | |
118 | pickled = pickle.dumps(lazy_string) | |
119 | unpickled = pickle.loads(pickled) | |
120 | ||
121 | assert unpickled == lazy_string |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import with_statement | |
2 | ||
3 | from decimal import Decimal | |
4 | ||
5 | import flask | |
6 | ||
7 | import flask_babel as babel | |
8 | ||
9 | ||
10 | def test_basics(): | |
11 | app = flask.Flask(__name__) | |
12 | babel.Babel(app) | |
13 | n = 1099 | |
14 | ||
15 | with app.test_request_context(): | |
16 | assert babel.format_number(n) == u'1,099' | |
17 | assert babel.format_decimal(Decimal('1010.99')) == u'1,010.99' | |
18 | assert babel.format_currency(n, 'USD') == '$1,099.00' | |
19 | assert babel.format_percent(0.19) == '19%' | |
20 | assert babel.format_scientific(10000) == u'1E4' |
0 | # -*- coding: utf-8 -*- | |
1 | from __future__ import with_statement | |
2 | ||
3 | import sys | |
4 | import os | |
5 | sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) | |
6 | ||
7 | import pickle | |
8 | ||
9 | import unittest | |
10 | from decimal import Decimal | |
11 | import flask | |
12 | from datetime import datetime, timedelta | |
13 | import flask_babel as babel | |
14 | from flask_babel import gettext, ngettext, lazy_gettext, get_translations | |
15 | from babel.support import NullTranslations | |
16 | from flask_babel._compat import text_type | |
17 | ||
18 | ||
19 | class IntegrationTestCase(unittest.TestCase): | |
20 | def test_no_request_context(self): | |
21 | b = babel.Babel() | |
22 | app = flask.Flask(__name__) | |
23 | b.init_app(app) | |
24 | ||
25 | with app.app_context(): | |
26 | assert isinstance(get_translations(), NullTranslations) | |
27 | ||
28 | def test_multiple_directories(self): | |
29 | """ | |
30 | Ensure we can load translations from multiple directories. | |
31 | """ | |
32 | b = babel.Babel() | |
33 | app = flask.Flask(__name__) | |
34 | ||
35 | app.config.update({ | |
36 | 'BABEL_TRANSLATION_DIRECTORIES': ';'.join(( | |
37 | 'translations', | |
38 | 'renamed_translations' | |
39 | )), | |
40 | 'BABEL_DEFAULT_LOCALE': 'de_DE' | |
41 | }) | |
42 | ||
43 | b.init_app(app) | |
44 | ||
45 | with app.test_request_context(): | |
46 | translations = b.list_translations() | |
47 | ||
48 | assert(len(translations) == 2) | |
49 | assert(str(translations[0]) == 'de') | |
50 | assert(str(translations[1]) == 'de') | |
51 | ||
52 | assert gettext( | |
53 | u'Hello %(name)s!', | |
54 | name='Peter' | |
55 | ) == 'Hallo Peter!' | |
56 | ||
57 | def test_different_domain(self): | |
58 | """ | |
59 | Ensure we can load translations from multiple directories. | |
60 | """ | |
61 | b = babel.Babel() | |
62 | app = flask.Flask(__name__) | |
63 | ||
64 | app.config.update({ | |
65 | 'BABEL_TRANSLATION_DIRECTORIES': 'translations_different_domain', | |
66 | 'BABEL_DEFAULT_LOCALE': 'de_DE', | |
67 | 'BABEL_DOMAIN': 'myapp' | |
68 | }) | |
69 | ||
70 | b.init_app(app) | |
71 | ||
72 | with app.test_request_context(): | |
73 | translations = b.list_translations() | |
74 | ||
75 | assert(len(translations) == 1) | |
76 | assert(str(translations[0]) == 'de') | |
77 | ||
78 | assert gettext(u'Good bye') == 'Auf Wiedersehen' | |
79 | ||
80 | def test_lazy_old_style_formatting(self): | |
81 | lazy_string = lazy_gettext(u'Hello %(name)s') | |
82 | assert lazy_string % {u'name': u'test'} == u'Hello test' | |
83 | ||
84 | lazy_string = lazy_gettext(u'test') | |
85 | assert u'Hello %s' % lazy_string == u'Hello test' | |
86 | ||
87 | def test_lazy_pickling(self): | |
88 | lazy_string = lazy_gettext(u'Foo') | |
89 | pickled = pickle.dumps(lazy_string) | |
90 | unpickled = pickle.loads(pickled) | |
91 | ||
92 | assert unpickled == lazy_string | |
93 | ||
94 | ||
95 | class DateFormattingTestCase(unittest.TestCase): | |
96 | ||
97 | def test_basics(self): | |
98 | app = flask.Flask(__name__) | |
99 | babel.Babel(app) | |
100 | d = datetime(2010, 4, 12, 13, 46) | |
101 | delta = timedelta(days=6) | |
102 | ||
103 | with app.test_request_context(): | |
104 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
105 | assert babel.format_date(d) == 'Apr 12, 2010' | |
106 | assert babel.format_time(d) == '1:46:00 PM' | |
107 | assert babel.format_timedelta(delta) == '1 week' | |
108 | assert babel.format_timedelta(delta, threshold=1) == '6 days' | |
109 | ||
110 | with app.test_request_context(): | |
111 | app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna' | |
112 | assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM' | |
113 | assert babel.format_date(d) == 'Apr 12, 2010' | |
114 | assert babel.format_time(d) == '3:46:00 PM' | |
115 | ||
116 | with app.test_request_context(): | |
117 | app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE' | |
118 | assert babel.format_datetime(d, 'long') == \ | |
119 | '12. April 2010 um 15:46:00 MESZ' | |
120 | ||
121 | def test_init_app(self): | |
122 | b = babel.Babel() | |
123 | app = flask.Flask(__name__) | |
124 | b.init_app(app) | |
125 | d = datetime(2010, 4, 12, 13, 46) | |
126 | ||
127 | with app.test_request_context(): | |
128 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
129 | assert babel.format_date(d) == 'Apr 12, 2010' | |
130 | assert babel.format_time(d) == '1:46:00 PM' | |
131 | ||
132 | with app.test_request_context(): | |
133 | app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna' | |
134 | assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM' | |
135 | assert babel.format_date(d) == 'Apr 12, 2010' | |
136 | assert babel.format_time(d) == '3:46:00 PM' | |
137 | ||
138 | with app.test_request_context(): | |
139 | app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE' | |
140 | assert babel.format_datetime(d, 'long') == \ | |
141 | '12. April 2010 um 15:46:00 MESZ' | |
142 | ||
143 | def test_custom_formats(self): | |
144 | app = flask.Flask(__name__) | |
145 | app.config.update( | |
146 | BABEL_DEFAULT_LOCALE='en_US', | |
147 | BABEL_DEFAULT_TIMEZONE='Pacific/Johnston' | |
148 | ) | |
149 | b = babel.Babel(app) | |
150 | b.date_formats['datetime'] = 'long' | |
151 | b.date_formats['datetime.long'] = 'MMMM d, yyyy h:mm:ss a' | |
152 | d = datetime(2010, 4, 12, 13, 46) | |
153 | ||
154 | with app.test_request_context(): | |
155 | assert babel.format_datetime(d) == 'April 12, 2010 3:46:00 AM' | |
156 | ||
157 | def test_custom_locale_selector(self): | |
158 | app = flask.Flask(__name__) | |
159 | b = babel.Babel(app) | |
160 | d = datetime(2010, 4, 12, 13, 46) | |
161 | ||
162 | the_timezone = 'UTC' | |
163 | the_locale = 'en_US' | |
164 | ||
165 | @b.localeselector | |
166 | def select_locale(): | |
167 | return the_locale | |
168 | ||
169 | @b.timezoneselector | |
170 | def select_timezone(): | |
171 | return the_timezone | |
172 | ||
173 | with app.test_request_context(): | |
174 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
175 | ||
176 | the_locale = 'de_DE' | |
177 | the_timezone = 'Europe/Vienna' | |
178 | ||
179 | with app.test_request_context(): | |
180 | assert babel.format_datetime(d) == '12.04.2010, 15:46:00' | |
181 | ||
182 | def test_refreshing(self): | |
183 | app = flask.Flask(__name__) | |
184 | babel.Babel(app) | |
185 | d = datetime(2010, 4, 12, 13, 46) | |
186 | with app.test_request_context(): | |
187 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' | |
188 | app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna' | |
189 | babel.refresh() | |
190 | assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM' | |
191 | ||
192 | def test_force_locale(self): | |
193 | app = flask.Flask(__name__) | |
194 | b = babel.Babel(app) | |
195 | ||
196 | @b.localeselector | |
197 | def select_locale(): | |
198 | return 'de_DE' | |
199 | ||
200 | with app.test_request_context(): | |
201 | assert str(babel.get_locale()) == 'de_DE' | |
202 | with babel.force_locale('en_US'): | |
203 | assert str(babel.get_locale()) == 'en_US' | |
204 | assert str(babel.get_locale()) == 'de_DE' | |
205 | ||
206 | ||
207 | class NumberFormattingTestCase(unittest.TestCase): | |
208 | ||
209 | def test_basics(self): | |
210 | app = flask.Flask(__name__) | |
211 | babel.Babel(app) | |
212 | n = 1099 | |
213 | ||
214 | with app.test_request_context(): | |
215 | assert babel.format_number(n) == u'1,099' | |
216 | assert babel.format_decimal(Decimal('1010.99')) == u'1,010.99' | |
217 | assert babel.format_currency(n, 'USD') == '$1,099.00' | |
218 | assert babel.format_percent(0.19) == '19%' | |
219 | assert babel.format_scientific(10000) == u'1E4' | |
220 | ||
221 | ||
222 | class GettextTestCase(unittest.TestCase): | |
223 | ||
224 | def test_basics(self): | |
225 | app = flask.Flask(__name__) | |
226 | babel.Babel(app, default_locale='de_DE') | |
227 | ||
228 | with app.test_request_context(): | |
229 | assert gettext(u'Hello %(name)s!', name='Peter') == 'Hallo Peter!' | |
230 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 3) == \ | |
231 | u'3 Äpfel' | |
232 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 1) == \ | |
233 | u'1 Apfel' | |
234 | ||
235 | def test_template_basics(self): | |
236 | app = flask.Flask(__name__) | |
237 | babel.Babel(app, default_locale='de_DE') | |
238 | ||
239 | t = lambda x: flask.render_template_string('{{ %s }}' % x) | |
240 | ||
241 | with app.test_request_context(): | |
242 | assert t("gettext('Hello %(name)s!', name='Peter')") == \ | |
243 | u'Hallo Peter!' | |
244 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 3)") == \ | |
245 | u'3 Äpfel' | |
246 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 1)") == \ | |
247 | u'1 Apfel' | |
248 | assert flask.render_template_string(''' | |
249 | {% trans %}Hello {{ name }}!{% endtrans %} | |
250 | ''', name='Peter').strip() == 'Hallo Peter!' | |
251 | assert flask.render_template_string(''' | |
252 | {% trans num=3 %}{{ num }} Apple | |
253 | {%- pluralize %}{{ num }} Apples{% endtrans %} | |
254 | ''', name='Peter').strip() == u'3 Äpfel' | |
255 | ||
256 | def test_lazy_gettext(self): | |
257 | app = flask.Flask(__name__) | |
258 | babel.Babel(app, default_locale='de_DE') | |
259 | yes = lazy_gettext(u'Yes') | |
260 | with app.test_request_context(): | |
261 | assert text_type(yes) == 'Ja' | |
262 | assert yes.__html__() == 'Ja' | |
263 | app.config['BABEL_DEFAULT_LOCALE'] = 'en_US' | |
264 | with app.test_request_context(): | |
265 | assert text_type(yes) == 'Yes' | |
266 | assert yes.__html__() == 'Yes' | |
267 | ||
268 | def test_list_translations(self): | |
269 | app = flask.Flask(__name__) | |
270 | b = babel.Babel(app, default_locale='de_DE') | |
271 | translations = b.list_translations() | |
272 | assert len(translations) == 1 | |
273 | assert str(translations[0]) == 'de' | |
274 | ||
275 | def test_no_formatting(self): | |
276 | """ | |
277 | Ensure we don't format strings unless a variable is passed. | |
278 | """ | |
279 | app = flask.Flask(__name__) | |
280 | babel.Babel(app) | |
281 | ||
282 | with app.test_request_context(): | |
283 | assert gettext(u'Test %s') == u'Test %s' | |
284 | assert gettext(u'Test %(name)s', name=u'test') == u'Test test' | |
285 | assert gettext(u'Test %s') % 'test' == u'Test test' | |
286 | ||
287 | ||
288 | if __name__ == '__main__': | |
289 | unittest.main() |
Binary diff not shown
0 | # Translations template for PROJECT. | |
1 | # Copyright (C) 2010 ORGANIZATION | |
2 | # This file is distributed under the same license as the PROJECT project. | |
3 | # FIRST AUTHOR <EMAIL@ADDRESS>, 2010. | |
4 | # | |
5 | msgid "" | |
6 | msgstr "" | |
7 | "Project-Id-Version: PROJECT VERSION\n" | |
8 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | |
9 | "POT-Creation-Date: 2010-05-30 12:56+0200\n" | |
10 | "PO-Revision-Date: 2012-04-11 15:18+0200\n" | |
11 | "Last-Translator: Serge S. Koval <serge.koval+github@gmail.com>\n" | |
12 | "Language-Team: LANGUAGE <LL@li.org>\n" | |
13 | "MIME-Version: 1.0\n" | |
14 | "Content-Type: text/plain; charset=utf-8\n" | |
15 | "Content-Transfer-Encoding: 8bit\n" | |
16 | "Generated-By: Babel 0.9.5\n" | |
17 | ||
18 | #: tests.py:94 | |
19 | #, python-format | |
20 | msgid "first" | |
21 | msgstr "erste" | |
22 |