|
1
by Fabien Tassin
* Initial revision |
1 |
#!/usr/bin/python
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2 |
# -*- coding: utf-8 -*-
|
|
1
by Fabien Tassin
* Initial revision |
3 |
|
|
65
by Fabien Tassin
* Bump the (c) to 2011 |
4 |
# (c) 2010-2011, Fabien Tassin <fta@ubuntu.com>
|
|
1
by Fabien Tassin
* Initial revision |
5 |
|
6 |
# Convert grd/xtb files into pot/po for integration into the Launchpad
|
|
7 |
# translation system
|
|
8 |
||
9 |
## grd files contain the strings for the 'pot' file(s).
|
|
10 |
## Keys are alphabetical (IDS_XXX).
|
|
11 |
# Sources:
|
|
12 |
# - $SRC/chrome/app/*.grd
|
|
13 |
# - $SRC/webkit/glue/*.grd
|
|
14 |
||
15 |
## xtb files are referenced to by the grd files. They contain the translated
|
|
16 |
## strings for the 'po' our files. Keys are numerical (64bit ids).
|
|
17 |
# Sources:
|
|
18 |
# - $SRC/chrome/app/resources/*.xtb
|
|
19 |
# - $SRC/webkit/glue/resources/*.xtb
|
|
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
20 |
# and for launchpad contributed strings that already landed:
|
|
86
by Fabien Tassin
* Move third_party/launchpad_translations/ outside of the chrome/ dir |
21 |
# - $SRC/third_party/launchpad_translations/*.xtb
|
|
1
by Fabien Tassin
* Initial revision |
22 |
|
23 |
## the mapping between those keys is done using FingerPrint()
|
|
24 |
## [ taken from grit ] on a stripped version of the untranslated string
|
|
25 |
||
26 |
## grd files contain a lot of <if expr="..."> (python-like) conditions.
|
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
27 |
## Evaluate those expressions but only skip strings with a lang restriction.
|
28 |
## For all other conditions (os, defines), simply expose them so translators
|
|
29 |
## know when a given string is expected.
|
|
30 |
||
31 |
## TODO: handle <message translateable="false">
|
|
|
1
by Fabien Tassin
* Initial revision |
32 |
|
|
46
by Fabien Tassin
* Add a link back to the faulty strings in launchpad in the logs |
33 |
import os, sys, shutil, re, getopt, codecs, urllib |
|
1
by Fabien Tassin
* Initial revision |
34 |
from xml.dom import minidom |
35 |
from xml.sax.saxutils import unescape |
|
36 |
from datetime import datetime |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
37 |
from difflib import unified_diff |
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
38 |
import textwrap, filecmp, json |
|
1
by Fabien Tassin
* Initial revision |
39 |
|
|
8
by Fabien Tassin
* Add a lang-mapping table to allow locales renaming (like no->nb, pt-PT->pt) |
40 |
lang_mapping = { |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
41 |
'no': 'nb', # 'no' is obsolete and the more specific 'nb' (Norwegian Bokmal) |
42 |
# and 'nn' (Norwegian Nynorsk) are preferred.
|
|
|
8
by Fabien Tassin
* Add a lang-mapping table to allow locales renaming (like no->nb, pt-PT->pt) |
43 |
'pt-PT': 'pt' |
44 |
}
|
|
45 |
||
|
1
by Fabien Tassin
* Initial revision |
46 |
####
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
47 |
# vanilla from $SRC/tools/grit/grit/extern/FP.py (r10982)
|
48 |
# See svn log http://src.chromium.org/svn/trunk/src/tools/grit/grit/extern/FP.py
|
|
49 |
||
50 |
# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
|
51 |
# Use of this source code is governed by a BSD-style license that can be
|
|
52 |
# found in the LICENSE file.
|
|
53 |
||
|
1
by Fabien Tassin
* Initial revision |
54 |
try: |
55 |
import hashlib |
|
56 |
_new_md5 = hashlib.md5 |
|
57 |
except ImportError: |
|
58 |
import md5 |
|
59 |
_new_md5 = md5.new |
|
60 |
||
61 |
def UnsignedFingerPrint(str, encoding='utf-8'): |
|
62 |
"""Generate a 64-bit fingerprint by taking the first half of the md5
|
|
63 |
of the string."""
|
|
64 |
hex128 = _new_md5(str).hexdigest() |
|
65 |
int64 = long(hex128[:16], 16) |
|
66 |
return int64 |
|
67 |
||
68 |
def FingerPrint(str, encoding='utf-8'): |
|
69 |
fp = UnsignedFingerPrint(str, encoding=encoding) |
|
70 |
# interpret fingerprint as signed longs
|
|
71 |
if fp & 0x8000000000000000L: |
|
72 |
fp = - ((~fp & 0xFFFFFFFFFFFFFFFFL) + 1) |
|
73 |
return fp |
|
74 |
####
|
|
75 |
||
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
76 |
class EvalConditions: |
77 |
""" A class allowing an <if expr="xx"/> to be evaluated, based on an array of defines,
|
|
78 |
a dict of local variables.
|
|
79 |
As of Chromium 10:
|
|
80 |
- the known defines are:
|
|
81 |
[ 'chromeos', '_google_chrome', 'toolkit_views', 'touchui', 'use_titlecase' ]
|
|
82 |
On Linux, only [ 'use_titlecase' ] is set.
|
|
83 |
- the known variables are:
|
|
84 |
'os' ('linux2' on Linux)
|
|
85 |
'lang'
|
|
86 |
See http://src.chromium.org/svn/trunk/src/build/common.gypi
|
|
87 |
"""
|
|
88 |
||
89 |
def eval(self, expression, defines = [ 'use_titlecase' ], vars = { 'os': "linux2" }): |
|
90 |
||
91 |
def pp_ifdef(match): |
|
92 |
return str(match.group(1) in defines) |
|
93 |
||
94 |
# evaluate all ifdefs
|
|
95 |
expression = re.sub(r"pp_ifdef\('(.*?)'\)", pp_ifdef, expression) |
|
96 |
# evaluate the whole expression using the vars dict
|
|
97 |
vars['__builtins__'] = { 'True': True, 'False': False } # prevent eval from using the real current globals |
|
98 |
return eval(expression, vars) |
|
99 |
||
100 |
def lang_eval(self, expression, lang): |
|
101 |
""" only evaluate the expression against the lang, ignore all defines and other variables.
|
|
102 |
This is needed to ignore a string that has lang restrictions (numerals, plurals, ..) but
|
|
103 |
still keep it even if it's OS or defined don't match the local platform.
|
|
104 |
"""
|
|
105 |
conditions = [ x for x in re.split(r'\s+(and|or)\s+', expression) if x.find('lang') >= 0 ] |
|
106 |
if len(conditions) == 0: |
|
107 |
return True |
|
108 |
assert len(conditions) == 1, "Expression '%s' has multiple lang conditions" % expression |
|
109 |
vars = { 'lang': lang, '__builtins__': { 'True': True, 'False': False } } |
|
110 |
return eval(conditions[0], vars) |
|
111 |
||
112 |
def test(self): |
|
113 |
data = [ |
|
114 |
{ 'expr': "lang == 'ar'", |
|
115 |
'vars': { 'lang': 'ar' }, |
|
116 |
'result': True |
|
117 |
},
|
|
118 |
{ 'expr': "lang == 'ar'", |
|
119 |
'vars': { 'lang': 'fr' }, |
|
120 |
'result': False |
|
121 |
},
|
|
122 |
{ 'expr': "lang in ['ar', 'ro', 'lv']", |
|
123 |
'vars': { 'lang': 'ar' }, |
|
124 |
'result': True |
|
125 |
},
|
|
126 |
{ 'expr': "lang in ['ar', 'ro', 'lv']", |
|
127 |
'vars': { 'lang': 'pt-BR' }, |
|
128 |
'result': False |
|
129 |
},
|
|
130 |
{ 'expr': "lang not in ['ar', 'ro', 'lv']", |
|
131 |
'vars': { 'lang': 'ar' }, |
|
132 |
'result': False |
|
133 |
},
|
|
134 |
{ 'expr': "lang not in ['ar', 'ro', 'lv']", |
|
135 |
'vars': { 'lang': 'no' }, |
|
136 |
'result': True |
|
137 |
},
|
|
138 |
{ 'expr': "os != 'linux2' and os != 'darwin' and os.find('bsd') == -1", |
|
139 |
'vars': { 'lang': 'no', 'os': 'bsdos' }, |
|
140 |
'result': False, |
|
141 |
'lresult': True # no lang restriction in 'expr', so 'no' is ok |
|
142 |
},
|
|
143 |
{ 'expr': "os != 'linux2' and os != 'darwin' and os.find('bsd') > -1", |
|
144 |
'vars': { 'lang': 'no', 'os': 'bsdos' }, |
|
145 |
'result': True, |
|
146 |
},
|
|
147 |
{ 'expr': "not pp_ifdef('chromeos')", |
|
148 |
'vars': { 'lang': 'no' }, |
|
149 |
'defines': [], |
|
150 |
'result': True, |
|
151 |
},
|
|
152 |
{ 'expr': "not pp_ifdef('chromeos')", |
|
153 |
'vars': { 'lang': 'no' }, |
|
154 |
'defines': [ 'chromeos' ], |
|
155 |
'result': False, |
|
156 |
'lresult': True # no lang restriction in 'expr', so 'no' is ok |
|
157 |
},
|
|
158 |
{ 'expr': "pp_ifdef('_google_chrome') and (os == 'darwin')", |
|
159 |
'vars': { 'lang': 'no', 'os': 'linux2' }, |
|
160 |
'defines': [ 'chromeos' ], |
|
161 |
'result': False, |
|
162 |
'lresult': True # no lang restriction in 'expr', so 'no' is ok |
|
163 |
},
|
|
164 |
{ 'expr': "pp_ifdef('_google_chrome') and (os == 'darwin')", |
|
165 |
'vars': { 'lang': 'no', 'os': 'darwin' }, |
|
166 |
'defines': [ '_google_chrome' ], |
|
167 |
'result': True |
|
168 |
},
|
|
169 |
{ 'expr': "not pp_ifdef('chromeos') and pp_ifdef('_google_chrome') and 'pt-PT' == lang", |
|
170 |
'vars': { 'lang': 'pt-PT', 'os': 'darwin' }, |
|
171 |
'defines': [ '_google_chrome' ], |
|
172 |
'result': True |
|
173 |
},
|
|
174 |
{ 'expr': "not pp_ifdef('chromeos') and pp_ifdef('_google_chrome') and 'pt-PT' == lang", |
|
175 |
'vars': { 'lang': 'pt-PT', 'os': 'darwin' }, |
|
176 |
'defines': [ ], |
|
177 |
'result': False, |
|
178 |
'lresult': True |
|
179 |
},
|
|
180 |
]
|
|
181 |
i = -1 |
|
182 |
for d in data: |
|
183 |
i += 1 |
|
184 |
defines = d['defines'] if 'defines' in d else [] |
|
185 |
vars = d['vars'] if 'vars' in d else {} |
|
186 |
lvars = vars.copy() # make a copy because eval modifies it |
|
187 |
res = self.eval(d['expr'], defines = defines, vars = lvars) |
|
188 |
assert res == d['result'], "FAILED %d: expr: \"%s\" returned %s with vars = %s and defines = %s" % \ |
|
189 |
(i, d['expr'], repr(res), repr(vars), repr(defines)) |
|
190 |
print "All %d tests passed for EvalConditions.eval()" % (i + 1) |
|
191 |
i = -1 |
|
192 |
for d in data: |
|
193 |
i += 1 |
|
194 |
assert 'lang' in vars, "All test must have a 'lang' in 'vars', test %d doesn't: %s" % (i, repr(d)) |
|
195 |
res = self.lang_eval(d['expr'], lang = d['vars']['lang']) |
|
196 |
expected = d['lresult'] if 'lresult' in d else d['result'] |
|
197 |
assert res == expected, "FAILED %d: expr: \"%s\" returned %s with lang = %s for the lang_eval test" % \ |
|
198 |
(i, d['expr'], repr(res), d['vars']['lang']) |
|
199 |
print "All %d tests passed for EvalConditions.lang_eval()" % (i + 1) |
|
200 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
201 |
class StringCvt: |
202 |
""" A class converting grit formatted strings to gettext back and forth.
|
|
203 |
The idea is to always have:
|
|
204 |
a/ grd2gettext(xtb2gettext(s)) == s
|
|
205 |
b/ xtb2gettext(s) produces a string that the msgfmt checker likes and
|
|
206 |
that makes sense to translators
|
|
207 |
c/ grd2gettext(s) produces a string acceptable by upstream
|
|
208 |
"""
|
|
209 |
||
210 |
def xtb2gettext(self, string): |
|
211 |
""" parse the xtb (xml encoded) string and convert it to a gettext string """
|
|
212 |
||
213 |
def fold(string): |
|
214 |
return textwrap.wrap(string, break_long_words=False, width=76, drop_whitespace=False, |
|
215 |
expand_tabs=False, replace_whitespace=False, break_on_hyphens=False) |
|
216 |
||
217 |
s = string.replace('\\n', '\\\\n') |
|
218 |
# escape all single '\' (not followed by 'n')
|
|
219 |
s = re.sub(r'(?<!\\)(\\[^n\\\\])', r'\\\1', s) |
|
220 |
# remove all xml encodings
|
|
|
37
by Fabien Tassin
* Decode more xml entities (in the form of { and ) |
221 |
s = self.unescape_xml(s) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
222 |
# replace '<ph name="FOO"/>' by '%{FOO}'
|
223 |
s = re.sub(r'<ph name="(.*?)"/>', r'%{\1}', s) |
|
224 |
# fold
|
|
225 |
# 1/ fold at \n
|
|
226 |
# 2/ fold each part at ~76 char
|
|
227 |
v = [] |
|
228 |
ll = s.split('\n') |
|
229 |
sz = len(ll) |
|
230 |
if sz > 1: |
|
231 |
i = 0 |
|
232 |
for l in ll: |
|
233 |
i += 1 |
|
234 |
if i == sz: |
|
235 |
v.extend(fold(l)) |
|
236 |
else: |
|
237 |
v.extend(fold(l + '\\n')) |
|
238 |
else: |
|
239 |
v.extend(fold(ll[0])) |
|
240 |
if len(v) > 1: |
|
241 |
v[:0] = [ '' ] |
|
242 |
s = '"' + '"\n"'.join(v) + '"' |
|
243 |
return s |
|
244 |
||
|
40
by Fabien Tassin
* Split decode_xml_entities() away from unescape_xml() |
245 |
def decode_xml_entities(self, string): |
|
37
by Fabien Tassin
* Decode more xml entities (in the form of { and ) |
246 |
def replace_xmlent(match): |
247 |
if match.group(1)[:1] == 'x': |
|
248 |
return unichr(int("0" + match.group(1), 16)) |
|
249 |
else: |
|
250 |
return unichr(int(match.group(1))) |
|
251 |
||
|
40
by Fabien Tassin
* Split decode_xml_entities() away from unescape_xml() |
252 |
return re.sub(r'&#(x\w+|\d+);', replace_xmlent, string) |
253 |
||
254 |
def unescape_xml(self, string): |
|
|
37
by Fabien Tassin
* Decode more xml entities (in the form of { and ) |
255 |
string = unescape(string).replace('"', '\\"').replace(''', "'") |
|
40
by Fabien Tassin
* Split decode_xml_entities() away from unescape_xml() |
256 |
string = self.decode_xml_entities(string) |
|
37
by Fabien Tassin
* Decode more xml entities (in the form of { and ) |
257 |
return string |
258 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
259 |
def grd2gettext(self, string): |
260 |
""" parse the string returned from minidom and convert it to a gettext string.
|
|
261 |
This is similar to str_cvt_xtb2gettext but minidom has its own magic for encoding
|
|
262 |
"""
|
|
263 |
return self.xtb2gettext(string) |
|
264 |
||
265 |
def gettext2xtb(self, string): |
|
266 |
""" parse the gettext string and convert it to an xtb (xml encoded) string. """
|
|
267 |
u = [] |
|
268 |
for s in string.split(u'\n'): |
|
269 |
# remove the enclosing double quotes
|
|
|
19
by Fabien Tassin
* Fix gettext2xtb() when launchpad folds strings at a quoted LF |
270 |
u.append(s[1:][:-1]) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
271 |
s = u"".join(u) |
|
19
by Fabien Tassin
* Fix gettext2xtb() when launchpad folds strings at a quoted LF |
272 |
|
273 |
# encode the xml special chars
|
|
274 |
s = s.replace("&", "&") # must be first! |
|
275 |
s = s.replace("<", "<") |
|
276 |
s = s.replace(">", ">") |
|
277 |
s = s.replace('\\"', """) |
|
|
39
by Fabien Tassin
* Fix HTML comments wrongly quoted |
278 |
# special case, html comments
|
279 |
s = re.sub(r'<!--(.*?)-->', r'<!--\1-->', s, re.S) |
|
|
19
by Fabien Tassin
* Fix gettext2xtb() when launchpad folds strings at a quoted LF |
280 |
# replace non-ascii by &#xxx; codes
|
281 |
# s = s.encode("ascii", "xmlcharrefreplace")
|
|
282 |
# replace '%{FOO}' by '<ph name="FOO"/>'
|
|
283 |
s = re.sub(r'%{(.*?)}', r'<ph name="\1"/>', s) |
|
284 |
# unquote \\n and \\\\n
|
|
285 |
s = re.sub(r'(?<!\\)\\n', r'\n', s) |
|
286 |
# unquote all control chars
|
|
287 |
s = re.sub(r'\\\\([^\\])', r'\\\1', s) |
|
|
20
by Fabien Tassin
* Work-around Launchpad quoting tabs in po files |
288 |
|
289 |
# launchpad seems to always quote tabs
|
|
290 |
s = s.replace("\\t", "\t") |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
291 |
return s |
292 |
||
293 |
def test(self): |
|
294 |
# unit tests
|
|
295 |
data = [ |
|
296 |
# tab
|
|
297 |
{ 'id': '0', |
|
298 |
'xtb': u'foo bar', |
|
299 |
'po': u'"foo bar"' }, |
|
|
20
by Fabien Tassin
* Work-around Launchpad quoting tabs in po files |
300 |
{ 'id': '1', |
301 |
'xtb': u'foo\tbar', |
|
302 |
'po': u'"foo\tbar"' }, |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
303 |
# &
|
304 |
{ 'id': '6779164083355903755', |
|
305 |
'xtb': u'Supprime&r', |
|
306 |
'po': u'"Supprime&r"' }, |
|
307 |
# "
|
|
308 |
{ 'id': '4194570336751258953', |
|
309 |
'xtb': u'Activer la fonction "taper pour cliquer"', |
|
310 |
'po': u'"Activer la fonction \\"taper pour cliquer\\""' }, |
|
311 |
# < / >
|
|
312 |
{ 'id': '7615851733760445951', |
|
313 |
'xtb': u'<aucun cookie sélectionné>', |
|
314 |
'po': u'"<aucun cookie sélectionné>"' }, |
|
315 |
# <ph name="FOO"/>
|
|
316 |
{ 'id': '5070288309321689174', |
|
317 |
'xtb': u'<ph name="EXTENSION_NAME"/> :', |
|
318 |
'po': u'"%{EXTENSION_NAME} :"' }, |
|
319 |
{ 'id': '1467071896935429871', |
|
320 |
'xtb': u'Téléchargement de la mise à jour du système : <ph name="PERCENT"/>% terminé', |
|
321 |
'po': u'"Téléchargement de la mise à jour du système : %{PERCENT}% terminé"' }, |
|
322 |
# line folding
|
|
323 |
{ 'id': '1526811905352917883', |
|
324 |
'xtb': u'Une nouvelle tentative de connexion avec SSL 3.0 a dû être effectuée. Cette opération indique généralement que le serveur utilise un logiciel très ancien et qu\'il est susceptible de présenter d\'autres problèmes de sécurité.', |
|
325 |
'po': u'""\n"Une nouvelle tentative de connexion avec SSL 3.0 a dû être effectuée. Cette "\n"opération indique généralement que le serveur utilise un logiciel très "\n"ancien et qu\'il est susceptible de présenter d\'autres problèmes de sécurité."' }, |
|
326 |
{ 'id': '7999229196265990314', |
|
327 |
'xtb': u'Les fichiers suivants ont été créés :\n\nExtension : <ph name="EXTENSION_FILE"/>\nFichier de clé : <ph name="KEY_FILE"/>\n\nConservez votre fichier de clé en lieu sûr. Vous en aurez besoin lors de la création de nouvelles versions de l\'extension.', |
|
328 |
'po': u'""\n"Les fichiers suivants ont été créés :\\n"\n"\\n"\n"Extension : %{EXTENSION_FILE}\\n"\n"Fichier de clé : %{KEY_FILE}\\n"\n"\\n"\n"Conservez votre fichier de clé en lieu sûr. Vous en aurez besoin lors de la "\n"création de nouvelles versions de l\'extension."' }, |
|
329 |
# quoted LF
|
|
330 |
{ 'id': '4845656988780854088', |
|
331 |
'xtb': u'Synchroniser uniquement les paramètres et\\ndonnées qui ont changé depuis la dernière connexion\\n(requiert votre mot de passe précédent)', |
|
332 |
'po': u'""\n"Synchroniser uniquement les paramètres et\\\\ndonnées qui ont changé depuis la"\n" dernière connexion\\\\n(requiert votre mot de passe précédent)"' }, |
|
333 |
{ 'id': '1761265592227862828', # lang: 'el' |
|
334 |
'xtb': u'Συγχρονισμός όλων των ρυθμίσεων και των δεδομένων\\n (ενδέχεται να διαρκέσει ορισμένο χρονικό διάστημα)', |
|
335 |
'po': u'""\n"Συγχρονισμός όλων των ρυθμίσεων και των δεδομένων\\\\n (ενδέχεται να διαρκέσει"\n" ορισμένο χρονικό διάστημα)"' }, |
|
|
19
by Fabien Tassin
* Fix gettext2xtb() when launchpad folds strings at a quoted LF |
336 |
{ 'id': '1768211415369530011', # lang: 'de' |
337 |
'xtb': u'Folgende Anwendung wird gestartet, wenn Sie diese Anforderung akzeptieren:\\n\\n <ph name="APPLICATION"/>', |
|
338 |
'po': u'""\n"Folgende Anwendung wird gestartet, wenn Sie diese Anforderung "\n"akzeptieren:\\\\n\\\\n %{APPLICATION}"' }, |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
339 |
# weird controls
|
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
340 |
{ 'id': '5107325588313356747', # lang: 'es-419' |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
341 |
'xtb': u'Para ocultar el acceso a este programa, debes desinstalarlo. Para ello, utiliza\\n<ph name="CONTROL_PANEL_APPLET_NAME"/> del Panel de control.\\n\¿Deseas iniciar <ph name="CONTROL_PANEL_APPLET_NAME"/>?', |
342 |
'po': u'""\n"Para ocultar el acceso a este programa, debes desinstalarlo. Para ello, "\n"utiliza\\\\n%{CONTROL_PANEL_APPLET_NAME} del Panel de control.\\\\n\\\\¿Deseas "\n"iniciar %{CONTROL_PANEL_APPLET_NAME}?"' } |
|
343 |
]
|
|
344 |
||
345 |
for string in data: |
|
346 |
s = u"<x>" + string['xtb'] + u"</x>" |
|
347 |
s = s.encode('ascii', 'xmlcharrefreplace') |
|
348 |
dom = minidom.parseString(s) |
|
349 |
s = dom.firstChild.toxml()[3:][:-4] |
|
350 |
e = self.grd2gettext(s) |
|
351 |
if e != string['po']: |
|
352 |
assert False, "grd2gettext() failed for id " + string['id'] + \ |
|
353 |
". \nExpected: " + repr(string['po']) + "\nGot: " + repr(e) |
|
354 |
e = self.xtb2gettext(string['xtb']) |
|
355 |
if e != string['po']: |
|
356 |
assert False, "xtb2gettext() failed for id " + string['id'] + \ |
|
357 |
". \nExpected: " + repr(string['po']) + "\nGot: " + repr(e) |
|
358 |
u = self.gettext2xtb(e) |
|
359 |
if u != string['xtb']: |
|
360 |
assert False, "gettext2xtb() failed for id " + string['id'] + \ |
|
361 |
". \nExpected: " + repr(string['xtb']) + "\nGot: " + repr(u) |
|
362 |
print string['id'] + " ok" |
|
363 |
||
|
19
by Fabien Tassin
* Fix gettext2xtb() when launchpad folds strings at a quoted LF |
364 |
# more tests with only po to xtb to test some weird launchpad po exports
|
365 |
data2 = [ |
|
366 |
{ 'id': '1768211415369530011', # lang: 'de' |
|
367 |
'po': u'""\n"Folgende Anwendung wird gestartet, wenn Sie diese Anforderung akzeptieren:\\\\"\n"n\\\\n %{APPLICATION}"', |
|
368 |
'xtb': u'Folgende Anwendung wird gestartet, wenn Sie diese Anforderung akzeptieren:\\n\\n <ph name="APPLICATION"/>' }, |
|
369 |
]
|
|
370 |
for string in data2: |
|
371 |
u = self.gettext2xtb(string['po']) |
|
372 |
if u != string['xtb']: |
|
373 |
assert False, "gettext2xtb() failed for id " + string['id'] + \ |
|
374 |
". \nExpected: " + repr(string['xtb']) + "\nGot: " + repr(u) |
|
375 |
print string['id'] + " ok" |
|
376 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
377 |
######
|
378 |
||
|
15
by Fabien Tassin
* Reorganize the code into classes |
379 |
class PotFile(dict): |
380 |
"""
|
|
381 |
Read and write gettext pot files
|
|
382 |
"""
|
|
383 |
||
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
384 |
def __init__(self, filename, date = None, debug = False, branch_name = "default", branch_dir = os.getcwd()): |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
385 |
self.debug = debug |
|
15
by Fabien Tassin
* Reorganize the code into classes |
386 |
self.lang = None |
387 |
self.filename = filename |
|
388 |
self.tfile = filename + ".new" |
|
|
82
by Fabien Tassin
* Fix the bogus paths in the grit patches (regression introduced in the |
389 |
self.branch_dir = branch_dir |
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
390 |
self.branch_name = branch_name |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
391 |
self.template_date = date |
392 |
self.translation_date = "YEAR-MO-DA HO:MI+ZONE" |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
393 |
self.is_pot = True |
394 |
self.fd = None |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
395 |
self.fd_mode = "rb" |
396 |
if self.template_date is None: |
|
397 |
self.template_date = datetime.utcnow().strftime("%Y-%m-%d %H:%M+0000") |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
398 |
self.strings = [] |
399 |
||
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
400 |
def add_string(self, id, comment, string, translation = "", origin = None): |
|
15
by Fabien Tassin
* Reorganize the code into classes |
401 |
self.strings.append({ 'id': id, 'comment': comment, 'string': string, |
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
402 |
'origin': origin, 'translation': translation }) |
|
15
by Fabien Tassin
* Reorganize the code into classes |
403 |
|
404 |
def replace_file_if_newer(self): |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
405 |
filename = os.path.join(self.branch_dir, self.filename) if self.branch_dir is not None \ |
|
82
by Fabien Tassin
* Fix the bogus paths in the grit patches (regression introduced in the |
406 |
else self.filename |
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
407 |
tfile = os.path.join(self.branch_dir, self.tfile) if self.branch_dir is not None \ |
|
82
by Fabien Tassin
* Fix the bogus paths in the grit patches (regression introduced in the |
408 |
else self.tfile |
409 |
if os.path.isfile(filename) and filecmp.cmp(filename, tfile) == 1: |
|
410 |
os.unlink(tfile) |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
411 |
return 0 |
412 |
else: |
|
|
82
by Fabien Tassin
* Fix the bogus paths in the grit patches (regression introduced in the |
413 |
os.rename(tfile, filename) |
|
15
by Fabien Tassin
* Reorganize the code into classes |
414 |
return 1 |
415 |
||
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
416 |
def get_mtime(self, file): |
417 |
rfile = os.path.join(self.branch_dir, file) |
|
418 |
if self.debug: |
|
419 |
print "getmtime(%s) [%s]" % (file, os.path.abspath(rfile)) |
|
420 |
return os.path.getmtime(rfile) |
|
421 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
422 |
def open(self, mode = "rb", filename = None): |
423 |
if filename is not None: |
|
424 |
self.filename = filename |
|
425 |
self.tfile = filename + ".new" |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
426 |
rfile = os.path.join(self.branch_dir, self.filename) |
427 |
rtfile = os.path.join(self.branch_dir, self.tfile) |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
428 |
if self.fd is not None: |
429 |
self.close() |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
430 |
self.fd_mode = mode |
431 |
if mode.find("r") != -1: |
|
432 |
if self.debug: |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
433 |
print "open %s [mode=%s] from branch '%s' [%s]" % (self.filename, mode, self.branch_name, os.path.abspath(rfile)) |
434 |
self.fd = codecs.open(rfile, mode, encoding="utf-8") |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
435 |
else: |
436 |
if self.debug: |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
437 |
print "open %s [mode=%s] from branch '%s' [%s]" % (self.tfile, mode, self.branch_name, os.path.abspath(rtfile)) |
438 |
self.fd = codecs.open(rtfile, mode, encoding="utf-8") |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
439 |
|
440 |
def close(self): |
|
441 |
self.fd.close() |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
442 |
self.fd = None |
443 |
if self.fd_mode.find("w") != -1: |
|
444 |
return self.replace_file_if_newer() |
|
445 |
||
446 |
def read_string(self): |
|
447 |
string = {} |
|
448 |
cur = None |
|
449 |
while 1: |
|
450 |
s = self.fd.readline() |
|
451 |
if len(s) == 0 or s == "\n": |
|
452 |
break # EOF or end of block |
|
453 |
if s.rfind('\n') == len(s) - 1: |
|
454 |
s = s[:-1] # chomp |
|
455 |
if s.find("# ") == 0 or s == "#": # translator-comment |
|
456 |
if 'comment' not in string: |
|
457 |
string['comment'] = '' |
|
458 |
string['comment'] += s[2:] |
|
459 |
continue
|
|
460 |
if s.find("#:") == 0: # reference |
|
461 |
if 'reference' not in string: |
|
462 |
string['reference'] = '' |
|
463 |
string['reference'] += s[2:] |
|
464 |
if s[2:].find(" id: ") == 0: |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
465 |
string['id'] = s[7:].split(' ')[0] |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
466 |
continue
|
467 |
if s.find("#.") == 0: # extracted-comments |
|
468 |
if 'extracted' not in string: |
|
469 |
string['extracted'] = '' |
|
470 |
string['extracted'] += s[2:] |
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
471 |
if s[2:].find(" - condition: ") == 0: |
472 |
if 'conditions' not in string: |
|
473 |
string['conditions'] = [] |
|
474 |
string['conditions'].append(s[16:]) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
475 |
continue
|
|
22
by Fabien Tassin
* Ignore obsolete messages in po files from Launchpad |
476 |
if s.find("#~") == 0: # obsolete messages |
477 |
continue
|
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
478 |
if s.find("#") == 0: # something else |
|
23
by Fabien Tassin
* use repr() for debug messages, to prevent python from aborting on bad encoding |
479 |
print "%s not expected. Skip" % repr(s) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
480 |
continue # not supported/expected |
481 |
if s.find("msgid ") == 0: |
|
482 |
cur = "string" |
|
483 |
if cur not in string: |
|
484 |
string[cur] = u"" |
|
485 |
else: |
|
486 |
string[cur] += "\n" |
|
487 |
string[cur] += s[6:] |
|
488 |
continue
|
|
489 |
if s.find("msgstr ") == 0: |
|
490 |
cur = "translation" |
|
491 |
if cur not in string: |
|
492 |
string[cur] = u"" |
|
493 |
else: |
|
494 |
string[cur] += "\n" |
|
495 |
string[cur] += s[7:] |
|
496 |
continue
|
|
497 |
if s.find('"') == 0: |
|
498 |
if cur is None: |
|
499 |
print "'%s' not expected here. Skip" % s |
|
500 |
continue
|
|
501 |
string[cur] += "\n" + s |
|
502 |
continue
|
|
503 |
print "'%s' not expected here. Skip" % s |
|
504 |
return None if string == {} else string |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
505 |
|
506 |
def write(self, string): |
|
507 |
self.fd.write(string) |
|
508 |
||
509 |
def write_header(self): |
|
510 |
lang_team = "LANGUAGE <LL@li.org>" if self.is_pot else "%s <%s@li.org>" % (self.lang, self.lang) |
|
511 |
lang_str = "template" if self.is_pot else "for lang '%s'" % self.lang |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
512 |
date = "YEAR-MO-DA HO:MI+ZONE" if self.is_pot else \ |
513 |
datetime.fromtimestamp(self.translation_date).strftime("%Y-%m-%d %H:%M+0000") |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
514 |
self.write("# Chromium Translations %s.\n" |
|
65
by Fabien Tassin
* Bump the (c) to 2011 |
515 |
"# Copyright (C) 2010-2011 Fabien Tassin\n" |
|
16
by Fabien Tassin
* Fill-up the package name in the gettext headers |
516 |
"# This file is distributed under the same license as the chromium-browser package.\n" |
|
65
by Fabien Tassin
* Bump the (c) to 2011 |
517 |
"# Fabien Tassin <fta@ubuntu.com>, 2010-2011.\n" |
|
15
by Fabien Tassin
* Reorganize the code into classes |
518 |
"#\n" % lang_str) |
519 |
# FIXME: collect contributors (can LP export them?)
|
|
520 |
self.write('msgid ""\n' |
|
521 |
'msgstr ""\n' |
|
522 |
'"Project-Id-Version: chromium-browser.head\\n"\n' |
|
523 |
'"Report-Msgid-Bugs-To: https://bugs.launchpad.net/ubuntu/+source/chromium-browser/+filebug\\n"\n' |
|
524 |
'"POT-Creation-Date: %s\\n"\n' |
|
525 |
'"PO-Revision-Date: %s\\n"\n' |
|
526 |
'"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"\n' |
|
527 |
'"Language-Team: %s\\n"\n' |
|
528 |
'"MIME-Version: 1.0\\n"\n' |
|
529 |
'"Content-Type: text/plain; charset=UTF-8\\n"\n' |
|
530 |
'"Content-Transfer-Encoding: 8bit\\n"\n\n' % \ |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
531 |
(datetime.fromtimestamp(self.template_date).strftime("%Y-%m-%d %H:%M+0000"), |
532 |
date, lang_team)) |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
533 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
534 |
def write_footer(self): |
535 |
pass
|
|
536 |
||
|
15
by Fabien Tassin
* Reorganize the code into classes |
537 |
def write_all_strings(self): |
538 |
for string in self.strings: |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
539 |
self.write(u"#. %s\n" % u"\n#. ".join(string['comment'].split("\n"))) |
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
540 |
self.write(u"#: id: %s (used in the following branches: %s)\n" % \ |
541 |
(string['id'], ", ".join(string['origin']))) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
542 |
self.write(u'msgid %s\n' % StringCvt().xtb2gettext(string['string'])) |
543 |
self.write(u'msgstr %s\n\n' % StringCvt().xtb2gettext(string['translation'])) |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
544 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
545 |
def export_file(self, directory = None, filename = None): |
546 |
self.open(mode = "wb", filename = filename) |
|
|
15
by Fabien Tassin
* Reorganize the code into classes |
547 |
self.write_header() |
548 |
self.write_all_strings() |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
549 |
self.write_footer() |
|
15
by Fabien Tassin
* Reorganize the code into classes |
550 |
return self.close() |
551 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
552 |
def import_file(self): |
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
553 |
self.mtime = self.get_mtime(self.filename) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
554 |
self.open() |
555 |
while 1: |
|
556 |
string = self.read_string() |
|
557 |
if string is None: |
|
558 |
break
|
|
559 |
self.strings.append(string) |
|
560 |
self.close() |
|
561 |
||
562 |
def pack_comment(self, data): |
|
563 |
comment = "" |
|
564 |
for ent in sorted(data, lambda x,y: cmp(x['code'], y['code'])): |
|
565 |
comment += "%s\n- description: %s\n" % (ent['code'], ent['desc']) |
|
566 |
if ent['test'] is not None: |
|
567 |
comment += "- condition: %s\n" % ent['test'] |
|
568 |
comment = comment[:-1] # strip trailing \n |
|
569 |
return comment |
|
570 |
||
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
571 |
def get_origins(self, data): |
572 |
o = [] |
|
573 |
for ent in sorted(data, lambda x,y: cmp(x['code'], y['code'])): |
|
574 |
for origin in ent['origin']: |
|
575 |
if origin not in o: |
|
576 |
o.append(origin) |
|
577 |
return o |
|
578 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
579 |
def import_grd(self, grd): |
580 |
imported = 0 |
|
581 |
for id in sorted(grd.supported_ids.keys()): |
|
582 |
if 'ids' not in grd.supported_ids[id]: |
|
583 |
continue
|
|
584 |
comment = self.pack_comment(grd.supported_ids[id]['ids']) |
|
585 |
string = grd.supported_ids[id]['ids'][0]['val'] |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
586 |
origin = self.get_origins(grd.supported_ids[id]['ids']) |
587 |
self.strings.append({ 'id': id, 'comment': comment, 'string': string, |
|
588 |
'origin': origin, 'translation': '' }) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
589 |
imported += 1 |
590 |
if self.debug: |
|
591 |
print "imported %d strings from the grd template" % imported |
|
592 |
||
|
15
by Fabien Tassin
* Reorganize the code into classes |
593 |
class PoFile(PotFile): |
594 |
"""
|
|
595 |
Read and write gettext po files
|
|
596 |
"""
|
|
597 |
||
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
598 |
def __init__(self, lang, filename, template, date = None, debug = None, |
599 |
branch_name = "default", branch_dir = os.getcwd()): |
|
600 |
super(PoFile, self).__init__(filename, date = template.template_date, debug = debug, |
|
601 |
branch_name = branch_name, branch_dir = branch_dir) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
602 |
self.template = template |
|
15
by Fabien Tassin
* Reorganize the code into classes |
603 |
self.lang = lang |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
604 |
self.translation_date = date |
|
15
by Fabien Tassin
* Reorganize the code into classes |
605 |
self.is_pot = False |
606 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
607 |
def import_xtb(self, xtb): |
608 |
# only import strings present in the current template
|
|
609 |
imported = 0 |
|
610 |
for id in sorted(xtb.template.supported_ids.keys()): |
|
611 |
if 'ids' not in xtb.template.supported_ids[id]: |
|
612 |
continue
|
|
613 |
translation = xtb.strings[id] if id in xtb.strings else "" |
|
614 |
comment = self.template.pack_comment(xtb.template.supported_ids[id]['ids']) |
|
615 |
string = xtb.template.supported_ids[id]['ids'][0]['val'] |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
616 |
origin = self.get_origins(xtb.template.supported_ids[id]['ids']) |
617 |
self.add_string(id, comment, string, translation, origin) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
618 |
imported += 1 |
619 |
if self.debug: |
|
620 |
print "imported %d translations for lang %s from xtb into po %s" % (imported, self.lang, self.filename) |
|
621 |
||
622 |
class GrdFile(PotFile): |
|
623 |
"""
|
|
624 |
Read a Grit GRD file (write is not supported)
|
|
625 |
"""
|
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
626 |
def __init__(self, filename, date = None, lang_mapping = None, debug = None, |
627 |
branch_name = "default", branch_dir = os.getcwd()): |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
628 |
super(GrdFile, self).__init__(filename, date = date, debug = debug, |
629 |
branch_name = branch_name, branch_dir = branch_dir) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
630 |
self.lang_mapping = lang_mapping |
631 |
self.mapped_langs = {} |
|
632 |
self.supported_langs = {} |
|
633 |
self.supported_ids = {} |
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
634 |
self.supported_ids_counts = {} |
|
1
by Fabien Tassin
* Initial revision |
635 |
self.translated_strings = {} |
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
636 |
self.stats = {} # per lang |
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
637 |
self.debug = debug |
|
1
by Fabien Tassin
* Initial revision |
638 |
self._PH_REGEXP = re.compile('(<ph name=")([^"]*)("/>)') |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
639 |
|
640 |
def open(self): |
|
641 |
pass
|
|
642 |
||
643 |
def close(self): |
|
644 |
pass
|
|
645 |
||
646 |
def write_header(self): |
|
647 |
raise Exception("Not implemented!") |
|
648 |
||
649 |
def write_footer(self): |
|
650 |
raise Exception("Not implemented!") |
|
651 |
||
652 |
def write_all_strings(self): |
|
653 |
raise Exception("Not implemented!") |
|
654 |
||
|
101
by Fabien Tassin
* Fix a regression in #99 where .pak files were lost leading to FTBFS |
655 |
def export_file(self, directory = None, filename = None, global_langs = None, langs = None): |
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
656 |
fdi = codecs.open(self.filename, 'rb', encoding="utf-8") |
657 |
fdo = codecs.open(filename, 'wb', encoding="utf-8") |
|
658 |
# can't use minidom here as the file is manually generated and the
|
|
659 |
# output will create big diffs. parse the source file line by line
|
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
660 |
# and insert our xtb in the <translations> section. Also insert new
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
661 |
# langs in the <outputs> section (with type="data_package" or type="js_map_format").
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
662 |
# Let everything else untouched
|
663 |
tr_found = False |
|
664 |
tr_saved = [] |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
665 |
tr_has_ifs = False |
|
120
by Ken VanDine
handled latest grd format |
666 |
tr_skipping_if_not = False |
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
667 |
pak_found = False |
668 |
pak_saved = [] |
|
669 |
# langs, sorted by their xtb names
|
|
670 |
our_langs = map(lambda x: x[0], |
|
671 |
sorted(map(lambda x: (x, self.mapped_langs[x]['xtb_file']), |
|
672 |
self.mapped_langs), |
|
673 |
key = lambda x: x[1])) # d'oh! |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
674 |
if langs is None: |
675 |
langs = our_langs[:] |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
676 |
for line in fdi.readlines(): |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
677 |
if re.match(r'.*?<output filename=".*?" type="(data_package|js_map_format)"', line): |
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
678 |
pak_found = True |
679 |
pak_saved.append(line) |
|
680 |
continue
|
|
681 |
if line.find('</outputs>') > 0: |
|
682 |
pak_found = False |
|
|
101
by Fabien Tassin
* Fix a regression in #99 where .pak files were lost leading to FTBFS |
683 |
ours = global_langs[:] |
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
684 |
chunks = {} |
685 |
c = None |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
686 |
pak_if = None |
687 |
pak_is_in_if = False |
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
688 |
for l in pak_saved: |
689 |
if l.find("<!-- ") > 0: |
|
690 |
c = l |
|
691 |
continue
|
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
692 |
if l.find("<if ") > -1: |
693 |
c = l if c is None else c + l |
|
694 |
tr_has_ifs = True |
|
695 |
pak_is_in_if = True |
|
696 |
continue
|
|
697 |
if l.find("</if>") > -1: |
|
698 |
c = l if c is None else c + l |
|
699 |
pak_is_in_if = False |
|
700 |
continue
|
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
701 |
m = re.match(r'.*?<output filename="(.*?)_([^_\.]+)\.(pak|js)" type="(data_package|js_map_format)" lang="(.*?)" />', l) |
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
702 |
if m is not None: |
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
703 |
x = { 'name': m.group(1), 'ext': m.group(3), 'lang': m.group(5), 'file_lang': m.group(2), |
704 |
'type': m.group(4), 'in_if': pak_is_in_if, 'line': l } |
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
705 |
if c is not None: |
706 |
x['comment'] = c |
|
707 |
c = None |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
708 |
k = m.group(2) if m.group(2) != 'nb' else 'no' |
709 |
chunks[k] = x |
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
710 |
else: |
711 |
if c is None: |
|
712 |
c = l |
|
713 |
else: |
|
714 |
c += l |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
715 |
is_in_if = False |
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
716 |
for lang in sorted(chunks.keys()): |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
717 |
tlang = lang if lang != 'no' else 'nb' |
718 |
while len(ours) > 0 and ((ours[0] == 'nb' and 'no' < tlang) or (ours[0] != 'nb' and ours[0] < tlang)): |
|
|
102
by Fabien Tassin
* Include a pak file in all grds for every lang for which we have at least one |
719 |
if ours[0] in chunks: |
|
99
by Fabien Tassin
* When an xtb disappears, also drop it from the corresponding grd file |
720 |
ours = ours[1:] |
721 |
continue
|
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
722 |
if tr_has_ifs and is_in_if is False: |
723 |
fdo.write(' <if expr="pp_ifdef(\'use_third_party_translations\')">\n') |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
724 |
f = "%s_%s.%s" % (chunks[lang]['name'], ours[0], chunks[lang]['ext']) |
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
725 |
fdo.write(' %s<output filename="%s" type="%s" lang="%s" />\n' % \ |
726 |
(' ' if tr_has_ifs else '', f, chunks[lang]['type'], ours[0])) |
|
727 |
is_in_if = True |
|
728 |
if tr_has_ifs and chunks[lang]['in_if'] is False: |
|
|
109
by Fabien Tassin
* Fix badly closed <if/> blocks in grd files |
729 |
if 'comment' not in chunks[lang] or chunks[lang]['comment'].find('</if>') == -1: |
730 |
fdo.write(' </if>\n') |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
731 |
is_in_if = False |
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
732 |
ours = ours[1:] |
733 |
if 'comment' in chunks[lang]: |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
734 |
for s in chunks[lang]['comment'].split('\n')[:-1]: |
735 |
if chunks[lang]['in_if'] is True and is_in_if and s.find('<if ') > -1: |
|
736 |
continue
|
|
737 |
if s.find('<!-- No translations available. -->') > -1: |
|
738 |
continue
|
|
739 |
fdo.write(s + '\n') |
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
740 |
fdo.write(chunks[lang]['line']) |
|
115
by Fabien Tassin
* Fix a regression introduced by the new fake-bidi pseudo locale |
741 |
if ours[0] == tlang: |
742 |
ours = ours[1:] |
|
743 |
is_in_if = chunks[lang]['in_if'] |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
744 |
if len(chunks.keys()) > 0: |
745 |
while len(ours) > 0: |
|
746 |
f = "%s_%s.%s" % (chunks[lang]['name'], ours[0], chunks[lang]['ext']) |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
747 |
if tr_has_ifs and is_in_if is False: |
748 |
fdo.write(' <if expr="pp_ifdef(\'use_third_party_translations\')">\n') |
|
749 |
fdo.write(' %s<output filename="%s" type="data_package" lang="%s" />\n' % \ |
|
750 |
(' ' if tr_has_ifs else '', f, ours[0])) |
|
751 |
is_in_if = True |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
752 |
ours = ours[1:] |
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
753 |
if tr_has_ifs and is_in_if: |
754 |
fdo.write(' </if>\n') |
|
755 |
is_in_if = False |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
756 |
if c is not None: |
757 |
for s in c.split('\n')[:-1]: |
|
758 |
if s.find('<!-- No translations available. -->') > -1: |
|
759 |
continue
|
|
|
89
by Fabien Tassin
* Don't double-close trailing <if> |
760 |
if s.find('</if>') > -1: |
761 |
continue
|
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
762 |
fdo.write(s + '\n') |
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
763 |
if line.find('<translations>') > 0: |
764 |
fdo.write(line) |
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
765 |
tr_found = True |
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
766 |
continue
|
767 |
if line.find('</translations>') > 0: |
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
768 |
tr_found = False |
769 |
ours = our_langs[:] |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
770 |
chunks = {} |
|
99
by Fabien Tassin
* When an xtb disappears, also drop it from the corresponding grd file |
771 |
obsolete = [] |
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
772 |
c = None |
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
773 |
tr_if = None |
774 |
tr_is_in_if = False |
|
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
775 |
for l in tr_saved: |
|
120
by Ken VanDine
handled latest grd format |
776 |
if l.find("</if>") > -1: |
777 |
if tr_skipping_if_not: |
|
778 |
tr_skipping_if_not = False |
|
779 |
continue
|
|
780 |
tr_is_in_if = False |
|
781 |
continue
|
|
782 |
if tr_skipping_if_not: |
|
783 |
continue
|
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
784 |
if l.find("<!-- ") > 0: |
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
785 |
c = l if c is None else c + l |
786 |
continue
|
|
787 |
if l.find("<if ") > -1: |
|
|
120
by Ken VanDine
handled latest grd format |
788 |
m = re.match(r'.*?<if expr="not pp_ifdef\(\'use_third_party_translations\'\)"', l) |
789 |
if m is not None: |
|
790 |
tr_skipping_if_not = True |
|
791 |
continue
|
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
792 |
tr_has_ifs = True |
793 |
tr_is_in_if = True |
|
794 |
continue
|
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
795 |
m = re.match(r'.*?<file path=".*_([^_]+)\.xtb" lang="(.*?)"', l) |
796 |
if m is not None: |
|
|
104
by Fabien Tassin
* Use '-' instead of '@' in the xtb filenames for langs with a sub-code like 'ca@valencia' |
797 |
tlang = m.group(2) |
798 |
if m.group(1) == 'iw': |
|
799 |
tlang = m.group(1) |
|
800 |
x = { 'lang': tlang, 'line': l, 'in_if': tr_is_in_if } |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
801 |
if c is not None: |
802 |
x['comment'] = c |
|
803 |
c = None |
|
|
104
by Fabien Tassin
* Use '-' instead of '@' in the xtb filenames for langs with a sub-code like 'ca@valencia' |
804 |
chunks[tlang] = x |
805 |
if tlang not in langs and tlang not in map(lambda t: self.mapped_langs[t]['grit'], langs): |
|
806 |
obsolete.append(tlang) |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
807 |
else: |
808 |
if c is None: |
|
809 |
c = l |
|
810 |
else: |
|
811 |
c += l |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
812 |
is_in_if = False |
|
103
by Fabien Tassin
* Drop the <if/> in the <translations/> blocks, they are only mandatory |
813 |
# Do we want <if/> in the <translations/> block? (they are only mandatory in the <outputs/> block)
|
814 |
want_ifs_in_translations = False |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
815 |
for lang in sorted(chunks.keys()): |
|
105
by Fabien Tassin
* Fix a regression introduced in the previous commit where xtb for lang codes |
816 |
while len(ours) > 0 and self.mapped_langs[ours[0]]['xtb_file'] < lang.replace('@', '-'): |
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
817 |
if ours[0] not in self.supported_langs: |
818 |
if self.debug: |
|
819 |
print "Skipped export of lang '%s' (most probably a 'po' file without any translated strings)" % ours[0] |
|
820 |
ours = ours[1:] |
|
821 |
continue
|
|
|
99
by Fabien Tassin
* When an xtb disappears, also drop it from the corresponding grd file |
822 |
if ours[0] in obsolete: |
823 |
if self.debug: |
|
824 |
print "Skipped export of lang '%s' (now obsolete)" % ours[0] |
|
825 |
ours = ours[1:] |
|
826 |
continue
|
|
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
827 |
f = os.path.relpath(self.supported_langs[ours[0]], os.path.dirname(self.filename)) |
|
103
by Fabien Tassin
* Drop the <if/> in the <translations/> blocks, they are only mandatory |
828 |
if want_ifs_in_translations and tr_has_ifs and is_in_if is False: |
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
829 |
fdo.write(' <if expr="pp_ifdef(\'use_third_party_translations\')">\n') |
|
103
by Fabien Tassin
* Drop the <if/> in the <translations/> blocks, they are only mandatory |
830 |
is_in_if = True |
|
111
by Fabien Tassin
* Properly indent new xtb files in grds using <if/> blocks |
831 |
fdo.write(' %s<file path="%s" lang="%s" />\n' % |
832 |
(' ' if (is_in_if or want_ifs_in_translations) and tr_has_ifs else '', f, ours[0])) |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
833 |
if tr_has_ifs and chunks[lang]['in_if'] is False: |
|
103
by Fabien Tassin
* Drop the <if/> in the <translations/> blocks, they are only mandatory |
834 |
if want_ifs_in_translations: |
835 |
fdo.write(' </if>\n') |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
836 |
is_in_if = False |
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
837 |
ours = ours[1:] |
838 |
if 'comment' in chunks[lang]: |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
839 |
for s in chunks[lang]['comment'].split('\n')[:-1]: |
840 |
if chunks[lang]['in_if'] is True and is_in_if and s.find('<if ') > -1: |
|
841 |
continue
|
|
842 |
if s.find('<!-- No translations available. -->') > -1: |
|
843 |
continue
|
|
844 |
fdo.write(s + '\n') |
|
|
99
by Fabien Tassin
* When an xtb disappears, also drop it from the corresponding grd file |
845 |
if lang not in obsolete: |
846 |
fdo.write(chunks[lang]['line']) |
|
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
847 |
ours = ours[1:] |
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
848 |
is_in_if = chunks[lang]['in_if'] |
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
849 |
while len(ours) > 0: |
|
30
by Fabien Tassin
* Don't generate an xtb if the imported po only has empty translations |
850 |
if ours[0] in self.supported_langs: |
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
851 |
f = os.path.relpath(self.supported_langs[ours[0]], os.path.dirname(self.filename)) |
|
103
by Fabien Tassin
* Drop the <if/> in the <translations/> blocks, they are only mandatory |
852 |
if want_ifs_in_translations and tr_has_ifs and is_in_if is False: |
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
853 |
fdo.write(' <if expr="pp_ifdef(\'use_third_party_translations\')">\n') |
|
103
by Fabien Tassin
* Drop the <if/> in the <translations/> blocks, they are only mandatory |
854 |
is_in_if = True |
|
111
by Fabien Tassin
* Properly indent new xtb files in grds using <if/> blocks |
855 |
fdo.write(' %s<file path="%s" lang="%s" />\n' % |
856 |
(' ' if (is_in_if or want_ifs_in_translations) and tr_has_ifs else '', f, ours[0])) |
|
|
30
by Fabien Tassin
* Don't generate an xtb if the imported po only has empty translations |
857 |
elif self.debug: |
858 |
print "Skipped lang %s with no translated strings" % ours[0] |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
859 |
ours = ours[1:] |
|
120
by Ken VanDine
handled latest grd format |
860 |
|
861 |
if is_in_if and want_ifs_in_translations: |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
862 |
fdo.write(' </if>\n') |
863 |
is_in_if = False |
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
864 |
if c is not None: |
865 |
for s in c.split('\n')[:-1]: |
|
866 |
if s.find('<!-- No translations available. -->') > -1: |
|
867 |
continue
|
|
|
89
by Fabien Tassin
* Don't double-close trailing <if> |
868 |
if s.find('</if>') > -1: |
869 |
continue
|
|
|
83
by Fabien Tassin
* Add support for the new <if expr="pp_ifdef('use_third_party_translations')"> |
870 |
fdo.write(s + '\n') |
|
52
by Fabien Tassin
* When patching grd files, also add <output type=data_package ..> entries for new langs |
871 |
if tr_found: |
872 |
tr_saved.append(line) |
|
873 |
continue
|
|
874 |
if pak_found: |
|
875 |
pak_saved.append(line) |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
876 |
continue
|
877 |
fdo.write(line) |
|
878 |
fdi.close() |
|
879 |
fdo.close() |
|
|
1
by Fabien Tassin
* Initial revision |
880 |
|
881 |
def uc(self, match): |
|
882 |
return match.group(2).upper() |
|
883 |
||
884 |
def uc_name(self, match): |
|
885 |
return match.group(1) + match.group(2).upper() + match.group(3) |
|
886 |
||
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
887 |
def is_string_valid_for_lang(self, id, lang): |
888 |
ok = False |
|
889 |
for string in self.supported_ids[id]['ids']: |
|
890 |
if string['test'] is not None: |
|
891 |
ok |= EvalConditions().lang_eval(string['test'], lang) |
|
892 |
if ok: |
|
893 |
break
|
|
894 |
else: |
|
895 |
ok = True |
|
896 |
break
|
|
897 |
return ok |
|
898 |
||
899 |
def get_supported_strings_count(self, lang): |
|
900 |
# need to ignore strings for which this lang is not wanted in the <if> conditions
|
|
901 |
if lang in self.supported_ids_counts: |
|
902 |
return self.supported_ids_counts[lang]['count'], self.supported_ids_counts[lang]['skipped'] |
|
903 |
count = 0 |
|
904 |
skipped = 0 |
|
905 |
for id in self.supported_ids: |
|
906 |
ok = self.is_string_valid_for_lang(id, lang) |
|
907 |
if ok: |
|
908 |
count += 1 |
|
909 |
else: |
|
910 |
skipped += 1 |
|
911 |
assert count + skipped == len(self.supported_ids.keys()) |
|
912 |
self.supported_ids_counts[lang] = { 'count': count, 'skipped': skipped } |
|
913 |
return count, skipped |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
914 |
|
|
1
by Fabien Tassin
* Initial revision |
915 |
def get_supported_langs(self): |
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
916 |
return sorted(self.supported_langs.keys()) |
|
1
by Fabien Tassin
* Initial revision |
917 |
|
918 |
def get_supported_lang_filenames(self): |
|
919 |
""" return the list of (xtb) filenames sorted by langs (so it's
|
|
920 |
possible to zip() it) """
|
|
921 |
return map(lambda l: self.supported_langs[l], sorted(self.supported_langs.keys())) |
|
922 |
||
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
923 |
def update_stats(self, lang, translated_upstream = 0, obsolete = 0, |
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
924 |
new = 0, updated = 0, skipped_lang = 0, mandatory_linux = 0): |
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
925 |
if lang not in self.stats: |
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
926 |
self.stats[lang] = { 'translated_upstream': 0, 'skipped_lang': 0, |
927 |
'obsolete': 0, 'new': 0, 'updated': 0, |
|
928 |
'mandatory_linux': 0 } |
|
|
68
by Fabien Tassin
* Fix the 'translated_upstream' counter wrongly including 'updated' |
929 |
self.stats[lang]['translated_upstream'] += translated_upstream - updated |
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
930 |
self.stats[lang]['obsolete'] += obsolete |
931 |
self.stats[lang]['new'] += new |
|
932 |
self.stats[lang]['updated'] += updated |
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
933 |
self.stats[lang]['skipped_lang'] += skipped_lang |
934 |
self.stats[lang]['mandatory_linux'] += mandatory_linux |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
935 |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
936 |
def merge_template(self, template, newer_preferred = True): |
937 |
""" merge strings from 'template' into self (the master template).
|
|
938 |
If the string differs, prefer the new one when newer_preferred is set """
|
|
939 |
for id in template.supported_ids: |
|
940 |
if id not in self.supported_ids: |
|
941 |
if self.debug: |
|
942 |
print "merged code %s (id %s) from branch '%s' from %s" % \ |
|
943 |
(template.supported_ids[id]['ids'][0]['code'], id, |
|
944 |
template.supported_ids[id]['ids'][0]['origin'][0], template.filename) |
|
945 |
self.supported_ids[id] = template.supported_ids[id] |
|
946 |
else: |
|
947 |
for ent in template.supported_ids[id]['ids']: |
|
948 |
found = False |
|
949 |
for ent2 in self.supported_ids[id]['ids']: |
|
950 |
if ent2['code'] != ent['code']: |
|
951 |
continue
|
|
952 |
found = True |
|
953 |
ent2['origin'].append(ent['origin'][0]) |
|
954 |
if ent['test'] != ent2['test'] or \ |
|
955 |
ent['desc'] != ent2['desc']: |
|
956 |
if newer_preferred: |
|
957 |
ent2['test'] = ent['test'] |
|
958 |
ent2['desc'] = ent['desc'] |
|
959 |
if not found: |
|
960 |
if self.debug: |
|
961 |
print "adding new ids code '%s' from branch '%s' for string id %s" % \ |
|
962 |
(ent['code'], template.supported_ids[id]['ids'][0]['origin'][0], id) |
|
963 |
self.supported_ids[id]['ids'].append(ent) |
|
964 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
965 |
def add_translation(self, lang, id, translation): |
966 |
if id not in self.supported_ids: |
|
967 |
if self.debug: |
|
968 |
print "*warn* obsolete string id %s for lang %s" % (id, lang) |
|
969 |
return
|
|
970 |
self.supported_ids[id]['lang'][lang] = translation |
|
971 |
||
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
972 |
def merge_translations(self, lang, xtb, master_xtb = None, newer_preferred = True): |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
973 |
if lang not in self.supported_langs: |
974 |
self.supported_langs[lang] = xtb.filename |
|
975 |
for id in xtb.strings: |
|
976 |
if id not in self.supported_ids: |
|
977 |
# d'oh!! obsolete translation?
|
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
978 |
self.update_stats(lang, obsolete = 1) |
979 |
continue
|
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
980 |
if not self.is_string_valid_for_lang(id, lang): |
981 |
# string not wanted for that lang, skipped
|
|
982 |
continue
|
|
|
1
by Fabien Tassin
* Initial revision |
983 |
if 'lang' not in self.supported_ids[id]: |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
984 |
self.supported_ids[id]['lang'] = {} |
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
985 |
if lang in self.supported_ids[id]['lang']: |
986 |
# already have a translation for this string
|
|
987 |
if newer_preferred and xtb.strings[id] != self.supported_ids[id]['lang'][lang]: |
|
988 |
self.supported_ids[id]['lang'][lang] = xtb.strings[id] |
|
989 |
else: |
|
990 |
self.update_stats(lang, translated_upstream = 1) |
|
991 |
self.supported_ids[id]['lang'][lang] = xtb.strings[id] |
|
992 |
if master_xtb is not None: |
|
993 |
master_xtb.strings[id] = xtb.strings[id] |
|
|
1
by Fabien Tassin
* Initial revision |
994 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
995 |
def read_string(self, node, test = None): |
|
1
by Fabien Tassin
* Initial revision |
996 |
desc = node.getAttribute('desc') |
997 |
name = node.getAttribute('name') |
|
998 |
if not node.firstChild: |
|
999 |
# no string? weird. Skip. (e.g. IDS_LOAD_STATE_IDLE)
|
|
1000 |
return
|
|
1001 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1002 |
# Get a/ the full string from the grd, b/ its transformation
|
1003 |
# into the smaller version found in xtb files (val) and c/ another into
|
|
|
1
by Fabien Tassin
* Initial revision |
1004 |
# something suitable for the 64bit key generator (kval)
|
1005 |
||
1006 |
orig_val = "".join([ n.toxml() for n in node.childNodes ]) |
|
1007 |
||
1008 |
# encode the value to create the 64bit ID needed for the xtb mapping.
|
|
1009 |
#
|
|
1010 |
# grd: 'f&oo "<ph name="IDS_xX">$1<ex>blabla</ex></ph>" bar'
|
|
1011 |
# xtb: 'f&oo "<ph name="IDS_XX"/>" bar'
|
|
1012 |
# but the string used to create the 64bit id is only 'f&oo "IDS_XX" bar'.
|
|
1013 |
# Also, the final value must be positive, while FingerPrint() returns
|
|
1014 |
# a signed long. Of course, none of this is documented...
|
|
1015 |
||
1016 |
# grd->xtb
|
|
1017 |
for x in node.getElementsByTagName('ph'): |
|
1018 |
while x.hasChildNodes(): |
|
1019 |
x.removeChild(x.childNodes[0]) |
|
1020 |
val = "".join([ n.toxml() for n in node.childNodes ]).strip() |
|
1021 |
# xtb->id
|
|
|
40
by Fabien Tassin
* Split decode_xml_entities() away from unescape_xml() |
1022 |
kval = StringCvt().decode_xml_entities(unescape(self._PH_REGEXP.sub(self.uc, val))).encode('utf-8') |
|
1
by Fabien Tassin
* Initial revision |
1023 |
kval = kval.replace('"', '"') # not replaced by unescape() |
1024 |
||
1025 |
val = self._PH_REGEXP.sub(self.uc_name, val) |
|
1026 |
val = val.encode("ascii", "xmlcharrefreplace").strip().encode('utf-8') |
|
1027 |
||
1028 |
# finally, create the 64bit ID
|
|
1029 |
id = str(FingerPrint(kval) & 0x7fffffffffffffffL) |
|
1030 |
||
|
110
by Fabien Tassin
* Skip unexpected empty <message/> blocks inside grd files |
1031 |
if val == '': |
1032 |
# unexpect <message/> block with attributes but without value, skip
|
|
1033 |
return
|
|
1034 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1035 |
if id not in self.supported_ids: |
1036 |
self.supported_ids[id] = { 'ids': [] } |
|
1037 |
self.supported_ids[id]['ids'].append({ 'code': name, 'desc': desc, |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1038 |
'val': val, 'test': test, |
1039 |
'origin': [ self.branch_name ] }) |
|
|
1
by Fabien Tassin
* Initial revision |
1040 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1041 |
def read_strings(self, node, test = None): |
|
1
by Fabien Tassin
* Initial revision |
1042 |
for n in node.childNodes: |
1043 |
if n.nodeName == '#text' or n.nodeName == '#comment': |
|
1044 |
# comments, skip
|
|
1045 |
continue
|
|
1046 |
if n.nodeName == 'message': |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1047 |
self.read_string(n, test) |
|
1
by Fabien Tassin
* Initial revision |
1048 |
continue
|
1049 |
if n.nodeName == 'if': |
|
1050 |
expr = n.getAttribute('expr') |
|
1051 |
if expr is not None and test is not None: |
|
1052 |
assert "nested <if> not supported" |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1053 |
self.read_strings(n, expr) |
|
1
by Fabien Tassin
* Initial revision |
1054 |
continue
|
|
121
by Chad MILLER
Handle GRD partial files. |
1055 |
if n.nodeName == 'part': |
1056 |
f = n.getAttribute('file') |
|
1057 |
qualified_file = os.path.join(os.path.dirname(self.filename), f) |
|
1058 |
self.import_file(override_filename=qualified_file) |
|
1059 |
continue
|
|
1060 |
raise Exception("unknown tag (<%s> type %s): ''%s''" % \ |
|
1061 |
(n.nodeName, n.nodeType, n.toxml())) |
|
|
1
by Fabien Tassin
* Initial revision |
1062 |
|
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1063 |
def import_json_file(self, filename): |
1064 |
# unlike its name seems to indicate, this file is definitely not a json file.
|
|
1065 |
# It's a python object, dumped in a file. It means it's far easier to parse
|
|
1066 |
# because there's no extra unescaping to do on all the strings. It also
|
|
1067 |
# means we can't use the json module
|
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1068 |
rfile = os.path.join(self.branch_dir, filename) |
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1069 |
if self.debug: |
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1070 |
print "parse_json('%s') [%s]" % (filename, rfile) |
1071 |
fd = open(rfile, "rb") |
|
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1072 |
data = fd.read() |
1073 |
fd.close() |
|
1074 |
vars = { '__builtins__': { 'True': True, 'False': False } } # prevent eval from using the real current globals |
|
1075 |
data = eval(data, vars) |
|
|
78
by Fabien Tassin
* Only support the new json format from Chromium 10 |
1076 |
# Check if this is a format we support
|
1077 |
if 'policy_definitions' in data and len(data['policy_definitions']) > 0 and \ |
|
1078 |
'caption' not in data['policy_definitions'][0]: |
|
1079 |
# most probably Chromium v9. It used 'annotations' instead of 'caption'
|
|
1080 |
# Not worth supporting that, all the strings we need in v9 are already in
|
|
1081 |
# the grd file. Skip this json file
|
|
1082 |
if self.debug: |
|
1083 |
print "Found older unsupported json format. Skipped" |
|
1084 |
return
|
|
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1085 |
if 'messages' in data: |
1086 |
for msg in data['messages']: |
|
1087 |
self.read_policy('IDS_POLICY_' + msg.upper(), |
|
1088 |
data['messages'][msg]['desc'], |
|
1089 |
data['messages'][msg]['text']) |
|
1090 |
if 'policy_definitions' in data: |
|
1091 |
for policy in data['policy_definitions']: |
|
1092 |
name = 'IDS_POLICY_' + policy['name'].upper() |
|
|
121
by Chad MILLER
Handle GRD partial files. |
1093 |
if policy['type'] in [ 'main', 'int', 'string', 'list', 'string-enum', 'int-enum', 'string-enum-list' ]: |
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1094 |
# caption
|
1095 |
self.read_policy(name + '_CAPTION', |
|
1096 |
"Caption of the '%s' policy." % policy['name'], |
|
1097 |
policy['caption']) |
|
1098 |
# label (optional)
|
|
1099 |
if 'label' in policy: |
|
1100 |
self.read_policy(name + '_LABEL', |
|
1101 |
"Label of the '%s' policy." % policy['name'], |
|
1102 |
policy['label']) |
|
1103 |
# desc
|
|
1104 |
self.read_policy(name + '_DESC', |
|
1105 |
"Description of the '%s' policy." % policy['name'], |
|
1106 |
policy['desc']) |
|
|
121
by Chad MILLER
Handle GRD partial files. |
1107 |
if policy['type'] in [ 'string-enum', 'int-enum', 'string-enum-list' ]: |
|
113
by Fabien Tassin
* Add support for 'string-enum' and 'int-enum' outside of 'group' policies |
1108 |
for item in policy['items']: |
1109 |
self.read_policy('IDS_POLICY_ENUM_' + item['name'].upper().replace(' ', '_') + '_CAPTION', |
|
1110 |
"Label in a '%s' dropdown menu for selecting '%s'" % \ |
|
1111 |
(policy['name'], item['name']), |
|
1112 |
item['caption']) |
|
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1113 |
continue
|
1114 |
if policy['type'] == 'group': |
|
1115 |
# group caption
|
|
1116 |
self.read_policy(name + '_CAPTION', |
|
1117 |
"Caption of the group of '%s' related policies." % name, |
|
1118 |
policy['caption']) |
|
1119 |
# group label (optional)
|
|
1120 |
if 'label' in policy: |
|
1121 |
self.read_policy(name + '_LABEL', |
|
1122 |
"Label of the group of '%s' related policies." % name, |
|
1123 |
policy['label']) |
|
1124 |
# group desc
|
|
1125 |
self.read_policy(name + '_DESC', |
|
1126 |
"Description of the group of '%s' related policies." % name, |
|
1127 |
policy['desc']) |
|
1128 |
for spolicy in policy['policies']: |
|
1129 |
sname = 'IDS_POLICY_' + spolicy['name'].upper() |
|
1130 |
# desc
|
|
1131 |
self.read_policy(sname + '_DESC', |
|
1132 |
"Description of the '%s' policy." % spolicy['name'], |
|
1133 |
spolicy['desc']) |
|
1134 |
# label (optional)
|
|
1135 |
if 'label' in spolicy: |
|
1136 |
self.read_policy(sname + '_LABEL', |
|
1137 |
"Label of the '%s' policy." % spolicy['name'], |
|
1138 |
spolicy['label']) |
|
1139 |
# caption
|
|
1140 |
self.read_policy(sname + '_CAPTION', |
|
1141 |
"Caption of the '%s' policy." % spolicy['name'], |
|
1142 |
spolicy['caption']) |
|
1143 |
if spolicy['type'] in [ 'int-enum', 'string-enum' ]: |
|
1144 |
# only caption
|
|
1145 |
for item in spolicy['items']: |
|
1146 |
self.read_policy('IDS_POLICY_ENUM_' + item['name'].upper() + '_CAPTION', |
|
1147 |
"Label in a '%s' dropdown menu for selecting a '%s' of '%s'" % \ |
|
1148 |
(policy['name'], spolicy['name'], item['name']), |
|
1149 |
item['caption']) |
|
1150 |
continue
|
|
|
118
by Christian Dywan
* Add temporary workaround for new type not being used yet |
1151 |
# The new type is not yet being used: http://code.google.com/p/chromium/issues/detail?id=108992
|
|
121
by Chad MILLER
Handle GRD partial files. |
1152 |
if policy['type'] == 'external': |
1153 |
continue
|
|
|
118
by Christian Dywan
* Add temporary workaround for new type not being used yet |
1154 |
if policy['type'] == 'dict': |
1155 |
continue
|
|
1156 |
||
|
113
by Fabien Tassin
* Add support for 'string-enum' and 'int-enum' outside of 'group' policies |
1157 |
assert False, "Policy type '%s' not supported while parsing %s" % (policy['type'], rfile) |
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1158 |
|
1159 |
def read_policy(self, name, desc, text): |
|
1160 |
xml = '<x><message name="%s" desc="%s">\n%s\n</message></x>' % (name, desc, text) |
|
1161 |
dom = minidom.parseString(xml) |
|
1162 |
self.read_strings(dom.getElementsByTagName('x')[0]) |
|
1163 |
||
|
87
by Fabien Tassin
* When reading a grd file with minidom, don't skip the xtb files inside <if/> blocks. |
1164 |
def _add_xtb(self, node): |
|
88
by Fabien Tassin
* Oops, weak python |
1165 |
if node.nodeName != 'file': |
|
87
by Fabien Tassin
* When reading a grd file with minidom, don't skip the xtb files inside <if/> blocks. |
1166 |
return
|
1167 |
path = node.getAttribute('path') |
|
1168 |
m = re.match(r'.*_([^_]+)\.xtb', path) |
|
1169 |
flang = m.group(1) |
|
1170 |
lang = node.getAttribute('lang') |
|
1171 |
tlang = lang |
|
1172 |
if self.lang_mapping is not None and lang in self.lang_mapping: |
|
1173 |
if self.debug: |
|
1174 |
print "# mapping lang '%s' to '%s'" % (lang, self.lang_mapping[lang]) |
|
1175 |
tlang = self.lang_mapping[lang] |
|
1176 |
tlang = tlang.replace('-', '_') |
|
1177 |
self.supported_langs[lang] = os.path.normpath(os.path.join(os.path.dirname(self.filename), path)) |
|
1178 |
self.translated_strings[lang] = {} |
|
|
104
by Fabien Tassin
* Use '-' instead of '@' in the xtb filenames for langs with a sub-code like 'ca@valencia' |
1179 |
glang = lang |
1180 |
if flang == 'iw': |
|
1181 |
glang = flang |
|
|
119
by Micah Gersten
* Temporarily workaround muliple bg locales in generated_resources |
1182 |
#assert lang not in self.mapped_langs, "'%s' already in self.mapped_langs" % lang
|
1183 |
if lang not in self.mapped_langs: |
|
1184 |
self.mapped_langs[lang] = { 'xtb_file': flang, 'grit': glang, 'gettext': tlang } |
|
|
87
by Fabien Tassin
* When reading a grd file with minidom, don't skip the xtb files inside <if/> blocks. |
1185 |
|
|
121
by Chad MILLER
Handle GRD partial files. |
1186 |
def import_file(self, override_filename=None): |
1187 |
if override_filename: |
|
1188 |
assert self.branch_dir |
|
1189 |
filename = os.path.join(self.branch_dir, override_filename) |
|
1190 |
else: |
|
1191 |
filename = os.path.join(self.branch_dir, self.filename) if self.branch_dir is not None \ |
|
1192 |
else self.filename |
|
|
1
by Fabien Tassin
* Initial revision |
1193 |
self.supported_langs = {} |
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1194 |
self.mtime = self.get_mtime(self.filename) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1195 |
if self.debug: |
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1196 |
print "minidom.parse(%s)" % filename |
1197 |
dom = minidom.parse(filename) |
|
|
121
by Chad MILLER
Handle GRD partial files. |
1198 |
grits = dom.getElementsByTagName('grit') |
1199 |
if not grits: |
|
1200 |
grits = dom.getElementsByTagName('grit-part') |
|
1201 |
grit = grits[0] |
|
|
1
by Fabien Tassin
* Initial revision |
1202 |
for node in grit.childNodes: |
|
48
by Fabien Tassin
* Ignore more xml comments found inside grd files |
1203 |
if node.nodeName == '#text' or node.nodeName == '#comment': |
|
1
by Fabien Tassin
* Initial revision |
1204 |
# comments, skip
|
1205 |
continue
|
|
1206 |
if node.nodeName == 'outputs': |
|
1207 |
# skip, nothing for us here
|
|
1208 |
continue
|
|
1209 |
if node.nodeName == 'translations': |
|
1210 |
# collect the supported langs by scanning the list of xtb files
|
|
1211 |
for n in node.childNodes: |
|
|
87
by Fabien Tassin
* When reading a grd file with minidom, don't skip the xtb files inside <if/> blocks. |
1212 |
if n.nodeName == 'if': |
1213 |
for nn in n.childNodes: |
|
1214 |
self._add_xtb(nn) |
|
|
1
by Fabien Tassin
* Initial revision |
1215 |
continue
|
|
87
by Fabien Tassin
* When reading a grd file with minidom, don't skip the xtb files inside <if/> blocks. |
1216 |
self._add_xtb(n) |
|
1
by Fabien Tassin
* Initial revision |
1217 |
continue
|
1218 |
if node.nodeName == 'release': |
|
1219 |
for n in node.childNodes: |
|
|
48
by Fabien Tassin
* Ignore more xml comments found inside grd files |
1220 |
if n.nodeName == '#text' or n.nodeName == '#comment': |
|
1
by Fabien Tassin
* Initial revision |
1221 |
# comments, skip
|
1222 |
continue
|
|
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1223 |
if n.nodeName == 'includes': |
|
1
by Fabien Tassin
* Initial revision |
1224 |
# skip, nothing for us here
|
1225 |
continue
|
|
|
77
by Fabien Tassin
* Add support for the new <structures> type 'policy_template_metafile' in grd files |
1226 |
if n.nodeName == 'structures': |
1227 |
for sn in n.childNodes: |
|
1228 |
if sn.nodeName != 'structure': |
|
1229 |
continue
|
|
1230 |
type = sn.getAttribute('type') |
|
1231 |
if type == 'dialog': |
|
1232 |
# nothing for us here
|
|
1233 |
continue
|
|
1234 |
name = sn.getAttribute('name') |
|
1235 |
file = sn.getAttribute('file') |
|
1236 |
if type == 'policy_template_metafile': |
|
1237 |
# included file containing the strings that are usually in the <messages> tree.
|
|
1238 |
fname = os.path.normpath(os.path.join(os.path.dirname(self.filename), file)) |
|
1239 |
self.import_json_file(fname) |
|
1240 |
continue
|
|
1241 |
else: |
|
1242 |
if self.debug: |
|
1243 |
print "unknown <structure> type found ('%s') in %s" % (type, self.filename) |
|
1244 |
continue
|
|
|
1
by Fabien Tassin
* Initial revision |
1245 |
if n.nodeName == 'messages': |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1246 |
self.read_strings(n) |
|
1
by Fabien Tassin
* Initial revision |
1247 |
continue
|
|
48
by Fabien Tassin
* Ignore more xml comments found inside grd files |
1248 |
print "unknown tag (<%s> type %s): ''%s''" % (n.nodeName, n.nodeType, n.toxml()) |
|
1
by Fabien Tassin
* Initial revision |
1249 |
continue
|
|
48
by Fabien Tassin
* Ignore more xml comments found inside grd files |
1250 |
print "unknown tag (<%s> type %s): ''%s''" % (node.nodeName, node.nodeType, node.toxml()) |
|
1
by Fabien Tassin
* Initial revision |
1251 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1252 |
class XtbFile(PoFile): |
1253 |
"""
|
|
1254 |
Read and write a Grit XTB file
|
|
1255 |
"""
|
|
1256 |
||
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1257 |
def __init__(self, lang, filename, grd, date = None, debug = None, |
1258 |
branch_name = "default", branch_dir = os.getcwd()): |
|
1259 |
super(XtbFile, self).__init__(lang, filename, grd, date = date, debug = debug, |
|
1260 |
branch_name = branch_name, branch_dir = branch_dir) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1261 |
self.template = grd |
1262 |
self.strings = {} |
|
1263 |
self.strings_updated = 0 |
|
1264 |
self.strings_new = 0 |
|
1265 |
self.strings_order = [] # needed to recreate xtb files in a similar order :( |
|
1266 |
||
1267 |
def add_translation(self, id, string): |
|
|
96
by Fabien Tassin
* Skip obsolete translations found in upstream xtb files |
1268 |
assert id in self.template.supported_ids, "'%s' is not in supported_ids (file=%s)" % (id, self.filename) |
|
106
by Fabien Tassin
* Keep dropping the heading and trailing \n from translations when they |
1269 |
while string[-1:] == '\n' and self.template.supported_ids[id]['ids'][0]['val'][-1:] != '\n': |
|
71
by Fabien Tassin
* Fix the "`msgid' and `msgstr' entries do not both begin with '\n'" error |
1270 |
# prevent the `msgid' and `msgstr' entries do not both end with '\n' error
|
1271 |
if self.debug: |
|
1272 |
print "Found unwanted \\n at the end of translation id " + id + " lang " + self.lang + ". Dropped" |
|
1273 |
string = string[:-1] |
|
|
106
by Fabien Tassin
* Keep dropping the heading and trailing \n from translations when they |
1274 |
while string[0] == '\n' and self.template.supported_ids[id]['ids'][0]['val'][0] != '\n': |
|
71
by Fabien Tassin
* Fix the "`msgid' and `msgstr' entries do not both begin with '\n'" error |
1275 |
# prevent the `msgid' and `msgstr' entries do not both begin with '\n' error
|
1276 |
if self.debug: |
|
1277 |
print "Found unwanted \\n at the begin of translation id " + id + " lang " + self.lang + ". Dropped" |
|
1278 |
string = string[1:] |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1279 |
self.strings[id] = string |
1280 |
self.strings_order.append(id) |
|
1281 |
||
1282 |
def write_header(self): |
|
1283 |
self.write('<?xml version="1.0" ?>\n') |
|
1284 |
self.write('<!DOCTYPE translationbundle>\n') |
|
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
1285 |
self.write('<translationbundle lang="%s">\n' % \ |
|
104
by Fabien Tassin
* Use '-' instead of '@' in the xtb filenames for langs with a sub-code like 'ca@valencia' |
1286 |
self.template.mapped_langs[self.lang]['grit']) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1287 |
|
1288 |
def write_footer(self): |
|
1289 |
self.write('</translationbundle>') |
|
1290 |
||
1291 |
def write_all_strings(self): |
|
1292 |
for id in self.strings_order: |
|
1293 |
if id in self.strings: |
|
1294 |
self.write('<translation id="%s">%s</translation>\n' % \ |
|
1295 |
(id, self.strings[id])) |
|
1296 |
for id in sorted(self.strings.keys()): |
|
1297 |
if id in self.strings_order: |
|
1298 |
continue
|
|
1299 |
self.write('<translation id="%s">%s</translation>\n' % \ |
|
1300 |
(id, self.strings[id])) |
|
1301 |
||
1302 |
def import_po(self, po): |
|
1303 |
for string in po.strings: |
|
1304 |
if string['string'] == '': |
|
1305 |
continue
|
|
1306 |
self.add_string(string['id'], string['extracted'], |
|
1307 |
string['string'], string['translation']) |
|
1308 |
||
1309 |
def import_file(self): |
|
1310 |
self.open() |
|
1311 |
file = self.fd.read() # *sigh* |
|
1312 |
self.close() |
|
1313 |
imported = 0 |
|
|
1
by Fabien Tassin
* Initial revision |
1314 |
for m in re.finditer('<translation id="(.*?)">(.*?)</translation>', |
1315 |
file, re.S): |
|
|
96
by Fabien Tassin
* Skip obsolete translations found in upstream xtb files |
1316 |
if m.group(1) not in self.template.supported_ids: |
1317 |
if self.debug: |
|
1318 |
print "found a translation for obsolete string id %s in upstream xtb %s" % (m.group(1), self.filename) |
|
1319 |
continue
|
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1320 |
self.add_translation(m.group(1), m.group(2)) |
1321 |
imported += 1 |
|
|
1
by Fabien Tassin
* Initial revision |
1322 |
for m in re.finditer('<translationbundle lang="(.*?)">', file): |
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
1323 |
lang = m.group(1) |
|
100
by Fabien Tassin
* Fix an issue with the gettext export when an xtb file disappear from the |
1324 |
if self.lang in self.template.mapped_langs: |
|
104
by Fabien Tassin
* Use '-' instead of '@' in the xtb filenames for langs with a sub-code like 'ca@valencia' |
1325 |
assert self.template.mapped_langs[self.lang]['grit'] == lang, \ |
1326 |
"bad lang mapping for '%s' while importing %s, expected '%s'" % \ |
|
1327 |
(lang, self.filename, self.template.mapped_langs[self.lang]['grit']) |
|
|
100
by Fabien Tassin
* Fix an issue with the gettext export when an xtb file disappear from the |
1328 |
else: |
1329 |
tlang = lang |
|
1330 |
if self.template.lang_mapping is not None and lang in self.template.lang_mapping: |
|
1331 |
if self.debug: |
|
1332 |
print "# mapping lang '%s' to '%s'" % (lang, self.template.lang_mapping[lang]) |
|
1333 |
tlang = self.template.lang_mapping[lang] |
|
1334 |
tlang = tlang.replace('-', '_') |
|
|
104
by Fabien Tassin
* Use '-' instead of '@' in the xtb filenames for langs with a sub-code like 'ca@valencia' |
1335 |
flang = lang.replace('@', '-') |
1336 |
self.template.mapped_langs[lang] = { 'xtb_file': flang, 'grit': lang, 'gettext': tlang } |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1337 |
if self.debug: |
1338 |
print "imported %d strings from the xtb file into lang '%s'" % (imported, self.lang) |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1339 |
self.mtime = self.get_mtime(self.filename) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1340 |
|
1341 |
###
|
|
1342 |
||
1343 |
class Converter(dict): |
|
1344 |
"""
|
|
1345 |
Given a grd template and its xtb translations,
|
|
1346 |
a/ exports gettext pot template and po translations,
|
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1347 |
possibly by merging grd/xtb files from multiple branches
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1348 |
or
|
1349 |
b/ imports and merges some gettext po translations,
|
|
1350 |
and exports xtb translations
|
|
1351 |
"""
|
|
1352 |
||
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1353 |
def __init__(self, template_filename, lang_mapping = None, date = None, debug = False, |
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1354 |
template_mapping = {}, html_output = False, branches = None): |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1355 |
self.debug = debug |
1356 |
self.translations = {} |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
1357 |
self.errors = 0 |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1358 |
self.template_changes = 0 |
1359 |
self.translations_changes = 0 |
|
1360 |
self.lang_mapping = lang_mapping |
|
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1361 |
self.template_mapping = template_mapping |
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1362 |
self.file_mapping = {} |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
1363 |
self.html_output = html_output |
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
1364 |
self.stats = {} |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
1365 |
self.branches = branches if branches is not None else [ { 'branch': 'default', 'dir': os.getcwd(), 'grd': template_filename } ] |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1366 |
|
1367 |
# read a grd template from a file
|
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
1368 |
self.template = GrdFile(self.branches[0]['grd'], date, lang_mapping = self.lang_mapping, debug = self.debug, |
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1369 |
branch_name = self.branches[0]['branch'], branch_dir = self.branches[0]['dir']) |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
1370 |
self.file_mapping['grd'] = { 'src': self.branches[0]['grd'], |
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1371 |
'branches': { self.branches[0]['branch']: self.branches[0]['dir'] } } |
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1372 |
if 'mapped_grd' in self.branches[0]: |
1373 |
self.file_mapping['grd']['mapped_grd'] = self.branches[0]['mapped_grd'] |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1374 |
self.template.import_file() |
1375 |
self.template_pot = None |
|
1376 |
for lang, file in zip(self.template.get_supported_langs(), |
|
1377 |
self.template.get_supported_lang_filenames()): |
|
|
120
by Ken VanDine
handled latest grd format |
1378 |
try: |
1379 |
# also read all the xtb files referenced by this grd template
|
|
1380 |
rfile = os.path.join(self.branches[0]['dir'] , file) |
|
1381 |
xtb = XtbFile(lang, file, self.template, date = self.template.get_mtime(file), debug = self.debug, |
|
1382 |
branch_name = self.branches[0]['branch'], branch_dir = self.branches[0]['dir']) |
|
1383 |
xtb.import_file() |
|
1384 |
||
1385 |
self.file_mapping['lang_' + lang] = { 'src': file, |
|
1386 |
'branches': { self.branches[0]['branch']: self.branches[0]['dir'] } } |
|
1387 |
self.stats[lang] = { 'strings': self.template.get_supported_strings_count(lang), |
|
1388 |
'translated_upstream': 0, |
|
1389 |
'changed_in_gettext': 0, |
|
1390 |
'rejected': 0 |
|
1391 |
}
|
|
1392 |
self.template.merge_translations(lang, xtb) |
|
1393 |
self.translations[lang] = xtb |
|
1394 |
except Exception, e: |
|
1395 |
print "Skipping a XTB file, ERROR while importing xtb %s from grd file %s: %s" % (file, self.branches[0]['grd'], str(e)) |
|
1396 |
||
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1397 |
# read other grd templates
|
1398 |
if len(self.branches) > 1: |
|
1399 |
for branch in self.branches[1:]: |
|
1400 |
if self.debug: |
|
|
100
by Fabien Tassin
* Fix an issue with the gettext export when an xtb file disappear from the |
1401 |
print "merging %s from branch '%s' from %s" % (branch['grd'], branch['branch'], branch['dir']) |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
1402 |
template = GrdFile(branch['grd'], date, lang_mapping = self.lang_mapping, debug = self.debug, |
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1403 |
branch_name = branch['branch'], branch_dir = branch['dir']) |
1404 |
self.file_mapping['grd']['branches'][branch['branch']] = branch['dir'] |
|
1405 |
template.import_file() |
|
1406 |
self.template.merge_template(template, newer_preferred = False) |
|
1407 |
for lang, file in zip(template.get_supported_langs(), |
|
1408 |
template.get_supported_lang_filenames()): |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1409 |
xtb = XtbFile(lang, file, self.template, date = template.get_mtime(file), debug = self.debug, |
1410 |
branch_name = branch['branch'], branch_dir = branch['dir']) |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1411 |
if 'lang_' + lang not in self.file_mapping: |
1412 |
self.file_mapping['lang_' + lang] = { 'src': file, 'branches': {} } |
|
1413 |
self.file_mapping['lang_' + lang]['branches'][branch['branch']] = branch['dir'] |
|
1414 |
# TODO: stats
|
|
1415 |
xtb.import_file() |
|
|
100
by Fabien Tassin
* Fix an issue with the gettext export when an xtb file disappear from the |
1416 |
if lang not in self.translations: |
1417 |
if self.debug: |
|
1418 |
print "Add lang '%s' as master xtb for alt branch '%s'" % (lang, branch['branch']) |
|
1419 |
self.translations[lang] = xtb |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1420 |
self.template.merge_translations(lang, xtb, master_xtb = self.translations[lang], |
1421 |
newer_preferred = False) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1422 |
|
1423 |
def export_gettext_files(self, directory): |
|
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1424 |
fname = self.file_mapping['grd']['mapped_grd'] \ |
1425 |
if 'mapped_grd' in self.file_mapping['grd'] else self.template.filename |
|
1426 |
name = os.path.splitext(os.path.basename(fname))[0] |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1427 |
if directory is not None: |
1428 |
directory = os.path.join(directory, name) |
|
1429 |
if not os.path.isdir(directory): |
|
1430 |
os.makedirs(directory, 0755) |
|
1431 |
filename = os.path.join(directory, name + ".pot") |
|
1432 |
else: |
|
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1433 |
filename = os.path.splitext(fname)[0] + ".pot" |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1434 |
# create a pot template and merge the grd strings into it
|
1435 |
self.template_pot = PotFile(filename, date = self.template.mtime, debug = self.debug) |
|
1436 |
self.template_pot.import_grd(self.template) |
|
1437 |
# write it to a file
|
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
1438 |
self.template_changes += self.template_pot.export_file(directory = directory) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1439 |
|
1440 |
# do the same for all langs (xtb -> po)
|
|
1441 |
for lang in self.translations: |
|
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
1442 |
gtlang = self.template.mapped_langs[lang]['gettext'] |
1443 |
file = os.path.join(os.path.dirname(filename), gtlang + ".po") |
|
1444 |
po = PoFile(gtlang, file, self.template_pot, |
|
1445 |
date = self.translations[lang].translation_date, debug = self.debug) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1446 |
po.import_xtb(self.translations[lang]) |
1447 |
self.translations_changes += po.export_file(directory) |
|
1448 |
||
1449 |
def export_grit_xtb_file(self, lang, directory): |
|
1450 |
name = os.path.splitext(os.path.basename(self.template.filename))[0] |
|
1451 |
file = os.path.join(directory, os.path.basename(self.template.supported_langs[lang])) |
|
|
24
by Fabien Tassin
* Fix the xtb export for new langs |
1452 |
if len(self.translations[lang].strings.keys()) > 0: |
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1453 |
if 'lang_' + lang in self.file_mapping: |
1454 |
self.file_mapping['lang_' + lang]['dst'] = file |
|
1455 |
else: |
|
1456 |
self.file_mapping['lang_' + lang] = { 'src': None, 'dst': file } |
|
|
24
by Fabien Tassin
* Fix the xtb export for new langs |
1457 |
self.translations[lang].export_file(filename = file) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1458 |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
1459 |
def export_grit_files(self, directory, langs): |
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
1460 |
grd_dst = os.path.join(directory, os.path.basename(self.template.filename)) |
|
24
by Fabien Tassin
* Fix the xtb export for new langs |
1461 |
if len(self.translations.keys()) == 0: |
1462 |
if self.debug: |
|
1463 |
print "no translation at all, nothing to export here (template: %s)" % self.template.filename |
|
1464 |
return
|
|
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
1465 |
if not os.path.isdir(directory): |
1466 |
os.makedirs(directory, 0755) |
|
|
99
by Fabien Tassin
* When an xtb disappears, also drop it from the corresponding grd file |
1467 |
# 'langs' may contain langs for which this template no longer have translations for.
|
1468 |
# They need to be dropped from the grd file
|
|
|
101
by Fabien Tassin
* Fix a regression in #99 where .pak files were lost leading to FTBFS |
1469 |
self.template.export_file(filename = grd_dst, global_langs = langs, langs = self.translations.keys()) |
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1470 |
self.file_mapping['grd']['dst'] = grd_dst |
|
28
by Fabien Tassin
* Fix a broken path in the generated patches |
1471 |
self.file_mapping['grd']['dir'] = directory[:-len(os.path.dirname(self.template.filename)) - 1] |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1472 |
for lang in self.translations: |
|
112
by Fabien Tassin
* Move all new xtb files to third_party/launchpad_translations (relative to $SRC) |
1473 |
prefix = self.template.supported_langs[lang] |
1474 |
fdirectory = os.path.normpath(os.path.join(self.file_mapping['grd']['dir'], os.path.dirname(prefix))) |
|
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
1475 |
if not os.path.isdir(fdirectory): |
1476 |
os.makedirs(fdirectory, 0755) |
|
|
26
by Fabien Tassin
* Generate grd files during --export-grit. That includes missing xtb in <translations/> |
1477 |
self.export_grit_xtb_file(lang, fdirectory) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1478 |
|
1479 |
def get_supported_strings_count(self): |
|
1480 |
return len(self.template.supported_ids.keys()) |
|
1481 |
||
|
34
by Fabien Tassin
* Improve inform message for updated translations |
1482 |
def compare_translations(self, old, new, id, lang): |
|
21
by Fabien Tassin
* Strip leading and trailing whitespaces from the upstream strings |
1483 |
# strip leading and trailing whitespaces from the upstream strings
|
1484 |
# (this should be done upstream)
|
|
1485 |
old = old.strip() |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1486 |
if old != new: |
|
38
by Fabien Tassin
* Protect the compare function from failure when a string is not in the template |
1487 |
s = self.template.supported_ids[id]['ids'][0]['val'] if 'ids' in self.template.supported_ids[id] else "<none?>" |
|
42
by Fabien Tassin
* Only report the updated translations in debug mode |
1488 |
if self.debug: |
1489 |
print "Found a different translation for id %s in lang '%s':\n string: \"%s\"\n " \ |
|
1490 |
"upstream: \"%s\"\n launchpad: \"%s\"\n" % (id, lang, s, old, new) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1491 |
return old == new |
1492 |
||
1493 |
def import_gettext_po_file(self, lang, filename): |
|
1494 |
""" import a single lang file into the current translations set,
|
|
1495 |
matching the current template. Could be useful to merge the upstream
|
|
1496 |
and launchpad translations, or to merge strings from another project
|
|
1497 |
(like webkit) """
|
|
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
1498 |
po = PoFile(self.template.mapped_langs[lang]['gettext'], filename, self.template, |
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1499 |
date = self.template.get_mtime(filename), debug = self.debug) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1500 |
po.import_file() |
|
30
by Fabien Tassin
* Don't generate an xtb if the imported po only has empty translations |
1501 |
# no need to continue if there are no translation in this po
|
1502 |
translated_count = 0 |
|
1503 |
for s in po.strings: |
|
1504 |
if s['string'] != '""' and s['translation'] != '""': |
|
1505 |
translated_count += 1 |
|
1506 |
if translated_count == 0: |
|
1507 |
if self.debug: |
|
1508 |
print "No translation found for lang %s in %s" % (lang, filename) |
|
1509 |
return
|
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1510 |
if lang not in self.translations: |
|
112
by Fabien Tassin
* Move all new xtb files to third_party/launchpad_translations (relative to $SRC) |
1511 |
# assuming the filename should be third_party/launchpad_translations/<template_name>_<lang>.xtb
|
1512 |
# (relative to $SRC), we need it relatively to the grd directory
|
|
|
24
by Fabien Tassin
* Fix the xtb export for new langs |
1513 |
tname = os.path.splitext(os.path.basename(self.template.filename))[0] |
|
112
by Fabien Tassin
* Move all new xtb files to third_party/launchpad_translations (relative to $SRC) |
1514 |
f = os.path.normpath(os.path.join('third_party/launchpad_translations', |
|
47
by Fabien Tassin
* Fix the xtb exports now that upstream moved us to ../third_party/launchpad_translations |
1515 |
tname + '_' + self.template.mapped_langs[lang]['xtb_file'] + '.xtb')) |
|
24
by Fabien Tassin
* Fix the xtb export for new langs |
1516 |
self.translations[lang] = XtbFile(lang, f, self.template, date = po.mtime, debug = self.debug) |
1517 |
self.template.supported_langs[lang] = f # *sigh* |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1518 |
|
|
29
by Fabien Tassin
* Add a work-around for https://bugs.launchpad.net/rosetta/+bug/669831 |
1519 |
lp669831_skipped = 0 |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1520 |
for string in po.strings: |
1521 |
if 'id' not in string: |
|
1522 |
continue # PO header |
|
1523 |
id = string['id'] |
|
1524 |
if id in self.template.supported_ids: |
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
1525 |
if 'conditions' in string: |
1526 |
# test the lang against all those conditions. If at least one passes, we need
|
|
1527 |
# the string
|
|
1528 |
found = False |
|
1529 |
for c in string['conditions']: |
|
1530 |
found |= EvalConditions().lang_eval(c, lang) |
|
1531 |
if found is False: |
|
1532 |
self.template.update_stats(lang, skipped_lang = 1) |
|
1533 |
if self.debug: |
|
1534 |
print "Skipped string (lang condition) for %s/%s: %s" % \ |
|
1535 |
(os.path.splitext(os.path.basename(self.template.filename))[0], |
|
1536 |
lang, repr(string)) |
|
1537 |
continue
|
|
|
29
by Fabien Tassin
* Add a work-around for https://bugs.launchpad.net/rosetta/+bug/669831 |
1538 |
# workaround bug https://bugs.launchpad.net/rosetta/+bug/669831
|
1539 |
ustring = StringCvt().gettext2xtb(string['string']) |
|
|
46
by Fabien Tassin
* Add a link back to the faulty strings in launchpad in the logs |
1540 |
gt_translation = string['translation'][1:-1].replace('"\n"', '') |
|
29
by Fabien Tassin
* Add a work-around for https://bugs.launchpad.net/rosetta/+bug/669831 |
1541 |
string['translation'] = StringCvt().gettext2xtb(string['translation']) |
|
107
by Fabien Tassin
* Sanitize the gettext translations /wrt the \n |
1542 |
if string['translation'] != "": |
1543 |
while string['translation'][-1:] == '\n' and ustring[-1:] != '\n': |
|
1544 |
# prevent the `msgid' and `msgstr' entries do not both end with '\n' error
|
|
1545 |
if self.debug: |
|
1546 |
print "Found unwanted \\n at the end of translation id " + id + " lang " + self.lang + ". Dropped" |
|
1547 |
string['translation'] = string['translation'][:-1] |
|
1548 |
while string['translation'][0] == '\n' and ustring[0] != '\n': |
|
1549 |
# prevent the `msgid' and `msgstr' entries do not both begin with '\n' error
|
|
1550 |
if self.debug: |
|
1551 |
print "Found unwanted \\n at the begin of translation id " + id + " lang " + self.lang + ". Dropped" |
|
1552 |
string['translation'] = string['translation'][1:] |
|
|
56
by Fabien Tassin
* Improve the workaround for lp669831, we were rejecting ~20 strings because |
1553 |
grit_str = StringCvt().decode_xml_entities(self.template.supported_ids[id]['ids'][0]['val']) |
|
61
by Fabien Tassin
* Disable the last workaround for LP #669831 |
1554 |
if False and 'ids' in self.template.supported_ids[id] and \ |
|
56
by Fabien Tassin
* Improve the workaround for lp669831, we were rejecting ~20 strings because |
1555 |
ustring != grit_str: |
|
41
by Fabien Tassin
* Stop fixing the bogus strings for LP #669831, this bug really needs to be fixed |
1556 |
# the string for this id is no longer the same, skip it
|
1557 |
lp669831_skipped += 1 |
|
1558 |
if self.debug: |
|
|
56
by Fabien Tassin
* Improve the workaround for lp669831, we were rejecting ~20 strings because |
1559 |
print "lp669831_skipped:\n lp: '%s'\n grd: '%s'" % (ustring, grit_str) |
|
41
by Fabien Tassin
* Stop fixing the bogus strings for LP #669831, this bug really needs to be fixed |
1560 |
continue
|
|
31
by Fabien Tassin
* Reject translations that are not parsable by the sax parser to prevent a FTBFS. |
1561 |
# check for xml errors when '<' or '>' are in the string
|
1562 |
if string['translation'].find('<') >= 0 or \ |
|
1563 |
string['translation'].find('>') >= 0: |
|
1564 |
try: |
|
1565 |
# try to parse it with minidom (it's slow!!), and skip if it fails
|
|
1566 |
s = u"<x>" + string['translation'] + u"</x>" |
|
1567 |
dom = minidom.parseString(s.encode('utf-8')) |
|
1568 |
except Exception as inst: |
|
1569 |
print "Parse error in '%s/%s' for id %s. Skipped.\n%s\n%s" % \ |
|
1570 |
(os.path.splitext(os.path.basename(self.template.filename))[0], lang, id, |
|
1571 |
repr(string['translation']), inst) |
|
1572 |
continue
|
|
|
33
by Fabien Tassin
* Don't add empty strings in the xtb if they are in the upstream xtbs but no longer in LP |
1573 |
# if the upstream string is not empty, but the contributed string is, keep
|
1574 |
# the upstream string untouched
|
|
1575 |
if string['translation'] == '': |
|
1576 |
continue
|
|
|
43
by Fabien Tassin
* Add a sanity checker for mismatching placeholder variables |
1577 |
# check if we have the same variables in both the upstream string and its
|
1578 |
# translation. Otherwise, complain and reject the translation
|
|
1579 |
if 'ids' in self.template.supported_ids[id]: |
|
1580 |
uvars = sorted([e for e in re.split('(<ph name=".*?"/>)', self.template.supported_ids[id]['ids'][0]['val']) \ |
|
1581 |
if re.match('^<ph name=".*?"/>$', e)]) |
|
1582 |
tvars = sorted([e for e in re.split('(<ph name=".*?"/>)', string['translation'])\ |
|
1583 |
if re.match('^<ph name=".*?"/>$', e)]) |
|
1584 |
lostvars = list(set(uvars).difference(set(tvars))) |
|
1585 |
createdvars = list(set(tvars).difference(set(uvars))) |
|
1586 |
if len(lostvars) or len(createdvars): |
|
|
46
by Fabien Tassin
* Add a link back to the faulty strings in launchpad in the logs |
1587 |
template = os.path.splitext(os.path.basename(self.template.filename))[0].replace('_', '-') |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
1588 |
self.errors += 1 |
1589 |
if self.html_output: |
|
1590 |
print "<div class='error'>[<a id='pherr-%s-%d' href='javascript:toggle(\"pherr-%s-%d\");'>+</a>] " \ |
|
1591 |
"<b>ERROR</b>: Found mismatching placeholder variables in string id %s of <b>%s</b> lang <b>%s</b>" % \ |
|
1592 |
(template, self.errors, template, self.errors, id, template, lang) |
|
1593 |
else: |
|
1594 |
print "ERROR: Found mismatching placeholder variables in string id %s of %s/%s:" % \ |
|
1595 |
(id, template, lang) |
|
|
46
by Fabien Tassin
* Add a link back to the faulty strings in launchpad in the logs |
1596 |
url = 'https://translations.launchpad.net/chromium-browser/translations/+pots/%s/%s/+translate?batch=10&show=all&search=%s' % \ |
1597 |
(template, self.template.mapped_langs[lang]['gettext'], urllib.quote(gt_translation.encode('utf-8'))) |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
1598 |
if self.html_output: |
1599 |
print "<div id='pherr-%s-%d-t' style='display: none'>\n" \ |
|
1600 |
"<fieldset><legend>Details</legend><p><ul>" % (template, self.errors) |
|
1601 |
print "<li> <a href='%s'>this string in Launchpad</a>\n" % url |
|
1602 |
if len(lostvars): |
|
1603 |
print " <li> expected but not found: <code>%s</code>" % " ".join([ re.sub(r'<ph name="(.*?)"/>', r'%{\1}', s) for s in lostvars ]) |
|
1604 |
if len(createdvars): |
|
1605 |
print " <li> found but not expected: <code>%s</code>" % " ".join([ re.sub(r'<ph name="(.*?)"/>', r'%{\1}', s) for s in createdvars ]) |
|
1606 |
print "</ul><table border='1'>" \ |
|
1607 |
"<tr><th rowspan='2'>GetText</th><th>template</th><td><code>%s</code></td></tr>\n" \ |
|
1608 |
"<tr><th>translation</th><td><code>%s</code></td></tr>\n" \ |
|
1609 |
"<tr><th rowspan='2'>Grit</th><th>template</th><td><code>%s</code></td></tr>\n" \ |
|
1610 |
"<tr><th>translation</th><td><code>%s</code></td></tr>\n" \ |
|
1611 |
"</table><p> => <b>translation skipped</b>\n" % \ |
|
1612 |
(string['string'][1:-1].replace('"\n"', '').replace('<', '<').replace('>', '>'), |
|
1613 |
gt_translation.replace('<', '<').replace('>', '>'), |
|
1614 |
self.template.supported_ids[id]['ids'][0]['val'].replace('<', '<').replace('>', '>'), |
|
1615 |
string['translation'].replace('<', '<').replace('>', '>')) |
|
1616 |
print "</fieldset></div></div>" |
|
1617 |
else: |
|
1618 |
if len(lostvars): |
|
1619 |
print " - expected but not found: " + " ".join(lostvars) |
|
1620 |
if len(createdvars): |
|
1621 |
print " - found but not expected: " + " ".join(createdvars) |
|
1622 |
print " string: '%s'\n translation: '%s'\n gettext: '%s'\n url: %s\n => translation skipped\n" % \ |
|
1623 |
(self.template.supported_ids[id]['ids'][0]['val'], string['translation'], gt_translation, url) |
|
|
43
by Fabien Tassin
* Add a sanity checker for mismatching placeholder variables |
1624 |
continue
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1625 |
# check if the translated string is the same
|
1626 |
if 'lang' in self.template.supported_ids[id] and \ |
|
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
1627 |
lang in self.template.supported_ids[id]['lang']: |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1628 |
# compare
|
1629 |
if self.compare_translations(self.template.supported_ids[id]['lang'][lang], |
|
|
34
by Fabien Tassin
* Improve inform message for updated translations |
1630 |
string['translation'], id, lang): |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1631 |
continue # it's the same |
|
91
by Fabien Tassin
* When using --import-gettext along with --export-gettext, try to be smart |
1632 |
if id in self.translations[lang].strings: |
1633 |
# already added from a previously merged gettext po file
|
|
1634 |
if self.debug: |
|
1635 |
print "already added from a previously merged gettext po file for" + \ |
|
1636 |
" template %s %s id %s in lang %s: %s" % \ |
|
1637 |
(self.template.branch_name, self.template.filename, |
|
1638 |
id, lang, repr(string['translation'])) |
|
1639 |
# compare
|
|
1640 |
if self.compare_translations(self.translations[lang].strings[id], |
|
1641 |
string['translation'], id, lang): |
|
1642 |
continue # it's the same |
|
1643 |
# update it..
|
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1644 |
if self.debug: |
|
91
by Fabien Tassin
* When using --import-gettext along with --export-gettext, try to be smart |
1645 |
print "updated string for template %s %s id %s in lang %s: %s" % \ |
1646 |
(self.template.branch_name, self.template.filename, id, lang, |
|
1647 |
repr(string['translation'])) |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
1648 |
self.template.update_stats(lang, updated = 1) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1649 |
self.translations[lang].strings[id] = string['translation'] |
1650 |
self.translations[lang].strings_updated += 1 |
|
|
91
by Fabien Tassin
* When using --import-gettext along with --export-gettext, try to be smart |
1651 |
elif id in self.translations[lang].strings: |
1652 |
# already added from a previously merged gettext po file
|
|
1653 |
if self.debug: |
|
1654 |
print "already added from a previously merged gettext po file for" + \ |
|
1655 |
"template %s %s id %s in lang %s: %s" % \ |
|
1656 |
(self.template.branch_name, self.template.filename, |
|
1657 |
id, lang, repr(string['translation'])) |
|
1658 |
# compare
|
|
1659 |
if self.compare_translations(self.translations[lang].strings[id], |
|
1660 |
string['translation'], id, lang): |
|
1661 |
continue # it's the same |
|
1662 |
# update it..
|
|
1663 |
self.translations[lang].strings[id] = string['translation'] |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1664 |
else: |
1665 |
# add
|
|
1666 |
if self.debug: |
|
|
91
by Fabien Tassin
* When using --import-gettext along with --export-gettext, try to be smart |
1667 |
print "add new string for template %s %s id %s in lang %s: %s" % \ |
1668 |
(self.template.branch_name, self.template.filename, |
|
1669 |
id, lang, repr(string['translation'])) |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
1670 |
self.template.update_stats(lang, new = 1) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1671 |
self.translations[lang].strings[id] = string['translation'] |
1672 |
self.translations[lang].strings_new += 1 |
|
|
44
by Fabien Tassin
* Remove the warning for lp669831_skipped (see the reason in the corresponding LP bug) |
1673 |
if self.debug and lp669831_skipped > 0: |
|
41
by Fabien Tassin
* Stop fixing the bogus strings for LP #669831, this bug really needs to be fixed |
1674 |
print "lp669831: skipped %s bogus/obsolete strings from %s" % \ |
1675 |
(lp669831_skipped, filename[filename[:filename.rfind('/')].rfind('/') + 1:]) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1676 |
|
1677 |
def import_gettext_po_files(self, directory): |
|
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1678 |
fname = self.file_mapping['grd']['mapped_grd'] \ |
1679 |
if 'mapped_grd' in self.file_mapping['grd'] else self.template.filename |
|
1680 |
template_name = os.path.splitext(os.path.basename(fname))[0] |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1681 |
directory = os.path.join(directory, template_name) |
|
49
by Fabien Tassin
* Don't die when we merge strings for a template that Launchpad doesn't know yet |
1682 |
if not os.path.isdir(directory): |
1683 |
if self.debug: |
|
|
91
by Fabien Tassin
* When using --import-gettext along with --export-gettext, try to be smart |
1684 |
print "WARN: Launchpad didn't export anything for template '%s' [%s]" % (template_name, directory) |
|
49
by Fabien Tassin
* Don't die when we merge strings for a template that Launchpad doesn't know yet |
1685 |
return
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1686 |
for file in os.listdir(directory): |
1687 |
base, ext = os.path.splitext(file) |
|
1688 |
if ext != ".po": |
|
|
1
by Fabien Tassin
* Initial revision |
1689 |
continue
|
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
1690 |
# 'base' is a gettext lang, map it
|
1691 |
lang = None |
|
1692 |
for l in self.template.mapped_langs: |
|
1693 |
if base == self.template.mapped_langs[l]['gettext']: |
|
1694 |
lang = l |
|
1695 |
break
|
|
1696 |
if lang is None: # most probably a new lang, map back |
|
1697 |
lang = base.replace('_', '-') |
|
1698 |
for l in self.lang_mapping: |
|
1699 |
if lang == self.lang_mapping[l]: |
|
1700 |
lang = l |
|
1701 |
break
|
|
|
104
by Fabien Tassin
* Use '-' instead of '@' in the xtb filenames for langs with a sub-code like 'ca@valencia' |
1702 |
flang = lang.replace('@', '-') |
1703 |
self.template.mapped_langs[lang] = { 'xtb_file': flang, 'grit': lang, 'gettext': base } |
|
|
25
by Fabien Tassin
* Clean-up the mess with the lang mapping |
1704 |
self.import_gettext_po_file(lang, os.path.join(directory, file)) |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
1705 |
# remove from the supported langs list all langs with no translated strings
|
1706 |
# (to catch either empty 'po' files exported by Launchpad, or 'po' files
|
|
1707 |
# containing only obsolete or too new strings for this branch)
|
|
1708 |
dropped = [] |
|
1709 |
for lang in self.translations: |
|
1710 |
if len(self.translations[lang].strings.keys()) == 0: |
|
1711 |
if self.debug: |
|
1712 |
print "no translation found for template '%s' and lang '%s'. lang removed from the supported lang list" % \ |
|
1713 |
(os.path.splitext(os.path.basename(self.template.filename))[0], lang) |
|
1714 |
del(self.template.supported_langs[lang]) |
|
1715 |
dropped.append(lang) |
|
1716 |
for lang in dropped: |
|
1717 |
del(self.translations[lang]) |
|
|
1
by Fabien Tassin
* Initial revision |
1718 |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1719 |
def copy_grit_files(self, directory): |
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1720 |
fname = self.file_mapping['grd']['mapped_grd'] \ |
1721 |
if 'mapped_grd' in self.file_mapping['grd'] else self.template.filename |
|
1722 |
dst = os.path.join(directory, os.path.dirname(fname)) |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1723 |
if not os.path.isdir(dst): |
1724 |
os.makedirs(dst, 0755) |
|
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
1725 |
shutil.copy2(fname, dst) |
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1726 |
for lang in self.template.supported_langs: |
1727 |
dst = os.path.join(directory, os.path.dirname(self.translations[lang].filename)) |
|
1728 |
if not os.path.isdir(dst): |
|
1729 |
os.makedirs(dst, 0755) |
|
1730 |
shutil.copy2(self.translations[lang].filename, dst) |
|
1731 |
||
1732 |
def create_patches(self, directory): |
|
1733 |
if not os.path.isdir(directory): |
|
1734 |
os.makedirs(directory, 0755) |
|
1735 |
template_name = os.path.splitext(os.path.basename(self.template.filename))[0] |
|
1736 |
patch = codecs.open(os.path.join(directory, "translations-" + template_name + ".patch"), |
|
1737 |
"wb", encoding="utf-8") |
|
1738 |
for e in sorted(self.file_mapping.keys()): |
|
|
97
by Fabien Tassin
* Don't die when we need to drop an empty xtb file (once its strings became obsolete) |
1739 |
if 'dst' not in self.file_mapping[e]: |
1740 |
self.file_mapping[e]['dst'] = None |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1741 |
if self.file_mapping[e]['src'] is not None and \ |
1742 |
self.file_mapping[e]['dst'] is not None and \ |
|
1743 |
filecmp.cmp(self.file_mapping[e]['src'], self.file_mapping[e]['dst']) == True: |
|
1744 |
continue # files are the same |
|
1745 |
||
1746 |
if self.file_mapping[e]['src'] is not None: |
|
1747 |
fromfile = "old/" + self.file_mapping[e]['src'] |
|
1748 |
tofile = "new/" + self.file_mapping[e]['src'] |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1749 |
fromdate = datetime.fromtimestamp(self.template.get_mtime( |
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1750 |
self.file_mapping[e]['src'])).strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
1751 |
fromlines = codecs.open(self.file_mapping[e]['src'], 'rb', encoding="utf-8").readlines() |
|
1752 |
else: |
|
1753 |
fromfile = "old/" + self.file_mapping[e]['dst'][len(self.file_mapping['grd']['dir']) + 1:] |
|
1754 |
tofile = "new/" + self.file_mapping[e]['dst'][len(self.file_mapping['grd']['dir']) + 1:] |
|
1755 |
fromdate = datetime.fromtimestamp(0).strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
|
1756 |
fromlines = "" |
|
1757 |
if self.file_mapping[e]['dst'] is not None: |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1758 |
todate = datetime.fromtimestamp(self.template.get_mtime( |
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1759 |
self.file_mapping[e]['dst'])).strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
1760 |
tolines = codecs.open(self.file_mapping[e]['dst'], 'rb', encoding="utf-8").readlines() |
|
1761 |
else: |
|
1762 |
todate = datetime.fromtimestamp(0).strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
|
1763 |
tolines = "" |
|
1764 |
diff = unified_diff(fromlines, tolines, fromfile, tofile, |
|
1765 |
fromdate, todate, n=3) |
|
1766 |
patch.write("diff -Nur %s %s\n" % (fromfile, tofile)) |
|
1767 |
s = ''.join(diff) |
|
|
32
by Fabien Tassin
* Fix the diffs so that older patch (<< 2.6) don't fail on new files |
1768 |
# fix the diff so that older patch (<< 2.6) don't fail on new files
|
1769 |
s = re.sub(r'@@ -1,0 ', '@@ -0,0 ', s) |
|
|
98
by Fabien Tassin
* Unified diffs created by python's difflib don't allow the gnu patch to |
1770 |
# ..and make sure patch is able to detect a patch removing files
|
1771 |
s = re.sub(r'(@@ \S+) \+1,0 @@', '\\1 +0,0 @@', s) |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
1772 |
patch.writelines(s) |
1773 |
if s[-1:] != '\n': |
|
1774 |
patch.write("\n\\ No newline at end of file\n") |
|
1775 |
patch.close() |
|
1776 |
||
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1777 |
def update_supported_langs_in_grd(self, grd_in, grd_out, langs): |
1778 |
fdi = codecs.open(grd_in, 'rb', encoding="utf-8") |
|
1779 |
fdo = codecs.open(grd_out, 'wb', encoding="utf-8") |
|
1780 |
# can't use minidom here as the file is manually generated and the
|
|
1781 |
# output will create big diffs. parse the source file line by line
|
|
1782 |
# and insert new langs in the <outputs> section (with type="data_package"
|
|
1783 |
# or type="js_map_format"). Let everything else untouched
|
|
1784 |
# FIXME: this is mostly a copy of GrdFile::export_file()
|
|
1785 |
pak_found = False |
|
1786 |
pak_saved = [] |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1787 |
has_ifs = False |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1788 |
for line in fdi.readlines(): |
1789 |
if re.match(r'.*?<output filename=".*?" type="(data_package|js_map_format)"', line): |
|
1790 |
pak_found = True |
|
1791 |
pak_saved.append(line) |
|
1792 |
continue
|
|
1793 |
if line.find('</outputs>') > 0: |
|
1794 |
pak_found = False |
|
1795 |
ours = langs[:] |
|
1796 |
chunks = {} |
|
1797 |
c = None |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1798 |
pak_if = None |
1799 |
pak_is_in_if = False |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1800 |
for l in pak_saved: |
1801 |
if l.find("<!-- ") > 0: |
|
1802 |
c = l |
|
1803 |
continue
|
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1804 |
if l.find("<if ") > -1: |
1805 |
c = l if c is None else c + l |
|
1806 |
has_ifs = True |
|
1807 |
pak_is_in_if = True |
|
1808 |
continue
|
|
1809 |
if l.find("</if>") > -1: |
|
1810 |
c = l if c is None else c + l |
|
1811 |
pak_is_in_if = False |
|
1812 |
continue
|
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1813 |
m = re.match(r'.*?<output filename="(.*?)_([^_\.]+)\.(pak|js)" type="(data_package|js_map_format)" lang="(.*?)" />', l) |
1814 |
if m is not None: |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1815 |
x = { 'name': m.group(1), 'ext': m.group(3), 'lang': m.group(5), 'file_lang': m.group(2), |
1816 |
'type': m.group(4), 'in_if': pak_is_in_if, 'line': l } |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1817 |
if c is not None: |
1818 |
x['comment'] = c |
|
1819 |
c = None |
|
1820 |
k = m.group(2) if m.group(2) != 'nb' else 'no' |
|
1821 |
chunks[k] = x |
|
1822 |
else: |
|
1823 |
if c is None: |
|
1824 |
c = l |
|
1825 |
else: |
|
1826 |
c += l |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1827 |
is_in_if = False |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1828 |
for lang in sorted(chunks.keys()): |
1829 |
tlang = lang if lang != 'no' else 'nb' |
|
1830 |
while len(ours) > 0 and ((ours[0] == 'nb' and 'no' < tlang) or (ours[0] != 'nb' and ours[0] < tlang)): |
|
|
115
by Fabien Tassin
* Fix a regression introduced by the new fake-bidi pseudo locale |
1831 |
if ours[0] in chunks: |
1832 |
ours = ours[1:] |
|
1833 |
continue
|
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1834 |
if has_ifs and is_in_if is False: |
1835 |
fdo.write(' <if expr="pp_ifdef(\'use_third_party_translations\')">\n') |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1836 |
f = "%s_%s.%s" % (chunks[lang]['name'], ours[0], chunks[lang]['ext']) |
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1837 |
fdo.write(' %s<output filename="%s" type="%s" lang="%s" />\n' % \ |
1838 |
(' ' if has_ifs else '', f, chunks[lang]['type'], ours[0])) |
|
1839 |
is_in_if = True |
|
1840 |
if has_ifs and chunks[lang]['in_if'] is False: |
|
|
109
by Fabien Tassin
* Fix badly closed <if/> blocks in grd files |
1841 |
if 'comment' not in chunks[lang] or chunks[lang]['comment'].find('</if>') == -1: |
1842 |
fdo.write(' </if>\n') |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1843 |
is_in_if = False |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1844 |
ours = ours[1:] |
1845 |
if 'comment' in chunks[lang]: |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1846 |
for s in chunks[lang]['comment'].split('\n')[:-1]: |
1847 |
if chunks[lang]['in_if'] is True and is_in_if and s.find('<if ') > -1: |
|
1848 |
continue
|
|
1849 |
if s.find('<!-- No translations available. -->') > -1: |
|
1850 |
continue
|
|
1851 |
fdo.write(s + '\n') |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1852 |
fdo.write(chunks[lang]['line']) |
|
115
by Fabien Tassin
* Fix a regression introduced by the new fake-bidi pseudo locale |
1853 |
if ours[0] == tlang: |
1854 |
ours = ours[1:] |
|
1855 |
is_in_if = chunks[lang]['in_if'] |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1856 |
if len(chunks.keys()) > 0: |
1857 |
while len(ours) > 0: |
|
1858 |
f = "%s_%s.%s" % (chunks[lang]['name'], ours[0], chunks[lang]['ext']) |
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1859 |
if has_ifs and is_in_if is False: |
1860 |
fdo.write(' <if expr="pp_ifdef(\'use_third_party_translations\')">\n') |
|
1861 |
fdo.write(' %s<output filename="%s" type="data_package" lang="%s" />\n' % \ |
|
1862 |
(' ' if has_ifs else '', f, ours[0])) |
|
1863 |
is_in_if = True |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1864 |
ours = ours[1:] |
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1865 |
if has_ifs and is_in_if: |
1866 |
fdo.write(' </if>\n') |
|
1867 |
is_in_if = False |
|
1868 |
if c is not None: |
|
1869 |
for s in c.split('\n')[:-1]: |
|
1870 |
if s.find('<!-- No translations available. -->') > -1: |
|
1871 |
continue
|
|
|
89
by Fabien Tassin
* Don't double-close trailing <if> |
1872 |
if s.find('</if>') > -1: |
1873 |
continue
|
|
|
84
by Fabien Tassin
* Improve the previous commit to encapsulate more tags into the same <if/> |
1874 |
fdo.write(s + '\n') |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1875 |
if pak_found: |
1876 |
pak_saved.append(line) |
|
1877 |
continue
|
|
1878 |
fdo.write(line) |
|
1879 |
fdi.close() |
|
1880 |
fdo.close() |
|
1881 |
||
|
73
by Fabien Tassin
* Add a --whitelisted-new-langs flag that can be used to only enable new |
1882 |
def create_build_gyp_patch(self, directory, build_gyp_file, other_grd_files, nlangs, |
1883 |
whitelisted_new_langs = None): |
|
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
1884 |
# read the list of langs supported upstream
|
1885 |
fd = open(build_gyp_file, "r") |
|
1886 |
data = fd.read() |
|
1887 |
fd.close() |
|
1888 |
r = data[data.find("'locales':"):] |
|
1889 |
olangs = sorted(re.findall("'(.*?)'", r[r.find('['):r.find(']')])) |
|
|
85
by Fabien Tassin
* Support the new use_third_party_translations feature in create_build_gyp_patch(). |
1890 |
# check for an optional use_third_party_translations list of locales
|
1891 |
tpt = data.find('use_third_party_translations==1') |
|
1892 |
if tpt > 0: |
|
1893 |
tpt += data[tpt:].find("'locales':") |
|
1894 |
r = data[tpt:] |
|
1895 |
tptlangs = sorted(re.findall("'(.*?)'", r[r.find('['):r.find(']')])) |
|
1896 |
if nlangs == sorted(tptlangs + olangs): |
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
1897 |
return tptlangs |
|
85
by Fabien Tassin
* Support the new use_third_party_translations feature in create_build_gyp_patch(). |
1898 |
else: |
1899 |
if nlangs == olangs: |
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
1900 |
return [] |
|
73
by Fabien Tassin
* Add a --whitelisted-new-langs flag that can be used to only enable new |
1901 |
# check if we need to only activate some whitelisted new langs
|
1902 |
xlangs = None |
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
1903 |
nnlangs = [ x for x in nlangs if x not in olangs ] |
|
73
by Fabien Tassin
* Add a --whitelisted-new-langs flag that can be used to only enable new |
1904 |
if whitelisted_new_langs is not None: |
|
85
by Fabien Tassin
* Support the new use_third_party_translations feature in create_build_gyp_patch(). |
1905 |
if tpt > 0: |
1906 |
nlangs = [ x for x in nlangs if x not in olangs and x in whitelisted_new_langs ] |
|
1907 |
else: |
|
1908 |
xlangs = [ x for x in nlangs if x not in olangs and x not in whitelisted_new_langs ] |
|
1909 |
nlangs = [ x for x in nlangs if x in olangs or x in whitelisted_new_langs ] |
|
1910 |
elif tpt > 0: |
|
1911 |
nlangs = [ x for x in nlangs if x not in olangs ] |
|
1912 |
||
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1913 |
# we need a patch
|
|
85
by Fabien Tassin
* Support the new use_third_party_translations feature in create_build_gyp_patch(). |
1914 |
if tpt > 0: |
1915 |
pos = tpt + data[tpt:].find('[') |
|
1916 |
end = data[:pos + 1] |
|
1917 |
ndata = end[:] |
|
1918 |
else: |
|
1919 |
pos = data.find("'locales':") |
|
1920 |
begin = data[pos:] |
|
1921 |
end = data[:pos + begin.find('\n')] |
|
1922 |
ndata = end[:] |
|
1923 |
end = data[pos + data[pos:].find(']'):] |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1924 |
|
|
116
by Fabien Tassin
* When updating common.gypi, fold 'locales' by size (instead of by groups of 10) |
1925 |
# list of langs, folded
|
1926 |
if len(nlangs) > 9: |
|
1927 |
ndata += '\n' + \ |
|
1928 |
'\n'.join(textwrap.wrap("'" + "', '".join(nlangs) + "'", |
|
1929 |
break_long_words=False, width=76, |
|
1930 |
drop_whitespace=False, |
|
1931 |
expand_tabs=False, |
|
1932 |
replace_whitespace=False, |
|
1933 |
initial_indent=' ', |
|
1934 |
subsequent_indent=' ', |
|
1935 |
break_on_hyphens=False)) + '\n ' |
|
|
85
by Fabien Tassin
* Support the new use_third_party_translations feature in create_build_gyp_patch(). |
1936 |
else: |
1937 |
ndata += "'%s'" % "', '".join(nlangs) |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1938 |
|
1939 |
ndata += end |
|
1940 |
||
1941 |
# write the patch
|
|
1942 |
fromfile = "old/" + build_gyp_file |
|
1943 |
tofile = "new/" + build_gyp_file |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1944 |
fromdate = datetime.fromtimestamp(self.template.get_mtime(build_gyp_file)).strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1945 |
fromlines = [ x for x in re.split('(.*\n?)', data) if x != '' ] |
1946 |
todate = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
|
1947 |
tolines = [ x for x in re.split('(.*\n?)', ndata) if x != '' ] |
|
1948 |
patch = codecs.open(os.path.join(directory, "build.patch"), "wb", encoding="utf-8") |
|
1949 |
diff = unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=3) |
|
1950 |
patch.write("diff -Nur %s %s\n" % (fromfile, tofile)) |
|
1951 |
patch.writelines(''.join(diff)) |
|
1952 |
||
1953 |
for grd in other_grd_files: |
|
1954 |
grd_out = os.path.join(directory, os.path.basename(grd)) |
|
1955 |
self.update_supported_langs_in_grd(grd, grd_out, langs) |
|
1956 |
if filecmp.cmp(grd, grd_out) == True: |
|
1957 |
os.unlink(grd_out) |
|
1958 |
continue # files are the same |
|
1959 |
# add it to the patch
|
|
1960 |
fromfile = "old/" + grd |
|
1961 |
tofile = "new/" + grd |
|
|
90
by Fabien Tassin
* Improve the merge of templates from different branches |
1962 |
fromdate = datetime.fromtimestamp(self.template.get_mtime(grd)).strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1963 |
fromlines = codecs.open(grd, 'rb', encoding="utf-8").readlines() |
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
1964 |
todate = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f000 +0000") |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1965 |
tolines = codecs.open(grd_out, 'rb', encoding="utf-8").readlines() |
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
1966 |
diff = unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=3) |
1967 |
patch.write("diff -Nur %s %s\n" % (fromfile, tofile)) |
|
1968 |
patch.writelines(''.join(diff)) |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
1969 |
os.unlink(grd_out) |
1970 |
patch.close() |
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
1971 |
return nnlangs |
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
1972 |
|
|
1
by Fabien Tassin
* Initial revision |
1973 |
def usage(): |
1974 |
print """ |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
1975 |
Usage: %s [options] [grd_file [more_grd_files]] |
|
1
by Fabien Tassin
* Initial revision |
1976 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1977 |
Convert Chromium translation files (grd/xtb) into gettext files (pot/po) and back
|
|
1
by Fabien Tassin
* Initial revision |
1978 |
|
1979 |
options could be:
|
|
1980 |
-d | --debug debug mode
|
|
1981 |
-v | --verbose verbose mode
|
|
1982 |
-h | --help this help screen
|
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1983 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
1984 |
--export-gettext dir
|
1985 |
export pot/po gettext files to dir
|
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1986 |
|
|
92
by Fabien Tassin
* Add a way to import several gettext repositories using --import-gettext |
1987 |
--import-gettext dir[,dir2][...]
|
1988 |
import gettext pot/po files from those directories.
|
|
1989 |
Directories must be ordered from the oldest to
|
|
1990 |
the freshest. Only strings different from the grit
|
|
1991 |
(upstream) translations are considered.
|
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1992 |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
1993 |
--import-grit-branch name:dir:grd1[,grd2,...]]
|
1994 |
import the Grit files for this branch from this
|
|
1995 |
directory. --import-grit-branch could be used several
|
|
1996 |
times, and then, branches must be specified from the
|
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
1997 |
freshest (trunk) to the more stable ones.
|
1998 |
The default value is trunk:<cwd>
|
|
1999 |
Note: must not be used along with --export-grit
|
|
2000 |
||
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
2001 |
--export-grit dir
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2002 |
export grd/xtb grit files to dir
|
2003 |
||
2004 |
--copy-grit dir copy the src grit files containing strings to dir
|
|
2005 |
(useful to create diffs after --export-grit)
|
|
2006 |
||
|
73
by Fabien Tassin
* Add a --whitelisted-new-langs flag that can be used to only enable new |
2007 |
--whitelisted-new-langs lang1[,lang2][..]
|
2008 |
comma separated list of new langs that have to be enabled
|
|
2009 |
(assuming they have some strings translated). The default
|
|
2010 |
is to enable all new langs, but for stable builds, a good
|
|
2011 |
enough coverage is preferred
|
|
2012 |
||
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2013 |
--create-patches dir
|
2014 |
create unified patches per template in dir
|
|
2015 |
(only useful after --export-grit)
|
|
|
1
by Fabien Tassin
* Initial revision |
2016 |
|
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
2017 |
--build-gyp-file file
|
2018 |
location of the build/common.gypi file, used only
|
|
2019 |
with --create-patches to add all new langs
|
|
2020 |
for which we merged translated strings
|
|
2021 |
||
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
2022 |
--other-grd-files file1[,file2][..]
|
2023 |
comma separated list of grd files to also patch
|
|
2024 |
to add new langs for (see --build-gyp-file)
|
|
2025 |
||
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2026 |
--html-output produce nice some HTML as output (on stdout)
|
2027 |
||
2028 |
--json-branches-info file
|
|
2029 |
location of a json file containing the url, revision
|
|
2030 |
and last date of both the upstream branch and
|
|
2031 |
launchpad export. optionally used in the html output
|
|
2032 |
||
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2033 |
--map-template-names new1=old1[,new2=old2][...]
|
2034 |
comma separated list of template names mappings.
|
|
2035 |
It is useful when upstream renames a grd file in a branch
|
|
2036 |
to preserve the old name in gettext for the older branches
|
|
2037 |
||
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2038 |
--landable-templates template1[,template2][...]
|
2039 |
comma separated list of templates that are landable upstream
|
|
2040 |
for all langs
|
|
2041 |
||
2042 |
--unlandable-templates template1[,template2][...]
|
|
2043 |
comma separated list of templates that are not landable upstream,
|
|
2044 |
even for new langs
|
|
2045 |
||
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2046 |
--test-strcvt run the grit2gettext2grit checker
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
2047 |
--test-conditions run the conditions evaluation checker
|
|
1
by Fabien Tassin
* Initial revision |
2048 |
|
2049 |
""" % sys.argv[0].rpartition('/')[2] |
|
2050 |
||
2051 |
if '__main__' == __name__: |
|
|
35
by Fabien Tassin
* Prevent python from groaning while printing utf-8 strings to a redirected stdout |
2052 |
sys.stdout = codecs.getwriter('utf8')(sys.stdout) |
|
1
by Fabien Tassin
* Initial revision |
2053 |
try: |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2054 |
opts, args = getopt.getopt(sys.argv[1:], "dhv", |
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
2055 |
[ "test-strcvt", "test-conditions", "debug", "verbose", "help", "copy-grit=", |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2056 |
"import-grit-branch=", "export-gettext=", "import-gettext=", "export-grit=", |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2057 |
"create-patches=", "build-gyp-file=", "other-grd-files=", |
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2058 |
"landable-templates=", "unlandable-templates=", "map-template-names=", |
|
73
by Fabien Tassin
* Add a --whitelisted-new-langs flag that can be used to only enable new |
2059 |
"whitelisted-new-langs=", "html-output", "json-branches-info=" ]) |
|
1
by Fabien Tassin
* Initial revision |
2060 |
except getopt.GetoptError, err: |
2061 |
print str(err) |
|
2062 |
usage() |
|
2063 |
sys.exit(2) |
|
2064 |
||
2065 |
verbose = False |
|
2066 |
debug = False |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2067 |
html_output = False |
|
1
by Fabien Tassin
* Initial revision |
2068 |
outdir = None |
2069 |
indir = None |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2070 |
export_gettext = None |
2071 |
import_gettext = None |
|
2072 |
export_grit = None |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2073 |
copy_grit = None |
2074 |
create_patches = None |
|
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
2075 |
build_gyp_file = None |
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2076 |
json_info = None |
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
2077 |
other_grd_files = [] |
|
73
by Fabien Tassin
* Add a --whitelisted-new-langs flag that can be used to only enable new |
2078 |
whitelisted_new_langs = None |
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2079 |
templatenames_mapping = {} |
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2080 |
landable_templates = [] |
2081 |
unlandable_templates = [] |
|
|
81
by Fabien Tassin
* Add --import-grit-branches allowing the merge of several branches during a |
2082 |
branches = None |
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2083 |
nbranches = [] |
|
1
by Fabien Tassin
* Initial revision |
2084 |
for o, a in opts: |
2085 |
if o in ("-v", "--verbose"): |
|
2086 |
verbose = True |
|
2087 |
elif o in ("-h", "--help"): |
|
2088 |
usage() |
|
2089 |
sys.exit() |
|
2090 |
elif o in ("-d", "--debug"): |
|
2091 |
debug = True |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2092 |
elif o == "--import-grit-branch": |
2093 |
if branches is None: |
|
2094 |
branches = {} |
|
2095 |
branch, dir, grds = a.split(':') |
|
2096 |
for grd in grds.split(','): |
|
2097 |
name = os.path.basename(grd) |
|
2098 |
if name not in branches: |
|
2099 |
branches[name] = [] |
|
2100 |
branches[name].append({ 'branch': branch, 'dir': dir, 'grd': grd }) |
|
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2101 |
if branch not in nbranches: |
2102 |
nbranches.append(branch) |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2103 |
elif o == "--export-gettext": |
2104 |
export_gettext = a |
|
2105 |
elif o == "--import-gettext": |
|
|
92
by Fabien Tassin
* Add a way to import several gettext repositories using --import-gettext |
2106 |
import_gettext = a.split(",") |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2107 |
elif o == "--export-grit": |
2108 |
export_grit = a |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2109 |
elif o == "--copy-grit": |
2110 |
copy_grit = a |
|
|
73
by Fabien Tassin
* Add a --whitelisted-new-langs flag that can be used to only enable new |
2111 |
elif o == "--whitelisted-new-langs": |
2112 |
whitelisted_new_langs = a.split(",") |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2113 |
elif o == "--create-patches": |
2114 |
create_patches = a |
|
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
2115 |
elif o == "--build-gyp-file": |
2116 |
build_gyp_file = a |
|
|
54
by Fabien Tassin
* Add --other-grd-files to pass a list of grd files to also update when |
2117 |
elif o == "--other-grd-files": |
2118 |
other_grd_files = a.split(',') |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2119 |
elif o == "--html-output": |
2120 |
html_output = True |
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2121 |
elif o == "--json-branches-info": |
2122 |
json_info = a |
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2123 |
elif o == "--landable-templates": |
2124 |
landable_templates = a.split(",") |
|
2125 |
elif o == "--unlandable-templates": |
|
2126 |
unlandable_templates = a.split(",") |
|
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2127 |
elif o == "--map-template-names": |
2128 |
for c in a.split(','): |
|
2129 |
x = c.split('=') |
|
2130 |
templatenames_mapping[x[0]] = x[1] |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2131 |
elif o == "--test-strcvt": |
2132 |
StringCvt().test() |
|
2133 |
sys.exit() |
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
2134 |
elif o == "--test-conditions": |
2135 |
EvalConditions().test() |
|
2136 |
sys.exit() |
|
|
1
by Fabien Tassin
* Initial revision |
2137 |
else: |
2138 |
assert False, "unhandled option" |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2139 |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2140 |
if branches is None and len(args) != 0: |
2141 |
branches = {} |
|
2142 |
for arg in args: |
|
2143 |
branches[os.path.basename(arg)] = [ { 'branch': 'default', 'dir': os.getcwd(), 'grd': arg } ] |
|
2144 |
if branches is None: |
|
2145 |
print "Please specify at least one grd file or use --import-grit-branch" |
|
|
1
by Fabien Tassin
* Initial revision |
2146 |
usage() |
2147 |
sys.exit(2) |
|
2148 |
||
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2149 |
# re-map the templates, if needed
|
2150 |
for grd in templatenames_mapping.keys(): |
|
2151 |
new = os.path.basename(grd) |
|
2152 |
old = os.path.basename(templatenames_mapping[grd]) |
|
2153 |
if new in branches: |
|
2154 |
if old not in branches: |
|
2155 |
branches[old] = [] |
|
2156 |
for branch in branches[new]: |
|
2157 |
branch['mapped_grd'] = old |
|
2158 |
branches[old].extend(branches[new]) |
|
2159 |
# re-sort the branches
|
|
2160 |
branches[old] = sorted(branches[old], lambda x,y: cmp(nbranches.index(x['branch']), nbranches.index(y['branch']))) |
|
2161 |
del(branches[new]) |
|
2162 |
||
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2163 |
if html_output: |
2164 |
print """\ |
|
2165 |
<html>
|
|
2166 |
<head><meta charset="UTF-8">
|
|
2167 |
</head><body>
|
|
2168 |
<style type="text/css">
|
|
2169 |
body {
|
|
2170 |
font-family: UbuntuBeta,Ubuntu,"Bitstream Vera Sans","DejaVu Sans",Tahoma,sans-serif;
|
|
2171 |
}
|
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2172 |
div#legend {
|
2173 |
float: left;
|
|
2174 |
}
|
|
2175 |
fieldset {
|
|
2176 |
border-width: 1px;
|
|
2177 |
border-color: #f0f0f0;
|
|
2178 |
}
|
|
2179 |
div#legend fieldset, div#branches fieldset {
|
|
2180 |
border-width: 0px;
|
|
2181 |
}
|
|
2182 |
legend {
|
|
2183 |
font-size: 80%;
|
|
2184 |
}
|
|
2185 |
div#branches {
|
|
2186 |
float: left;
|
|
2187 |
padding-left: 40px;
|
|
2188 |
}
|
|
2189 |
div#branches td {
|
|
2190 |
padding-right: 5px;
|
|
2191 |
}
|
|
2192 |
div#stats {
|
|
2193 |
padding-top: 5px;
|
|
2194 |
clear: both;
|
|
2195 |
}
|
|
2196 |
a {
|
|
2197 |
text-decoration: none;
|
|
2198 |
}
|
|
|
72
by Fabien Tassin
* Add a link to Launchpad for each lang in the HTML report |
2199 |
a.l:link, a.l:visited {
|
2200 |
color: black;
|
|
2201 |
}
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2202 |
.error {
|
2203 |
font-size: 90%;
|
|
2204 |
}
|
|
2205 |
div.error a {
|
|
2206 |
font-family: monospace;
|
|
2207 |
font-size: 120%;
|
|
2208 |
}
|
|
2209 |
table {
|
|
2210 |
border-collapse: collapse;
|
|
2211 |
border-spacing: 1px;
|
|
2212 |
font-size: 0.9em;
|
|
2213 |
}
|
|
2214 |
th {
|
|
2215 |
font-weight: bold;
|
|
2216 |
color: #666;
|
|
2217 |
padding-right: 5px;
|
|
2218 |
}
|
|
2219 |
th, td {
|
|
2220 |
border: 1px #d2d2d2;
|
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2221 |
border-style: solid;
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2222 |
padding-left: 4px;
|
2223 |
padding-top: 0px;
|
|
2224 |
padding-bottom: 0px;
|
|
2225 |
}
|
|
2226 |
td.d {
|
|
2227 |
font-size: 90%;
|
|
2228 |
text-align: right;
|
|
2229 |
}
|
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2230 |
td.n {
|
2231 |
background: #FFA;
|
|
2232 |
}
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2233 |
.lang {
|
2234 |
font-weight: bold;
|
|
2235 |
padding-left: 0.5em;
|
|
2236 |
padding-right: 0.5em;
|
|
2237 |
white-space: nowrap;
|
|
2238 |
}
|
|
2239 |
.progress_bar {
|
|
2240 |
width: 100px; overflow: hidden; position: relative; padding: 0px;
|
|
2241 |
}
|
|
2242 |
.pb_label {
|
|
2243 |
text-align: center; width: 100%;
|
|
2244 |
position: absolute; z-index: 1001; left: 4px; top: -2px; color: white; font-size: 0.7em;
|
|
2245 |
}
|
|
2246 |
.pb_label2 {
|
|
2247 |
text-align: center; width: 100%;
|
|
2248 |
position: absolute; z-index: 1000; left: 5px; top: -1px; color: black; font-size: 0.7em;
|
|
2249 |
}
|
|
2250 |
.green_gradient {
|
|
2251 |
height: 1em; position: relative; float: left;
|
|
2252 |
background: #00ff00;
|
|
2253 |
background: -moz-linear-gradient(top, #00ff00, #007700);
|
|
2254 |
background: -webkit-gradient(linear, left top, left bottom, from(#00ff00), to(#007700));
|
|
2255 |
filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr='#00ff00', EndColorStr='#007700', GradientType=0);
|
|
2256 |
}
|
|
2257 |
.red_gradient {
|
|
2258 |
height: 1em; position: relative; float: left;
|
|
2259 |
background: #ff8888;
|
|
2260 |
background: -moz-linear-gradient(top, #ff8888, #771111);
|
|
2261 |
background: -webkit-gradient(linear, left top, left bottom, from(#ff8888), to(#771111));
|
|
2262 |
filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr='#ff8888', EndColorStr='#771111', GradientType=0);
|
|
2263 |
}
|
|
2264 |
.blue_gradient {
|
|
2265 |
height: 1em; position: relative; float: left;
|
|
2266 |
background: #62b0dd;
|
|
2267 |
background: -moz-linear-gradient(top, #62b0dd, #1f3d4a);
|
|
2268 |
background: -webkit-gradient(linear, left top, left bottom, from(#62b0dd), to(#1f3d4a));
|
|
2269 |
filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr='#62b0dd', EndColorStr='#1f3d4a', GradientType=0);
|
|
2270 |
}
|
|
2271 |
.purple_gradient {
|
|
2272 |
height: 1em; position: relative; float: left;
|
|
2273 |
background: #b8a4ba;
|
|
|
59
by Fabien Tassin
* Fix bogus color in the purple_gradient class for Firefox |
2274 |
background: -moz-linear-gradient(top, #b8a4ba, #5c3765);
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2275 |
background: -webkit-gradient(linear, left top, left bottom, from(#b8a4ba), to(#5c3765));
|
|
60
by Fabien Tassin
* Fix another bogus color in the purple_gradient class for IE |
2276 |
filter: progid:DXImageTransform.Microsoft.Gradient(StartColorStr='#b8a4ba', EndColorStr='#5c3765', GradientType=0);
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2277 |
}
|
2278 |
</style>
|
|
2279 |
<script type="text/javascript" language="javascript">
|
|
2280 |
function progress_bar(where, red, green, purple, blue) {
|
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2281 |
var total = green + red + blue + purple;
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2282 |
if (total == 0)
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2283 |
total = 1;
|
2284 |
var d = document.getElementById(where);
|
|
2285 |
var v = 100 * (1 - (red / total));
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2286 |
if (total != 1) {
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2287 |
d.innerHTML += '<div class="pb_label">' + v.toFixed(1) + "%</div>";
|
2288 |
d.innerHTML += '<div class="pb_label2">' + v.toFixed(1) + "%</div>";
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2289 |
}
|
2290 |
else
|
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2291 |
d.style.width = "25px";
|
2292 |
var pgreen = parseInt(100 * green / total);
|
|
2293 |
var pblue = parseInt(100 * blue / total);
|
|
2294 |
var ppurple = parseInt(100 * purple / total);
|
|
2295 |
var pred = parseInt(100 * red / total);
|
|
2296 |
if (pgreen + pblue + ppurple + pred != 100) {
|
|
2297 |
if (red > 0)
|
|
2298 |
pred = 100 - pgreen - pblue - ppurple;
|
|
2299 |
else if (purple > 0)
|
|
2300 |
ppurple = 100 - pgreen - pblue;
|
|
2301 |
else if (blue > 0)
|
|
2302 |
pblue = 100 - pgreen;
|
|
2303 |
else
|
|
2304 |
pgreen = 100;
|
|
2305 |
}
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2306 |
if (green > 0)
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2307 |
d.innerHTML += '<div class="green_gradient" style="width:' + pgreen + '%;"></div>';
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2308 |
if (blue > 0)
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2309 |
d.innerHTML += '<div class="blue_gradient" style="width:' + pblue + '%;"></div>';
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2310 |
if (purple > 0)
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2311 |
d.innerHTML += '<div class="purple_gradient" style="width:' + ppurple + '%;"></div>';
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2312 |
if (red > 0)
|
|
66
by Fabien Tassin
* Rewrite the CSS of the progress bar to improve the alignment |
2313 |
d.innerHTML += '<div class="red_gradient" style="width:' + pred + '%;"></div>';
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2314 |
return true;
|
2315 |
}
|
|
2316 |
||
2317 |
function toggle(e) {
|
|
2318 |
var elt = document.getElementById(e + "-t");
|
|
2319 |
var text = document.getElementById(e);
|
|
2320 |
if (elt.style.display == "block") {
|
|
2321 |
elt.style.display = "none";
|
|
2322 |
text.innerHTML = "+";
|
|
2323 |
}
|
|
2324 |
else {
|
|
2325 |
elt.style.display = "block";
|
|
2326 |
text.innerHTML = "-";
|
|
2327 |
}
|
|
2328 |
}
|
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2329 |
|
2330 |
function time_delta(date, e) {
|
|
2331 |
var now = new Date();
|
|
2332 |
var d = new Date(date);
|
|
2333 |
var delta = (now - d) / 1000;
|
|
2334 |
var elt = document.getElementById(e);
|
|
2335 |
if (delta >= 3600) {
|
|
2336 |
var h = parseInt(delta / 3600);
|
|
2337 |
var m = parseInt((delta - h * 3600) / 60);
|
|
2338 |
elt.innerHTML = '(' + h + 'h ' + m + 'min ago)';
|
|
2339 |
return;
|
|
2340 |
}
|
|
2341 |
if (delta >= 60) {
|
|
2342 |
var m = parseInt(delta / 60);
|
|
2343 |
elt.innerHTML = '(' + m + 'min ago)';
|
|
2344 |
return;
|
|
2345 |
}
|
|
2346 |
elt.innerHTML = '(seconds ago)';
|
|
2347 |
}
|
|
2348 |
||
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2349 |
</script>
|
2350 |
"""
|
|
2351 |
||
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2352 |
prefix = os.path.commonprefix([ branches[x][0]['grd'] for x in branches.keys() ]) |
|
14
by Fabien Tassin
* Exit with 1 when some strings changed, 0 otherwise |
2353 |
changes = 0 |
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
2354 |
langs = [] |
|
72
by Fabien Tassin
* Add a link to Launchpad for each lang in the HTML report |
2355 |
mapped_langs = {} |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
2356 |
cvts = {} |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2357 |
for grd in branches.keys(): |
|
114
by Fabien Tassin
* Add a --map-template-names knob allowing to handle renamed templates |
2358 |
cvts[grd] = Converter(branches[grd][0]['grd'], |
2359 |
lang_mapping = lang_mapping, |
|
2360 |
template_mapping = templatenames_mapping, |
|
2361 |
debug = debug, |
|
2362 |
html_output = html_output, |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2363 |
branches = branches[grd]) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2364 |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
2365 |
if cvts[grd].get_supported_strings_count() == 0: |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2366 |
if debug: |
2367 |
print "no string found in %s" % grd |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2368 |
if export_grit is not None and copy_grit is None: |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2369 |
directory = os.path.join(export_grit, os.path.dirname(branches[grd][0]['grd'])[len(prefix):]) |
|
74
by Fabien Tassin
* Create the grit outdir before copying grit files without strings |
2370 |
if not os.path.isdir(directory): |
2371 |
os.makedirs(directory, 0755) |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2372 |
shutil.copy2(branches[grd][0]['grd'], directory) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2373 |
continue
|
2374 |
||
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2375 |
if copy_grit is not None: |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
2376 |
cvts[grd].copy_grit_files(copy_grit) |
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2377 |
|
|
80
by Fabien Tassin
* Perform the optional gettext import before the (also optional) gettext export |
2378 |
if import_gettext is not None: |
|
92
by Fabien Tassin
* Add a way to import several gettext repositories using --import-gettext |
2379 |
for directory in import_gettext: |
2380 |
cvts[grd].import_gettext_po_files(directory) |
|
2381 |
langs.extend(cvts[grd].translations.keys()) |
|
|
80
by Fabien Tassin
* Perform the optional gettext import before the (also optional) gettext export |
2382 |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2383 |
if export_gettext is not None: |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
2384 |
cvts[grd].export_gettext_files(export_gettext) |
2385 |
changes += cvts[grd].template_changes + cvts[grd].translations_changes |
|
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2386 |
|
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
2387 |
# as we need to add all supported langs to the <outputs> section of all grd files,
|
2388 |
# we have to wait for all the 'po' files to be imported and merged before we export
|
|
2389 |
# the grit files and create the patches.
|
|
2390 |
||
2391 |
# supported langs
|
|
2392 |
langs.append('en-US') # special case, it's not translated, but needs to be here |
|
2393 |
for lang in [ 'no' ]: # workaround for cases like the infamous no->nb mapping |
|
2394 |
while lang in langs: |
|
2395 |
langs.remove(lang) |
|
2396 |
langs.append(lang_mapping[lang]) |
|
2397 |
r = {} |
|
2398 |
langs = sorted([ r.setdefault(e, e) for e in langs if e not in r ]) |
|
2399 |
||
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2400 |
for grd in branches.keys(): |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2401 |
if export_grit is not None: |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2402 |
cvts[grd].export_grit_files(os.path.join(export_grit, os.path.dirname(branches[grd][0]['grd'])[len(prefix):]), langs) |
|
72
by Fabien Tassin
* Add a link to Launchpad for each lang in the HTML report |
2403 |
for lang in cvts[grd].template.mapped_langs: |
2404 |
mapped_langs[lang] = cvts[grd].template.mapped_langs[lang]['gettext'] |
|
|
27
by Fabien Tassin
* Add a knob creating one grit patch per template after an export-grit |
2405 |
if create_patches is not None: |
|
53
by Fabien Tassin
* Insert new langs in all grd files having <output/> entries of one of the data_package or js_map_format types |
2406 |
cvts[grd].create_patches(create_patches) |
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
2407 |
|
2408 |
# patch the build/common.gypi file if we have to
|
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2409 |
nlangs = None |
|
51
by Fabien Tassin
* Add a --build-gyp-file flag so --create-patches also patches build/common.gypi |
2410 |
if create_patches is not None and build_gyp_file is not None: |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2411 |
nlangs = cvts[branches.keys()[0]].create_build_gyp_patch(create_patches, build_gyp_file, other_grd_files, langs, |
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2412 |
whitelisted_new_langs) |
|
18
by Fabien Tassin
* Clean-up the strings by using %{} instead of xml tags, add merge and export features |
2413 |
|
|
62
by Fabien Tassin
* Only display the stats in create_patches mode |
2414 |
if create_patches is None: |
2415 |
# no need to display the stats
|
|
2416 |
exit(1 if changes > 0 else 0) |
|
2417 |
||
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2418 |
# display some stats
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2419 |
html_js = "" |
2420 |
if html_output: |
|
2421 |
print """ |
|
2422 |
<p>
|
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2423 |
<div>
|
2424 |
<div id="legend">
|
|
2425 |
<fieldset><legend>Legend</legend>
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2426 |
<table border="0">
|
2427 |
<tr><td><div id='green_l' class='progress_bar'></td><td>translated upstream</td></tr>
|
|
2428 |
<tr><td><div id='blue_l' class='progress_bar'></td><td>translations updated in Launchpad</td></tr>
|
|
2429 |
<tr><td><div id='purple_l' class='progress_bar'></td><td>translated in Launchpad</td></tr>
|
|
2430 |
<tr><td><div id='red_l' class='progress_bar'></td><td>untranslated</td></tr>
|
|
2431 |
</table>
|
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2432 |
</fieldset>
|
2433 |
</div>
|
|
2434 |
"""
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2435 |
html_js += "progress_bar('%s', %d, %d, %d, %d);\n" % ('green_l', 0, 1, 0, 0) |
2436 |
html_js += "progress_bar('%s', %d, %d, %d, %d);\n" % ('blue_l', 0, 0, 0, 1) |
|
2437 |
html_js += "progress_bar('%s', %d, %d, %d, %d);\n" % ('purple_l', 0, 0, 1, 0) |
|
2438 |
html_js += "progress_bar('%s', %d, %d, %d, %d);\n" % ('red_l', 1, 0, 0, 0) |
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2439 |
if json_info: |
|
64
by Fabien Tassin
* Get the timestamp of the json file in UTC |
2440 |
now = datetime.utcfromtimestamp(os.path.getmtime(json_info)).strftime("%a %b %e %H:%M:%S UTC %Y") |
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2441 |
binfo = json.loads(open(json_info, "r").read()) |
2442 |
print """ |
|
2443 |
<div id="branches">
|
|
2444 |
<fieldset><legend>Last update info</legend>
|
|
2445 |
<table border="0">
|
|
2446 |
<tr><th>Branch</th><th>Revision</th><th>Date</th></tr>
|
|
2447 |
<tr><td><a href="%s">Upstream</a></td><td>r%s</td><td>%s <em id='em-u'></em> </td></tr> |
|
2448 |
<tr><td><a href="%s">Launchpad export</a></td><td>r%s</td><td>%s <em id='em-lp'></em> </td></tr> |
|
2449 |
<tr><td>This page</a></td><td>-</td><td>%s <em id='em-now'></em> </td></tr> |
|
2450 |
</table>
|
|
2451 |
</fieldset>
|
|
2452 |
</div>
|
|
2453 |
""" % (binfo['upstream']['url'], binfo['upstream']['revision'], binfo['upstream']['date'], |
|
2454 |
binfo['launchpad-export']['url'], binfo['launchpad-export']['revision'], |
|
2455 |
binfo['launchpad-export']['date'], now) |
|
|
76
by Fabien Tassin
* Don't fail when we want the html report without the json file |
2456 |
html_js += "time_delta('%s', '%s');\n" % (binfo['upstream']['date'], 'em-u') |
2457 |
html_js += "time_delta('%s', '%s');\n" % (binfo['launchpad-export']['date'], 'em-lp') |
|
2458 |
html_js += "time_delta('%s', '%s');\n" % (now, 'em-now') |
|
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2459 |
print """ |
2460 |
<div id="stats">
|
|
2461 |
<table border="0">
|
|
|
69
by Fabien Tassin
* Add a link to the commit logs in the HTML report |
2462 |
<tr><th rowspan="2">Rank</th><th rowspan="2">Lang</th><th colspan='5'>TOTAL</th><th colspan='5'>"""
|
2463 |
print ("</th><th colspan='5'>".join([ "%s (<a href='http://git.chromium.org/gitweb/?p=chromium.git;a=history;f=%s;hb=HEAD'>+</a>)" \ |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2464 |
% (os.path.splitext(grd)[0], branches[grd][0]['grd']) \ |
2465 |
for grd in sorted(branches.keys()) ])) + "</th></tr><tr>" |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2466 |
j = 0 |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2467 |
for grd in [ 'TOTAL' ] + sorted(branches.keys()): |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2468 |
print """ |
2469 |
<th>Status</th>
|
|
2470 |
<th><div id='%s_t%d' class='progress_bar'></th> |
|
2471 |
<th><div id='%s_t%d' class='progress_bar'></th> |
|
2472 |
<th><div id='%s_t%d' class='progress_bar'></th> |
|
2473 |
<th><div id='%s_t%d' class='progress_bar'></th>""" % ('red', j, 'green', j, 'purple', j, 'blue', j) |
|
2474 |
html_js += "progress_bar('%s_t%d', %d, %d, %d, %d);\n" % ('green', j, 0, 1, 0, 0) |
|
2475 |
html_js += "progress_bar('%s_t%d', %d, %d, %d, %d);\n" % ('blue', j, 0, 0, 0, 1) |
|
2476 |
html_js += "progress_bar('%s_t%d', %d, %d, %d, %d);\n" % ('purple', j, 0, 0, 1, 0) |
|
2477 |
html_js += "progress_bar('%s_t%d', %d, %d, %d, %d);\n" % ('red', j, 1, 0, 0, 0) |
|
2478 |
j += 1 |
|
2479 |
print "</tr>" |
|
2480 |
else: |
|
2481 |
print """\ |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2482 |
+----------------------- % translated
|
2483 |
| +----------------- untranslated
|
|
2484 |
| | +------------ translated upstream
|
|
2485 |
| | | +------- translated in Launchpad
|
|
2486 |
| | | | +-- translations updated in Launchpad
|
|
2487 |
| | | | |
|
|
2488 |
V V V V V"""
|
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2489 |
print "-- lang -- " + \ |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2490 |
' '.join([ (" %s " % os.path.splitext(grd)[0]).center(25, "-") \ |
2491 |
for grd in [ 'TOTAL' ] + sorted(branches.keys()) ]) |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2492 |
totals = {} |
2493 |
for lang in langs: |
|
2494 |
klang = lang |
|
2495 |
if lang == 'nb': |
|
2496 |
klang = 'no' |
|
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
2497 |
totals[klang] = { 'total': 0, 'missing': 0, 'translated_upstream': 0, 'new': 0, 'updated': 0, 'lskipped': 0 } |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2498 |
for grd in branches.keys(): |
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
2499 |
tot, lskipped = cvts[grd].template.get_supported_strings_count(klang) |
2500 |
totals[klang]['lskipped'] += lskipped |
|
2501 |
totals[klang]['total'] += tot |
|
2502 |
totals[klang]['missing'] += tot |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2503 |
if klang in cvts[grd].template.stats: |
2504 |
totals[klang]['missing'] -= cvts[grd].template.stats[klang]['translated_upstream'] + \ |
|
|
68
by Fabien Tassin
* Fix the 'translated_upstream' counter wrongly including 'updated' |
2505 |
cvts[grd].template.stats[klang]['new'] + cvts[grd].template.stats[klang]['updated'] |
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2506 |
totals[klang]['translated_upstream'] += cvts[grd].template.stats[klang]['translated_upstream'] |
2507 |
totals[klang]['new'] += cvts[grd].template.stats[klang]['new'] |
|
2508 |
totals[klang]['updated'] += cvts[grd].template.stats[klang]['updated'] |
|
2509 |
||
2510 |
rank = 0 |
|
2511 |
p_rank = 0 |
|
2512 |
p_score = -1 |
|
|
95
by Fabien Tassin
* Add the total of the landable strings at the bottom of the HTML dashboard |
2513 |
t_landable = 0 |
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2514 |
for lang in sorted(totals, lambda x, y: cmp("%05d %05d %s" % (totals[x]['missing'], totals[x]['total'] - totals[x]['updated'] - totals[x]['new'], x), |
2515 |
"%05d %05d %s" % (totals[y]['missing'], totals[y]['total'] - totals[y]['updated'] - totals[y]['new'], y))): |
|
2516 |
if lang == 'en-US': |
|
2517 |
continue
|
|
2518 |
rank += 1 |
|
2519 |
if p_score != totals[lang]['missing']: |
|
2520 |
p_score = totals[lang]['missing'] |
|
2521 |
p_rank = rank |
|
2522 |
rlang = lang |
|
2523 |
if lang in lang_mapping: |
|
2524 |
rlang = lang_mapping[lang] |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2525 |
if html_output: |
|
72
by Fabien Tassin
* Add a link to Launchpad for each lang in the HTML report |
2526 |
s = "<tr><td>%s</td><td class='lang'><a class='l' href='%s'>%s</a></td>" % \ |
2527 |
("#%d" % p_rank, 'https://translations.launchpad.net/chromium-browser/translations/+lang/' + \ |
|
2528 |
mapped_langs[lang], rlang) |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2529 |
s += "<td><div id='%s' class='progress_bar'></div></td>" % rlang |
2530 |
s += "<td class='d'>%d</td><td class='d'>%d</td><td class='d'>%d</td><td class='d'>%d</td>" % \ |
|
2531 |
(totals[lang]['missing'], totals[lang]['translated_upstream'], |
|
2532 |
totals[lang]['new'], totals[lang]['updated']) |
|
2533 |
html_js += "progress_bar('%s', %d, %d, %d, %d);\n" % \ |
|
2534 |
(rlang, totals[lang]['missing'], totals[lang]['translated_upstream'], |
|
2535 |
totals[lang]['new'], totals[lang]['updated']) |
|
2536 |
else: |
|
2537 |
s = "%-3s %-6s " % ("#%d" % p_rank, rlang) |
|
2538 |
s += "%3d%% %4d %4d %4d %4d" % \ |
|
2539 |
(100.0 * float(totals[lang]['total'] - totals[lang]['missing']) / float(totals[lang]['total']), |
|
2540 |
totals[lang]['missing'], totals[lang]['translated_upstream'], |
|
2541 |
totals[lang]['new'], totals[lang]['updated']) |
|
2542 |
j = 0 |
|
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2543 |
for grd in sorted(branches.keys()): |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2544 |
j += 1 |
|
94
by Fabien Tassin
* Change --import-grit-branches into --import-grit-branch, reusable multiple |
2545 |
tplt = os.path.splitext(grd)[0].replace('_', '-') |
|
67
by Fabien Tassin
* Skip strings having an <if expr=""> excluding the lang. It applies to |
2546 |
total, lskipped = cvts[grd].template.get_supported_strings_count(lang) |
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2547 |
if lang in cvts[grd].template.stats: |
2548 |
missing = total - cvts[grd].template.stats[lang]['translated_upstream'] - \ |
|
|
70
by Fabien Tassin
* Also fix the 'missing' counter for each template |
2549 |
cvts[grd].template.stats[lang]['new'] - cvts[grd].template.stats[lang]['updated'] |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2550 |
if html_output: |
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2551 |
if len(unlandable_templates) == 0 and len(landable_templates) == 0: |
2552 |
landable = False |
|
2553 |
else: |
|
2554 |
landable = (nlangs is not None and lang in nlangs and tplt not in unlandable_templates) or \ |
|
2555 |
(nlangs is not None and lang not in nlangs and tplt in landable_templates) |
|
|
95
by Fabien Tassin
* Add the total of the landable strings at the bottom of the HTML dashboard |
2556 |
if landable: |
2557 |
t_landable += cvts[grd].template.stats[lang]['new'] + cvts[grd].template.stats[lang]['updated'] |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2558 |
s += "<td><div id='%s_%d' class='progress_bar'></div></td>" % (rlang, j) |
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2559 |
s += "<td class='d'>%d</td><td class='d'>%d</td><td class='d%s'>%d</td><td class='d%s'>%d</td>" % \ |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2560 |
(missing, |
2561 |
cvts[grd].template.stats[lang]['translated_upstream'], |
|
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2562 |
" n" if landable and cvts[grd].template.stats[lang]['new'] > 0 else "", |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2563 |
cvts[grd].template.stats[lang]['new'], |
|
93
by Fabien Tassin
* Tag the landable strings in yellow in the HTML report. This is done |
2564 |
" n" if landable and cvts[grd].template.stats[lang]['updated'] > 0 else "", |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2565 |
cvts[grd].template.stats[lang]['updated']) |
2566 |
html_js += "progress_bar('%s_%d', %d, %d, %d, %d);\n" % \ |
|
2567 |
(rlang, j, missing, |
|
2568 |
cvts[grd].template.stats[lang]['translated_upstream'], |
|
2569 |
cvts[grd].template.stats[lang]['new'], |
|
2570 |
cvts[grd].template.stats[lang]['updated']) |
|
2571 |
else: |
|
|
75
by Fabien Tassin
* Don't fail when a grd disappear |
2572 |
if float(total) > 0: |
2573 |
pct = 100.0 * float(total - missing) / float(total) |
|
2574 |
else: |
|
2575 |
pct = 0 |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2576 |
s += " %3d%% %4d %4d %4d %4d" % \ |
|
75
by Fabien Tassin
* Don't fail when a grd disappear |
2577 |
(pct, missing, |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2578 |
cvts[grd].template.stats[lang]['translated_upstream'], |
2579 |
cvts[grd].template.stats[lang]['new'], |
|
2580 |
cvts[grd].template.stats[lang]['updated']) |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2581 |
else: |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2582 |
if html_output: |
2583 |
s += "<td><div id='%s_%d' class='progress_bar'></div></td>" % (rlang, j) |
|
2584 |
s += "<td class='d'>%d</td><td class='d'>%d</td><td class='d'>%d</td><td class='d'>%d</td>" % \ |
|
2585 |
(total, 0, 0, 0) |
|
2586 |
html_js += "progress_bar('%s_%d', %d, %d, %d, %d);\n" % \ |
|
2587 |
(rlang, j, total, 0, 0, 0) |
|
2588 |
else: |
|
2589 |
s += " %3d%% %4d %4d %4d %4d" % (0, total, 0, 0, 0) |
|
2590 |
if html_output: |
|
2591 |
s += "</tr>" |
|
|
57
by Fabien Tassin
* Display some stats ourselves, now that LP stopped displaying what we need. |
2592 |
print s |
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2593 |
if html_output: |
|
95
by Fabien Tassin
* Add the total of the landable strings at the bottom of the HTML dashboard |
2594 |
landable_sum = "" |
2595 |
if t_landable > 0: |
|
2596 |
landable_sum = """<p> |
|
2597 |
<div name='landable'>
|
|
2598 |
<table border="0"><tr><td class="d n">%d strings are landable upstream</td></tr></table></div> |
|
2599 |
""" % t_landable |
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2600 |
print """\ |
2601 |
</table>
|
|
|
95
by Fabien Tassin
* Add the total of the landable strings at the bottom of the HTML dashboard |
2602 |
%s</div> |
|
63
by Fabien Tassin
* Add a 'Last update info' table in the HTML report |
2603 |
</div>
|
|
58
by Fabien Tassin
* Add a --html-output flag creating a nicely formated HTML report |
2604 |
<script type="text/javascript" language="javascript">
|
2605 |
%s
|
|
2606 |
</script>
|
|
2607 |
</body>
|
|
|
95
by Fabien Tassin
* Add the total of the landable strings at the bottom of the HTML dashboard |
2608 |
</html>""" % (landable_sum, html_js) |
|
14
by Fabien Tassin
* Exit with 1 when some strings changed, 0 otherwise |
2609 |
exit(1 if changes > 0 else 0) |
|
1
by Fabien Tassin
* Initial revision |
2610 |