Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
  • Loading branch information...
commit 5917fdcf2d07e54e7d83076b26e22bcadf65eb54 1 parent 946bd1e
Georg Bauer authored
View
55 django/bin/make-messages.py
@@ -7,6 +7,8 @@
from django.utils.translation import templateize
+pythonize_re = re.compile(r'\n\s*//')
+
localedir = None
if os.path.isdir(os.path.join('conf', 'locale')):
@@ -39,6 +41,9 @@
elif o == '-a':
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:
print "usage: make-messages.py -l <language>"
print " or: make-messages.py -a"
@@ -66,7 +71,28 @@
for (dirpath, dirnames, filenames) in os.walk("."):
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
if file.endswith('.html'):
src = open(os.path.join(dirpath, file), "rb").read()
@@ -91,22 +117,23 @@
if thefile != file:
os.unlink(os.path.join(dirpath, thefile))
- (stdin, stdout, stderr) = os.popen3('msguniq %s' % potfile, 'b')
- msgs = stdout.read()
- 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')
+ if os.path.exists(potfile):
+ (stdin, stdout, stderr) = os.popen3('msguniq %s' % potfile, 'b')
msgs = stdout.read()
errors = stderr.read()
if errors:
- print "errors happened while running msgmerge"
+ print "errors happened while running msguniq"
print errors
sys.exit(8)
- open(pofile, 'wb').write(msgs)
- os.unlink(potfile)
+ 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()
+ 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
19 django/utils/text.py
@@ -1,5 +1,7 @@
import re
+from django.conf.settings import DEFAULT_CHARSET
+
# Capitalizes the first letter of a string.
capfirst = lambda x: x and x[0].upper() + x[1:]
@@ -90,3 +92,20 @@ def compress_string(s):
zfile.write(s)
zfile.close()
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
15 django/utils/translation.py
@@ -212,6 +212,21 @@ def get_language():
from django.conf.settings import 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):
"""
This function will be patched into the builtins module to provide the _
View
169 django/views/i18n.py
@@ -1,5 +1,12 @@
+import re
+import os
+
+import gettext as gettext_module
+
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):
"""
@@ -20,3 +27,163 @@ def set_language(request):
else:
response.set_cookie('django_language', lang_code)
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')
+
Please sign in to comment.
Something went wrong with that request. Please try again.