1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """Create string and word counts for supported localization files including:
22 XLIFF, TMX, Gettex PO and MO, Qt .ts and .qm, Wordfast TM, etc
23
24 See: http://translate.sourceforge.net/wiki/toolkit/pocount for examples and
25 usage instructions
26 """
27
28 from translate.storage import factory
29 from translate.storage import statsdb
30 from optparse import OptionParser
31 import sys
32 import os
33
34
35 style_full, style_csv, style_short_strings, style_short_words = range(4)
36
37
38 default_style = style_full
39
40
42 """This is the previous implementation of calcstats() and is left for
43 comparison and debuging purposes."""
44
45 try:
46 store = factory.getobject(filename)
47 except ValueError, e:
48 print str(e)
49 return {}
50 units = filter(lambda unit: not unit.isheader(), store.units)
51 translated = translatedmessages(units)
52 fuzzy = fuzzymessages(units)
53 review = filter(lambda unit: unit.isreview(), units)
54 untranslated = untranslatedmessages(units)
55 wordcounts = dict(map(lambda unit: (unit, statsdb.wordsinunit(unit)), units))
56 sourcewords = lambda elementlist: sum(map(lambda unit: wordcounts[unit][0], elementlist))
57 targetwords = lambda elementlist: sum(map(lambda unit: wordcounts[unit][1], elementlist))
58 stats = {}
59
60
61 stats["translated"] = len(translated)
62 stats["fuzzy"] = len(fuzzy)
63 stats["untranslated"] = len(untranslated)
64 stats["review"] = len(review)
65 stats["total"] = stats["translated"] + stats["fuzzy"] + stats["untranslated"]
66
67
68 stats["translatedsourcewords"] = sourcewords(translated)
69 stats["translatedtargetwords"] = targetwords(translated)
70 stats["fuzzysourcewords"] = sourcewords(fuzzy)
71 stats["untranslatedsourcewords"] = sourcewords(untranslated)
72 stats["reviewsourcewords"] = sourcewords(review)
73 stats["totalsourcewords"] = stats["translatedsourcewords"] + \
74 stats["fuzzysourcewords"] + \
75 stats["untranslatedsourcewords"]
76 return stats
77
81
82 -def summarize(title, stats, style=style_full, indent=8, incomplete_only=False):
83 """
84 Print summary for a .po file in specified format.
85
86 @param title: name of .po file
87 @param stats: array with translation statistics for the file specified
88 @param indent: indentation of the 2nd column (length of longest filename)
89 @param incomplete_only: omit fully translated files
90 @type incomplete_only: Boolean
91 @rtype: Boolean
92 @return: 1 if counting incomplete files (incomplete_only=True) and the
93 file is completely translated, 0 otherwise
94 """
95 def percent(denominator, devisor):
96 if devisor == 0:
97 return 0
98 else:
99 return denominator*100/devisor
100
101 if incomplete_only and (stats["total"] == stats["translated"]):
102 return 1
103
104 if (style == style_csv):
105 print "%s, " % title,
106 print "%d, %d, %d," % (stats["translated"], stats["translatedsourcewords"], stats["translatedtargetwords"]),
107 print "%d, %d," % (stats["fuzzy"], stats["fuzzysourcewords"]),
108 print "%d, %d," % (stats["untranslated"], stats["untranslatedsourcewords"]),
109 print "%d, %d" % (stats["total"], stats["totalsourcewords"]),
110 if stats["review"] > 0:
111 print ", %d, %d" % (stats["review"], stats["reviewsourdcewords"]),
112 print
113 elif (style == style_short_strings):
114 spaces = " "*(indent - len(title))
115 print "%s%s strings: total: %d\t| %dt\t%df\t%du\t| %d%%t\t%d%%f\t%d%%u" % (title, spaces,\
116 stats["total"], stats["translated"], stats["fuzzy"], stats["untranslated"], \
117 percent(stats["translated"], stats["total"]), \
118 percent(stats["fuzzy"], stats["total"]), \
119 percent(stats["untranslated"], stats["total"]))
120 elif (style == style_short_words):
121 spaces = " "*(indent - len(title))
122 print "%s%s source words: total: %d\t| %dt\t%df\t%du\t| %d%%t\t%d%%f\t%d%%u" % (title, spaces,\
123 stats["totalsourcewords"], stats["translatedsourcewords"], stats["fuzzysourcewords"], stats["untranslatedsourcewords"], \
124 percent(stats["translatedsourcewords"], stats["totalsourcewords"]), \
125 percent(stats["fuzzysourcewords"], stats["totalsourcewords"]), \
126 percent(stats["untranslatedsourcewords"], stats["totalsourcewords"]))
127 else:
128 print title
129 print "type strings words (source) words (translation)"
130 print "translated: %5d (%3d%%) %10d (%3d%%) %15d" % \
131 (stats["translated"], \
132 percent(stats["translated"], stats["total"]), \
133 stats["translatedsourcewords"], \
134 percent(stats["translatedsourcewords"], stats["totalsourcewords"]), \
135 stats["translatedtargetwords"])
136 print "fuzzy: %5d (%3d%%) %10d (%3d%%) n/a" % \
137 (stats["fuzzy"], \
138 percent(stats["fuzzy"], stats["total"]), \
139 stats["fuzzysourcewords"], \
140 percent(stats["fuzzysourcewords"], stats["totalsourcewords"]))
141 print "untranslated: %5d (%3d%%) %10d (%3d%%) n/a" % \
142 (stats["untranslated"], \
143 percent(stats["untranslated"], stats["total"]), \
144 stats["untranslatedsourcewords"], \
145 percent(stats["untranslatedsourcewords"], stats["totalsourcewords"]))
146 print "Total: %5d %17d %22d" % \
147 (stats["total"], \
148 stats["totalsourcewords"], \
149 stats["translatedtargetwords"])
150 if stats["review"] > 0:
151 print "review: %5d %17d n/a" % \
152 (stats["review"], stats["reviewsourcewords"])
153 print
154 return 0
155
158
161
164
167 self.totals = {}
168 self.filecount = 0
169 self.longestfilename = 0
170 self.style = style
171 self.incomplete_only = incomplete_only
172 self.complete_count = 0
173
174 if (self.style == style_csv):
175 print "Filename, Translated Messages, Translated Source Words, Translated \
176 Target Words, Fuzzy Messages, Fuzzy Source Words, Untranslated Messages, \
177 Untranslated Source Words, Total Message, Total Source Words, \
178 Review Messages, Review Source Words"
179 if (self.style == style_short_strings or self.style == style_short_words):
180 for filename in filenames:
181 if (len(filename) > self.longestfilename):
182 self.longestfilename = len(filename)
183 for filename in filenames:
184 if not os.path.exists(filename):
185 print >> sys.stderr, "cannot process %s: does not exist" % filename
186 continue
187 elif os.path.isdir(filename):
188 self.handledir(filename)
189 else:
190 self.handlefile(filename)
191 if self.filecount > 1 and (self.style == style_full):
192 if self.incomplete_only:
193 summarize("TOTAL (incomplete only):", self.totals, incomplete_only=True)
194 print "File count (incomplete): %5d" % (self.filecount - self.complete_count)
195 else:
196 summarize("TOTAL:", self.totals, incomplete_only=False)
197 print "File count: %5d" % (self.filecount)
198 print
199
201 """Update self.totals with the statistics in stats."""
202 for key in stats.keys():
203 if not self.totals.has_key(key):
204 self.totals[key] = 0
205 self.totals[key] += stats[key]
206
208 try:
209 stats = calcstats(filename)
210 self.updatetotals(stats)
211 self.complete_count += summarize(filename, stats, self.style, self.longestfilename, self.incomplete_only)
212 self.filecount += 1
213 except:
214 print >> sys.stderr, sys.exc_info()[1]
215
217 for filename in filenames:
218 pathname = os.path.join(dirname, filename)
219 if os.path.isdir(pathname):
220 self.handledir(pathname)
221 else:
222 self.handlefile(pathname)
223
225 path, name = os.path.split(dirname)
226 if name in ["CVS", ".svn", "_darcs", ".git", ".hg", ".bzr"]:
227 return
228 entries = os.listdir(dirname)
229 self.handlefiles(dirname, entries)
230
232 parser = OptionParser(usage="usage: %prog [options] po-files")
233 parser.add_option("--incomplete", action="store_const", const = True, dest = "incomplete_only",
234 help="skip 100% translated files.")
235
236 parser.add_option("--full", action="store_const", const = style_csv, dest = "style_full",
237 help="(default) statistics in full, verbose format")
238 parser.add_option("--csv", action="store_const", const = style_csv, dest = "style_csv",
239 help="statistics in CSV format")
240 parser.add_option("--short", action="store_const", const = style_csv, dest = "style_short_strings",
241 help="same as --short-strings")
242 parser.add_option("--short-strings", action="store_const", const = style_csv, dest = "style_short_strings",
243 help="statistics of strings in short format - one line per file")
244 parser.add_option("--short-words", action="store_const", const = style_csv, dest = "style_short_words",
245 help="statistics of words in short format - one line per file")
246
247 (options, args) = parser.parse_args()
248
249 if (options.incomplete_only == None):
250 options.incomplete_only = False
251
252 if (options.style_full and options.style_csv) or \
253 (options.style_full and options.style_short_strings) or \
254 (options.style_full and options.style_short_words) or \
255 (options.style_csv and options.style_short_strings) or \
256 (options.style_csv and options.style_short_words) or \
257 (options.style_short_strings and options.style_short_words):
258 parser.error("options --full, --csv, --short-strings and --short-words are mutually exclusive")
259 sys.exit(2)
260
261 style = default_style
262 if options.style_csv:
263 style = style_csv
264 if options.style_full:
265 style = style_full
266 if options.style_short_strings:
267 style = style_short_strings
268 if options.style_short_words:
269 style = style_short_words
270
271 try:
272 import psyco
273 psyco.full()
274 except Exception:
275 pass
276
277 summarizer(args, style, options.incomplete_only)
278
279 if __name__ == '__main__':
280 main()
281