From 4eb73a35848bb31e84ee6ae002224ba5023968b4 Mon Sep 17 00:00:00 2001 From: Georg Bauer Date: Sat, 1 Oct 2005 12:47:22 +0000 Subject: [PATCH] i18n now has support for ngettext and has unittests git-svn-id: http://code.djangoproject.com/svn/django/branches/i18n@755 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/defaulttags.py | 32 +++++++++++++++++++++----------- django/utils/translation.py | 8 ++++++++ tests/othertests/templates.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/django/core/defaulttags.py b/django/core/defaulttags.py index e351a70f7e..4e1b4e551c 100644 --- a/django/core/defaulttags.py +++ b/django/core/defaulttags.py @@ -291,22 +291,31 @@ class I18NNode(template.Node): def __init__(self, cmd): self.cmd = cmd self.i18n_re = re.compile(r'^\s*_\((.*)\)\s*$') + self.ngettext_re = re.compile(r'''^\s*ngettext\(((?:".+")|(?:'.+')|(?:""".+"""))\s*,\s*((?:".+")|(?:'.+')|(?:""".+"""))\s*,\s*(.*)\)\s*$''') + + def _resolve_var(self, s, context): + if s.startswith("'") and s.endswith("'"): + s = s[1:-1] + elif s.startswith('"""') and s.endswith('"""'): + s = s[3:-3] + elif s.startswith('"') and s.endswith('"'): + s = s[1:-1] + else: + s = template.resolve_variable_with_filters(s, context) + return s def render(self, context): m = self.i18n_re.match(self.cmd) if m: - s = m.group(1) - if s.startswith("'") and s.endswith("'"): - s = s[1:-1] - elif s.startswith('"""') and s.endswith('"""'): - s = s[3:-3] - elif s.startswith('"') and s.endswith('"'): - s = s[1:-1] - else: - s = template.resolve_variable_with_filters(s, context) + s = self._resolve_var(m.group(1), context) return translation.gettext(s) % context - else: - raise template.TemplateSyntaxError("i18n must be called as {% i18n _('some message') %}") + m = self.ngettext_re.match(self.cmd) + if m: + singular = self._resolve_var(m.group(1), context) + plural = self._resolve_var(m.group(2), context) + var = template.resolve_variable_with_filters(m.group(3), context) + return translation.ngettext(singular, plural, var) % context + raise template.TemplateSyntaxError("i18n must be called as {% i18n _('some message') %} or {% i18n ngettext('singular', 'plural', var) %}") def do_comment(parser, token): """ @@ -778,6 +787,7 @@ def do_i18n(parser, token): For example:: {% i18n _('test') %} + {% i18n ngettext('singular', 'plural', counter) %} """ args = token.contents.split(' ', 1) diff --git a/django/utils/translation.py b/django/utils/translation.py index 6385c7b26b..7cbaa27217 100644 --- a/django/utils/translation.py +++ b/django/utils/translation.py @@ -149,6 +149,14 @@ def gettext_noop(message): """ return message +def ngettext(singular, plural, number): + """ + This function returns the translation of either the singular + or plural, based on the number. + """ + if number == 1: return gettext(singular) + else: return gettext(plural) + def get_language_from_request(request): """ analyze the request to find what language the user diff --git a/tests/othertests/templates.py b/tests/othertests/templates.py index 31fea0e1ba..f848863f4b 100644 --- a/tests/othertests/templates.py +++ b/tests/othertests/templates.py @@ -1,4 +1,5 @@ from django.core import template, template_loader +from django.utils.translation import activate, deactivate # Helper objects for template tests class SomeClass: @@ -210,6 +211,33 @@ TEMPLATE_TESTS = { # Raise exception for custom tags used in child with {% load %} tag in parent, not in child 'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError), + + # simple translation of a string delimited by ' + 'i18n01': ("{% i18n _('xxxyyyxxx') %}", {}, "xxxyyyxxx"), + + # simple translation of a string delimited by " + 'i18n02': ('{% i18n _("xxxyyyxxx") %}', {}, "xxxyyyxxx"), + + # simple translation of a string delimited by """ + 'i18n03': ('{% i18n _("""xxxyyyxxx""") %}', {}, "xxxyyyxxx"), + + # simple translation of a variable + 'i18n04': ('{% i18n _(anton) %}', {'anton': 'xxxyyyxxx'}, "xxxyyyxxx"), + + # simple translation of a variable + 'i18n05': ('{% i18n _(anton|lower) %}', {'anton': 'XXXYYYXXX'}, "xxxyyyxxx"), + + # simple translation of a string with interpolation + 'i18n05': ('{% i18n _("xxx%(anton)sxxx") %}', {'anton': 'yyy'}, "xxxyyyxxx"), + + # simple translation of a string to german + 'i18n07': ('{% i18n _("Page not found") %}', {'LANGUAGE_CODE': 'de'}, "Seite nicht gefunden"), + + # translation of singular form + 'i18n08': ('{% i18n ngettext("singular", "plural", count) %}', {'count': 1}, "singular"), + + # translation of plural form + 'i18n09': ('{% i18n ngettext("singular", "plural", count) %}', {'count': 2}, "plural"), } # This replaces the standard template_loader. @@ -225,6 +253,8 @@ def run_tests(verbosity=0, standalone=False): tests = TEMPLATE_TESTS.items() tests.sort() for name, vals in tests: + if 'LANGUAGE_CODE' in vals[1]: + activate('*', vals[1]['LANGUAGE_CODE']) try: output = template_loader.get_template(name).render(template.Context(vals[1])) except Exception, e: @@ -236,6 +266,8 @@ def run_tests(verbosity=0, standalone=False): print "Template test: %s -- FAILED. Got %s, exception: %s" % (name, e.__class__, e) failed_tests.append(name) continue + if 'LANGUAGE_CODE' in vals[1]: + deactivate() if output == vals[2]: if verbosity: print "Template test: %s -- Passed" % name