Ticket #9988: pgettext-2.patch

File pgettext-2.patch, 11.7 KB (added by claudep, 5 years ago)

pgettext implementation including js and docs

  • django/core/management/commands/makemessages.py

     
    190190                    f.write(src)
    191191                finally:
    192192                    f.close()
    193                 cmd = 'xgettext -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (domain, os.path.join(dirpath, thefile))
     193                cmd = 'xgettext -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 --from-code UTF-8 -o - "%s"' % (domain, os.path.join(dirpath, thefile))
    194194                msgs, errors = _popen(cmd)
    195195                if errors:
    196196                    raise CommandError("errors happened while running xgettext on %s\n%s" % (file, errors))
     
    225225                        raise SyntaxError(msg)
    226226                if verbosity > 1:
    227227                    sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
    228                 cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % (
     228                cmd = 'xgettext -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 --keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 -o - "%s"' % (
    229229                    domain, os.path.join(dirpath, thefile))
    230230                msgs, errors = _popen(cmd)
    231231                if errors:
  • django/views/i18n.py

     
    6868function gettext(msgid) { return msgid; }
    6969function ngettext(singular, plural, count) { return (count == 1) ? singular : plural; }
    7070function gettext_noop(msgid) { return msgid; }
     71function pgettext(context, msgid) { return msgid; }
     72function npgettext(context, singular, plural, count) { return (count == 1) ? singular : plural; }
    7173"""
    7274
    7375LibHead = """
     
    98100
    99101function gettext_noop(msgid) { return msgid; }
    100102
     103function pgettext(context, msgid) {
     104  var value = gettext(context + '\x04' + msgid);
     105  if (value.indexOf('\x04') != -1) {
     106    value = msgid;
     107  }
     108  return value;
     109}
     110
     111function npgettext(context, singular, plural, count) {
     112  var value = ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
     113  if (value.indexOf('\x04') != -1) {
     114    value = ngettext(singular, plural, count);
     115  }
     116  return value;
     117}
    101118"""
    102119
    103120LibFormatHead = """
  • django/utils/translation/trans_real.py

     
    279279def ugettext(message):
    280280    return do_translate(message, 'ugettext')
    281281
     282def pgettext(context, message):
     283    # \x04 is a magic gettext number to separate context from message
     284    result = do_translate(u"%s\x04%s" % (context, message), 'ugettext')
     285    if "\x04" in result:
     286        # Translation not found
     287        result = message
     288    return result
     289
    282290def gettext_noop(message):
    283291    """
    284292    Marks strings for translation but doesn't translate them now. This can be
     
    313321    """
    314322    return do_ntranslate(singular, plural, number, 'ungettext')
    315323
     324def npgettext(context, singular, plural, number):
     325    # \x04 is a magic gettext number to separate context from message
     326    result = do_ntranslate(u"%s\x04%s" % (context, singular),
     327                           u"%s\x04%s" % (context, plural), number, 'ungettext')
     328    if "\x04" in result:
     329        # Translation not found
     330        result = do_ntranslate(singular, plural, number, 'ungettext')
     331    return result
     332
    316333def check_for_language(lang_code):
    317334    """
    318335    Checks whether there is a global language file for the given language
  • django/utils/translation/__init__.py

     
    1010        'get_language', 'get_language_bidi', 'get_date_formats',
    1111        'get_partial_date_formats', 'check_for_language', 'to_locale',
    1212        'get_language_from_request', 'templatize', 'ugettext', 'ugettext_lazy',
    13         'ungettext', 'deactivate_all']
     13        'ungettext', 'ungettext_lazy', 'pgettext', 'pgettext_lazy',
     14        'npgettext', 'npgettext_lazy', 'deactivate_all']
    1415
    1516# Here be dragons, so a short explanation of the logic won't hurt:
    1617# We are trying to solve two problems: (1) access settings, in particular
     
    6364def ungettext(singular, plural, number):
    6465    return _trans.ungettext(singular, plural, number)
    6566
     67def pgettext(context, message):
     68    return _trans.pgettext(context, message)
     69
     70def npgettext(context, singular, plural, number):
     71    return _trans.npgettext(context, singular, plural, number)
     72
    6673ngettext_lazy = lazy(ngettext, str)
    6774gettext_lazy = lazy(gettext, str)
    6875ungettext_lazy = lazy(ungettext, unicode)
    6976ugettext_lazy = lazy(ugettext, unicode)
     77pgettext_lazy = lazy(pgettext, unicode)
     78npgettext_lazy = lazy(npgettext, unicode)
    7079
    7180def activate(language):
    7281    return _trans.activate(language)
  • django/utils/translation/trans_null.py

     
    1515def ungettext(singular, plural, number):
    1616    return force_unicode(ngettext(singular, plural, number))
    1717
     18def pgettext(context, message):
     19    return ugettext(message)
     20
     21def npgettext(context, singular, plural, number):
     22    return ungettext(singular, plural, number)
     23
    1824activate = lambda x: None
    1925deactivate = deactivate_all = lambda: None
    2026get_language = lambda: settings.LANGUAGE_CODE
  • tests/regressiontests/views/locale/fr/LC_MESSAGES/djangojs.po

     
    2222
    2323msgid "Choose a time"
    2424msgstr "Choisir une heure"
     25
     26msgctxt "month name"
     27msgid "May"
     28msgstr "mai"
  • tests/regressiontests/views/tests/i18n.py

     
    3030            # catalog['this is to be translated'] = 'same_that_trans_txt'
    3131            # javascript_quote is used to be able to check unicode strings
    3232            self.assertContains(response, javascript_quote(trans_txt), 1)
     33            if lang_code == 'fr':
     34                # Message with context (msgctxt)
     35                self.assertContains(response, "['month name\x04May'] = 'mai';", 1)
    3336
    3437
    3538class JsI18NTests(TestCase):
  • tests/regressiontests/i18n/other/locale/de/LC_MESSAGES/django.po

     
    2020#: models.py:3
    2121msgid "Date/time"
    2222msgstr "Datum/Zeit (LOCALE_PATHS)"
     23
     24#: models.py:5
     25msgctxt "month name"
     26msgid "May"
     27msgstr "Mai"
     28
     29#: models.py:7
     30msgctxt "verb"
     31msgid "May"
     32msgstr "Kann"
     33
     34#: models.py:9
     35msgctxt "search"
     36msgid "%d result"
     37msgid_plural "%d results"
     38msgstr[0] "%d Resultat"
     39msgstr[1] "%d Resultate"
  • tests/regressiontests/i18n/tests.py

     
    1111from django.utils.formats import get_format, date_format, time_format, localize, localize_input, iter_format_modules
    1212from django.utils.numberformat import format as nformat
    1313from django.utils.safestring import mark_safe, SafeString, SafeUnicode
    14 from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, to_locale
     14from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, pgettext, npgettext, to_locale
    1515from django.utils.importlib import import_module
    1616
    1717
     
    5454        s2 = pickle.loads(pickle.dumps(s1))
    5555        self.assertEqual(unicode(s2), "test")
    5656
     57    def test_pgettext(self):
     58        # Reset translation catalog to include other/locale/de
     59        self.old_locale_paths = settings.LOCALE_PATHS
     60        settings.LOCALE_PATHS += (os.path.join(os.path.dirname(os.path.abspath(__file__)), 'other', 'locale'),)
     61        from django.utils.translation import trans_real
     62        trans_real._active = {}
     63        trans_real._translations = {}
     64        activate('de')
     65
     66        self.assertEqual(pgettext("unexisting", "May"), u"May")
     67        self.assertEqual(pgettext("month name", "May"), u"Mai")
     68        self.assertEqual(pgettext("verb", "May"), u"Kann")
     69        self.assertEqual(npgettext("search", "%d result", "%d results", 4) % 4, u"4 Resultate")
     70
     71        settings.LOCALE_PATHS = self.old_locale_paths
     72
    5773    def test_string_concat(self):
    5874        """
    5975        unicode(string_concat(...)) should not raise a TypeError - #4796
  • docs/topics/i18n/internationalization.txt

     
    193193    ``django-admin.py compilemessages`` or a ``KeyError`` Python exception at
    194194    runtime.
    195195
     196.. _contextual-markers:
     197
     198Contextual markers
     199------------------
     200
     201.. versionadded:: 1.3
     202
     203In certain cases, English words may have several meanings, such as ``"May"``
     204which can refer to a month name or to a verb. If this same word is then used in
     205the code with both meanings, the translator cannot translate it two times
     206differently. To be able to disambiguate such strings, you can use the
     207``django.utils.translation.pgettext()`` function, or the
     208``django.utils.translation.npgettext()`` function if the string needs
     209pluralization.
     210
     211In the resulting .po file, the string will then appear as often as there are
     212different contextual markers for the same string (the context will appear on the
     213``msgctxt`` line), allowing the translator to give a different translation for
     214each of them.
     215
     216For example:
     217
     218    from django.utils.translation import pgettext
     219
     220    month = pgettext("month name", "May")
     221
     222which will appear in the .po file as:
     223
     224    msgctxt "month name"
     225    msgid "May"
     226    msgstr ""
     227
    196228.. _lazy-translations:
    197229
    198230Lazy translation
  • docs/releases/1.3.txt

     
    8686
    8787For more information, see :ref:`transaction-management-functions`.
    8888
     89Contextual markers in translatable strings
     90~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     91
     92When a single English word or string appear in your code with different meanings,
     93you can now use the ``pgettext`` function to specify the context of the string.
     94
     95For more information, see :ref:`contextual-markers`
     96
    8997Everything else
    9098~~~~~~~~~~~~~~~
    9199
Back to Top