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:
parent
f6ce403140
commit
d5368d341c
|
@ -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()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue