This repository has been archived by the owner on May 12, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
commands.py
226 lines (186 loc) · 7.39 KB
/
commands.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import os
from subprocess import PIPE, Popen, call
from tempfile import TemporaryFile
from babel.messages.catalog import Catalog
from babel.messages.extract import extract_from_dir
from babel.messages.pofile import write_po
from django.conf import settings
from django.core.management.base import CommandError
from puente.utils import monkeypatch_i18n
def generate_options_map():
"""Generate an ``options_map` to pass to ``extract_from_dir``
This is the options_map that's used to generate a Jinja2 environment. We
want to generate and environment for extraction that's the same as the
environment we use for rendering.
This allows developers to explicitly set a ``JINJA2_CONFIG`` in settings.
If that's not there, then this will pull the relevant bits from the first
Jinja2 backend listed in ``TEMPLATES``.
"""
try:
return settings.PUENTE['JINJA2_CONFIG']
except KeyError:
pass
# If using Django 1.8+, we can skim the TEMPLATES for a backend that we
# know about and extract the settings from that.
for tmpl_config in getattr(settings, 'TEMPLATES', []):
try:
backend = tmpl_config['BACKEND']
except KeyError:
continue
if backend == 'django_jinja.backend.Jinja2':
extensions = tmpl_config.get('OPTIONS', {}).get('extensions', [])
return {
'**.*': {
'extensions': ','.join(extensions),
'silent': 'False',
}
}
# If this is Django 1.7 and Jingo, try to grab extensions from
# JINJA_CONFIG.
if getattr(settings, 'JINJA_CONFIG'):
jinja_config = settings.JINJA_CONFIG
if callable(jinja_config):
jinja_config = jinja_config()
return {
'**.*': {
'extensions': ','.join(jinja_config['extensions']),
'silent': 'False',
}
}
raise CommandError(
'No valid jinja2 config found in settings. See configuration '
'documentation.'
)
def extract_command(outputdir, domain_methods, text_domain, keywords,
comment_tags, base_dir, project, version,
msgid_bugs_address):
"""Extracts strings into .pot files
:arg domain: domains to generate strings for or 'all' for all domains
:arg outputdir: output dir for .pot files; usually
locale/templates/LC_MESSAGES/
:arg domain_methods: DOMAIN_METHODS setting
:arg text_domain: TEXT_DOMAIN settings
:arg keywords: KEYWORDS setting
:arg comment_tags: COMMENT_TAGS setting
:arg base_dir: BASE_DIR setting
:arg project: PROJECT setting
:arg version: VERSION setting
:arg msgid_bugs_address: MSGID_BUGS_ADDRESS setting
"""
# Must monkeypatch first to fix i18n extensions stomping issues!
monkeypatch_i18n()
# Create the outputdir if it doesn't exist
outputdir = os.path.abspath(outputdir)
if not os.path.isdir(outputdir):
print('Creating output dir %s ...' % outputdir)
os.makedirs(outputdir)
domains = domain_methods.keys()
def callback(filename, method, options):
if method != 'ignore':
print(' %s' % filename)
# Extract string for each domain
for domain in domains:
print('Extracting all strings in domain %s...' % domain)
methods = domain_methods[domain]
catalog = Catalog(
header_comment='',
project=project,
version=version,
msgid_bugs_address=msgid_bugs_address,
charset='utf-8',
)
extracted = extract_from_dir(
base_dir,
method_map=methods,
options_map=generate_options_map(),
keywords=keywords,
comment_tags=comment_tags,
callback=callback,
)
for filename, lineno, msg, cmts, ctxt in extracted:
catalog.add(msg, None, [(filename, lineno)], auto_comments=cmts,
context=ctxt)
with open(os.path.join(outputdir, '%s.pot' % domain), 'wb') as fp:
write_po(fp, catalog, width=80)
print('Done')
def merge_command(create, backup, base_dir, domain_methods, languages):
"""
:arg create: whether or not to create directories if they don't
exist
:arg backup: whether or not to create backup .po files
:arg base_dir: BASE_DIR setting
:arg domain_methods: DOMAIN_METHODS setting
:arg languages: LANGUAGES setting
"""
locale_dir = os.path.join(base_dir, 'locale')
# Verify existence of msginit and msgmerge
if not call(['which', 'msginit'], stdout=PIPE) == 0:
raise CommandError('You do not have gettext installed.')
if not call(['which', 'msgmerge'], stdout=PIPE) == 0:
raise CommandError('You do not have gettext installed.')
if languages and isinstance(languages[0], (tuple, list)):
# Django's LANGUAGES setting takes a value like:
#
# LANGUAGES = (
# ('de', _('German')),
# ('en', _('English')),
# )
#
# but we only want the language codes, so we pull the first
# part from all the tuples.
languages = [lang[0] for lang in languages]
if create:
for lang in languages:
d = os.path.join(locale_dir, lang.replace('-', '_'),
'LC_MESSAGES')
if not os.path.exists(d):
os.makedirs(d)
domains = domain_methods.keys()
for domain in domains:
print('Merging %s strings to each locale...' % domain)
domain_pot = os.path.join(locale_dir, 'templates', 'LC_MESSAGES',
'%s.pot' % domain)
if not os.path.isfile(domain_pot):
raise CommandError('Can not find %s.pot' % domain)
for locale in os.listdir(locale_dir):
if ((not os.path.isdir(os.path.join(locale_dir, locale)) or
locale.startswith('.') or
locale == 'templates')):
continue
domain_po = os.path.join(locale_dir, locale, 'LC_MESSAGES',
'%s.po' % domain)
if not os.path.isfile(domain_po):
print(' Can not find (%s). Creating...' % domain_po)
p1 = Popen([
'msginit',
'--no-translator',
'--locale=%s' % locale,
'--input=%s' % domain_pot,
'--output-file=%s' % domain_po,
'--width=200'
])
p1.communicate()
print('Merging %s.po for %s' % (domain, locale))
domain_pot_file = open(domain_pot)
if locale == 'en_US':
enmerged = TemporaryFile('w+t')
p2 = Popen(['msgen', '-'], stdin=domain_pot_file,
stdout=enmerged)
p2.communicate()
mergeme = enmerged
else:
mergeme = domain_pot_file
mergeme.seek(0)
command = [
'msgmerge',
'--update',
'--width=200',
'--backup=%s' % ('simple' if backup else 'off'),
domain_po,
'-'
]
p3 = Popen(command, stdin=mergeme)
p3.communicate()
mergeme.close()
print('Domain %s finished' % domain)
print('All finished')