测试gitnore
This commit is contained in:
@@ -1,37 +1,31 @@
|
||||
"""
|
||||
Internationalization support.
|
||||
"""
|
||||
import warnings
|
||||
from contextlib import ContextDecorator
|
||||
from decimal import ROUND_UP, Decimal
|
||||
|
||||
from django.utils.autoreload import autoreload_started, file_changed
|
||||
from django.utils.deprecation import RemovedInDjango40Warning
|
||||
from django.utils.functional import lazy
|
||||
from django.utils.regex_helper import _lazy_re_compile
|
||||
|
||||
__all__ = [
|
||||
"activate",
|
||||
"deactivate",
|
||||
"override",
|
||||
"deactivate_all",
|
||||
"get_language",
|
||||
"get_language_from_request",
|
||||
"get_language_info",
|
||||
"get_language_bidi",
|
||||
"check_for_language",
|
||||
"to_language",
|
||||
"to_locale",
|
||||
"templatize",
|
||||
"gettext",
|
||||
"gettext_lazy",
|
||||
"gettext_noop",
|
||||
"ngettext",
|
||||
"ngettext_lazy",
|
||||
"pgettext",
|
||||
"pgettext_lazy",
|
||||
"npgettext",
|
||||
"npgettext_lazy",
|
||||
'activate', 'deactivate', 'override', 'deactivate_all',
|
||||
'get_language', 'get_language_from_request',
|
||||
'get_language_info', 'get_language_bidi',
|
||||
'check_for_language', 'to_language', 'to_locale', 'templatize',
|
||||
'gettext', 'gettext_lazy', 'gettext_noop',
|
||||
'ugettext', 'ugettext_lazy', 'ugettext_noop',
|
||||
'ngettext', 'ngettext_lazy',
|
||||
'ungettext', 'ungettext_lazy',
|
||||
'pgettext', 'pgettext_lazy',
|
||||
'npgettext', 'npgettext_lazy',
|
||||
'LANGUAGE_SESSION_KEY',
|
||||
]
|
||||
|
||||
LANGUAGE_SESSION_KEY = '_language'
|
||||
|
||||
|
||||
class TranslatorCommentWarning(SyntaxWarning):
|
||||
pass
|
||||
@@ -45,7 +39,6 @@ class TranslatorCommentWarning(SyntaxWarning):
|
||||
# replace the functions with their real counterparts (once we do access the
|
||||
# settings).
|
||||
|
||||
|
||||
class Trans:
|
||||
"""
|
||||
The purpose of this class is to store the actual translation function upon
|
||||
@@ -61,20 +54,13 @@ class Trans:
|
||||
|
||||
def __getattr__(self, real_name):
|
||||
from django.conf import settings
|
||||
|
||||
if settings.USE_I18N:
|
||||
from django.utils.translation import trans_real as trans
|
||||
from django.utils.translation.reloader import (
|
||||
translation_file_changed,
|
||||
watch_for_translation_changes,
|
||||
)
|
||||
|
||||
autoreload_started.connect(
|
||||
watch_for_translation_changes, dispatch_uid="translation_file_changed"
|
||||
)
|
||||
file_changed.connect(
|
||||
translation_file_changed, dispatch_uid="translation_file_changed"
|
||||
translation_file_changed, watch_for_translation_changes,
|
||||
)
|
||||
autoreload_started.connect(watch_for_translation_changes, dispatch_uid='translation_file_changed')
|
||||
file_changed.connect(translation_file_changed, dispatch_uid='translation_file_changed')
|
||||
else:
|
||||
from django.utils.translation import trans_null as trans
|
||||
setattr(self, real_name, getattr(trans, real_name))
|
||||
@@ -91,14 +77,53 @@ def gettext_noop(message):
|
||||
return _trans.gettext_noop(message)
|
||||
|
||||
|
||||
def ugettext_noop(message):
|
||||
"""
|
||||
A legacy compatibility wrapper for Unicode handling on Python 2.
|
||||
Alias of gettext_noop() since Django 2.0.
|
||||
"""
|
||||
warnings.warn(
|
||||
'django.utils.translation.ugettext_noop() is deprecated in favor of '
|
||||
'django.utils.translation.gettext_noop().',
|
||||
RemovedInDjango40Warning, stacklevel=2,
|
||||
)
|
||||
return gettext_noop(message)
|
||||
|
||||
|
||||
def gettext(message):
|
||||
return _trans.gettext(message)
|
||||
|
||||
|
||||
def ugettext(message):
|
||||
"""
|
||||
A legacy compatibility wrapper for Unicode handling on Python 2.
|
||||
Alias of gettext() since Django 2.0.
|
||||
"""
|
||||
warnings.warn(
|
||||
'django.utils.translation.ugettext() is deprecated in favor of '
|
||||
'django.utils.translation.gettext().',
|
||||
RemovedInDjango40Warning, stacklevel=2,
|
||||
)
|
||||
return gettext(message)
|
||||
|
||||
|
||||
def ngettext(singular, plural, number):
|
||||
return _trans.ngettext(singular, plural, number)
|
||||
|
||||
|
||||
def ungettext(singular, plural, number):
|
||||
"""
|
||||
A legacy compatibility wrapper for Unicode handling on Python 2.
|
||||
Alias of ngettext() since Django 2.0.
|
||||
"""
|
||||
warnings.warn(
|
||||
'django.utils.translation.ungettext() is deprecated in favor of '
|
||||
'django.utils.translation.ngettext().',
|
||||
RemovedInDjango40Warning, stacklevel=2,
|
||||
)
|
||||
return ngettext(singular, plural, number)
|
||||
|
||||
|
||||
def pgettext(context, message):
|
||||
return _trans.pgettext(context, message)
|
||||
|
||||
@@ -111,35 +136,46 @@ gettext_lazy = lazy(gettext, str)
|
||||
pgettext_lazy = lazy(pgettext, str)
|
||||
|
||||
|
||||
def ugettext_lazy(message):
|
||||
"""
|
||||
A legacy compatibility wrapper for Unicode handling on Python 2. Has been
|
||||
Alias of gettext_lazy since Django 2.0.
|
||||
"""
|
||||
warnings.warn(
|
||||
'django.utils.translation.ugettext_lazy() is deprecated in favor of '
|
||||
'django.utils.translation.gettext_lazy().',
|
||||
RemovedInDjango40Warning, stacklevel=2,
|
||||
)
|
||||
return gettext_lazy(message)
|
||||
|
||||
|
||||
def lazy_number(func, resultclass, number=None, **kwargs):
|
||||
if isinstance(number, int):
|
||||
kwargs["number"] = number
|
||||
kwargs['number'] = number
|
||||
proxy = lazy(func, resultclass)(**kwargs)
|
||||
else:
|
||||
original_kwargs = kwargs.copy()
|
||||
|
||||
class NumberAwareString(resultclass):
|
||||
def __bool__(self):
|
||||
return bool(kwargs["singular"])
|
||||
return bool(kwargs['singular'])
|
||||
|
||||
def _get_number_value(self, values):
|
||||
try:
|
||||
return values[number]
|
||||
except KeyError:
|
||||
raise KeyError(
|
||||
"Your dictionary lacks key '%s'. Please provide "
|
||||
"Your dictionary lacks key '%s\'. Please provide "
|
||||
"it, because it is required to determine whether "
|
||||
"string is singular or plural." % number
|
||||
)
|
||||
|
||||
def _translate(self, number_value):
|
||||
kwargs["number"] = number_value
|
||||
kwargs['number'] = number_value
|
||||
return func(**kwargs)
|
||||
|
||||
def format(self, *args, **kwargs):
|
||||
number_value = (
|
||||
self._get_number_value(kwargs) if kwargs and number else args[0]
|
||||
)
|
||||
number_value = self._get_number_value(kwargs) if kwargs and number else args[0]
|
||||
return self._translate(number_value).format(*args, **kwargs)
|
||||
|
||||
def __mod__(self, rhs):
|
||||
@@ -156,10 +192,7 @@ def lazy_number(func, resultclass, number=None, **kwargs):
|
||||
return translated
|
||||
|
||||
proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs)
|
||||
proxy.__reduce__ = lambda: (
|
||||
_lazy_number_unpickle,
|
||||
(func, resultclass, number, original_kwargs),
|
||||
)
|
||||
proxy.__reduce__ = lambda: (_lazy_number_unpickle, (func, resultclass, number, original_kwargs))
|
||||
return proxy
|
||||
|
||||
|
||||
@@ -171,10 +204,21 @@ def ngettext_lazy(singular, plural, number=None):
|
||||
return lazy_number(ngettext, str, singular=singular, plural=plural, number=number)
|
||||
|
||||
|
||||
def npgettext_lazy(context, singular, plural, number=None):
|
||||
return lazy_number(
|
||||
npgettext, str, context=context, singular=singular, plural=plural, number=number
|
||||
def ungettext_lazy(singular, plural, number=None):
|
||||
"""
|
||||
A legacy compatibility wrapper for Unicode handling on Python 2.
|
||||
An alias of ungettext_lazy() since Django 2.0.
|
||||
"""
|
||||
warnings.warn(
|
||||
'django.utils.translation.ungettext_lazy() is deprecated in favor of '
|
||||
'django.utils.translation.ngettext_lazy().',
|
||||
RemovedInDjango40Warning, stacklevel=2,
|
||||
)
|
||||
return ngettext_lazy(singular, plural, number)
|
||||
|
||||
|
||||
def npgettext_lazy(context, singular, plural, number=None):
|
||||
return lazy_number(npgettext, str, context=context, singular=singular, plural=plural, number=number)
|
||||
|
||||
|
||||
def activate(language):
|
||||
@@ -220,27 +264,27 @@ def check_for_language(lang_code):
|
||||
|
||||
def to_language(locale):
|
||||
"""Turn a locale name (en_US) into a language name (en-us)."""
|
||||
p = locale.find("_")
|
||||
p = locale.find('_')
|
||||
if p >= 0:
|
||||
return locale[:p].lower() + "-" + locale[p + 1 :].lower()
|
||||
return locale[:p].lower() + '-' + locale[p + 1:].lower()
|
||||
else:
|
||||
return locale.lower()
|
||||
|
||||
|
||||
def to_locale(language):
|
||||
"""Turn a language name (en-us) into a locale name (en_US)."""
|
||||
lang, _, country = language.lower().partition("-")
|
||||
language, _, country = language.lower().partition('-')
|
||||
if not country:
|
||||
return language[:3].lower() + language[3:]
|
||||
return language
|
||||
# A language with > 2 characters after the dash only has its first
|
||||
# character after the dash capitalized; e.g. sr-latn becomes sr_Latn.
|
||||
# A language with 2 characters after the dash has both characters
|
||||
# capitalized; e.g. en-us becomes en_US.
|
||||
country, _, tail = country.partition("-")
|
||||
country, _, tail = country.partition('-')
|
||||
country = country.title() if len(country) > 2 else country.upper()
|
||||
if tail:
|
||||
country += "-" + tail
|
||||
return lang + "_" + country
|
||||
country += '-' + tail
|
||||
return language + '_' + country
|
||||
|
||||
|
||||
def get_language_from_request(request, check_path=False):
|
||||
@@ -257,7 +301,6 @@ def get_supported_language_variant(lang_code, *, strict=False):
|
||||
|
||||
def templatize(src, **kwargs):
|
||||
from .template import templatize
|
||||
|
||||
return templatize(src, **kwargs)
|
||||
|
||||
|
||||
@@ -267,35 +310,32 @@ def deactivate_all():
|
||||
|
||||
def get_language_info(lang_code):
|
||||
from django.conf.locale import LANG_INFO
|
||||
|
||||
try:
|
||||
lang_info = LANG_INFO[lang_code]
|
||||
if "fallback" in lang_info and "name" not in lang_info:
|
||||
info = get_language_info(lang_info["fallback"][0])
|
||||
if 'fallback' in lang_info and 'name' not in lang_info:
|
||||
info = get_language_info(lang_info['fallback'][0])
|
||||
else:
|
||||
info = lang_info
|
||||
except KeyError:
|
||||
if "-" not in lang_code:
|
||||
if '-' not in lang_code:
|
||||
raise KeyError("Unknown language code %s." % lang_code)
|
||||
generic_lang_code = lang_code.split("-")[0]
|
||||
generic_lang_code = lang_code.split('-')[0]
|
||||
try:
|
||||
info = LANG_INFO[generic_lang_code]
|
||||
except KeyError:
|
||||
raise KeyError(
|
||||
"Unknown language code %s and %s." % (lang_code, generic_lang_code)
|
||||
)
|
||||
raise KeyError("Unknown language code %s and %s." % (lang_code, generic_lang_code))
|
||||
|
||||
if info:
|
||||
info["name_translated"] = gettext_lazy(info["name"])
|
||||
info['name_translated'] = gettext_lazy(info['name'])
|
||||
return info
|
||||
|
||||
|
||||
trim_whitespace_re = _lazy_re_compile(r"\s*\n\s*")
|
||||
trim_whitespace_re = _lazy_re_compile(r'\s*\n\s*')
|
||||
|
||||
|
||||
def trim_whitespace(s):
|
||||
return trim_whitespace_re.sub(" ", s.strip())
|
||||
return trim_whitespace_re.sub(' ', s.strip())
|
||||
|
||||
|
||||
def round_away_from_one(value):
|
||||
return int(Decimal(value - 1).quantize(Decimal("0"), rounding=ROUND_UP)) + 1
|
||||
return int(Decimal(value - 1).quantize(Decimal('0'), rounding=ROUND_UP)) + 1
|
||||
|
||||
@@ -11,24 +11,23 @@ def watch_for_translation_changes(sender, **kwargs):
|
||||
from django.conf import settings
|
||||
|
||||
if settings.USE_I18N:
|
||||
directories = [Path("locale")]
|
||||
directories = [Path('locale')]
|
||||
directories.extend(
|
||||
Path(config.path) / "locale"
|
||||
Path(config.path) / 'locale'
|
||||
for config in apps.get_app_configs()
|
||||
if not is_django_module(config.module)
|
||||
)
|
||||
directories.extend(Path(p) for p in settings.LOCALE_PATHS)
|
||||
for path in directories:
|
||||
sender.watch_dir(path, "**/*.mo")
|
||||
sender.watch_dir(path, '**/*.mo')
|
||||
|
||||
|
||||
def translation_file_changed(sender, file_path, **kwargs):
|
||||
"""Clear the internal translations cache if a .mo file is modified."""
|
||||
if file_path.suffix == ".mo":
|
||||
if file_path.suffix == '.mo':
|
||||
import gettext
|
||||
|
||||
from django.utils.translation import trans_real
|
||||
|
||||
gettext._translations = {}
|
||||
trans_real._translations = {}
|
||||
trans_real._default = None
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import warnings
|
||||
from io import StringIO
|
||||
|
||||
from django.template.base import Lexer, TokenType
|
||||
from django.template.base import TRANSLATOR_COMMENT_MARK, Lexer, TokenType
|
||||
from django.utils.regex_helper import _lazy_re_compile
|
||||
|
||||
from . import TranslatorCommentWarning, trim_whitespace
|
||||
|
||||
TRANSLATOR_COMMENT_MARK = "Translators"
|
||||
|
||||
dot_re = _lazy_re_compile(r"\S")
|
||||
dot_re = _lazy_re_compile(r'\S')
|
||||
|
||||
|
||||
def blankout(src, char):
|
||||
@@ -28,9 +26,7 @@ inline_re = _lazy_re_compile(
|
||||
# Match the optional context part
|
||||
r"""(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?')))?\s*"""
|
||||
)
|
||||
block_re = _lazy_re_compile(
|
||||
r"""^\s*blocktrans(?:late)?(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?')))?(?:\s+|$)"""
|
||||
)
|
||||
block_re = _lazy_re_compile(r"""^\s*blocktrans(?:late)?(\s+.*context\s+((?:"[^"]*?")|(?:'[^']*?')))?(?:\s+|$)""")
|
||||
endblock_re = _lazy_re_compile(r"""^\s*endblocktrans(?:late)?$""")
|
||||
plural_re = _lazy_re_compile(r"""^\s*plural$""")
|
||||
constant_re = _lazy_re_compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
|
||||
@@ -42,7 +38,7 @@ def templatize(src, origin=None):
|
||||
does so by translating the Django translation tags into standard gettext
|
||||
function invocations.
|
||||
"""
|
||||
out = StringIO("")
|
||||
out = StringIO('')
|
||||
message_context = None
|
||||
intrans = False
|
||||
inplural = False
|
||||
@@ -54,30 +50,27 @@ def templatize(src, origin=None):
|
||||
lineno_comment_map = {}
|
||||
comment_lineno_cache = None
|
||||
# Adding the u prefix allows gettext to recognize the string (#26093).
|
||||
raw_prefix = "u"
|
||||
raw_prefix = 'u'
|
||||
|
||||
def join_tokens(tokens, trim=False):
|
||||
message = "".join(tokens)
|
||||
message = ''.join(tokens)
|
||||
if trim:
|
||||
message = trim_whitespace(message)
|
||||
return message
|
||||
|
||||
for t in Lexer(src).tokenize():
|
||||
if incomment:
|
||||
if t.token_type == TokenType.BLOCK and t.contents == "endcomment":
|
||||
content = "".join(comment)
|
||||
if t.token_type == TokenType.BLOCK and t.contents == 'endcomment':
|
||||
content = ''.join(comment)
|
||||
translators_comment_start = None
|
||||
for lineno, line in enumerate(content.splitlines(True)):
|
||||
if line.lstrip().startswith(TRANSLATOR_COMMENT_MARK):
|
||||
translators_comment_start = lineno
|
||||
for lineno, line in enumerate(content.splitlines(True)):
|
||||
if (
|
||||
translators_comment_start is not None
|
||||
and lineno >= translators_comment_start
|
||||
):
|
||||
out.write(" # %s" % line)
|
||||
if translators_comment_start is not None and lineno >= translators_comment_start:
|
||||
out.write(' # %s' % line)
|
||||
else:
|
||||
out.write(" #\n")
|
||||
out.write(' #\n')
|
||||
incomment = False
|
||||
comment = []
|
||||
else:
|
||||
@@ -89,44 +82,36 @@ def templatize(src, origin=None):
|
||||
if endbmatch:
|
||||
if inplural:
|
||||
if message_context:
|
||||
out.write(
|
||||
" npgettext({p}{!r}, {p}{!r}, {p}{!r},count) ".format(
|
||||
message_context,
|
||||
join_tokens(singular, trimmed),
|
||||
join_tokens(plural, trimmed),
|
||||
p=raw_prefix,
|
||||
)
|
||||
)
|
||||
out.write(' npgettext({p}{!r}, {p}{!r}, {p}{!r},count) '.format(
|
||||
message_context,
|
||||
join_tokens(singular, trimmed),
|
||||
join_tokens(plural, trimmed),
|
||||
p=raw_prefix,
|
||||
))
|
||||
else:
|
||||
out.write(
|
||||
" ngettext({p}{!r}, {p}{!r}, count) ".format(
|
||||
join_tokens(singular, trimmed),
|
||||
join_tokens(plural, trimmed),
|
||||
p=raw_prefix,
|
||||
)
|
||||
)
|
||||
out.write(' ngettext({p}{!r}, {p}{!r}, count) '.format(
|
||||
join_tokens(singular, trimmed),
|
||||
join_tokens(plural, trimmed),
|
||||
p=raw_prefix,
|
||||
))
|
||||
for part in singular:
|
||||
out.write(blankout(part, "S"))
|
||||
out.write(blankout(part, 'S'))
|
||||
for part in plural:
|
||||
out.write(blankout(part, "P"))
|
||||
out.write(blankout(part, 'P'))
|
||||
else:
|
||||
if message_context:
|
||||
out.write(
|
||||
" pgettext({p}{!r}, {p}{!r}) ".format(
|
||||
message_context,
|
||||
join_tokens(singular, trimmed),
|
||||
p=raw_prefix,
|
||||
)
|
||||
)
|
||||
out.write(' pgettext({p}{!r}, {p}{!r}) '.format(
|
||||
message_context,
|
||||
join_tokens(singular, trimmed),
|
||||
p=raw_prefix,
|
||||
))
|
||||
else:
|
||||
out.write(
|
||||
" gettext({p}{!r}) ".format(
|
||||
join_tokens(singular, trimmed),
|
||||
p=raw_prefix,
|
||||
)
|
||||
)
|
||||
out.write(' gettext({p}{!r}) '.format(
|
||||
join_tokens(singular, trimmed),
|
||||
p=raw_prefix,
|
||||
))
|
||||
for part in singular:
|
||||
out.write(blankout(part, "S"))
|
||||
out.write(blankout(part, 'S'))
|
||||
message_context = None
|
||||
intrans = False
|
||||
inplural = False
|
||||
@@ -135,20 +120,20 @@ def templatize(src, origin=None):
|
||||
elif pluralmatch:
|
||||
inplural = True
|
||||
else:
|
||||
filemsg = ""
|
||||
filemsg = ''
|
||||
if origin:
|
||||
filemsg = "file %s, " % origin
|
||||
filemsg = 'file %s, ' % origin
|
||||
raise SyntaxError(
|
||||
"Translation blocks must not include other block tags: "
|
||||
"%s (%sline %d)" % (t.contents, filemsg, t.lineno)
|
||||
)
|
||||
elif t.token_type == TokenType.VAR:
|
||||
if inplural:
|
||||
plural.append("%%(%s)s" % t.contents)
|
||||
plural.append('%%(%s)s' % t.contents)
|
||||
else:
|
||||
singular.append("%%(%s)s" % t.contents)
|
||||
singular.append('%%(%s)s' % t.contents)
|
||||
elif t.token_type == TokenType.TEXT:
|
||||
contents = t.contents.replace("%", "%%")
|
||||
contents = t.contents.replace('%', '%%')
|
||||
if inplural:
|
||||
plural.append(contents)
|
||||
else:
|
||||
@@ -157,13 +142,13 @@ def templatize(src, origin=None):
|
||||
# Handle comment tokens (`{# ... #}`) plus other constructs on
|
||||
# the same line:
|
||||
if comment_lineno_cache is not None:
|
||||
cur_lineno = t.lineno + t.contents.count("\n")
|
||||
cur_lineno = t.lineno + t.contents.count('\n')
|
||||
if comment_lineno_cache == cur_lineno:
|
||||
if t.token_type != TokenType.COMMENT:
|
||||
for c in lineno_comment_map[comment_lineno_cache]:
|
||||
filemsg = ""
|
||||
filemsg = ''
|
||||
if origin:
|
||||
filemsg = "file %s, " % origin
|
||||
filemsg = 'file %s, ' % origin
|
||||
warn_msg = (
|
||||
"The translator-targeted comment '%s' "
|
||||
"(%sline %d) was ignored, because it wasn't "
|
||||
@@ -172,9 +157,7 @@ def templatize(src, origin=None):
|
||||
warnings.warn(warn_msg, TranslatorCommentWarning)
|
||||
lineno_comment_map[comment_lineno_cache] = []
|
||||
else:
|
||||
out.write(
|
||||
"# %s" % " | ".join(lineno_comment_map[comment_lineno_cache])
|
||||
)
|
||||
out.write('# %s' % ' | '.join(lineno_comment_map[comment_lineno_cache]))
|
||||
comment_lineno_cache = None
|
||||
|
||||
if t.token_type == TokenType.BLOCK:
|
||||
@@ -187,7 +170,7 @@ def templatize(src, origin=None):
|
||||
g = g.strip('"')
|
||||
elif g[0] == "'":
|
||||
g = g.strip("'")
|
||||
g = g.replace("%", "%%")
|
||||
g = g.replace('%', '%%')
|
||||
if imatch[2]:
|
||||
# A context is provided
|
||||
context_match = context_re.match(imatch[2])
|
||||
@@ -196,17 +179,15 @@ def templatize(src, origin=None):
|
||||
message_context = message_context.strip('"')
|
||||
elif message_context[0] == "'":
|
||||
message_context = message_context.strip("'")
|
||||
out.write(
|
||||
" pgettext({p}{!r}, {p}{!r}) ".format(
|
||||
message_context, g, p=raw_prefix
|
||||
)
|
||||
)
|
||||
out.write(' pgettext({p}{!r}, {p}{!r}) '.format(
|
||||
message_context, g, p=raw_prefix
|
||||
))
|
||||
message_context = None
|
||||
else:
|
||||
out.write(" gettext({p}{!r}) ".format(g, p=raw_prefix))
|
||||
out.write(' gettext({p}{!r}) '.format(g, p=raw_prefix))
|
||||
elif bmatch:
|
||||
for fmatch in constant_re.findall(t.contents):
|
||||
out.write(" _(%s) " % fmatch)
|
||||
out.write(' _(%s) ' % fmatch)
|
||||
if bmatch[1]:
|
||||
# A context is provided
|
||||
context_match = context_re.match(bmatch[1])
|
||||
@@ -217,30 +198,30 @@ def templatize(src, origin=None):
|
||||
message_context = message_context.strip("'")
|
||||
intrans = True
|
||||
inplural = False
|
||||
trimmed = "trimmed" in t.split_contents()
|
||||
trimmed = 'trimmed' in t.split_contents()
|
||||
singular = []
|
||||
plural = []
|
||||
elif cmatches:
|
||||
for cmatch in cmatches:
|
||||
out.write(" _(%s) " % cmatch)
|
||||
elif t.contents == "comment":
|
||||
out.write(' _(%s) ' % cmatch)
|
||||
elif t.contents == 'comment':
|
||||
incomment = True
|
||||
else:
|
||||
out.write(blankout(t.contents, "B"))
|
||||
out.write(blankout(t.contents, 'B'))
|
||||
elif t.token_type == TokenType.VAR:
|
||||
parts = t.contents.split("|")
|
||||
parts = t.contents.split('|')
|
||||
cmatch = constant_re.match(parts[0])
|
||||
if cmatch:
|
||||
out.write(" _(%s) " % cmatch[1])
|
||||
out.write(' _(%s) ' % cmatch[1])
|
||||
for p in parts[1:]:
|
||||
if p.find(":_(") >= 0:
|
||||
out.write(" %s " % p.split(":", 1)[1])
|
||||
if p.find(':_(') >= 0:
|
||||
out.write(' %s ' % p.split(':', 1)[1])
|
||||
else:
|
||||
out.write(blankout(p, "F"))
|
||||
out.write(blankout(p, 'F'))
|
||||
elif t.token_type == TokenType.COMMENT:
|
||||
if t.contents.lstrip().startswith(TRANSLATOR_COMMENT_MARK):
|
||||
lineno_comment_map.setdefault(t.lineno, []).append(t.contents)
|
||||
comment_lineno_cache = t.lineno
|
||||
else:
|
||||
out.write(blankout(t.contents, "X"))
|
||||
out.write(blankout(t.contents, 'X'))
|
||||
return out.getvalue()
|
||||
|
||||
@@ -32,23 +32,18 @@ CONTEXT_SEPARATOR = "\x04"
|
||||
|
||||
# Format of Accept-Language header values. From RFC 2616, section 14.4 and 3.9
|
||||
# and RFC 3066, section 2.1
|
||||
accept_language_re = _lazy_re_compile(
|
||||
r"""
|
||||
# "en", "en-au", "x-y-z", "es-419", "*"
|
||||
([A-Za-z]{1,8}(?:-[A-Za-z0-9]{1,8})*|\*)
|
||||
# Optional "q=1.00", "q=0.8"
|
||||
(?:\s*;\s*q=(0(?:\.\d{,3})?|1(?:\.0{,3})?))?
|
||||
# Multiple accepts per header.
|
||||
(?:\s*,\s*|$)
|
||||
""",
|
||||
re.VERBOSE,
|
||||
)
|
||||
accept_language_re = _lazy_re_compile(r'''
|
||||
([A-Za-z]{1,8}(?:-[A-Za-z0-9]{1,8})*|\*) # "en", "en-au", "x-y-z", "es-419", "*"
|
||||
(?:\s*;\s*q=(0(?:\.\d{,3})?|1(?:\.0{,3})?))? # Optional "q=1.00", "q=0.8"
|
||||
(?:\s*,\s*|$) # Multiple accepts per header.
|
||||
''', re.VERBOSE)
|
||||
|
||||
language_code_re = _lazy_re_compile(
|
||||
r"^[a-z]{1,8}(?:-[a-z0-9]{1,8})*(?:@[a-z0-9]{1,20})?$", re.IGNORECASE
|
||||
r'^[a-z]{1,8}(?:-[a-z0-9]{1,8})*(?:@[a-z0-9]{1,20})?$',
|
||||
re.IGNORECASE
|
||||
)
|
||||
|
||||
language_code_prefix_re = _lazy_re_compile(r"^/(\w+([@-]\w+)?)(/|$)")
|
||||
language_code_prefix_re = _lazy_re_compile(r'^/(\w+([@-]\w+)?)(/|$)')
|
||||
|
||||
|
||||
@receiver(setting_changed)
|
||||
@@ -57,7 +52,7 @@ def reset_cache(**kwargs):
|
||||
Reset global state when LANGUAGES setting has been changed, as some
|
||||
languages should no longer be accepted.
|
||||
"""
|
||||
if kwargs["setting"] in ("LANGUAGES", "LANGUAGE_CODE"):
|
||||
if kwargs['setting'] in ('LANGUAGES', 'LANGUAGE_CODE'):
|
||||
check_for_language.cache_clear()
|
||||
get_languages.cache_clear()
|
||||
get_supported_language_variant.cache_clear()
|
||||
@@ -68,7 +63,6 @@ class TranslationCatalog:
|
||||
Simulate a dict for DjangoTranslation._catalog so as multiple catalogs
|
||||
with different plural equations are kept separate.
|
||||
"""
|
||||
|
||||
def __init__(self, trans=None):
|
||||
self._catalogs = [trans._catalog.copy()] if trans else [{}]
|
||||
self._plurals = [trans.plural] if trans else [lambda n: int(n != 1)]
|
||||
@@ -130,8 +124,7 @@ class DjangoTranslation(gettext_module.GNUTranslations):
|
||||
requested language and add a fallback to the default language, if it's
|
||||
different from the requested language.
|
||||
"""
|
||||
|
||||
domain = "django"
|
||||
domain = 'django'
|
||||
|
||||
def __init__(self, language, domain=None, localedirs=None):
|
||||
"""Create a GNUTranslations() using many locale directories"""
|
||||
@@ -147,12 +140,10 @@ class DjangoTranslation(gettext_module.GNUTranslations):
|
||||
# pluralization: anything except one is pluralized.
|
||||
self.plural = lambda n: int(n != 1)
|
||||
|
||||
if self.domain == "django":
|
||||
if self.domain == 'django':
|
||||
if localedirs is not None:
|
||||
# A module-level cache is used for caching 'django' translations
|
||||
warnings.warn(
|
||||
"localedirs is ignored when domain is 'django'.", RuntimeWarning
|
||||
)
|
||||
warnings.warn("localedirs is ignored when domain is 'django'.", RuntimeWarning)
|
||||
localedirs = None
|
||||
self._init_translation_catalog()
|
||||
|
||||
@@ -164,16 +155,9 @@ class DjangoTranslation(gettext_module.GNUTranslations):
|
||||
self._add_installed_apps_translations()
|
||||
|
||||
self._add_local_translations()
|
||||
if (
|
||||
self.__language == settings.LANGUAGE_CODE
|
||||
and self.domain == "django"
|
||||
and self._catalog is None
|
||||
):
|
||||
if self.__language == settings.LANGUAGE_CODE and self.domain == 'django' and self._catalog is None:
|
||||
# default lang should have at least one translation file available.
|
||||
raise OSError(
|
||||
"No translation files found for default language %s."
|
||||
% settings.LANGUAGE_CODE
|
||||
)
|
||||
raise OSError('No translation files found for default language %s.' % settings.LANGUAGE_CODE)
|
||||
self._add_fallback(localedirs)
|
||||
if self._catalog is None:
|
||||
# No catalogs found for this language, set an empty catalog.
|
||||
@@ -200,7 +184,7 @@ class DjangoTranslation(gettext_module.GNUTranslations):
|
||||
def _init_translation_catalog(self):
|
||||
"""Create a base catalog using global django translations."""
|
||||
settingsfile = sys.modules[settings.__module__].__file__
|
||||
localedir = os.path.join(os.path.dirname(settingsfile), "locale")
|
||||
localedir = os.path.join(os.path.dirname(settingsfile), 'locale')
|
||||
translation = self._new_gnu_trans(localedir)
|
||||
self.merge(translation)
|
||||
|
||||
@@ -212,10 +196,9 @@ class DjangoTranslation(gettext_module.GNUTranslations):
|
||||
raise AppRegistryNotReady(
|
||||
"The translation infrastructure cannot be initialized before the "
|
||||
"apps registry is ready. Check that you don't make non-lazy "
|
||||
"gettext calls at import time."
|
||||
)
|
||||
"gettext calls at import time.")
|
||||
for app_config in app_configs:
|
||||
localedir = os.path.join(app_config.path, "locale")
|
||||
localedir = os.path.join(app_config.path, 'locale')
|
||||
if os.path.exists(localedir):
|
||||
translation = self._new_gnu_trans(localedir)
|
||||
self.merge(translation)
|
||||
@@ -230,11 +213,9 @@ class DjangoTranslation(gettext_module.GNUTranslations):
|
||||
"""Set the GNUTranslations() fallback with the default language."""
|
||||
# Don't set a fallback for the default language or any English variant
|
||||
# (as it's empty, so it'll ALWAYS fall back to the default language)
|
||||
if self.__language == settings.LANGUAGE_CODE or self.__language.startswith(
|
||||
"en"
|
||||
):
|
||||
if self.__language == settings.LANGUAGE_CODE or self.__language.startswith('en'):
|
||||
return
|
||||
if self.domain == "django":
|
||||
if self.domain == 'django':
|
||||
# Get from cache
|
||||
default_translation = translation(settings.LANGUAGE_CODE)
|
||||
else:
|
||||
@@ -245,7 +226,7 @@ class DjangoTranslation(gettext_module.GNUTranslations):
|
||||
|
||||
def merge(self, other):
|
||||
"""Merge another translation into this catalog."""
|
||||
if not getattr(other, "_catalog", None):
|
||||
if not getattr(other, '_catalog', None):
|
||||
return # NullTranslations() has no _catalog
|
||||
if self._catalog is None:
|
||||
# Take plural and _info from first catalog found (generally Django's).
|
||||
@@ -340,7 +321,7 @@ def get_language_bidi():
|
||||
if lang is None:
|
||||
return False
|
||||
else:
|
||||
base_lang = get_language().split("-")[0]
|
||||
base_lang = get_language().split('-')[0]
|
||||
return base_lang in settings.LANGUAGES_BIDI
|
||||
|
||||
|
||||
@@ -368,7 +349,7 @@ def gettext(message):
|
||||
"""
|
||||
global _default
|
||||
|
||||
eol_message = message.replace("\r\n", "\n").replace("\r", "\n")
|
||||
eol_message = message.replace('\r\n', '\n').replace('\r', '\n')
|
||||
|
||||
if eol_message:
|
||||
_default = _default or translation(settings.LANGUAGE_CODE)
|
||||
@@ -378,7 +359,7 @@ def gettext(message):
|
||||
else:
|
||||
# Return an empty value of the corresponding type if an empty message
|
||||
# is given, instead of metadata, which is the default gettext behavior.
|
||||
result = type(message)("")
|
||||
result = type(message)('')
|
||||
|
||||
if isinstance(message, SafeData):
|
||||
return mark_safe(result)
|
||||
@@ -423,15 +404,13 @@ def ngettext(singular, plural, number):
|
||||
Return a string of the translation of either the singular or plural,
|
||||
based on the number.
|
||||
"""
|
||||
return do_ntranslate(singular, plural, number, "ngettext")
|
||||
return do_ntranslate(singular, plural, number, 'ngettext')
|
||||
|
||||
|
||||
def npgettext(context, singular, plural, number):
|
||||
msgs_with_ctxt = (
|
||||
"%s%s%s" % (context, CONTEXT_SEPARATOR, singular),
|
||||
"%s%s%s" % (context, CONTEXT_SEPARATOR, plural),
|
||||
number,
|
||||
)
|
||||
msgs_with_ctxt = ("%s%s%s" % (context, CONTEXT_SEPARATOR, singular),
|
||||
"%s%s%s" % (context, CONTEXT_SEPARATOR, plural),
|
||||
number)
|
||||
result = ngettext(*msgs_with_ctxt)
|
||||
if CONTEXT_SEPARATOR in result:
|
||||
# Translation not found
|
||||
@@ -444,11 +423,10 @@ def all_locale_paths():
|
||||
Return a list of paths to user-provides languages files.
|
||||
"""
|
||||
globalpath = os.path.join(
|
||||
os.path.dirname(sys.modules[settings.__module__].__file__), "locale"
|
||||
)
|
||||
os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
|
||||
app_paths = []
|
||||
for app_config in apps.get_app_configs():
|
||||
locale_path = os.path.join(app_config.path, "locale")
|
||||
locale_path = os.path.join(app_config.path, 'locale')
|
||||
if os.path.exists(locale_path):
|
||||
app_paths.append(locale_path)
|
||||
return [globalpath, *settings.LOCALE_PATHS, *app_paths]
|
||||
@@ -469,7 +447,7 @@ def check_for_language(lang_code):
|
||||
if lang_code is None or not language_code_re.search(lang_code):
|
||||
return False
|
||||
return any(
|
||||
gettext_module.find("django", path, [to_locale(lang_code)]) is not None
|
||||
gettext_module.find('django', path, [to_locale(lang_code)]) is not None
|
||||
for path in all_locale_paths()
|
||||
)
|
||||
|
||||
@@ -496,17 +474,14 @@ def get_supported_language_variant(lang_code, strict=False):
|
||||
<https://www.djangoproject.com/weblog/2007/oct/26/security-fix/>.
|
||||
"""
|
||||
if lang_code:
|
||||
# If 'zh-hant-tw' is not supported, try special fallback or subsequent
|
||||
# language codes i.e. 'zh-hant' and 'zh'.
|
||||
# If 'fr-ca' is not supported, try special fallback or language-only 'fr'.
|
||||
possible_lang_codes = [lang_code]
|
||||
try:
|
||||
possible_lang_codes.extend(LANG_INFO[lang_code]["fallback"])
|
||||
possible_lang_codes.extend(LANG_INFO[lang_code]['fallback'])
|
||||
except KeyError:
|
||||
pass
|
||||
i = None
|
||||
while (i := lang_code.rfind("-", 0, i)) > -1:
|
||||
possible_lang_codes.append(lang_code[:i])
|
||||
generic_lang_code = possible_lang_codes[-1]
|
||||
generic_lang_code = lang_code.split('-')[0]
|
||||
possible_lang_codes.append(generic_lang_code)
|
||||
supported_lang_codes = get_languages()
|
||||
|
||||
for code in possible_lang_codes:
|
||||
@@ -515,7 +490,7 @@ def get_supported_language_variant(lang_code, strict=False):
|
||||
if not strict:
|
||||
# if fr-fr is not supported, try fr-ca.
|
||||
for supported_code in supported_lang_codes:
|
||||
if supported_code.startswith(generic_lang_code + "-"):
|
||||
if supported_code.startswith(generic_lang_code + '-'):
|
||||
return supported_code
|
||||
raise LookupError(lang_code)
|
||||
|
||||
@@ -553,11 +528,7 @@ def get_language_from_request(request, check_path=False):
|
||||
return lang_code
|
||||
|
||||
lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
|
||||
if (
|
||||
lang_code is not None
|
||||
and lang_code in get_languages()
|
||||
and check_for_language(lang_code)
|
||||
):
|
||||
if lang_code is not None and lang_code in get_languages() and check_for_language(lang_code):
|
||||
return lang_code
|
||||
|
||||
try:
|
||||
@@ -565,9 +536,9 @@ def get_language_from_request(request, check_path=False):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
accept = request.META.get("HTTP_ACCEPT_LANGUAGE", "")
|
||||
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
|
||||
for accept_lang, unused in parse_accept_lang_header(accept):
|
||||
if accept_lang == "*":
|
||||
if accept_lang == '*':
|
||||
break
|
||||
|
||||
if not language_code_re.search(accept_lang):
|
||||
@@ -597,7 +568,7 @@ def parse_accept_lang_header(lang_string):
|
||||
if pieces[-1]:
|
||||
return ()
|
||||
for i in range(0, len(pieces) - 1, 3):
|
||||
first, lang, priority = pieces[i : i + 3]
|
||||
first, lang, priority = pieces[i:i + 3]
|
||||
if first:
|
||||
return ()
|
||||
if priority:
|
||||
|
||||
Reference in New Issue
Block a user