Import Upstream version 0.10.0
Håvard Flaget Aasen
4 years ago
0 | Metadata-Version: 1.0 | |
0 | Metadata-Version: 1.1 | |
1 | 1 | Name: Flask-Babel |
2 | Version: 0.9 | |
2 | Version: 0.10.0 | |
3 | 3 | Summary: Adds i18n/l10n support to Flask applications |
4 | Home-page: http://github.com/mitsuhiko/flask-babel | |
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 | 7 | License: BSD |
0 | 0 | LICENSE |
1 | 1 | MANIFEST.in |
2 | 2 | Makefile |
3 | README | |
4 | 3 | setup.cfg |
5 | 4 | setup.py |
6 | 5 | Flask_Babel.egg-info/PKG-INFO |
18 | 17 | flask_babel/_compat.py |
19 | 18 | tests/babel.cfg |
20 | 19 | tests/tests.py |
20 | tests/renamed_translations/messages.pot | |
21 | tests/renamed_translations/de/LC_MESSAGES/messages.mo | |
22 | tests/renamed_translations/de/LC_MESSAGES/messages.po | |
21 | 23 | tests/translations/messages.pot |
22 | 24 | tests/translations/de/LC_MESSAGES/messages.mo |
23 | 25 | tests/translations/de/LC_MESSAGES/messages.po⏎ |
16 | 16 | |
17 | 17 | upload-docs: |
18 | 18 | $(MAKE) -C docs html |
19 | python setup.py upload_sphinx | |
19 | python setup.py upload_docs | |
20 | 20 | |
21 | 21 | .PHONY: upload-docs clean-pyc clean tox-test test all |
0 | Metadata-Version: 1.0 | |
0 | Metadata-Version: 1.1 | |
1 | 1 | Name: Flask-Babel |
2 | Version: 0.9 | |
2 | Version: 0.10.0 | |
3 | 3 | Summary: Adds i18n/l10n support to Flask applications |
4 | Home-page: http://github.com/mitsuhiko/flask-babel | |
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 | 7 | License: BSD |
0 | Flask Babel | |
1 | ||
2 | Implements i18n and l10n support for Flask. This is based on the Python | |
3 | babel module as well as pytz both of which are installed automatically | |
4 | for you if you install this library. |
48 | 48 | # built documents. |
49 | 49 | # |
50 | 50 | # The short X.Y version. |
51 | version = '1.0' | |
51 | version = '0.10.0' | |
52 | 52 | # The full version, including alpha/beta/rc tags. |
53 | release = '1.0' | |
53 | release = '0.10.0' | |
54 | 54 | |
55 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation |
56 | 56 | # for a list of supported languages. |
133 | 133 | The other big part next to date formatting are translations. For that, |
134 | 134 | Flask uses :mod:`gettext` together with Babel. The idea of gettext is |
135 | 135 | that you can mark certain strings as translatable and a tool will pick all |
136 | those app, collect them in a separate file for you to translate. At | |
136 | those up, collect them in a separate file for you to translate. At | |
137 | 137 | runtime the original strings (which should be English) will be replaced by |
138 | 138 | the language you selected. |
139 | 139 | |
289 | 289 | |
290 | 290 | .. autofunction:: refresh |
291 | 291 | |
292 | .. autofunction:: force_locale | |
293 | ||
292 | 294 | |
293 | 295 | .. _Flask: http://flask.pocoo.org/ |
294 | 296 | .. _babel: http://babel.edgewall.org/ |
16 | 16 | os.environ['LC_CTYPE'] = 'en_US.utf-8' |
17 | 17 | |
18 | 18 | from datetime import datetime |
19 | from flask import _request_ctx_stack | |
19 | from contextlib import contextmanager | |
20 | from flask import current_app, request | |
21 | from flask.ctx import has_request_context | |
20 | 22 | from babel import dates, numbers, support, Locale |
21 | 23 | from werkzeug import ImmutableDict |
22 | 24 | try: |
27 | 29 | timezone = pytz.timezone |
28 | 30 | UTC = pytz.UTC |
29 | 31 | |
30 | from flask_babel._compat import string_types | |
32 | from flask_babel._compat import string_types, text_type | |
31 | 33 | |
32 | 34 | |
33 | 35 | class Babel(object): |
62 | 64 | self._date_formats = date_formats |
63 | 65 | self._configure_jinja = configure_jinja |
64 | 66 | self.app = app |
67 | self.locale_selector_func = None | |
68 | self.timezone_selector_func = None | |
65 | 69 | |
66 | 70 | if app is not None: |
67 | 71 | self.init_app(app) |
94 | 98 | #: otherwise the default for that language is used. |
95 | 99 | self.date_formats = self._date_formats |
96 | 100 | |
97 | self.locale_selector_func = None | |
98 | self.timezone_selector_func = None | |
99 | ||
100 | 101 | if self._configure_jinja: |
101 | 102 | app.jinja_env.filters.update( |
102 | 103 | datetimeformat=format_datetime, |
143 | 144 | self.timezone_selector_func = f |
144 | 145 | return f |
145 | 146 | |
146 | ||
147 | 147 | def list_translations(self): |
148 | 148 | """Returns a list of all the locales translations exist for. The |
149 | 149 | list returned will be filled with actual locale objects and not just |
151 | 151 | |
152 | 152 | .. versionadded:: 0.6 |
153 | 153 | """ |
154 | dirname = os.path.join(self.app.root_path, 'translations') | |
155 | if not os.path.isdir(dirname): | |
156 | return [] | |
157 | 154 | result = [] |
158 | for folder in os.listdir(dirname): | |
159 | locale_dir = os.path.join(dirname, folder, 'LC_MESSAGES') | |
160 | if not os.path.isdir(locale_dir): | |
155 | ||
156 | for dirname in self.translation_directories: | |
157 | if not os.path.isdir(dirname): | |
161 | 158 | continue |
162 | if filter(lambda x: x.endswith('.mo'), os.listdir(locale_dir)): | |
163 | result.append(Locale.parse(folder)) | |
159 | ||
160 | for folder in os.listdir(dirname): | |
161 | locale_dir = os.path.join(dirname, folder, 'LC_MESSAGES') | |
162 | if not os.path.isdir(locale_dir): | |
163 | continue | |
164 | ||
165 | if filter(lambda x: x.endswith('.mo'), os.listdir(locale_dir)): | |
166 | result.append(Locale.parse(folder)) | |
167 | ||
168 | # If not other translations are found, add the default locale. | |
164 | 169 | if not result: |
165 | 170 | result.append(Locale.parse(self._default_locale)) |
171 | ||
166 | 172 | return result |
167 | 173 | |
168 | 174 | @property |
179 | 185 | """ |
180 | 186 | return timezone(self.app.config['BABEL_DEFAULT_TIMEZONE']) |
181 | 187 | |
188 | @property | |
189 | def translation_directories(self): | |
190 | directories = self.app.config.get( | |
191 | 'BABEL_TRANSLATION_DIRECTORIES', | |
192 | 'translations' | |
193 | ).split(';') | |
194 | ||
195 | for path in directories: | |
196 | if os.path.isabs(path): | |
197 | yield path | |
198 | else: | |
199 | yield os.path.join(self.app.root_path, path) | |
200 | ||
182 | 201 | |
183 | 202 | def get_translations(): |
184 | 203 | """Returns the correct gettext translations that should be used for |
186 | 205 | object if used outside of the request or if a translation cannot be |
187 | 206 | found. |
188 | 207 | """ |
189 | ctx = _request_ctx_stack.top | |
190 | if ctx is None: | |
191 | return None | |
208 | ctx = _get_current_context() | |
209 | ||
192 | 210 | translations = getattr(ctx, 'babel_translations', None) |
193 | 211 | if translations is None: |
194 | dirname = os.path.join(ctx.app.root_path, 'translations') | |
195 | translations = support.Translations.load(dirname, [get_locale()]) | |
212 | translations = support.Translations() | |
213 | ||
214 | babel = current_app.extensions['babel'] | |
215 | for dirname in babel.translation_directories: | |
216 | translations.merge( | |
217 | support.Translations.load( | |
218 | dirname, | |
219 | [get_locale()] | |
220 | ) | |
221 | ) | |
222 | ||
196 | 223 | ctx.babel_translations = translations |
224 | ||
197 | 225 | return translations |
198 | 226 | |
199 | 227 | |
202 | 230 | `babel.Locale` object. This returns `None` if used outside of |
203 | 231 | a request. |
204 | 232 | """ |
205 | ctx = _request_ctx_stack.top | |
233 | ctx = _get_current_context() | |
206 | 234 | if ctx is None: |
207 | 235 | return None |
208 | 236 | locale = getattr(ctx, 'babel_locale', None) |
209 | 237 | if locale is None: |
210 | babel = ctx.app.extensions['babel'] | |
238 | babel = current_app.extensions['babel'] | |
211 | 239 | if babel.locale_selector_func is None: |
212 | 240 | locale = babel.default_locale |
213 | 241 | else: |
225 | 253 | `pytz.timezone` object. This returns `None` if used outside of |
226 | 254 | a request. |
227 | 255 | """ |
228 | ctx = _request_ctx_stack.top | |
256 | ctx = _get_current_context() | |
229 | 257 | tzinfo = getattr(ctx, 'babel_tzinfo', None) |
230 | 258 | if tzinfo is None: |
231 | babel = ctx.app.extensions['babel'] | |
259 | babel = current_app.extensions['babel'] | |
232 | 260 | if babel.timezone_selector_func is None: |
233 | 261 | tzinfo = babel.default_timezone |
234 | 262 | else: |
257 | 285 | Without that refresh, the :func:`~flask.flash` function would probably |
258 | 286 | return English text and a now German page. |
259 | 287 | """ |
260 | ctx = _request_ctx_stack.top | |
288 | ctx = _get_current_context() | |
261 | 289 | for key in 'babel_locale', 'babel_tzinfo', 'babel_translations': |
262 | 290 | if hasattr(ctx, key): |
263 | 291 | delattr(ctx, key) |
264 | 292 | |
265 | 293 | |
294 | @contextmanager | |
295 | def force_locale(locale): | |
296 | """Temporarily overrides the currently selected locale. | |
297 | ||
298 | Sometimes it is useful to switch the current locale to different one, do | |
299 | some tasks and then revert back to the original one. For example, if the | |
300 | user uses German on the web site, but you want to send them an email in | |
301 | English, you can use this function as a context manager:: | |
302 | ||
303 | with force_locale('en_US'): | |
304 | send_email(gettext('Hello!'), ...) | |
305 | ||
306 | :param locale: The locale to temporary switch to (ex: 'en_US'). | |
307 | """ | |
308 | ctx = _get_current_context() | |
309 | if ctx is None: | |
310 | yield | |
311 | return | |
312 | ||
313 | babel = current_app.extensions['babel'] | |
314 | ||
315 | orig_locale_selector_func = babel.locale_selector_func | |
316 | orig_attrs = {} | |
317 | for key in ('babel_translations', 'babel_locale'): | |
318 | orig_attrs[key] = getattr(ctx, key, None) | |
319 | ||
320 | try: | |
321 | babel.locale_selector_func = lambda: locale | |
322 | for key in orig_attrs: | |
323 | setattr(ctx, key, None) | |
324 | yield | |
325 | finally: | |
326 | babel.locale_selector_func = orig_locale_selector_func | |
327 | for key, value in orig_attrs.items(): | |
328 | setattr(ctx, key, value) | |
329 | ||
330 | ||
266 | 331 | def _get_format(key, format): |
267 | 332 | """A small helper for the datetime formatting functions. Looks up |
268 | 333 | format defaults for different kinds. |
269 | 334 | """ |
270 | babel = _request_ctx_stack.top.app.extensions['babel'] | |
335 | babel = current_app.extensions['babel'] | |
271 | 336 | if format is None: |
272 | 337 | format = babel.date_formats[key] |
273 | 338 | if format in ('short', 'medium', 'full', 'long'): |
360 | 425 | return _date_format(dates.format_time, time, format, rebase) |
361 | 426 | |
362 | 427 | |
363 | def format_timedelta(datetime_or_timedelta, granularity='second'): | |
428 | def format_timedelta(datetime_or_timedelta, granularity='second', | |
429 | add_direction=False): | |
364 | 430 | """Format the elapsed time from the given date to now or the given |
365 | 431 | timedelta. This currently requires an unreleased development |
366 | 432 | version of Babel. |
370 | 436 | """ |
371 | 437 | if isinstance(datetime_or_timedelta, datetime): |
372 | 438 | datetime_or_timedelta = datetime.utcnow() - datetime_or_timedelta |
373 | return dates.format_timedelta(datetime_or_timedelta, granularity, | |
374 | locale=get_locale()) | |
439 | return dates.format_timedelta( | |
440 | datetime_or_timedelta, | |
441 | granularity, | |
442 | add_direction=add_direction, | |
443 | locale=get_locale() | |
444 | ) | |
375 | 445 | |
376 | 446 | |
377 | 447 | def _date_format(formatter, obj, format, rebase, **extra): |
385 | 455 | |
386 | 456 | def format_number(number): |
387 | 457 | """Return the given number formatted for the locale in request |
388 | ||
458 | ||
389 | 459 | :param number: the number to format |
390 | 460 | :return: the formatted number |
391 | 461 | :rtype: unicode |
406 | 476 | return numbers.format_decimal(number, format=format, locale=locale) |
407 | 477 | |
408 | 478 | |
409 | def format_currency(number, currency, format=None): | |
479 | def format_currency(number, currency, format=None, currency_digits=True, | |
480 | format_type='standard'): | |
410 | 481 | """Return the given number formatted for the locale in request |
411 | 482 | |
412 | 483 | :param number: the number to format |
413 | 484 | :param currency: the currency code |
414 | 485 | :param format: the format to use |
486 | :param currency_digits: use the currency’s number of decimal digits | |
487 | [default: True] | |
488 | :param format_type: the currency format type to use | |
489 | [default: standard] | |
415 | 490 | :return: the formatted number |
416 | 491 | :rtype: unicode |
417 | 492 | """ |
418 | 493 | locale = get_locale() |
419 | 494 | return numbers.format_currency( |
420 | number, currency, format=format, locale=locale | |
495 | number, | |
496 | currency, | |
497 | format=format, | |
498 | locale=locale, | |
499 | currency_digits=currency_digits, | |
500 | format_type=format_type | |
421 | 501 | ) |
422 | 502 | |
423 | 503 | |
456 | 536 | """ |
457 | 537 | t = get_translations() |
458 | 538 | if t is None: |
459 | return string % variables | |
460 | return t.ugettext(string) % variables | |
539 | return string if not variables else string % variables | |
540 | s = t.ugettext(string) | |
541 | return s if not variables else s % variables | |
461 | 542 | _ = gettext |
462 | 543 | |
463 | 544 | |
476 | 557 | variables.setdefault('num', num) |
477 | 558 | t = get_translations() |
478 | 559 | if t is None: |
479 | return (singular if num == 1 else plural) % variables | |
480 | return t.ungettext(singular, plural, num) % variables | |
560 | s = singular if num == 1 else plural | |
561 | return s if not variables else s % variables | |
562 | ||
563 | s = t.ungettext(singular, plural, num) | |
564 | return s if not variables else s % variables | |
481 | 565 | |
482 | 566 | |
483 | 567 | def pgettext(context, string, **variables): |
487 | 571 | """ |
488 | 572 | t = get_translations() |
489 | 573 | if t is None: |
490 | return string % variables | |
491 | return t.upgettext(context, string) % variables | |
574 | return string if not variables else string % variables | |
575 | s = t.upgettext(context, string) | |
576 | return s if not variables else s % variables | |
492 | 577 | |
493 | 578 | |
494 | 579 | def npgettext(context, singular, plural, num, **variables): |
499 | 584 | variables.setdefault('num', num) |
500 | 585 | t = get_translations() |
501 | 586 | if t is None: |
502 | return (singular if num == 1 else plural) % variables | |
503 | return t.unpgettext(context, singular, plural, num) % variables | |
587 | s = singular if num == 1 else plural | |
588 | return s if not variables else s % variables | |
589 | s = t.unpgettext(context, singular, plural, num) | |
590 | return s if not variables else s % variables | |
591 | ||
592 | ||
593 | def make_json_lazy_string(func, *args, **kwargs): | |
594 | """Like :method:`speaklater.make_lazy_string` but returns a subclass | |
595 | that provides an :method:`__html__` method. That method is used by | |
596 | :class:`flask.json.JSONEncoder` to serialize objects of unrecognized | |
597 | types. | |
598 | """ | |
599 | from speaklater import _LazyString | |
600 | ||
601 | class JsonLazyString(_LazyString): | |
602 | def __html__(self): | |
603 | return text_type(self) | |
604 | ||
605 | return JsonLazyString(func, args, kwargs) | |
504 | 606 | |
505 | 607 | |
506 | 608 | def lazy_gettext(string, **variables): |
515 | 617 | def index(): |
516 | 618 | return unicode(hello) |
517 | 619 | """ |
518 | from speaklater import make_lazy_string | |
519 | return make_lazy_string(gettext, string, **variables) | |
620 | return make_json_lazy_string(gettext, string, **variables) | |
520 | 621 | |
521 | 622 | |
522 | 623 | def lazy_pgettext(context, string, **variables): |
525 | 626 | |
526 | 627 | .. versionadded:: 0.7 |
527 | 628 | """ |
528 | from speaklater import make_lazy_string | |
529 | return make_lazy_string(pgettext, context, string, **variables) | |
629 | return make_json_lazy_string(pgettext, context, string, **variables) | |
630 | ||
631 | ||
632 | def _get_current_context(): | |
633 | if has_request_context(): | |
634 | return request | |
635 | ||
636 | if current_app: | |
637 | return current_app |
0 | [build_sphinx] | |
1 | source-dir = docs/ | |
2 | build-dir = docs/_build | |
3 | all_files = 1 | |
4 | ||
5 | [upload_sphinx] | |
0 | [upload_docs] | |
6 | 1 | upload-dir = docs/_build/html |
7 | 2 | |
8 | 3 | [egg_info] |
19 | 19 | |
20 | 20 | setup( |
21 | 21 | name='Flask-Babel', |
22 | version='0.9', | |
23 | url='http://github.com/mitsuhiko/flask-babel', | |
22 | version='0.10.0', | |
23 | url='http://github.com/python-babel/flask-babel', | |
24 | 24 | license='BSD', |
25 | 25 | author='Armin Ronacher', |
26 | 26 | author_email='armin.ronacher@active-4.com', |
31 | 31 | platforms='any', |
32 | 32 | install_requires=[ |
33 | 33 | 'Flask', |
34 | 'Babel>=1.0', | |
34 | 'Babel>=2.3', | |
35 | 35 | 'speaklater>=1.2', |
36 | 36 | 'Jinja2>=2.5' |
37 | 37 | ], |
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 | # 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 | #, fuzzy | |
6 | msgid "" | |
7 | msgstr "" | |
8 | "Project-Id-Version: PROJECT VERSION\n" | |
9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | |
10 | "POT-Creation-Date: 2010-05-30 12:56+0200\n" | |
11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | |
12 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | |
13 | "Language-Team: LANGUAGE <LL@li.org>\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 "" | |
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] "" | |
29 | msgstr[1] "" | |
30 | ||
31 | #: tests.py:119 | |
32 | msgid "Yes" | |
33 | msgstr "" | |
34 |
9 | 9 | import flask |
10 | 10 | from datetime import datetime |
11 | 11 | import flask_babel as babel |
12 | from flask_babel import gettext, ngettext, lazy_gettext | |
12 | from flask_babel import gettext, ngettext, lazy_gettext, get_translations | |
13 | from babel.support import NullTranslations | |
13 | 14 | from flask_babel._compat import text_type |
14 | 15 | |
15 | 16 | |
17 | class IntegrationTestCase(unittest.TestCase): | |
18 | def test_no_request_context(self): | |
19 | b = babel.Babel() | |
20 | app = flask.Flask(__name__) | |
21 | b.init_app(app) | |
22 | ||
23 | with app.app_context(): | |
24 | assert isinstance(get_translations(), NullTranslations) | |
25 | ||
26 | def test_multiple_directories(self): | |
27 | """ | |
28 | Ensure we can load translations from multiple directories. | |
29 | """ | |
30 | b = babel.Babel() | |
31 | app = flask.Flask(__name__) | |
32 | ||
33 | app.config.update({ | |
34 | 'BABEL_TRANSLATION_DIRECTORIES': ';'.join(( | |
35 | 'translations', | |
36 | 'renamed_translations' | |
37 | )), | |
38 | 'BABEL_DEFAULT_LOCALE': 'de_DE' | |
39 | }) | |
40 | ||
41 | b.init_app(app) | |
42 | ||
43 | with app.test_request_context(): | |
44 | translations = b.list_translations() | |
45 | ||
46 | assert(len(translations) == 2) | |
47 | assert(str(translations[0]) == 'de') | |
48 | assert(str(translations[1]) == 'de') | |
49 | ||
50 | assert gettext( | |
51 | u'Hello %(name)s!', | |
52 | name='Peter' | |
53 | ) == 'Hallo Peter!' | |
54 | ||
55 | ||
16 | 56 | class DateFormattingTestCase(unittest.TestCase): |
17 | 57 | |
18 | 58 | def test_basics(self): |
19 | 59 | app = flask.Flask(__name__) |
20 | b = babel.Babel(app) | |
60 | babel.Babel(app) | |
21 | 61 | d = datetime(2010, 4, 12, 13, 46) |
22 | 62 | |
23 | 63 | with app.test_request_context(): |
34 | 74 | with app.test_request_context(): |
35 | 75 | app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE' |
36 | 76 | assert babel.format_datetime(d, 'long') == \ |
37 | '12. April 2010 15:46:00 MESZ' | |
77 | '12. April 2010 um 15:46:00 MESZ' | |
38 | 78 | |
39 | 79 | def test_init_app(self): |
40 | 80 | b = babel.Babel() |
56 | 96 | with app.test_request_context(): |
57 | 97 | app.config['BABEL_DEFAULT_LOCALE'] = 'de_DE' |
58 | 98 | assert babel.format_datetime(d, 'long') == \ |
59 | '12. April 2010 15:46:00 MESZ' | |
99 | '12. April 2010 um 15:46:00 MESZ' | |
60 | 100 | |
61 | 101 | def test_custom_formats(self): |
62 | 102 | app = flask.Flask(__name__) |
83 | 123 | @b.localeselector |
84 | 124 | def select_locale(): |
85 | 125 | return the_locale |
126 | ||
86 | 127 | @b.timezoneselector |
87 | 128 | def select_timezone(): |
88 | 129 | return the_timezone |
94 | 135 | the_timezone = 'Europe/Vienna' |
95 | 136 | |
96 | 137 | with app.test_request_context(): |
97 | assert babel.format_datetime(d) == '12.04.2010 15:46:00' | |
138 | assert babel.format_datetime(d) == '12.04.2010, 15:46:00' | |
98 | 139 | |
99 | 140 | def test_refreshing(self): |
100 | 141 | app = flask.Flask(__name__) |
101 | b = babel.Babel(app) | |
142 | babel.Babel(app) | |
102 | 143 | d = datetime(2010, 4, 12, 13, 46) |
103 | 144 | with app.test_request_context(): |
104 | 145 | assert babel.format_datetime(d) == 'Apr 12, 2010, 1:46:00 PM' |
106 | 147 | babel.refresh() |
107 | 148 | assert babel.format_datetime(d) == 'Apr 12, 2010, 3:46:00 PM' |
108 | 149 | |
150 | def test_force_locale(self): | |
151 | app = flask.Flask(__name__) | |
152 | b = babel.Babel(app) | |
153 | ||
154 | @b.localeselector | |
155 | def select_locale(): | |
156 | return 'de_DE' | |
157 | ||
158 | with app.test_request_context(): | |
159 | assert str(babel.get_locale()) == 'de_DE' | |
160 | with babel.force_locale('en_US'): | |
161 | assert str(babel.get_locale()) == 'en_US' | |
162 | assert str(babel.get_locale()) == 'de_DE' | |
163 | ||
109 | 164 | |
110 | 165 | class NumberFormattingTestCase(unittest.TestCase): |
111 | 166 | |
112 | 167 | def test_basics(self): |
113 | 168 | app = flask.Flask(__name__) |
114 | b = babel.Babel(app) | |
169 | babel.Babel(app) | |
115 | 170 | n = 1099 |
116 | 171 | |
117 | 172 | with app.test_request_context(): |
126 | 181 | |
127 | 182 | def test_basics(self): |
128 | 183 | app = flask.Flask(__name__) |
129 | b = babel.Babel(app, default_locale='de_DE') | |
184 | babel.Babel(app, default_locale='de_DE') | |
130 | 185 | |
131 | 186 | with app.test_request_context(): |
132 | 187 | assert gettext(u'Hello %(name)s!', name='Peter') == 'Hallo Peter!' |
133 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 3) == u'3 Äpfel' | |
134 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 1) == u'1 Apfel' | |
188 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 3) == \ | |
189 | u'3 Äpfel' | |
190 | assert ngettext(u'%(num)s Apple', u'%(num)s Apples', 1) == \ | |
191 | u'1 Apfel' | |
135 | 192 | |
136 | 193 | def test_template_basics(self): |
137 | 194 | app = flask.Flask(__name__) |
138 | b = babel.Babel(app, default_locale='de_DE') | |
195 | babel.Babel(app, default_locale='de_DE') | |
139 | 196 | |
140 | 197 | t = lambda x: flask.render_template_string('{{ %s }}' % x) |
141 | 198 | |
142 | 199 | with app.test_request_context(): |
143 | assert t("gettext('Hello %(name)s!', name='Peter')") == 'Hallo Peter!' | |
144 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 3)") == u'3 Äpfel' | |
145 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 1)") == u'1 Apfel' | |
200 | assert t("gettext('Hello %(name)s!', name='Peter')") == \ | |
201 | u'Hallo Peter!' | |
202 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 3)") == \ | |
203 | u'3 Äpfel' | |
204 | assert t("ngettext('%(num)s Apple', '%(num)s Apples', 1)") == \ | |
205 | u'1 Apfel' | |
146 | 206 | assert flask.render_template_string(''' |
147 | 207 | {% trans %}Hello {{ name }}!{% endtrans %} |
148 | 208 | ''', name='Peter').strip() == 'Hallo Peter!' |
153 | 213 | |
154 | 214 | def test_lazy_gettext(self): |
155 | 215 | app = flask.Flask(__name__) |
156 | b = babel.Babel(app, default_locale='de_DE') | |
216 | babel.Babel(app, default_locale='de_DE') | |
157 | 217 | yes = lazy_gettext(u'Yes') |
158 | 218 | with app.test_request_context(): |
159 | 219 | assert text_type(yes) == 'Ja' |
220 | assert yes.__html__() == 'Ja' | |
160 | 221 | app.config['BABEL_DEFAULT_LOCALE'] = 'en_US' |
161 | 222 | with app.test_request_context(): |
162 | 223 | assert text_type(yes) == 'Yes' |
224 | assert yes.__html__() == 'Yes' | |
163 | 225 | |
164 | 226 | def test_list_translations(self): |
165 | 227 | app = flask.Flask(__name__) |
168 | 230 | assert len(translations) == 1 |
169 | 231 | assert str(translations[0]) == 'de' |
170 | 232 | |
233 | def test_no_formatting(self): | |
234 | """ | |
235 | Ensure we don't format strings unless a variable is passed. | |
236 | """ | |
237 | app = flask.Flask(__name__) | |
238 | babel.Babel(app) | |
239 | ||
240 | with app.test_request_context(): | |
241 | assert gettext(u'Test %s') == u'Test %s' | |
242 | assert gettext(u'Test %(name)s', name=u'test') == u'Test test' | |
243 | assert gettext(u'Test %s') % 'test' == u'Test test' | |
244 | ||
171 | 245 | |
172 | 246 | if __name__ == '__main__': |
173 | 247 | unittest.main() |