added infrastructure code for later javascript translating (currently not active)
git-svn-id: http://code.djangoproject.com/svn/django/trunk@1529 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
946bd1e370
commit
5917fdcf2d
|
@ -7,6 +7,8 @@ import getopt
|
||||||
|
|
||||||
from django.utils.translation import templateize
|
from django.utils.translation import templateize
|
||||||
|
|
||||||
|
pythonize_re = re.compile(r'\n\s*//')
|
||||||
|
|
||||||
localedir = None
|
localedir = None
|
||||||
|
|
||||||
if os.path.isdir(os.path.join('conf', 'locale')):
|
if os.path.isdir(os.path.join('conf', 'locale')):
|
||||||
|
@ -39,6 +41,9 @@ for o, v in opts:
|
||||||
elif o == '-a':
|
elif o == '-a':
|
||||||
all = True
|
all = True
|
||||||
|
|
||||||
|
if domain not in ('django', 'djangojs'):
|
||||||
|
print "currently make-messages.py only supports domains 'django' and 'djangojs'"
|
||||||
|
sys.exit(1)
|
||||||
if (lang is None and not all) or domain is None:
|
if (lang is None and not all) or domain is None:
|
||||||
print "usage: make-messages.py -l <language>"
|
print "usage: make-messages.py -l <language>"
|
||||||
print " or: make-messages.py -a"
|
print " or: make-messages.py -a"
|
||||||
|
@ -66,7 +71,28 @@ for lang in languages:
|
||||||
|
|
||||||
for (dirpath, dirnames, filenames) in os.walk("."):
|
for (dirpath, dirnames, filenames) in os.walk("."):
|
||||||
for file in filenames:
|
for file in filenames:
|
||||||
if file.endswith('.py') or file.endswith('.html'):
|
if domain == 'djangojs' and file.endswith('.js'):
|
||||||
|
if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath))
|
||||||
|
src = open(os.path.join(dirpath, file), "rb").read()
|
||||||
|
src = pythonize_re.sub('\n#', src)
|
||||||
|
open(os.path.join(dirpath, '%s.py' % file), "wb").write(src)
|
||||||
|
thefile = '%s.py' % file
|
||||||
|
cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy -o - "%s"' % (
|
||||||
|
os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile))
|
||||||
|
(stdin, stdout, stderr) = os.popen3(cmd, 'b')
|
||||||
|
msgs = stdout.read()
|
||||||
|
errors = stderr.read()
|
||||||
|
if errors:
|
||||||
|
print "errors happened while running xgettext on %s" % file
|
||||||
|
print errors
|
||||||
|
sys.exit(8)
|
||||||
|
old = '#: '+os.path.join(dirpath, thefile)[2:]
|
||||||
|
new = '#: '+os.path.join(dirpath, file)[2:]
|
||||||
|
msgs = msgs.replace(old, new)
|
||||||
|
if msgs:
|
||||||
|
open(potfile, 'ab').write(msgs)
|
||||||
|
os.unlink(os.path.join(dirpath, thefile))
|
||||||
|
elif domain == 'django' and (file.endswith('.py') or file.endswith('.html')):
|
||||||
thefile = file
|
thefile = file
|
||||||
if file.endswith('.html'):
|
if file.endswith('.html'):
|
||||||
src = open(os.path.join(dirpath, file), "rb").read()
|
src = open(os.path.join(dirpath, file), "rb").read()
|
||||||
|
@ -91,6 +117,7 @@ for lang in languages:
|
||||||
if thefile != file:
|
if thefile != file:
|
||||||
os.unlink(os.path.join(dirpath, thefile))
|
os.unlink(os.path.join(dirpath, thefile))
|
||||||
|
|
||||||
|
if os.path.exists(potfile):
|
||||||
(stdin, stdout, stderr) = os.popen3('msguniq %s' % potfile, 'b')
|
(stdin, stdout, stderr) = os.popen3('msguniq %s' % potfile, 'b')
|
||||||
msgs = stdout.read()
|
msgs = stdout.read()
|
||||||
errors = stderr.read()
|
errors = stderr.read()
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from django.conf.settings import DEFAULT_CHARSET
|
||||||
|
|
||||||
# Capitalizes the first letter of a string.
|
# Capitalizes the first letter of a string.
|
||||||
capfirst = lambda x: x and x[0].upper() + x[1:]
|
capfirst = lambda x: x and x[0].upper() + x[1:]
|
||||||
|
|
||||||
|
@ -90,3 +92,20 @@ def compress_string(s):
|
||||||
zfile.write(s)
|
zfile.write(s)
|
||||||
zfile.close()
|
zfile.close()
|
||||||
return zbuf.getvalue()
|
return zbuf.getvalue()
|
||||||
|
|
||||||
|
ustring_re = re.compile(u"([\u0080-\uffff])")
|
||||||
|
def javascript_quote(s):
|
||||||
|
|
||||||
|
def fix(match):
|
||||||
|
return r"\u%04x" % ord(match.group(1))
|
||||||
|
|
||||||
|
if type(s) == str:
|
||||||
|
s = s.decode(DEFAULT_ENCODING)
|
||||||
|
elif type(s) != unicode:
|
||||||
|
raise TypeError, s
|
||||||
|
s = s.replace('\\', '\\\\')
|
||||||
|
s = s.replace('\n', '\\n')
|
||||||
|
s = s.replace('\t', '\\t')
|
||||||
|
s = s.replace("'", "\\'")
|
||||||
|
return str(ustring_re.sub(fix, s))
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,21 @@ def get_language():
|
||||||
from django.conf.settings import LANGUAGE_CODE
|
from django.conf.settings import LANGUAGE_CODE
|
||||||
return LANGUAGE_CODE
|
return LANGUAGE_CODE
|
||||||
|
|
||||||
|
def catalog():
|
||||||
|
"""
|
||||||
|
This function returns the current active catalog for further processing.
|
||||||
|
This can be used if you need to modify the catalog or want to access the
|
||||||
|
whole message catalog instead of just translating one string.
|
||||||
|
"""
|
||||||
|
global _default, _active
|
||||||
|
t = _active.get(currentThread(), None)
|
||||||
|
if t is not None:
|
||||||
|
return t
|
||||||
|
if _default is None:
|
||||||
|
from django.conf import settings
|
||||||
|
_default = translation(settings.LANGUAGE_CODE)
|
||||||
|
return _default
|
||||||
|
|
||||||
def gettext(message):
|
def gettext(message):
|
||||||
"""
|
"""
|
||||||
This function will be patched into the builtins module to provide the _
|
This function will be patched into the builtins module to provide the _
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
import gettext as gettext_module
|
||||||
|
|
||||||
from django.utils import httpwrappers
|
from django.utils import httpwrappers
|
||||||
from django.utils.translation import check_for_language
|
from django.utils.translation import check_for_language, activate, to_locale, get_language
|
||||||
|
from django.utils.text import javascript_quote
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
def set_language(request):
|
def set_language(request):
|
||||||
"""
|
"""
|
||||||
|
@ -20,3 +27,163 @@ def set_language(request):
|
||||||
else:
|
else:
|
||||||
response.set_cookie('django_language', lang_code)
|
response.set_cookie('django_language', lang_code)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
NullSource = """
|
||||||
|
/* gettext identity library */
|
||||||
|
|
||||||
|
function gettext(msgid) {
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ngettext(singular, plural, count) {
|
||||||
|
if (count == 1) {
|
||||||
|
return singular;
|
||||||
|
} else {
|
||||||
|
return plural;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gettext_noop(msgid) {
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
LibHead = """
|
||||||
|
/* gettext library */
|
||||||
|
|
||||||
|
var catalog = new Array();
|
||||||
|
"""
|
||||||
|
|
||||||
|
LibFoot = """
|
||||||
|
|
||||||
|
function gettext(msgid) {
|
||||||
|
var value = catalog[msgid];
|
||||||
|
if (typeof(value) == 'undefined') {
|
||||||
|
return msgid;
|
||||||
|
} else {
|
||||||
|
if (typeof(value) == 'string') {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return value[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ngettext(singular, plural, count) {
|
||||||
|
value = catalog[singular];
|
||||||
|
if (typeof(value) == 'undefined') {
|
||||||
|
if (count == 1) {
|
||||||
|
return singular;
|
||||||
|
} else {
|
||||||
|
return plural;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return value[pluralidx(count)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gettext_noop(msgid) {
|
||||||
|
return msgid;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
SimplePlural = """
|
||||||
|
function pluralidx(count) {
|
||||||
|
if (count == 1) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
InterPolate = r"""
|
||||||
|
function interpolate(fmt, obj, named) {
|
||||||
|
if (named) {
|
||||||
|
return fmt.replace(/%\(\w+\)s/, function(match){return String(obj[match.slice(2,-2)])});
|
||||||
|
} else {
|
||||||
|
return fmt.replace(/%s/, function(match){return String(obj.shift())});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
def javascript_catalog(request, domain='djangojs', packages=None):
|
||||||
|
"""
|
||||||
|
Returns the selected language catalog as a javascript library.
|
||||||
|
|
||||||
|
Receives the list of packages to check for translations in the
|
||||||
|
packages parameter either from an infodict or as a +-delimited
|
||||||
|
string from the request. Default is 'django.conf'.
|
||||||
|
|
||||||
|
Additionally you can override the gettext domain for this view,
|
||||||
|
but usually you don't want to do that, as JavaScript messages
|
||||||
|
go to the djangojs domain. But this might be needed if you
|
||||||
|
deliver your JavaScript source from Django templates.
|
||||||
|
"""
|
||||||
|
if request.GET:
|
||||||
|
if request.GET.has_key('language'):
|
||||||
|
if check_for_language(request.GET['language']):
|
||||||
|
activate(request.GET['language'])
|
||||||
|
if packages is None:
|
||||||
|
packages = ['django.conf']
|
||||||
|
if type(packages) in (str, unicode):
|
||||||
|
packages = packages.split('+')
|
||||||
|
default_locale = to_locale(settings.LANGUAGE_CODE)
|
||||||
|
locale = to_locale(get_language())
|
||||||
|
t = {}
|
||||||
|
paths = []
|
||||||
|
for package in packages:
|
||||||
|
p = __import__(package, {}, {}, [''])
|
||||||
|
path = os.path.join(os.path.dirname(p.__file__), 'locale')
|
||||||
|
paths.append(path)
|
||||||
|
#!!! add loading of catalogs from settings.LANGUAGE_CODE and request.LANGUAGE_CODE!
|
||||||
|
try:
|
||||||
|
catalog = gettext_module.translation(domain, path, [default_locale])
|
||||||
|
except IOError, e:
|
||||||
|
catalog = None
|
||||||
|
if catalog is not None:
|
||||||
|
t.update(catalog._catalog)
|
||||||
|
if locale != default_locale:
|
||||||
|
for path in paths:
|
||||||
|
try:
|
||||||
|
catalog = gettext_module.translation(domain, path, [locale])
|
||||||
|
except IOError, e:
|
||||||
|
catalog = None
|
||||||
|
if catalog is not None:
|
||||||
|
t.update(catalog._catalog)
|
||||||
|
src = [LibHead]
|
||||||
|
plural = None
|
||||||
|
for l in t[''].split('\n'):
|
||||||
|
if l.startswith('Plural-Forms:'):
|
||||||
|
plural = l.split(':',1)[1].strip()
|
||||||
|
if plural is not None:
|
||||||
|
# this should actually be a compiled function of a typical plural-form:
|
||||||
|
# Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
|
||||||
|
plural = [el.strip() for el in plural.split(';') if el.strip().startswith('plural=')][0].split('=',1)[1]
|
||||||
|
src.append('function pluralidx(n) {\n return %s;\n}\n' % plural)
|
||||||
|
else:
|
||||||
|
src.append(SimplePlural)
|
||||||
|
csrc = []
|
||||||
|
pdict = {}
|
||||||
|
for k, v in t.items():
|
||||||
|
if k == '':
|
||||||
|
continue
|
||||||
|
if type(k) in (str, unicode):
|
||||||
|
csrc.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(v)))
|
||||||
|
elif type(k) == tuple:
|
||||||
|
if not pdict.has_key(k[0]):
|
||||||
|
pdict[k[0]] = k[1]
|
||||||
|
else:
|
||||||
|
pdict[k[0]] = max(k[1], pdict[k[0]])
|
||||||
|
csrc.append("catalog['%s'][%d] = '%s';\n" % (javascript_quote(k[0]), k[1], javascript_quote(v)))
|
||||||
|
else:
|
||||||
|
raise TypeError, k
|
||||||
|
csrc.sort()
|
||||||
|
for k,v in pdict.items():
|
||||||
|
src.append("catalog['%s'] = [%s];\n" % (javascript_quote(k), ','.join(["''"]*(v+1))))
|
||||||
|
src.extend(csrc)
|
||||||
|
src.append(LibFoot)
|
||||||
|
src.append(InterPolate)
|
||||||
|
src = ''.join(src)
|
||||||
|
return httpwrappers.HttpResponse(src, 'text/javascript')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue