Skip to content

Commit 02fcf1a

Browse files
authored
Merge branch 'dev' into gae_pytz
2 parents ffe8eb9 + 1b2ca94 commit 02fcf1a

4 files changed

Lines changed: 82 additions & 10 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
dist/
66
docs/_build
77
.tox/
8+
.vscode
9+
*.code-workspace

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ older version you will have to upgrade or disable the Jinja support
2828
Configuration
2929
-------------
3030

31-
To get started all you need to do is to instanciate a :class:`Babel`
31+
To get started all you need to do is to instantiate a :class:`Babel`
3232
object after configuring the application::
3333

3434
from flask import Flask

flask_babel/__init__.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
from flask import current_app, request
1717
from flask.ctx import has_request_context
1818
from babel import dates, numbers, support, Locale
19-
from werkzeug import ImmutableDict
2019
from pytz import timezone, UTC
20+
from werkzeug.datastructures import ImmutableDict
2121

2222
from flask_babel._compat import string_types
2323
from flask_babel.speaklater import LazyString
@@ -299,6 +299,9 @@ def refresh():
299299
if hasattr(ctx, key):
300300
delattr(ctx, key)
301301

302+
if hasattr(ctx, 'forced_babel_locale'):
303+
ctx.babel_locale = ctx.forced_babel_locale
304+
302305

303306
@contextmanager
304307
def force_locale(locale):
@@ -319,20 +322,19 @@ def force_locale(locale):
319322
yield
320323
return
321324

322-
babel = current_app.extensions['babel']
323-
324-
orig_locale_selector_func = babel.locale_selector_func
325325
orig_attrs = {}
326326
for key in ('babel_translations', 'babel_locale'):
327327
orig_attrs[key] = getattr(ctx, key, None)
328328

329329
try:
330-
babel.locale_selector_func = lambda: locale
331-
for key in orig_attrs:
332-
setattr(ctx, key, None)
330+
ctx.babel_locale = Locale.parse(locale)
331+
ctx.forced_babel_locale = ctx.babel_locale
332+
ctx.babel_translations = None
333333
yield
334334
finally:
335-
babel.locale_selector_func = orig_locale_selector_func
335+
if hasattr(ctx, 'forced_babel_locale'):
336+
del ctx.forced_babel_locale
337+
336338
for key, value in orig_attrs.items():
337339
setattr(ctx, key, value)
338340

@@ -614,6 +616,21 @@ def index():
614616
return LazyString(gettext, string, **variables)
615617

616618

619+
def lazy_ngettext(singular, plural, num, **variables):
620+
"""Like :func:`ngettext` but the string returned is lazy which means
621+
it will be translated when it is used as an actual string.
622+
623+
Example::
624+
625+
apples = lazy_ngettext(u'%(num)d Apple', u'%(num)d Apples', num=len(apples))
626+
627+
@app.route('/')
628+
def index():
629+
return unicode(apples)
630+
"""
631+
return LazyString(ngettext, singular, plural, num, **variables)
632+
633+
617634
def lazy_pgettext(context, string, **variables):
618635
"""Like :func:`pgettext` but the string returned is lazy which means
619636
it will be translated when it is used as an actual string.

tests/tests.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
77

88
import pickle
9+
from threading import Thread, Semaphore
910

1011
import unittest
1112
from decimal import Decimal
1213
import flask
1314
from datetime import datetime, timedelta
1415
import flask_babel as babel
15-
from flask_babel import gettext, ngettext, lazy_gettext, get_translations
16+
from flask_babel import gettext, ngettext, lazy_gettext, lazy_ngettext, get_translations
1617
from babel.support import NullTranslations
1718
from flask_babel._compat import text_type
1819

@@ -204,6 +205,46 @@ def select_locale():
204205
assert str(babel.get_locale()) == 'en_US'
205206
assert str(babel.get_locale()) == 'de_DE'
206207

208+
def test_force_locale_with_threading(self):
209+
app = flask.Flask(__name__)
210+
b = babel.Babel(app)
211+
212+
@b.localeselector
213+
def select_locale():
214+
return 'de_DE'
215+
216+
semaphore = Semaphore(value=0)
217+
218+
def first_request():
219+
with app.test_request_context():
220+
with babel.force_locale('en_US'):
221+
assert str(babel.get_locale()) == 'en_US'
222+
semaphore.acquire()
223+
224+
thread = Thread(target=first_request)
225+
thread.start()
226+
227+
try:
228+
with app.test_request_context():
229+
assert str(babel.get_locale()) == 'de_DE'
230+
finally:
231+
semaphore.release()
232+
thread.join()
233+
234+
def test_refresh_during_force_locale(self):
235+
app = flask.Flask(__name__)
236+
b = babel.Babel(app)
237+
238+
@b.localeselector
239+
def select_locale():
240+
return 'de_DE'
241+
242+
with app.test_request_context():
243+
with babel.force_locale('en_US'):
244+
assert str(babel.get_locale()) == 'en_US'
245+
babel.refresh()
246+
assert str(babel.get_locale()) == 'en_US'
247+
207248

208249
class NumberFormattingTestCase(unittest.TestCase):
209250

@@ -266,6 +307,18 @@ def test_lazy_gettext(self):
266307
assert text_type(yes) == 'Yes'
267308
assert yes.__html__() == 'Yes'
268309

310+
def test_lazy_ngettext(self):
311+
app = flask.Flask(__name__)
312+
babel.Babel(app, default_locale='de_DE')
313+
one_apple = lazy_ngettext(u'%(num)s Apple', u'%(num)s Apples', 1)
314+
with app.test_request_context():
315+
assert text_type(one_apple) == '1 Apfel'
316+
assert one_apple.__html__() == '1 Apfel'
317+
two_apples = lazy_ngettext(u'%(num)s Apple', u'%(num)s Apples', 2)
318+
with app.test_request_context():
319+
assert text_type(two_apples) == u'2 Äpfel'
320+
assert two_apples.__html__() == u'2 Äpfel'
321+
269322
def test_list_translations(self):
270323
app = flask.Flask(__name__)
271324
b = babel.Babel(app, default_locale='de_DE')

0 commit comments

Comments
 (0)