mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +00:00 
			
		
		
		
	Fixed #9988 -- Added support for translation contexts. Thanks, Claude Paroz.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14450 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -190,7 +190,7 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False, | ||||
|                     f.write(src) | ||||
|                 finally: | ||||
|                     f.close() | ||||
|                 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)) | ||||
|                 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)) | ||||
|                 msgs, errors = _popen(cmd) | ||||
|                 if errors: | ||||
|                     raise CommandError("errors happened while running xgettext on %s\n%s" % (file, errors)) | ||||
| @@ -225,7 +225,7 @@ def make_messages(locale=None, domain='django', verbosity='1', all=False, | ||||
|                         raise SyntaxError(msg) | ||||
|                 if verbosity > 1: | ||||
|                     sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) | ||||
|                 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"' % ( | ||||
|                 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"' % ( | ||||
|                     domain, os.path.join(dirpath, thefile)) | ||||
|                 msgs, errors = _popen(cmd) | ||||
|                 if errors: | ||||
|   | ||||
| @@ -10,7 +10,8 @@ __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext', | ||||
|         'get_language', 'get_language_bidi', 'get_date_formats', | ||||
|         'get_partial_date_formats', 'check_for_language', 'to_locale', | ||||
|         'get_language_from_request', 'templatize', 'ugettext', 'ugettext_lazy', | ||||
|         'ungettext', 'deactivate_all'] | ||||
|         'ungettext', 'ungettext_lazy', 'pgettext', 'pgettext_lazy', | ||||
|         'npgettext', 'npgettext_lazy', 'deactivate_all'] | ||||
|  | ||||
| # Here be dragons, so a short explanation of the logic won't hurt: | ||||
| # We are trying to solve two problems: (1) access settings, in particular | ||||
| @@ -63,10 +64,18 @@ def ugettext(message): | ||||
| def ungettext(singular, plural, number): | ||||
|     return _trans.ungettext(singular, plural, number) | ||||
|  | ||||
| def pgettext(context, message): | ||||
|     return _trans.pgettext(context, message) | ||||
|  | ||||
| def npgettext(context, singular, plural, number): | ||||
|     return _trans.npgettext(context, singular, plural, number) | ||||
|  | ||||
| ngettext_lazy = lazy(ngettext, str) | ||||
| gettext_lazy = lazy(gettext, str) | ||||
| ungettext_lazy = lazy(ungettext, unicode) | ||||
| ugettext_lazy = lazy(ugettext, unicode) | ||||
| pgettext_lazy = lazy(pgettext, unicode) | ||||
| npgettext_lazy = lazy(npgettext, unicode) | ||||
|  | ||||
| def activate(language): | ||||
|     return _trans.activate(language) | ||||
|   | ||||
| @@ -15,6 +15,12 @@ ngettext_lazy = ngettext | ||||
| def ungettext(singular, plural, number): | ||||
|     return force_unicode(ngettext(singular, plural, number)) | ||||
|  | ||||
| def pgettext(context, message): | ||||
|     return ugettext(message) | ||||
|  | ||||
| def npgettext(context, singular, plural, number): | ||||
|     return ungettext(singular, plural, number) | ||||
|  | ||||
| activate = lambda x: None | ||||
| deactivate = deactivate_all = lambda: None | ||||
| get_language = lambda: settings.LANGUAGE_CODE | ||||
|   | ||||
| @@ -24,6 +24,9 @@ _default = None | ||||
| # file lookups when checking the same locale on repeated requests. | ||||
| _accepted = {} | ||||
|  | ||||
| # magic gettext number to separate context from message | ||||
| CONTEXT_SEPARATOR = u"\x04" | ||||
|  | ||||
| # Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9. | ||||
| accept_language_re = re.compile(r''' | ||||
|         ([A-Za-z]{1,8}(?:-[A-Za-z]{1,8})*|\*)   # "en", "en-au", "x-y-z", "*" | ||||
| @@ -279,6 +282,14 @@ def gettext(message): | ||||
| def ugettext(message): | ||||
|     return do_translate(message, 'ugettext') | ||||
|  | ||||
| def pgettext(context, message): | ||||
|     result = do_translate( | ||||
|         u"%s%s%s" % (context, CONTEXT_SEPARATOR, message), 'ugettext') | ||||
|     if CONTEXT_SEPARATOR in result: | ||||
|         # Translation not found | ||||
|         result = message | ||||
|     return result | ||||
|  | ||||
| def gettext_noop(message): | ||||
|     """ | ||||
|     Marks strings for translation but doesn't translate them now. This can be | ||||
| @@ -313,6 +324,15 @@ def ungettext(singular, plural, number): | ||||
|     """ | ||||
|     return do_ntranslate(singular, plural, number, 'ungettext') | ||||
|  | ||||
| def npgettext(context, singular, plural, number): | ||||
|     result = do_ntranslate(u"%s%s%s" % (context, CONTEXT_SEPARATOR, singular), | ||||
|                            u"%s%s%s" % (context, CONTEXT_SEPARATOR, plural), | ||||
|                            number, 'ungettext') | ||||
|     if CONTEXT_SEPARATOR in result: | ||||
|         # Translation not found | ||||
|         result = do_ntranslate(singular, plural, number, 'ungettext') | ||||
|     return result | ||||
|  | ||||
| def check_for_language(lang_code): | ||||
|     """ | ||||
|     Checks whether there is a global language file for the given language | ||||
|   | ||||
| @@ -68,6 +68,8 @@ NullSource = """ | ||||
| function gettext(msgid) { return msgid; } | ||||
| function ngettext(singular, plural, count) { return (count == 1) ? singular : plural; } | ||||
| function gettext_noop(msgid) { return msgid; } | ||||
| function pgettext(context, msgid) { return msgid; } | ||||
| function npgettext(context, singular, plural, count) { return (count == 1) ? singular : plural; } | ||||
| """ | ||||
|  | ||||
| LibHead = """ | ||||
| @@ -98,6 +100,21 @@ function ngettext(singular, plural, count) { | ||||
|  | ||||
| function gettext_noop(msgid) { return msgid; } | ||||
|  | ||||
| function pgettext(context, msgid) { | ||||
|   var value = gettext(context + '\x04' + msgid); | ||||
|   if (value.indexOf('\x04') != -1) { | ||||
|     value = msgid; | ||||
|   } | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| function npgettext(context, singular, plural, count) { | ||||
|   var value = ngettext(context + '\x04' + singular, context + '\x04' + plural, count); | ||||
|   if (value.indexOf('\x04') != -1) { | ||||
|     value = ngettext(singular, plural, count); | ||||
|   } | ||||
|   return value; | ||||
| } | ||||
| """ | ||||
|  | ||||
| LibFormatHead = """ | ||||
|   | ||||
| @@ -86,6 +86,14 @@ Users of Python 2.5 and above may now use :ref:`transaction management functions | ||||
|  | ||||
| For more information, see :ref:`transaction-management-functions`. | ||||
|  | ||||
| Contextual markers in translatable strings | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| For translation strings with ambiguous meaning, you can now | ||||
| use the ``pgettext`` function to specify the context of the string. | ||||
|  | ||||
| For more information, see :ref:`contextual-markers` | ||||
|  | ||||
| Everything else | ||||
| ~~~~~~~~~~~~~~~ | ||||
|  | ||||
|   | ||||
| @@ -193,6 +193,39 @@ cardinality of the elements at play. | ||||
|     ``django-admin.py compilemessages`` or a ``KeyError`` Python exception at | ||||
|     runtime. | ||||
|  | ||||
| .. _contextual-markers: | ||||
|  | ||||
| Contextual markers | ||||
| ------------------ | ||||
|  | ||||
| .. versionadded:: 1.3 | ||||
|  | ||||
| Sometimes words have several meanings, such as ``"May"`` in English, which | ||||
| refers to a month name and to a verb. To enable translators to translate | ||||
| these words correctly in different contexts, you can use the | ||||
| ``django.utils.translation.pgettext()`` function, or the | ||||
| ``django.utils.translation.npgettext()`` function if the string needs | ||||
| pluralization. Both take a context string as the first variable. | ||||
|  | ||||
| In the resulting .po file, the string will then appear as often as there are | ||||
| different contextual markers for the same string (the context will appear on | ||||
| the ``msgctxt`` line), allowing the translator to give a different translation | ||||
| for each of them. | ||||
|  | ||||
| For example:: | ||||
|  | ||||
|     from django.utils.translation import pgettext | ||||
|  | ||||
|     month = pgettext("month name", "May") | ||||
|  | ||||
| will appear in the .po file as: | ||||
|  | ||||
| .. code-block:: po | ||||
|  | ||||
|     msgctxt "month name" | ||||
|     msgid "May" | ||||
|     msgstr "" | ||||
|  | ||||
| .. _lazy-translations: | ||||
|  | ||||
| Lazy translation | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -20,3 +20,20 @@ msgstr "" | ||||
| #: models.py:3 | ||||
| msgid "Date/time" | ||||
| msgstr "Datum/Zeit (LOCALE_PATHS)" | ||||
|  | ||||
| #: models.py:5 | ||||
| msgctxt "month name" | ||||
| msgid "May" | ||||
| msgstr "Mai" | ||||
|  | ||||
| #: models.py:7 | ||||
| msgctxt "verb" | ||||
| msgid "May" | ||||
| msgstr "Kann" | ||||
|  | ||||
| #: models.py:9 | ||||
| msgctxt "search" | ||||
| msgid "%d result" | ||||
| msgid_plural "%d results" | ||||
| msgstr[0] "%d Resultat" | ||||
| msgstr[1] "%d Resultate" | ||||
|   | ||||
| @@ -11,7 +11,7 @@ from django.test import TestCase | ||||
| from django.utils.formats import get_format, date_format, time_format, localize, localize_input, iter_format_modules | ||||
| from django.utils.numberformat import format as nformat | ||||
| from django.utils.safestring import mark_safe, SafeString, SafeUnicode | ||||
| from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, to_locale | ||||
| from django.utils.translation import ugettext, ugettext_lazy, activate, deactivate, gettext_lazy, pgettext, npgettext, to_locale | ||||
| from django.utils.importlib import import_module | ||||
|  | ||||
|  | ||||
| @@ -54,6 +54,22 @@ class TranslationTests(TestCase): | ||||
|         s2 = pickle.loads(pickle.dumps(s1)) | ||||
|         self.assertEqual(unicode(s2), "test") | ||||
|  | ||||
|     def test_pgettext(self): | ||||
|         # Reset translation catalog to include other/locale/de | ||||
|         self.old_locale_paths = settings.LOCALE_PATHS | ||||
|         settings.LOCALE_PATHS += (os.path.join(os.path.dirname(os.path.abspath(__file__)), 'other', 'locale'),) | ||||
|         from django.utils.translation import trans_real | ||||
|         trans_real._active = {} | ||||
|         trans_real._translations = {} | ||||
|         activate('de') | ||||
|  | ||||
|         self.assertEqual(pgettext("unexisting", "May"), u"May") | ||||
|         self.assertEqual(pgettext("month name", "May"), u"Mai") | ||||
|         self.assertEqual(pgettext("verb", "May"), u"Kann") | ||||
|         self.assertEqual(npgettext("search", "%d result", "%d results", 4) % 4, u"4 Resultate") | ||||
|  | ||||
|         settings.LOCALE_PATHS = self.old_locale_paths | ||||
|  | ||||
|     def test_string_concat(self): | ||||
|         """ | ||||
|         unicode(string_concat(...)) should not raise a TypeError - #4796 | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -22,3 +22,7 @@ msgstr "il faut le traduire" | ||||
|  | ||||
| msgid "Choose a time" | ||||
| msgstr "Choisir une heure" | ||||
|  | ||||
| msgctxt "month name" | ||||
| msgid "May" | ||||
| msgstr "mai" | ||||
|   | ||||
| @@ -30,6 +30,9 @@ class I18NTests(TestCase): | ||||
|             # catalog['this is to be translated'] = 'same_that_trans_txt' | ||||
|             # javascript_quote is used to be able to check unicode strings | ||||
|             self.assertContains(response, javascript_quote(trans_txt), 1) | ||||
|             if lang_code == 'fr': | ||||
|                 # Message with context (msgctxt) | ||||
|                 self.assertContains(response, "['month name\x04May'] = 'mai';", 1) | ||||
|  | ||||
|  | ||||
| class JsI18NTests(TestCase): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user