Fixed #740 -- Abstracted hard-coded slash in utils/translation.py. Thanks, radek. Also cleaned up docstrings a bit.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@1095 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2005-11-06 21:55:39 +00:00
parent f6ce403140
commit d5368d341c
1 changed files with 55 additions and 83 deletions

View File

@ -1,11 +1,8 @@
"translation helper functions" "translation helper functions"
import os import os, re, sys
import re
import sys
import gettext as gettext_module import gettext as gettext_module
from cStringIO import StringIO from cStringIO import StringIO
from django.utils.functional import lazy from django.utils.functional import lazy
try: try:
@ -20,22 +17,20 @@ else:
def currentThread(): def currentThread():
return 'no threading' return 'no threading'
# translations are cached in a dictionary for # Translations are cached in a dictionary for every language+app tuple.
# every language+app tuple. The active translations # The active translations are stored by threadid to make them thread local.
# are stored by threadid to make them thread local.
_translations = {} _translations = {}
_active = {} _active = {}
# the default translation is based on the settings file # The default translation is based on the settings file.
_default = None _default = None
# this is a cache for accept-header to translation # This is a cache for accept-header to translation object mappings to prevent
# object mappings to prevent the accept parser to # the accept parser to run multiple times for one user.
# run multiple times for one user
_accepted = {} _accepted = {}
def to_locale(language): def to_locale(language):
"turn a language name (en-us) into a locale name (en_US)" "Turns a language name (en-us) into a locale name (en_US)."
p = language.find('-') p = language.find('-')
if p >= 0: if p >= 0:
return language[:p].lower()+'_'+language[p+1:].upper() return language[:p].lower()+'_'+language[p+1:].upper()
@ -43,7 +38,7 @@ def to_locale(language):
return language.lower() return language.lower()
def to_language(locale): def to_language(locale):
"turns a locale name (en_US) into a language name (en-us)" "Turns a locale name (en_US) into a language name (en-us)."
p = locale.find('_') p = locale.find('_')
if p >= 0: if p >= 0:
return locale[:p].lower()+'-'+locale[p+1:].lower() return locale[:p].lower()+'-'+locale[p+1:].lower()
@ -52,16 +47,14 @@ def to_language(locale):
class DjangoTranslation(gettext_module.GNUTranslations): class DjangoTranslation(gettext_module.GNUTranslations):
""" """
This class sets up the GNUTranslations context with This class sets up the GNUTranslations context with regard to output
regard to output charset. Django uses a defined charset. Django uses a defined DEFAULT_CHARSET as the output charset on
DEFAULT_CHARSET as the output charset on Python 2.4 - Python 2.4. With Python 2.3, use DjangoTranslation23.
with Python 2.3, you need to use DjangoTranslation23.
""" """
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
from django.conf import settings from django.conf import settings
gettext_module.GNUTranslations.__init__(self, *args, **kw) gettext_module.GNUTranslations.__init__(self, *args, **kw)
# starting with Python 2.4, there is a function to define # Starting with Python 2.4, there's a function to define
# the output charset. Before 2.4, the output charset is # the output charset. Before 2.4, the output charset is
# identical with the translation file charset. # identical with the translation file charset.
try: try:
@ -73,29 +66,25 @@ class DjangoTranslation(gettext_module.GNUTranslations):
def merge(self, other): def merge(self, other):
self._catalog.update(other._catalog) self._catalog.update(other._catalog)
def set_language(self, language): def set_language(self, language):
self.__language = language self.__language = language
def language(self): def language(self):
return self.__language return self.__language
def __repr__(self): def __repr__(self):
return "<DjangoTranslation lang:%s>" % self.__language return "<DjangoTranslation lang:%s>" % self.__language
class DjangoTranslation23(DjangoTranslation): class DjangoTranslation23(DjangoTranslation):
""" """
This is a compatibility class that is only used with Python 2.3. Compatibility class that is only used with Python 2.3.
The reason is, Python 2.3 doesn't support set_output_charset on Python 2.3 doesn't support set_output_charset on translation objects and
translation objects and so needs this wrapper class to make sure needs this wrapper class to make sure input charsets from translation files
that input charsets from translation files are correctly translated are correctly translated to output charsets.
to output charsets.
With a full switch to Python 2.4, this can be removed from the source. With a full switch to Python 2.4, this can be removed from the source.
""" """
def gettext(self, msgid): def gettext(self, msgid):
res = self.ugettext(msgid) res = self.ugettext(msgid)
return res.encode(self.django_output_charset) return res.encode(self.django_output_charset)
@ -106,20 +95,19 @@ class DjangoTranslation23(DjangoTranslation):
def translation(language): def translation(language):
""" """
This function returns a translation object. app must be the fully Returns a translation object.
qualified name of the application.
This translation object will be constructed out of multiple GNUTranslations This translation object will be constructed out of multiple GNUTranslations
objects by merging their catalogs. It will construct a object for the requested objects by merging their catalogs. It will construct a object for the
language and add a fallback to the default language, if that is different requested language and add a fallback to the default language, if it's
from the requested language. different from the requested language.
""" """
global _translations global _translations
t = _translations.get(language, None) t = _translations.get(language, None)
if t is not None: if t is not None:
return t return t
from django.conf import settings from django.conf import settings
# set up the right translation class # set up the right translation class
@ -150,7 +138,7 @@ def translation(language):
return t return t
except IOError, e: except IOError, e:
return None return None
res = _translation(globalpath) res = _translation(globalpath)
def _merge(path): def _merge(path):
@ -181,7 +169,7 @@ def translation(language):
if os.path.isdir(apppath): if os.path.isdir(apppath):
res = _merge(apppath) res = _merge(apppath)
if res is None: if res is None:
if fallback is not None: if fallback is not None:
res = fallback res = fallback
@ -197,49 +185,41 @@ def translation(language):
def activate(language): def activate(language):
""" """
This function fetches the translation object for a given Fetches the translation object for a given tuple of application name and
tuple of application name and language and installs it as language and installs it as the current translation object for the current
the current translation object for the current thread. thread.
""" """
_active[currentThread()] = translation(language) _active[currentThread()] = translation(language)
def deactivate(): def deactivate():
""" """
This function deinstalls the currently active translation Deinstalls the currently active translation object so that further _ calls
object so that further _ calls will resolve against the will resolve against the default translation object, again.
default translation object, again.
""" """
global _active global _active
if _active.has_key(currentThread()): if _active.has_key(currentThread()):
del _active[currentThread()] del _active[currentThread()]
def get_language(): def get_language():
""" "Returns the currently selected language."
This function returns the currently selected language.
"""
t = _active.get(currentThread(), None) t = _active.get(currentThread(), None)
if t is not None: if t is not None:
try: try:
return to_language(t.language()) return to_language(t.language())
except AttributeError: except AttributeError:
pass pass
# if we don't have a real translation object, we assume # If we don't have a real translation object, assume it's the default language.
# it's the default language.
from django.conf.settings import LANGUAGE_CODE from django.conf.settings import LANGUAGE_CODE
return LANGUAGE_CODE return LANGUAGE_CODE
def gettext(message): def gettext(message):
""" """
This function will be patched into the builtins module to This function will be patched into the builtins module to provide the _
provide the _ helper function. It will use the current helper function. It will use the current thread as a discriminator to find
thread as a discriminator to find the translation object the translation object to use. If no current translation is activated, the
to use. If no current translation is activated, the message will be run through the default translation object.
message will be run through the default translation
object.
""" """
global _default, _active global _default, _active
t = _active.get(currentThread(), None) t = _active.get(currentThread(), None)
if t is not None: if t is not None:
return t.gettext(message) return t.gettext(message)
@ -250,18 +230,15 @@ def gettext(message):
def gettext_noop(message): def gettext_noop(message):
""" """
This function is used to just mark strings for translation Marks strings for translation but doesn't translate them now. This can be
but to not translate them now. This can be used to store used to store strings in global variables that should stay in the base
strings in global variables that should stay in the base language (because they might be used externally) and will be translated later.
language (because they might be used externally) and will
be translated later on.
""" """
return message return message
def ngettext(singular, plural, number): def ngettext(singular, plural, number):
""" """
This function returns the translation of either the singular Returns the translation of either the singular or plural, based on the number.
or plural, based on the number.
""" """
global _default, _active global _default, _active
@ -278,9 +255,8 @@ ngettext_lazy = lazy(ngettext, str)
def check_for_language(lang_code): def check_for_language(lang_code):
""" """
This function checks wether there is a global language Checks whether there is a global language file for the given language code.
file for the given language code. This is used to decide This is used to decide whether a user-provided language is available.
wether a user-provided language is available.
""" """
from django.conf import settings from django.conf import settings
globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale') globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale')
@ -291,11 +267,9 @@ def check_for_language(lang_code):
def get_language_from_request(request): def get_language_from_request(request):
""" """
analyze the request to find what language the user Analyzes the request to find what language the user wants the system to show.
wants the system to show.
""" """
global _accepted global _accepted
from django.conf import settings from django.conf import settings
globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale') globalpath = os.path.join(os.path.dirname(settings.__file__), 'locale')
@ -303,11 +277,11 @@ def get_language_from_request(request):
lang_code = request.session.get('django_language', None) lang_code = request.session.get('django_language', None)
if lang_code is not None and check_for_language(lang_code): if lang_code is not None and check_for_language(lang_code):
return lang_code return lang_code
lang_code = request.COOKIES.get('django_language', None) lang_code = request.COOKIES.get('django_language', None)
if lang_code is not None and check_for_language(lang_code): if lang_code is not None and check_for_language(lang_code):
return lang_code return lang_code
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None) accept = request.META.get('HTTP_ACCEPT_LANGUAGE', None)
if accept is not None: if accept is not None:
@ -338,25 +312,24 @@ def get_language_from_request(request):
# filename, because otherwise we might incorrectly # filename, because otherwise we might incorrectly
# report de_DE if we only have de available, but # report de_DE if we only have de available, but
# did find de_DE because of language normalization # did find de_DE because of language normalization
lang = langfile[len(globalpath):].split('/')[1] lang = langfile[len(globalpath):].split(os.path.sep)[1]
_accepted[accept] = lang _accepted[accept] = lang
return lang return lang
return settings.LANGUAGE_CODE return settings.LANGUAGE_CODE
def install(): def install():
""" """
This installs the gettext function as the default Installs the gettext function as the default translation function under
translation function under the name _. the name _.
""" """
__builtins__['_'] = gettext __builtins__['_'] = gettext
dot_re = re.compile(r'\S') dot_re = re.compile(r'\S')
def blankout(src, char): def blankout(src, char):
""" """
This is used in the templateize function and changes every Changes every non-whitespace character to the given char.
non-whitespace character to the given char. Used in the templateize function.
""" """
return dot_re.sub(char, src) return dot_re.sub(char, src)
@ -368,9 +341,9 @@ constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
def templateize(src): def templateize(src):
from django.core.template import tokenize, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK from django.core.template import tokenize, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK
""" """
This function turns a django template into something that is Turns a Django template into something that is understood by xgettext. It
understood by xgettext. It does so by translating the django does so by translating the Django translation tags into standard gettext
translation tags into standard gettext function invocations. function invocations.
""" """
out = StringIO() out = StringIO()
intrans = False intrans = False
@ -400,7 +373,7 @@ def templateize(src):
elif pluralmatch: elif pluralmatch:
inplural = True inplural = True
else: else:
raise SyntaxError, "translation blocks must not include other block tags: %s" % t.contents raise SyntaxError, "Translation blocks must not include other block tags: %s" % t.contents
elif t.token_type == TOKEN_VAR: elif t.token_type == TOKEN_VAR:
if inplural: if inplural:
plural.append('%%(%s)s' % t.contents) plural.append('%%(%s)s' % t.contents)
@ -444,4 +417,3 @@ def templateize(src):
else: else:
out.write(blankout(t.contents, 'X')) out.write(blankout(t.contents, 'X'))
return out.getvalue() return out.getvalue()