diff --git a/django/contrib/gis/templates/gis/google/google-map.js b/django/contrib/gis/templates/gis/google/google-map.js
index 06f11e3..a8bcba5 100644
a
|
b
|
|
1 | 1 | {% autoescape off %} |
| 2 | {% localize off %} |
2 | 3 | {% block vars %}var geodjango = {};{% for icon in icons %} |
3 | 4 | var {{ icon.varname }} = new GIcon(G_DEFAULT_ICON); |
4 | 5 | {% if icon.image %}{{ icon.varname }}.image = "{{ icon.image }}";{% endif %} |
… |
… |
var {{ icon.varname }} = new GIcon(G_DEFAULT_ICON);
|
32 | 33 | alert("Sorry, the Google Maps API is not compatible with this browser."); |
33 | 34 | } |
34 | 35 | } |
35 | | {% endblock load %}{% endblock functions %}{% endautoescape %} |
| 36 | {% endblock load %}{% endblock functions %}{% endlocalize %}{% endautoescape %} |
diff --git a/django/template/__init__.py b/django/template/__init__.py
index c316786..0edcbe2 100644
a
|
b
|
from django.utils.itercompat import is_iterable
|
59 | 59 | from django.utils.functional import curry, Promise |
60 | 60 | from django.utils.text import smart_split, unescape_string_literal, get_text_list |
61 | 61 | from django.utils.encoding import smart_unicode, force_unicode, smart_str |
62 | | from django.utils.translation import ugettext as _ |
| 62 | from django.utils.translation import ugettext as _, get_language, activate |
63 | 63 | from django.utils.safestring import SafeData, EscapeData, mark_safe, mark_for_escaping |
64 | 64 | from django.utils.formats import localize |
65 | 65 | from django.utils.html import escape |
… |
… |
class TextNode(Node):
|
819 | 819 | def render(self, context): |
820 | 820 | return self.s |
821 | 821 | |
| 822 | def _localize_from_context(value, context): |
| 823 | """ |
| 824 | Checks if context requires special localization and applies localization |
| 825 | if necessary |
| 826 | """ |
| 827 | locale = context.get('_locale', None) |
| 828 | if locale is not None: |
| 829 | if not isinstance(locale, bool): |
| 830 | old_lang = get_language() |
| 831 | activate(locale) |
| 832 | value = localize(value, force=True) |
| 833 | elif locale: |
| 834 | value = localize(value, force=locale) |
| 835 | else: |
| 836 | value = localize(value) |
| 837 | return value |
| 838 | |
822 | 839 | def _render_value_in_context(value, context): |
823 | 840 | """ |
824 | 841 | Converts any value to a string to become part of a rendered template. This |
825 | 842 | means escaping, if required, and conversion to a unicode object. If value |
826 | 843 | is a string, it is expected to have already been translated. |
827 | 844 | """ |
828 | | value = localize(value) |
| 845 | value = _localize_from_context(value, context) |
829 | 846 | value = force_unicode(value) |
830 | 847 | if (context.autoescape and not isinstance(value, SafeData)) or isinstance(value, EscapeData): |
831 | 848 | return escape(value) |
diff --git a/django/template/debug.py b/django/template/debug.py
index c21fb50..0ba4e02 100644
a
|
b
|
|
1 | | from django.template import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError |
| 1 | from django.template import Lexer, Parser, tag_re, NodeList, VariableNode, TemplateSyntaxError, _localize_from_context |
2 | 2 | from django.utils.encoding import force_unicode |
3 | 3 | from django.utils.html import escape |
4 | 4 | from django.utils.safestring import SafeData, EscapeData |
… |
… |
class DebugVariableNode(VariableNode):
|
87 | 87 | def render(self, context): |
88 | 88 | try: |
89 | 89 | output = self.filter_expression.resolve(context) |
90 | | output = localize(output) |
| 90 | output = _localize_from_context(value, context) |
91 | 91 | output = force_unicode(output) |
92 | 92 | except TemplateSyntaxError, e: |
93 | 93 | if not hasattr(e, 'source'): |
diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 1b07413..c4c347a 100644
a
|
b
|
class WithNode(Node):
|
433 | 433 | context.pop() |
434 | 434 | return output |
435 | 435 | |
| 436 | class LocalizeNode(Node): |
| 437 | def __init__(self, nodelist, locale): |
| 438 | self.nodelist = nodelist |
| 439 | self.locale = locale |
| 440 | |
| 441 | def __repr__(self): |
| 442 | return "<LocalizeNode>" |
| 443 | |
| 444 | def render(self, context): |
| 445 | if isinstance(self.locale, bool): |
| 446 | context['_locale'] = self.locale |
| 447 | else: |
| 448 | context['_locale'] = self.locale.resolve(context) |
| 449 | output = self.nodelist.render(context) |
| 450 | del context['_locale'] |
| 451 | return output |
| 452 | |
436 | 453 | #@register.tag |
437 | 454 | def autoescape(parser, token): |
438 | 455 | """ |
… |
… |
def do_with(parser, token):
|
1216 | 1233 | parser.delete_first_token() |
1217 | 1234 | return WithNode(var, name, nodelist) |
1218 | 1235 | do_with = register.tag('with', do_with) |
| 1236 | |
| 1237 | @register.tag |
| 1238 | def localize(parser, token): |
| 1239 | """ |
| 1240 | Temporarely deactivates localization inside of this block, e.g. |
| 1241 | to avoid rendering syntactically incorrect JavaScript code. |
| 1242 | """ |
| 1243 | locale = None |
| 1244 | bits = list(token.split_contents()) |
| 1245 | if len(bits) == 1: |
| 1246 | locale = True |
| 1247 | elif len(bits) > 2: |
| 1248 | raise TemplateSyntaxError("%r expected argument is on/off or a single locale like de or en-us" % bits[0]) |
| 1249 | else: |
| 1250 | if bits[1] == 'off': |
| 1251 | print "off" |
| 1252 | locale = False |
| 1253 | elif bits[1] == 'on': |
| 1254 | print "on" |
| 1255 | locale = True |
| 1256 | else: |
| 1257 | locale = parser.compile_filter(bits[1]) |
| 1258 | nodelist = parser.parse(('endlocalize',)) |
| 1259 | parser.delete_first_token() |
| 1260 | return LocalizeNode(nodelist, locale) |
diff --git a/django/utils/formats.py b/django/utils/formats.py
index e64cc4e..6f8087d 100644
a
|
b
|
def get_format_modules(reverse=False):
|
41 | 41 | modules.reverse() |
42 | 42 | return modules |
43 | 43 | |
44 | | def get_format(format_type, lang=None): |
| 44 | def get_format(format_type, lang=None, force=False): |
45 | 45 | """ |
46 | 46 | For a specific format type, returns the format for the current |
47 | 47 | language (locale), defaults to the format in the settings. |
48 | | format_type is the name of the format, e.g. 'DATE_FORMAT' |
| 48 | format_type is the name of the format, e.g. 'DATE_FORMAT'. |
49 | 49 | """ |
50 | 50 | format_type = smart_str(format_type) |
51 | | if settings.USE_L10N: |
| 51 | if settings.USE_L10N or force: |
52 | 52 | if lang is None: |
53 | 53 | lang = get_language() |
54 | 54 | cache_key = (format_type, lang) |
… |
… |
def get_format(format_type, lang=None):
|
65 | 65 | _format_cache[cache_key] = None |
66 | 66 | return getattr(settings, format_type) |
67 | 67 | |
68 | | def date_format(value, format=None): |
| 68 | def date_format(value, format=None, force=False): |
69 | 69 | """ |
70 | 70 | Formats a datetime.date or datetime.datetime object using a |
71 | 71 | localizable format |
72 | 72 | """ |
73 | | return dateformat.format(value, get_format(format or 'DATE_FORMAT')) |
| 73 | return dateformat.format(value, get_format(format or 'DATE_FORMAT', force=force)) |
74 | 74 | |
75 | | def time_format(value, format=None): |
| 75 | def time_format(value, format=None, force=False): |
76 | 76 | """ |
77 | 77 | Formats a datetime.time object using a localizable format |
78 | 78 | """ |
79 | | return dateformat.time_format(value, get_format(format or 'TIME_FORMAT')) |
| 79 | return dateformat.time_format(value, get_format(format or 'TIME_FORMAT', force=force)) |
80 | 80 | |
81 | | def number_format(value, decimal_pos=None): |
| 81 | def number_format(value, decimal_pos=None, force=False): |
82 | 82 | """ |
83 | 83 | Formats a numeric value using localization settings |
84 | 84 | """ |
85 | | if settings.USE_L10N: |
| 85 | if settings.USE_L10N or force: |
86 | 86 | lang = get_language() |
87 | 87 | else: |
88 | 88 | lang = None |
89 | 89 | return numberformat.format( |
90 | 90 | value, |
91 | | get_format('DECIMAL_SEPARATOR', lang), |
| 91 | get_format('DECIMAL_SEPARATOR', lang, force=force), |
92 | 92 | decimal_pos, |
93 | | get_format('NUMBER_GROUPING', lang), |
94 | | get_format('THOUSAND_SEPARATOR', lang), |
| 93 | get_format('NUMBER_GROUPING', lang, force=force), |
| 94 | get_format('THOUSAND_SEPARATOR', lang, force=force), |
95 | 95 | ) |
96 | 96 | |
97 | | def localize(value): |
| 97 | def localize(value, force=False): |
98 | 98 | """ |
99 | 99 | Checks if value is a localizable type (date, number...) and returns it |
100 | 100 | formatted as a string using current locale format |
| 101 | If force is True, localization is enabled without respecting settings.USE_L10N. |
101 | 102 | """ |
102 | 103 | if isinstance(value, (decimal.Decimal, float, int, long)): |
103 | | return number_format(value) |
| 104 | return number_format(value, force=force) |
104 | 105 | elif isinstance(value, datetime.datetime): |
105 | | return date_format(value, 'DATETIME_FORMAT') |
| 106 | return date_format(value, 'DATETIME_FORMAT', force=force) |
106 | 107 | elif isinstance(value, datetime.date): |
107 | | return date_format(value) |
| 108 | return date_format(value, force=force) |
108 | 109 | elif isinstance(value, datetime.time): |
109 | | return time_format(value, 'TIME_FORMAT') |
| 110 | return time_format(value, 'TIME_FORMAT', force=force) |
110 | 111 | else: |
111 | 112 | return value |
112 | 113 | |
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index 70f0ffd..b846b58 100644
a
|
b
|
Load a custom template tag set.
|
639 | 639 | |
640 | 640 | See :doc:`Custom tag and filter libraries </howto/custom-template-tags>` for more information. |
641 | 641 | |
| 642 | .. templatetag:: localize |
| 643 | |
| 644 | localize |
| 645 | ~~~~~ |
| 646 | |
| 647 | .. versionadded:: 1.3 |
| 648 | |
| 649 | Adjusts localization behavior for contained block. |
| 650 | |
| 651 | This tag allows a more fine grained control of localization than |
| 652 | :setting:`USE_L10N`. |
| 653 | |
| 654 | To activate or deactivate localization for a template block, use:: |
| 655 | |
| 656 | {% localize on %} |
| 657 | {{ value }} |
| 658 | {% endlocalize %} |
| 659 | |
| 660 | {% localize off %} |
| 661 | {{ value }} |
| 662 | {% endlocalize %} |
| 663 | |
| 664 | You can use a different locale than the current one for a template block:: |
| 665 | |
| 666 | {% localize "de" %} |
| 667 | {{ value }} |
| 668 | {% endlocalize %} |
| 669 | |
| 670 | .. note:: |
| 671 | |
| 672 | The value of :setting:`USE_L10N` is not respected inside of a |
| 673 | `{% localize %}` block. |
| 674 | |
642 | 675 | .. templatetag:: now |
643 | 676 | |
644 | 677 | now |
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index 4aa52b6..19e4b6c 100644
a
|
b
|
class FormattingTests(TestCase):
|
453 | 453 | settings.FORMAT_MODULE_PATH = old_format_module_path |
454 | 454 | deactivate() |
455 | 455 | |
| 456 | def test_localize_templatetag(self): |
| 457 | """ |
| 458 | Tests the {% noloc %} templatetag |
| 459 | """ |
| 460 | context = Context({'value': 3.14 }) |
| 461 | template1 = Template("{{ value }};{% localize off %}{{ value }};{% endlocalize %}{{ value }}") |
| 462 | template2 = Template("{% localize %}{{ value }}{% endlocalize %};{% localize on %}{{ value }}{% endlocalize %}") |
| 463 | template3 = Template('{{ value }};{% localize "de" %}{{ value }}{% endlocalize %}') |
| 464 | output1 = '3,14;3.14;3,14' |
| 465 | output2 = '3,14;3,14' |
| 466 | output3 = '3.14;3,14' |
| 467 | old_debug = settings.TEMPLATE_DEBUG |
| 468 | old_localize = settings.USE_L10N |
| 469 | try: |
| 470 | for debug in (True, False): |
| 471 | settings.TEMPLATE_DEBUG = debug |
| 472 | settings.USE_L10N = False |
| 473 | self.assertEqual(template3.render(context), output3) |
| 474 | activate('de') |
| 475 | self.assertEqual(template2.render(context), output2) |
| 476 | settings.USE_L10N = True |
| 477 | self.assertEqual(template1.render(context), output1) |
| 478 | deactivate() |
| 479 | finally: |
| 480 | deactivate() |
| 481 | settings.TEMPLATE_DEBUG = old_debug |
| 482 | settings.USE_L10N = old_localize |
| 483 | |
456 | 484 | class MiscTests(TestCase): |
457 | 485 | |
458 | 486 | def test_parse_spec_http_header(self): |