Skip to content
This repository was archived by the owner on Mar 1, 2022. It is now read-only.

Commit 48cbce7

Browse files
author
Fred Wenzel
committed
Added tower to extract normalized msgids from Django templates. Bug 647352.
1 parent 816a725 commit 48cbce7

File tree

17 files changed

+3061
-736
lines changed

17 files changed

+3061
-736
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
*.py[co]
2-
*.pot
32
*.mo
3+
*.[mp]o~
44
ffenv
55

66
ffdemo/settings_local.py

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,26 @@ Apache, do this:
117117
AddType image/svg+xml svg
118118

119119

120-
## Javascript
120+
## Javascript (Minification)
121121

122-
[Jim][Jim] is used for managing the javascript in Mozilla MarkUp. More information is available [here][Jim].
122+
[Jim][Jim] is used for managing the JavaScript in Mozilla MarkUp. More information is available [here][Jim].
123123
[Jim]: https://github.com/quirkey/jim
124+
125+
126+
## L10n
127+
128+
Markup uses the [tower][tower] library for string extraction. To extract
129+
strings from template files, run something like:
130+
131+
./manage.py extract
132+
./manage.py verbatimize --rename
133+
./manage.py merge
134+
135+
For more information, consult the tower docs.
136+
137+
To compile .po files into .mo, run:
138+
139+
cd locale
140+
./compile-mo.sh .
141+
142+
[tower]: https://github.com/clouserw/tower

ffdemo/lib/__init__.py

Whitespace-only changes.

ffdemo/lib/shoehorn_l10n/__init__.py

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Monkeypatch to normalize blocktrans msgids to work with tower."""
2+
3+
from tower import strip_whitespace
4+
5+
from django.templatetags import i18n
6+
7+
8+
OldBlockTranslateNode = i18n.BlockTranslateNode
9+
10+
class ShoehornedBlockTranslateNode(OldBlockTranslateNode):
11+
def render_token_list(self, tokens):
12+
"""Strip whitespace from msgid before letting gettext touch it."""
13+
rendered = super(ShoehornedBlockTranslateNode, self).render_token_list(
14+
tokens)
15+
return strip_whitespace(rendered[0]), rendered[1]
16+
17+
18+
def monkeypatch():
19+
i18n.BlockTranslateNode = ShoehornedBlockTranslateNode
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""Modified Django templatize utility to translate Django L10n into something almost usable by Jinja2."""
2+
3+
from cStringIO import StringIO
4+
import re
5+
6+
7+
dot_re = re.compile(r'\S')
8+
def blankout(src, char):
9+
"""
10+
Changes every non-whitespace character to the given char.
11+
Used in the templatize function.
12+
"""
13+
return dot_re.sub(char, src)
14+
15+
inline_re = re.compile(r"""^\s*trans\s+((?:".*?")|(?:'.*?'))\s*""")
16+
block_re = re.compile(r"""^\s*blocktrans(?:\s+|$)""")
17+
endblock_re = re.compile(r"""^\s*endblocktrans$""")
18+
plural_re = re.compile(r"""^\s*plural$""")
19+
constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?'))\)""")
20+
21+
def templatize(src):
22+
"""
23+
Turns a Django template into something that is understood by xgettext. It
24+
does so by translating the Django translation tags into standard gettext
25+
function invocations.
26+
"""
27+
from django.template import Lexer, TOKEN_TEXT, TOKEN_VAR, TOKEN_BLOCK
28+
out = StringIO()
29+
intrans = False
30+
inplural = False
31+
singular = []
32+
plural = []
33+
for t in Lexer(src, None).tokenize():
34+
if intrans:
35+
if t.token_type == TOKEN_BLOCK:
36+
endbmatch = endblock_re.match(t.contents)
37+
pluralmatch = plural_re.match(t.contents)
38+
if endbmatch:
39+
if inplural:
40+
out.write(' {{ ngettext(%r,%r,count) }} ' % (''.join(singular), ''.join(plural)))
41+
for part in singular:
42+
out.write(blankout(part, 'S'))
43+
for part in plural:
44+
out.write(blankout(part, 'P'))
45+
else:
46+
out.write(' {{ gettext(%r) }} ' % ''.join(singular))
47+
for part in singular:
48+
out.write(blankout(part, 'S'))
49+
intrans = False
50+
inplural = False
51+
singular = []
52+
plural = []
53+
elif pluralmatch:
54+
inplural = True
55+
else:
56+
raise SyntaxError("Translation blocks must not include other block tags: %s" % t.contents)
57+
elif t.token_type == TOKEN_VAR:
58+
if inplural:
59+
plural.append('%%(%s)s' % t.contents)
60+
else:
61+
singular.append('%%(%s)s' % t.contents)
62+
elif t.token_type == TOKEN_TEXT:
63+
if inplural:
64+
plural.append(t.contents)
65+
else:
66+
singular.append(t.contents)
67+
else:
68+
if t.token_type == TOKEN_BLOCK:
69+
imatch = inline_re.match(t.contents)
70+
bmatch = block_re.match(t.contents)
71+
cmatches = constant_re.findall(t.contents)
72+
if imatch:
73+
g = imatch.group(1)
74+
if g[0] == '"': g = g.strip('"')
75+
elif g[0] == "'": g = g.strip("'")
76+
out.write(' {{ gettext(%r) }} ' % g)
77+
elif bmatch:
78+
for fmatch in constant_re.findall(t.contents):
79+
out.write(' {{ _(%s) }} ' % fmatch)
80+
intrans = True
81+
inplural = False
82+
singular = []
83+
plural = []
84+
elif cmatches:
85+
for cmatch in cmatches:
86+
out.write(' {{ _(%s) }} ' % cmatch)
87+
else:
88+
out.write(blankout(t.contents, 'B'))
89+
elif t.token_type == TOKEN_VAR:
90+
parts = t.contents.split('|')
91+
cmatch = constant_re.match(parts[0])
92+
if cmatch:
93+
out.write(' {{ _(%s) }} ' % cmatch.group(1))
94+
for p in parts[1:]:
95+
if p.find(':_(') >= 0:
96+
out.write(' %s ' % p.split(':',1)[1])
97+
else:
98+
out.write(blankout(p, 'F'))
99+
else:
100+
out.write(blankout(t.contents, 'X'))
101+
return out.getvalue()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Teach tower L10n library to hopefully extract from django templates."""
2+
from StringIO import StringIO
3+
4+
from tower.management.commands.extract import (extract_tower_template,
5+
tweak_message)
6+
from lib.shoehorn_l10n.templatize import templatize
7+
8+
9+
def extract_django_template(fileobj, keywords, comment_tags, options):
10+
src = fileobj.read()
11+
templatized = StringIO(templatize(src))
12+
return extract_tower_template(templatized, keywords, comment_tags, options)

ffdemo/locale/compile-mo.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
# syntax:
4+
# compile-mo.sh locale-dir/
5+
6+
function usage() {
7+
echo "syntax:"
8+
echo "compile.sh locale-dir/"
9+
exit 1
10+
}
11+
12+
# check if file and dir are there
13+
if [[ ($# -ne 1) || (! -d "$1") ]]; then usage; fi
14+
15+
for lang in `find $1 -type f -name "*.po"`; do
16+
dir=`dirname $lang`
17+
stem=`basename $lang .po`
18+
msgfmt -o ${dir}/${stem}.mo $lang
19+
done

0 commit comments

Comments
 (0)