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:
Georg Bauer 2005-12-04 12:06:16 +00:00
parent 946bd1e370
commit 5917fdcf2d
4 changed files with 243 additions and 15 deletions

View File

@ -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,22 +117,23 @@ for lang in languages:
if thefile != file: if thefile != file:
os.unlink(os.path.join(dirpath, thefile)) os.unlink(os.path.join(dirpath, thefile))
(stdin, stdout, stderr) = os.popen3('msguniq %s' % potfile, 'b') if os.path.exists(potfile):
msgs = stdout.read() (stdin, stdout, stderr) = os.popen3('msguniq %s' % potfile, 'b')
errors = stderr.read()
if errors:
print "errors happened while running msguniq"
print errors
sys.exit(8)
open(potfile, 'w').write(msgs)
if os.path.exists(pofile):
(stdin, stdout, stderr) = os.popen3('msgmerge -q %s %s' % (pofile, potfile), 'b')
msgs = stdout.read() msgs = stdout.read()
errors = stderr.read() errors = stderr.read()
if errors: if errors:
print "errors happened while running msgmerge" print "errors happened while running msguniq"
print errors print errors
sys.exit(8) sys.exit(8)
open(pofile, 'wb').write(msgs) open(potfile, 'w').write(msgs)
os.unlink(potfile) if os.path.exists(pofile):
(stdin, stdout, stderr) = os.popen3('msgmerge -q %s %s' % (pofile, potfile), 'b')
msgs = stdout.read()
errors = stderr.read()
if errors:
print "errors happened while running msgmerge"
print errors
sys.exit(8)
open(pofile, 'wb').write(msgs)
os.unlink(potfile)

View File

@ -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))

View File

@ -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 _

View File

@ -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')