Import upstream version 2.0.0+git20220810.1.38d5c3d
Debian Janitor
1 year, 4 months ago
7 | 7 | Maintainer: Tyler Kennedy |
8 | 8 | Maintainer-email: tk@tkte.ch |
9 | 9 | License: BSD |
10 | Description: # Flask Babel | |
11 | ||
12 | ![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master) | |
13 | [![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel) | |
14 | ||
15 | Implements i18n and l10n support for Flask. This is based on the Python | |
16 | [babel][] module as well as [pytz][] both of which are installed automatically | |
17 | for you if you install this library. | |
18 | ||
19 | # Documention | |
20 | ||
21 | The latest documentation is available [here][docs]. | |
22 | ||
23 | [babel]: https://github.com/python-babel/babel | |
24 | [pytz]: https://pypi.python.org/pypi/pytz/ | |
25 | [docs]: https://flask-babel.tkte.ch/ | |
26 | [semver]: https://semver.org/ | |
27 | ||
28 | Platform: UNKNOWN | |
29 | 10 | Classifier: Development Status :: 5 - Production/Stable |
30 | 11 | Classifier: Environment :: Web Environment |
31 | 12 | Classifier: Intended Audience :: Developers |
42 | 23 | Classifier: Topic :: Software Development :: Libraries :: Python Modules |
43 | 24 | Description-Content-Type: text/markdown |
44 | 25 | Provides-Extra: dev |
26 | License-File: LICENSE | |
27 | ||
28 | # Flask Babel | |
29 | ||
30 | ![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master) | |
31 | [![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel) | |
32 | ||
33 | Implements i18n and l10n support for Flask. This is based on the Python | |
34 | [babel][] module as well as [pytz][] both of which are installed automatically | |
35 | for you if you install this library. | |
36 | ||
37 | # Documention | |
38 | ||
39 | The latest documentation is available [here][docs]. | |
40 | ||
41 | [babel]: https://github.com/python-babel/babel | |
42 | [pytz]: https://pypi.python.org/pypi/pytz/ | |
43 | [docs]: https://python-babel.github.io/flask-babel/ | |
44 | [semver]: https://semver.org/ |
15 | 15 | flask_babel/speaklater.py |
16 | 16 | tests/babel.cfg |
17 | 17 | tests/test_date_formatting.py |
18 | tests/test_force_locale.py | |
18 | 19 | tests/test_gettext.py |
19 | 20 | tests/test_integration.py |
20 | 21 | tests/test_number_formatting.py |
28 | 29 | tests/translations/de/LC_MESSAGES/messages.po |
29 | 30 | tests/translations/de/LC_MESSAGES/test.mo |
30 | 31 | tests/translations/de/LC_MESSAGES/test.po |
32 | tests/translations/fr/LC_MESSAGES/.keep | |
31 | 33 | tests/translations_different_domain/myapp.pot |
32 | 34 | tests/translations_different_domain/de/LC_MESSAGES/myapp.mo |
33 | 35 | tests/translations_different_domain/de/LC_MESSAGES/myapp.po⏎ |
0 | Babel>=2.3 | |
1 | Flask | |
2 | Jinja2>=2.5 | |
0 | 3 | pytz |
1 | Flask | |
2 | Babel>=2.3 | |
3 | Jinja2>=2.5 | |
4 | 4 | |
5 | 5 | [dev] |
6 | Pallets-Sphinx-Themes | |
7 | bumpversion | |
8 | ghp-import | |
6 | 9 | pytest |
7 | 10 | pytest-mock |
8 | bumpversion | |
9 | ghp-import | |
10 | 11 | sphinx |
11 | Pallets-Sphinx-Themes |
7 | 7 | Maintainer: Tyler Kennedy |
8 | 8 | Maintainer-email: tk@tkte.ch |
9 | 9 | License: BSD |
10 | Description: # Flask Babel | |
11 | ||
12 | ![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master) | |
13 | [![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel) | |
14 | ||
15 | Implements i18n and l10n support for Flask. This is based on the Python | |
16 | [babel][] module as well as [pytz][] both of which are installed automatically | |
17 | for you if you install this library. | |
18 | ||
19 | # Documention | |
20 | ||
21 | The latest documentation is available [here][docs]. | |
22 | ||
23 | [babel]: https://github.com/python-babel/babel | |
24 | [pytz]: https://pypi.python.org/pypi/pytz/ | |
25 | [docs]: https://flask-babel.tkte.ch/ | |
26 | [semver]: https://semver.org/ | |
27 | ||
28 | Platform: UNKNOWN | |
29 | 10 | Classifier: Development Status :: 5 - Production/Stable |
30 | 11 | Classifier: Environment :: Web Environment |
31 | 12 | Classifier: Intended Audience :: Developers |
42 | 23 | Classifier: Topic :: Software Development :: Libraries :: Python Modules |
43 | 24 | Description-Content-Type: text/markdown |
44 | 25 | Provides-Extra: dev |
26 | License-File: LICENSE | |
27 | ||
28 | # Flask Babel | |
29 | ||
30 | ![Tests](https://github.com/python-babel/flask-babel/workflows/Tests/badge.svg?branch=master) | |
31 | [![PyPI](https://img.shields.io/pypi/v/flask-babel.svg?maxAge=2592000)](https://pypi.python.org/pypi/Flask-Babel) | |
32 | ||
33 | Implements i18n and l10n support for Flask. This is based on the Python | |
34 | [babel][] module as well as [pytz][] both of which are installed automatically | |
35 | for you if you install this library. | |
36 | ||
37 | # Documention | |
38 | ||
39 | The latest documentation is available [here][docs]. | |
40 | ||
41 | [babel]: https://github.com/python-babel/babel | |
42 | [pytz]: https://pypi.python.org/pypi/pytz/ | |
43 | [docs]: https://python-babel.github.io/flask-babel/ | |
44 | [semver]: https://semver.org/ |
12 | 12 | |
13 | 13 | [babel]: https://github.com/python-babel/babel |
14 | 14 | [pytz]: https://pypi.python.org/pypi/pytz/ |
15 | [docs]: https://flask-babel.tkte.ch/ | |
15 | [docs]: https://python-babel.github.io/flask-babel/ | |
16 | 16 | [semver]: https://semver.org/ |
296 | 296 | make sure to check them by hand and remove the fuzzy flag before |
297 | 297 | compiling. |
298 | 298 | |
299 | Reloading Translations | |
300 | ---------------------- | |
301 | ||
302 | The compiled translations will only be loaded initially. This means you have | |
303 | to restart the server whenever you compile translations and want to see | |
304 | those changes. To automatically reload translations you can tell the reloader | |
305 | to watch the compiled ``.mo`` files:: | |
306 | ||
307 | $ flask run --extra-files app/translations/en_GB/LC_MESSAGES/messages.mo | |
308 | # or | |
309 | $ export FLASK_RUN_EXTRA_FILES=app/translations/en_GB/LC_MESSAGES/messages.mo | |
310 | $ flask run | |
311 | ||
312 | See `reloader`_ for more details. | |
313 | ||
299 | 314 | Troubleshooting |
300 | 315 | --------------- |
301 | 316 | |
388 | 403 | .. _babel: http://babel.edgewall.org/ |
389 | 404 | .. _pytz: http://pytz.sourceforge.net/ |
390 | 405 | .. _speaklater: http://pypi.python.org/pypi/speaklater |
406 | .. _reloader: https://flask.palletsprojects.com/en/1.1.x/cli/#watch-extra-files-with-the-reloader |
0 | 0 | """ |
1 | flaskext.babel | |
2 | ~~~~~~~~~~~~~~ | |
1 | flask_babel | |
2 | ~~~~~~~~~~~ | |
3 | 3 | |
4 | 4 | Implements i18n/l10n support for Flask applications based on Babel. |
5 | 5 | |
8 | 8 | """ |
9 | 9 | from __future__ import absolute_import |
10 | 10 | import os |
11 | from types import SimpleNamespace | |
11 | 12 | |
12 | 13 | from datetime import datetime |
13 | 14 | from contextlib import contextmanager |
14 | from flask import current_app, request | |
15 | from flask.ctx import has_request_context | |
15 | from flask import current_app, g | |
16 | 16 | from flask.helpers import locked_cached_property |
17 | 17 | from babel import dates, numbers, support, Locale |
18 | 18 | from pytz import timezone, UTC |
150 | 150 | if not os.path.isdir(locale_dir): |
151 | 151 | continue |
152 | 152 | |
153 | if filter(lambda x: x.endswith('.mo'), os.listdir(locale_dir)): | |
153 | if any(x.endswith('.mo') for x in os.listdir(locale_dir)): | |
154 | 154 | result.append(Locale.parse(folder)) |
155 | 155 | |
156 | 156 | # If not other translations are found, add the default locale. |
328 | 328 | """Convert a datetime object to the user's timezone. This automatically |
329 | 329 | happens on all date formatting unless rebasing is disabled. If you need |
330 | 330 | to convert a :class:`datetime.datetime` object at any time to the user's |
331 | timezone (as returned by :func:`get_timezone` this function can be used). | |
331 | timezone (as returned by :func:`get_timezone`) this function can be used. | |
332 | 332 | """ |
333 | 333 | if datetime.tzinfo is None: |
334 | 334 | datetime = datetime.replace(tzinfo=UTC) |
354 | 354 | time. |
355 | 355 | |
356 | 356 | The format parameter can either be ``'short'``, ``'medium'``, |
357 | ``'long'`` or ``'full'`` (in which cause the language's default for | |
357 | ``'long'`` or ``'full'`` (in which case the language's default for | |
358 | 358 | that setting is used, or the default from the :attr:`Babel.date_formats` |
359 | 359 | mapping is used) or a format string as documented by Babel. |
360 | 360 | |
374 | 374 | of a :class:`~datetime.datetime` object. |
375 | 375 | |
376 | 376 | The format parameter can either be ``'short'``, ``'medium'``, |
377 | ``'long'`` or ``'full'`` (in which cause the language's default for | |
377 | ``'long'`` or ``'full'`` (in which case the language's default for | |
378 | 378 | that setting is used, or the default from the :attr:`Babel.date_formats` |
379 | 379 | mapping is used) or a format string as documented by Babel. |
380 | 380 | |
396 | 396 | time. |
397 | 397 | |
398 | 398 | The format parameter can either be ``'short'``, ``'medium'``, |
399 | ``'long'`` or ``'full'`` (in which cause the language's default for | |
399 | ``'long'`` or ``'full'`` (in which case the language's default for | |
400 | 400 | that setting is used, or the default from the :attr:`Babel.date_formats` |
401 | 401 | mapping is used) or a format string as documented by Babel. |
402 | 402 | |
660 | 660 | |
661 | 661 | |
662 | 662 | def _get_current_context(): |
663 | if has_request_context(): | |
664 | return request | |
665 | ||
666 | if current_app: | |
667 | return current_app | |
663 | if not g: | |
664 | return None | |
665 | ||
666 | if not hasattr(g, "_flask_babel"): | |
667 | g._flask_babel = SimpleNamespace() | |
668 | ||
669 | return g._flask_babel | |
668 | 670 | |
669 | 671 | |
670 | 672 | def get_domain(): |
1 | 1 | from __future__ import with_statement |
2 | 2 | |
3 | 3 | from datetime import datetime, timedelta |
4 | from threading import Semaphore, Thread | |
5 | 4 | |
6 | 5 | import flask |
7 | 6 | |
106 | 105 | app.config['BABEL_DEFAULT_TIMEZONE'] = 'Europe/Vienna' |
107 | 106 | babel.refresh() |
108 | 107 | 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 | from threading import Semaphore, Thread | |
1 | ||
2 | import flask | |
3 | ||
4 | import flask_babel as babel | |
5 | ||
6 | ||
7 | def test_force_locale(): | |
8 | app = flask.Flask(__name__) | |
9 | b = babel.Babel(app) | |
10 | ||
11 | @b.localeselector | |
12 | def select_locale(): | |
13 | return 'de_DE' | |
14 | ||
15 | with app.test_request_context(): | |
16 | assert str(babel.get_locale()) == 'de_DE' | |
17 | with babel.force_locale('en_US'): | |
18 | assert str(babel.get_locale()) == 'en_US' | |
19 | assert str(babel.get_locale()) == 'de_DE' | |
20 | ||
21 | ||
22 | def test_force_locale_with_threading(): | |
23 | app = flask.Flask(__name__) | |
24 | b = babel.Babel(app) | |
25 | ||
26 | @b.localeselector | |
27 | def select_locale(): | |
28 | return 'de_DE' | |
29 | ||
30 | semaphore = Semaphore(value=0) | |
31 | ||
32 | def first_request(): | |
33 | with app.test_request_context(): | |
34 | with babel.force_locale('en_US'): | |
35 | assert str(babel.get_locale()) == 'en_US' | |
36 | semaphore.acquire() | |
37 | ||
38 | thread = Thread(target=first_request) | |
39 | thread.start() | |
40 | ||
41 | try: | |
42 | with app.test_request_context(): | |
43 | assert str(babel.get_locale()) == 'de_DE' | |
44 | finally: | |
45 | semaphore.release() | |
46 | thread.join() | |
47 | ||
48 | ||
49 | def test_force_locale_with_threading_and_app_context(): | |
50 | app = flask.Flask(__name__) | |
51 | b = babel.Babel(app) | |
52 | ||
53 | @b.localeselector | |
54 | def select_locale(): | |
55 | return 'de_DE' | |
56 | ||
57 | semaphore = Semaphore(value=0) | |
58 | ||
59 | def first_app_context(): | |
60 | with app.app_context(): | |
61 | with babel.force_locale('en_US'): | |
62 | assert str(babel.get_locale()) == 'en_US' | |
63 | semaphore.acquire() | |
64 | ||
65 | thread = Thread(target=first_app_context) | |
66 | thread.start() | |
67 | ||
68 | try: | |
69 | with app.app_context(): | |
70 | assert str(babel.get_locale()) == 'de_DE' | |
71 | finally: | |
72 | semaphore.release() | |
73 | thread.join() | |
74 | ||
75 | ||
76 | def test_refresh_during_force_locale(): | |
77 | app = flask.Flask(__name__) | |
78 | b = babel.Babel(app) | |
79 | ||
80 | @b.localeselector | |
81 | def select_locale(): | |
82 | return 'de_DE' | |
83 | ||
84 | with app.test_request_context(): | |
85 | with babel.force_locale('en_US'): | |
86 | assert str(babel.get_locale()) == 'en_US' | |
87 | babel.refresh() | |
88 | assert str(babel.get_locale()) == 'en_US' |
21 | 21 | def test_multiple_directories(): |
22 | 22 | """ |
23 | 23 | Ensure we can load translations from multiple directories. |
24 | ||
25 | This also ensures that directories without any translation files | |
26 | are not taken into account. | |
24 | 27 | """ |
25 | 28 | b = babel.Babel() |
26 | 29 | app = flask.Flask(__name__) |