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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
|
#!/usr/bin/env python
import os
import shutil
import fnmatch
import json
import re
from optparse import OptionParser
import logging
section_line = re.compile('\[(?P<section>.*)\]')
import_line = re.compile('@import url\((?P<filename>.*)\)')
property_line = re.compile('(?P<id>.*)\s*[:=]\s*(?P<value>.*)')
def _get_locales(filename):
locales_list = json.load(open(filename), encoding="utf-8")
return locales_list.keys()
def find_files(dirs, pattern):
matches = []
for dir in dirs:
for current, dirnames, filenames in os.walk(dir):
for filename in fnmatch.filter(filenames, pattern):
matches.append(os.path.join(current, filename))
return matches
def parse_manifest_properties(filename):
with open(filename) as f:
data = f.readlines()
strings = {
"default": {},
"entry_points": {},
}
for line in data:
m = property_line.search(line)
if not m or line.strip().startswith('#'):
continue
value = m.group('value').strip()
if '.' in m.group('id'):
entry_point, key = m.group('id').split('.',1)
if entry_point not in strings["entry_points"]:
strings["entry_points"][entry_point] = {}
strings["entry_points"][entry_point][key.strip()] = value
else:
key = m.group('id')
strings["default"][key.strip()] = value
return strings
def parse_ini(filename):
log = logging.getLogger(__name__)
with open(filename) as f:
data = f.readlines()
section = 'default'
imports = { section: [] }
for line in data:
if line.strip() == "" or line.startswith('!') or line.startswith('#'):
continue
elif line.strip().startswith('['): # Section header
section = section_line.search(line).group('section')
imports[section] = []
elif '@import' in line: # Import lines
property_file = import_line.search(line).group('filename')
imports[section].append(property_file)
else:
log.warn('parse_ini - found a line with contents '
'unaccounted for "%s"', line.strip())
return imports
def serialize_ini(outfile, imports):
def _section(locale):
return "[%s]" % locale
def _import(path):
return "@import url(%s)" % path
output = []
for locale, paths in imports.items():
if locale == "default":
for path in paths:
output.insert(0, _import(path))
continue
output.append(_section(locale))
for path in paths:
output.append(_import(path))
with open(outfile, 'w') as o:
o.write("\n".join(output))
def add_locale_imports(locales, ini_file):
"""Recreate an ini file with all locales sections"""
log = logging.getLogger(__name__)
imports = {
"default": parse_ini(ini_file)["default"]
}
for locale in locales:
log.info("adding %s to %s" % (locale, ini_file))
imports[locale] = []
for path in imports["default"]:
locale_path = path.replace("en-US", locale)
imports[locale].append(locale_path)
log.debug("added %s" % locale_path)
serialize_ini(ini_file, imports)
log.info("updated %s saved" % ini_file)
def copy_properties(source, locales, ini_file):
log = logging.getLogger(__name__)
ini_dirname = os.path.dirname(ini_file)
imports = parse_ini(ini_file)
for locale in locales:
log.info("copying %s files as per %s" % (locale, ini_file))
for path in imports[locale]:
target_path = os.path.join(ini_dirname, path)
# apps/browser/locales/browser.fr.properties becomes
# apps/browser/browser.properties
source_path = target_path.replace('/locales', '') \
.replace('.%s' % locale, '')
source_path = os.path.join(source, locale, source_path)
if not os.path.exists(source_path):
log.warn('%s does not exist' % source_path)
continue
shutil.copy(source_path, target_path)
log.debug("copied %s to %s" % (source_path, target_path))
def add_locale_manifest(source, locales, manifest_file):
log = logging.getLogger(__name__)
with open(manifest_file) as f:
manifest = json.load(f, encoding="utf-8")
for locale in locales:
log.info("adding %s to %s" % (locale, manifest_file))
manifest_properties = os.path.join(source, locale,
os.path.dirname(manifest_file),
'manifest.properties')
log.debug("getting strings from %s" % manifest_properties)
if not os.path.exists(manifest_properties):
log.warn("%s does not exist" % manifest_properties)
continue
strings = parse_manifest_properties(manifest_properties)
if "entry_points" in manifest:
for name, ep in manifest["entry_points"].items():
if "locales" not in ep:
continue
log.debug("adding to entry_points.%s.locales" % name)
if name not in strings["entry_points"]:
log.warn("%s.* strings are missing from %s" %
(name, manifest_properties))
continue
ep["locales"][locale] = {}
ep["locales"][locale].update(strings["entry_points"][name])
if "locales" in manifest:
log.debug("adding to locales")
manifest["locales"][locale] = {}
manifest["locales"][locale].update(strings["default"])
f.close()
with open(manifest_file, 'w') as o:
json.dump(manifest, o, encoding="utf-8", indent=2)
log.debug("updated %s saved" % manifest_file)
def setup_logging(volume=1, console=True, filename=None):
logger = logging.getLogger(__name__)
levels = [logging.DEBUG,
logging.INFO,
logging.WARNING,
logging.ERROR,
logging.CRITICAL][::1]
if volume > len(levels):
volume = len(levels) - 1
elif volume < 0:
volume = 0
logger.setLevel(levels[len(levels)-volume])
if console:
console_handler = logging.StreamHandler()
console_formatter = logging.Formatter('%(levelname)s: %(message)s')
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)
if filename:
file_handler = logging.FileHandler(filename)
file_formatter = logging.Formatter('%(asctime) - %(levelname)s: %(message)s')
file_handler.addFormatter(file_formatter)
logger.addHandler(file_handler)
def main():
parser = OptionParser("%prog [OPTIONS] [LOCALES...] - create multilocale Gaia")
parser.add_option("-v", "--verbose",
action="count", dest="verbose", default=2,
help="use more to make louder")
parser.add_option("-i", "--ini",
action="store_true", dest="onlyini", default=False,
help=("just edit the ini files and exit; "
"use this with DEBUG=1 make profile"))
parser.add_option("--target",
action="append", dest="target",
help=("path to directory to make changes in "
"(more than one is fine)"))
parser.add_option("--source",
action="store", dest="source",
help="path to the l10n basedir")
parser.add_option("--config",
action="store", dest="config_file",
help=("path to the languages.json config file; "
"will be used instead of LOCALES"))
options, locales = parser.parse_args()
setup_logging(volume=options.verbose)
log = logging.getLogger(__name__)
if options.config_file is not None:
locales = _get_locales(options.config_file)
log.debug("config file specified; ignoring any locales passed as args")
elif len(locales) == 0:
parser.error("You need to specify --config or pass the list of locales")
if options.target is None:
parser.error("You need to specify at least one --target")
if options.source is None and not options.onlyini:
parser.error("You need to specify --source (unless you meant --ini)")
if "en-US" in locales:
locales.remove("en-US")
ini_files = find_files(options.target, "*.ini")
# 1. link properties files from the inis
for ini_file in ini_files:
log.info("########## adding locale import rules to %s" % ini_file)
add_locale_imports(locales, ini_file)
if options.onlyini:
parser.exit(1)
# 2. copy properties files as per the inis
for ini_file in ini_files:
log.info("########## copying locale files as per %s" % ini_file)
copy_properties(options.source, locales, ini_file)
# 3. edit manifests
manifest_files = find_files(options.target, 'manifest.webapp')
for manifest_file in manifest_files:
log.info("########## adding localized names to %s" % manifest_file)
add_locale_manifest(options.source, locales, manifest_file)
if __name__ == "__main__":
main()
|