Merge lp:~adiroiban/launchpad/bug-583934 into lp:launchpad

Proposed by Adi Roiban
Status: Work in progress
Proposed branch: lp:~adiroiban/launchpad/bug-583934
Merge into: lp:launchpad
Diff against target: 500 lines (+299/-17)
9 files modified
lib/lp/translations/browser/configure.zcml (+8/-0)
lib/lp/translations/browser/pofile.py (+12/-4)
lib/lp/translations/configure.zcml (+8/-0)
lib/lp/translations/doc/pofile.txt (+15/-0)
lib/lp/translations/interfaces/pofile.py (+29/-11)
lib/lp/translations/interfaces/statistics.py (+84/-0)
lib/lp/translations/interfaces/webservice.py (+3/-0)
lib/lp/translations/model/pofile.py (+57/-2)
lib/lp/translations/stories/webservice/xx-pofile.txt (+83/-0)
To merge this branch: bzr merge lp:~adiroiban/launchpad/bug-583934
Reviewer Review Type Date Requested Status
Canonical Launchpad Engineering Pending
Review via email: mp+26965@code.launchpad.net

Commit message

Initial API for POFile and translation statistics attributes.

Description of the change

= Bug 583934 =
Right now there is on API for exporting POFile attributes

== Proposed fix ==
This branch is only for POFile attributes and is part of the Translations Reporting API (https://dev.launchpad.net/Translations/Specs/ReportingAPI).

The main part of this branch is to define a translation statistics interface that is suitable for the API.

== Pre-implementation notes ==
IRC chat start from here http://irclogs.ubuntu.com/2010/06/07/%23launchpad-reviews.html#t17:21

Outstanding issues:
 * due to message sharing translation statistics are not updated in real time
   * this affects the last_updated, last_translator, untranslated ... etc
   * still, this branch is independent of this problem and we can go on and define/design the API

 * due to future work for ubuntu-upstream message sharing there may be changes in the way ubuntu changes from upstream are computed/represented.
  * we don't know how exactly this changes will look so maybe it is best to go on with this branch and make the changes only if they are required.

* Jeroen noted that (length - translated messages) is not always equal with untranslated messages, and we should count translation credits and outer automatic translations as "translated messages"

=== Launchpad Translations Reporting API Call - 2010-06-23 ===

Real-time stats update:

• There will be improvements, but they will most probably be gradual
• Not dependent on the message sharing script to complete
• For the current intended consumers the current delay is ok
• Only the series the translator is working will be updated in
real-time, other shared series will take a week to update. We assume
that the translator will mostly work on the translation focus series.

IRosettaStats:

• Not the best interface for statistics, the reason being because it is
parameterised on language
• The language parameter is only used for IPOTemplate, and in turn that
interface is only using message count
• Jeroen: it was probably done this way to a llow a script to be very
generic. It might be worth removing the IRosettaStats interface (or just
the language parameter) and see what breaks on the test suite
• Adi: replacement proposal with ITranslationStats
• An intended improvement is to also provide more descriptive names to
the interface
• AGREED that we should be working on a new translations interface

ITranslationStats:

• Adi's proposal for a new interface for statistics as a replacement for
IRosettaStats
• Right now only used for counters, which is ok if they are attributes
of POFiles
• If we want it to be generic, it might need to be extended and require
a 'target' attribute. This 'target' would be then replaced by a
reference to a language, source package, distro series, etc.
• AGREED to have a stats object to implement the ITranslationStatistics
interface and provide a method on objects to query those statistics. As
an example, a POFile would have a 'stats' attribute instead of separate
attributes for each of the counts. No conclusion on the implementation
on how to link back the object to query with the returned statistics.
Henning would like to see a merge proposal with actual code for better
understanding. Adi will submit it first with the 'target' parameter in
ITranslationStatistics approach.

Other:

• Attribute names: translated_message_*_count - if they are in their own
class, then the 'translated_message' prefix is not needed.
• Recife branch to land roughly on October. Agreed to work on the devel
branch instead for API work in order not to be a blocker. We should go
ahead with an API that's easily extensible and exposes only the
essential counts (e.g. translated, untranslated, unreviewed) and not
worry with the Recife branch changes. When the Recife branch is merged
with trunk, then we can extend the API and expose the rest.
• Jeroen and Henninge happy with a weekly call to track progress and
implementation discussion. David to follow up with Adi (dropped from the
call in the last few minutes) if he'd be happy to.

ACTIONS:

• Adi to submit a merge proposal: experiment removing the language
parameter and fixing what breaks
• Adi to resubmit the existing POFile API merge proposal:
        ∘ replace IRosettaStats with the new ITranslationStats interface
        ∘ with the 'target' parameter
        ∘ for now expose only attributes not dependent on the
        Ubuntu/upstream message sharing work (i.e. no "new" or "chaged"
        counts)
• David to set up a weekly call with Adi, Henning and Jeroen

== Implementation details ==

=== IRosettaStats problem ===
The current IRosettaStats interface is not suitable for API export since the number of various statistic are returned using a method that takes a language as a parameter.

From my point of view IRosettaStats needs a complete rework, since that language parameter is only used for IPOTemplate, and IPOTemplates only implement the message_count part of this interface. I would say that we could change the IPOTemplate to not implement IRosettaStats and remove the language parameter from all IRosettaStats methods.

=== ITranslationStatistics ===
Since this rework of IRosettaStats require some time and thinking, to move things forwards I have started a new interface ITranslationStatistics

Right now ITranslationStatistics has only those attributes required by the API.
In the future (maibe LP Epic) maybe we could decide the new shape of translation statistics interface and extend it to replace the current IRosettaStats.

There will be different TranslationStatistics object implementing the ITranslationStatistics interface in order to agregate the statistics for various translation templates sets.

=== Choosing what attribute to export for the translations statistics ===

Right now IRosettaStats contains a lot of counters, some of them having only internal API usage.

I tried to choose the one that are relevant to end users and use names that will describe their values.
Still, translation_message_new_count is challenging as that "new" can have many meanings.
Mabye we should have "translation_message_new_in_launchpad_count" and "translation_message_changed_in_launchpad_count".

Below is the list of the attribute names that will be exported in the API:

* changed_count
* new_count
* total_count
* translated_count
* unreviewed_count
* language
* template

=== Lint warnings ===

Since the lint warnings were already in the code, I will fix them after this branch is approved in order to make the review process easier.

== Tests ==

./bin/test -t xx-pofile.txt

== Demo and Q/A ==
Point your browser to https://launchpad.dev/api/devel/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/es

You should see the exported attributes.

There is also an „translation_statistics_link” attribute available at :
https://launchpad.dev/api/devel/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/es/+statistics

This will export the ITranslationStatistics attributes

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/lp/translations/configure.zcml
  lib/lp/translations/browser/configure.zcml
  lib/lp/translations/browser/pofile.py
  lib/lp/translations/interfaces/pofile.py
  lib/lp/translations/interfaces/statistics.py
  lib/lp/translations/interfaces/webservice.py
  lib/lp/translations/model/pofile.py
  lib/lp/translations/stories/webservice/xx-pofile.txt

== Pyflakes notices ==

lib/lp/translations/interfaces/webservice.py
    17: 'IHasTranslationImports' imported but unused
    17: 'ITranslationImportQueue' imported but unused
    17: 'ITranslationImportQueueEntry' imported but unused
    22: 'IPOTemplate' imported but unused
    24: 'IPOFile' imported but unused
    26: 'ITranslationStatistics' imported but unused

== Pylint notices ==

lib/lp/translations/browser/pofile.py
    158: [E1002, POFileBaseView.initialize] Use super on an old style class
    682: [E1002, POFileTranslateView.initialize] Use super on an old style class

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

We discussed how ongoing developments are going to affect some of these counts. A quick update on that: with the Recife work, the "changed count" and "new count" on an Ubuntu POFile can still work pretty much the way they did. The difference will be that they will compare the messages that are current in the Ubuntu POFile (each message either diverged or shared) to the shared messages on the upstream side. That way we still get useful numbers.

Another question is how we count "new" or "changed" in project POFiles, i.e. ones that are not part of Ubuntu. We'll no longer have upstream-vs-downstream information for those. We can count new/changed messages compared to the shared Ubuntu translations, and I think that will be useful. The meaning is very different from what we have now though.

lp:~adiroiban/launchpad/bug-583934 updated
10916. By Adi Roiban

Export POFile statistics as external object.

10917. By Adi Roiban

Add tests.

10918. By Adi Roiban

Add forgetten test file.

10919. By Adi Roiban

Add model tests.

Unmerged revisions

10919. By Adi Roiban

Add model tests.

10918. By Adi Roiban

Add forgetten test file.

10917. By Adi Roiban

Add tests.

10916. By Adi Roiban

Export POFile statistics as external object.

10915. By Adi Roiban

Update statistics docstring for pre-implementation chat.

10914. By Adi Roiban

Merge devel.

10913. By Adi Roiban

Export POFile attributes and TranslationsStatistics API.

10912. By Adi Roiban

Merge bug-525371.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/translations/browser/configure.zcml'
2--- lib/lp/translations/browser/configure.zcml 2010-04-19 08:11:52 +0000
3+++ lib/lp/translations/browser/configure.zcml 2010-07-05 21:28:29 +0000
4@@ -187,6 +187,14 @@
5 layer="canonical.launchpad.layers.TranslationsLayer"/>
6 <facet
7 facet="translations">
8+ <browser:url
9+ for="lp.translations.interfaces.statistics.ITranslationStatistics"
10+ path_expression="string:+statistics"
11+ attribute_to_parent="source"
12+ rootsite="translations"/>
13+ </facet>
14+ <facet
15+ facet="translations">
16 <browser:navigation
17 module="lp.translations.browser.pofile"
18 classes="
19
20=== modified file 'lib/lp/translations/browser/pofile.py'
21--- lib/lp/translations/browser/pofile.py 2010-06-17 08:28:33 +0000
22+++ lib/lp/translations/browser/pofile.py 2010-07-05 21:28:29 +0000
23@@ -14,6 +14,7 @@
24 'POFileTranslateView',
25 'POFileUploadView',
26 'POFileView',
27+ 'POFileStatisticsView',
28 ]
29
30 import re
31@@ -63,12 +64,19 @@
32 usedfor = IPOFile
33
34 def traverse(self, name):
35- """Return the IPOMsgSet associated with the given name."""
36- assert self.request.method in ['GET', 'HEAD', 'POST'], (
37- 'We only know about GET, HEAD, and POST')
38+ """Return the IPOMsgSet associated with the given name.
39+
40+ '+statistics' is used to retrieve the `ITranslationStatistics` entry,
41+ while INTEGER to retrieve the specific `ITranslationMessage`.
42+ """
43+ assert self.request.method in ['GET', 'HEAD', 'PATCH', 'POST'], (
44+ 'We only know about GET, HEAD, PATCH and POST')
45
46 try:
47- sequence = int(name)
48+ if name == u'+statistics':
49+ return self.context.translation_statistics
50+ else:
51+ sequence = int(name)
52 except ValueError:
53 # The URL does not have a number to do the traversal.
54 raise NotFoundError(
55
56=== modified file 'lib/lp/translations/configure.zcml'
57--- lib/lp/translations/configure.zcml 2010-05-04 13:42:25 +0000
58+++ lib/lp/translations/configure.zcml 2010-07-05 21:28:29 +0000
59@@ -357,6 +357,14 @@
60 interface="lp.translations.interfaces.pofile.IPOFile"/>
61 </class>
62
63+ <!-- PO File Statistics-->
64+
65+ <class
66+ class="lp.translations.model.pofile.POFileStatistics">
67+ <allow
68+ interface="lp.translations.interfaces.statistics.ITranslationStatistics"/>
69+ </class>
70+
71 <!-- POFileSet -->
72
73 <securedutility
74
75=== modified file 'lib/lp/translations/doc/pofile.txt'
76--- lib/lp/translations/doc/pofile.txt 2010-02-01 15:06:20 +0000
77+++ lib/lp/translations/doc/pofile.txt 2010-07-05 21:28:29 +0000
78@@ -831,6 +831,21 @@
79 >>> print pofile_changed.newCount()
80 0
81
82+Translation statistics are also available via the 'translation_statistics'
83+attribute from the `IPOFile`. It will return an object implementing the
84+`ITranslationStatistics` interface.
85+
86+ >>> print pofile_changed.translation_statistics.total_count
87+ 22
88+ >>> print pofile_changed.translation_statistics.translated_count
89+ 7
90+ >>> print pofile_changed.translation_statistics.new_count
91+ 0
92+ >>> print pofile_changed.translation_statistics.changed_count
93+ 1
94+ >>> print pofile_changed.translation_statistics.unreviewed_count
95+ 1
96+
97 We make sure that submissions on untranslated strings are not considered
98 'changed in Launchpad', since this method is mainly designed to help
99 translators revert translations to published translations.
100
101=== modified file 'lib/lp/translations/interfaces/pofile.py'
102--- lib/lp/translations/interfaces/pofile.py 2010-05-27 14:38:56 +0000
103+++ lib/lp/translations/interfaces/pofile.py 2010-07-05 21:28:29 +0000
104@@ -21,16 +21,20 @@
105
106 from lazr.restful.declarations import (
107 exported, export_as_webservice_entry)
108+from lazr.restful.fields import Reference, ReferenceChoice
109
110 from canonical.launchpad import _
111+from canonical.launchpad.fields import PublicPersonChoice
112 from canonical.launchpad.webapp.interfaces import ILaunchBag
113 from lp.registry.interfaces.person import IPerson
114+from lp.services.worlddata.interfaces.language import ILanguage
115 from lp.translations.interfaces.potemplate import IPOTemplate
116 from lp.translations.interfaces.rosettastats import IRosettaStats
117 from lp.translations.interfaces.translationgroup import (
118 TranslationPermission)
119 from lp.translations.interfaces.translationsperson import (
120 ITranslationsPerson)
121+from lp.translations.interfaces.statistics import ITranslationStatistics
122
123
124 class IPOFile(IRosettaStats):
125@@ -47,12 +51,12 @@
126 title=_('The translation file template.'),
127 required=True, readonly=True, schema=IPOTemplate)
128
129- language = Choice(
130+ language = exported(ReferenceChoice(
131 title=_('Language of this PO file.'),
132- vocabulary='Language', required=True)
133+ vocabulary='Language', required=True, schema=ILanguage))
134
135- variant = TextLine(
136- title=_('The language variant for this translation file.'))
137+ variant = exported(TextLine(
138+ title=_('The language variant for this translation file.')))
139
140 title = TextLine(
141 title=_('The translation file title.'), required=True, readonly=True)
142@@ -73,23 +77,28 @@
143 title=_('A flag indicating whether the header is fuzzy.'),
144 required=True)
145
146- lasttranslator = Object(
147- title=_('Last person that translated a message.'), schema=IPerson)
148+ lasttranslator = exported(
149+ Reference(
150+ title=_('Last person that translated a message.'),
151+ schema=IPerson),
152+ exported_as='last_translator')
153
154- date_changed = Datetime(
155- title=_('When this file was last changed.'), readonly=False,
156- required=True)
157+ date_changed = exported(
158+ Datetime(
159+ title=_('When this file was last changed.'), readonly=False,
160+ required=True),
161+ exported_as='date_last_updated')
162
163 lastparsed = Datetime(title=_('Last time this pofile was parsed.'))
164
165- owner = Choice(
166+ owner = exported(PublicPersonChoice(
167 title=_('Translation file owner'),
168 required=True,
169 description=_('''
170 The owner of the translation file in Launchpad can edit its
171 translations and upload new versions.
172 '''),
173- vocabulary="ValidOwner")
174+ vocabulary="ValidOwner"))
175
176 path = TextLine(
177 title=_('The path to the file that was imported'),
178@@ -141,6 +150,15 @@
179 '''),
180 required=True, readonly=True)
181
182+ translation_statistics = exported(
183+ Reference(
184+ title=_('Translation statistics.'),
185+ description=_('''
186+ An `ITranslationStatistics` used to retrieve statistics for
187+ this translation file.
188+ '''),
189+ schema=ITranslationStatistics))
190+
191 def translatedCount():
192 """
193 Returns the number of message sets which this PO file has current
194
195=== added file 'lib/lp/translations/interfaces/statistics.py'
196--- lib/lp/translations/interfaces/statistics.py 1970-01-01 00:00:00 +0000
197+++ lib/lp/translations/interfaces/statistics.py 2010-07-05 21:28:29 +0000
198@@ -0,0 +1,84 @@
199+# Copyright 2010 Canonical Ltd. This software is licensed under the
200+# GNU Affero General Public License version 3 (see the file LICENSE).
201+
202+__metaclass__ = type
203+
204+__all__ = [
205+ 'ITranslationStatistics',
206+ ]
207+
208+from zope.interface import Attribute, Interface
209+from zope.schema import Int
210+
211+from lazr.restful.declarations import exported, export_as_webservice_entry
212+from lazr.restful.fields import Reference
213+
214+from canonical.launchpad import _
215+from lp.services.worlddata.interfaces.language import ILanguage
216+from lp.translations.interfaces.potemplate import IPOTemplate
217+
218+
219+class ITranslationStatistics(Interface):
220+ """Interface for getting translation statistics of various entities."""
221+
222+ export_as_webservice_entry()
223+
224+ source = Attribute(
225+ _('The source used for generating the translation statistics.'))
226+
227+ language = exported(Reference(
228+ title=_('Source language used for translation statistics.'),
229+ required=True, readonly=True,
230+ schema=ILanguage))
231+
232+ template = exported(Reference(
233+ title=_('Source template used for translation statistics.'),
234+ description=_('''
235+ This field is not set when translation statistics are aggregated
236+ for multiple templates.
237+ '''),
238+ readonly=True,
239+ schema=IPOTemplate))
240+
241+ total_count = exported(Int(
242+ title=_('Number of total translation messages.'),
243+ description=_('''
244+ Total number of translation messages for this entry.
245+ '''),
246+ required=True, readonly=True))
247+
248+ translated_count = exported(Int(
249+ title=_('Number of translated translation messages.'),
250+ description=_('''
251+ The number of translation messages for this entry where we have a
252+ current translation.
253+ '''),
254+ required=True, readonly=True))
255+
256+ new_count = exported(Int(
257+ title=_('Number of newly translated translation messages '
258+ 'in Launchpad.'),
259+ description=_('''
260+ The number of translation messages for this entry where we have a
261+ new translation in Launchpad.
262+ '''),
263+ required=True, readonly=True))
264+
265+ changed_count = exported(Int(
266+ title=_('Number of changed translated translation messages '
267+ ' in Launchpad.'),
268+ description=_('''
269+ The number of translation messages for this entry where the
270+ current translation in Launchpad differs to the one in the
271+ original translation file.
272+ '''),
273+ required=True, readonly=True))
274+
275+ unreviewed_count = exported(Int(
276+ title=_('Number of translation messages with unreviewed '
277+ 'suggestions.'),
278+ description=_('''
279+ Unreviewed translations are those which contain suggestions
280+ submitted later than the last review date.
281+ '''),
282+ required=True, readonly=True))
283
284=== modified file 'lib/lp/translations/interfaces/webservice.py'
285--- lib/lp/translations/interfaces/webservice.py 2010-05-20 19:04:09 +0000
286+++ lib/lp/translations/interfaces/webservice.py 2010-07-05 21:28:29 +0000
287@@ -11,6 +11,7 @@
288 'IPOTemplate',
289 'ITranslationImportQueue',
290 'ITranslationImportQueueEntry',
291+ 'ITranslationStatistics',
292 ]
293
294 from lp.translations.interfaces.translationimportqueue import (
295@@ -22,3 +23,5 @@
296 IPOTemplate)
297 from lp.translations.interfaces.pofile import (
298 IPOFile)
299+from lp.translations.interfaces.statistics import (
300+ ITranslationStatistics)
301
302=== modified file 'lib/lp/translations/model/pofile.py'
303--- lib/lp/translations/model/pofile.py 2010-04-23 14:46:43 +0000
304+++ lib/lp/translations/model/pofile.py 2010-07-05 21:28:29 +0000
305@@ -12,6 +12,7 @@
306 'POFileSet',
307 'POFileToChangedFromPackagedAdapter',
308 'POFileToTranslationFileDataAdapter',
309+ 'POFileStatistics',
310 ]
311
312 import datetime
313@@ -57,6 +58,7 @@
314 from lp.translations.interfaces.translationsperson import (
315 ITranslationsPerson)
316 from lp.translations.interfaces.translations import TranslationConstants
317+from lp.translations.interfaces.statistics import ITranslationStatistics
318 from lp.translations.model.pomsgid import POMsgID
319 from lp.translations.model.potmsgset import POTMsgSet
320 from lp.translations.model.translationimportqueue import (
321@@ -431,6 +433,49 @@
322 return TranslatableMessage(potmsgset, self)
323
324
325+class POFileStatistics:
326+ """Retrieves translation statistics for a `IPOFile`."""
327+ implements(ITranslationStatistics)
328+
329+ def __init__(self, pofile):
330+ self.source = pofile
331+
332+ @property
333+ def language(self):
334+ """See `ITranslationStatistics`."""
335+ return self.source.language
336+
337+ @property
338+ def template(self):
339+ """See `ITranslationStatistics`."""
340+ return self.source.potemplate
341+
342+ @property
343+ def total_count(self):
344+ """See `ITranslationStatistics`."""
345+ return self.source.potemplate.messageCount()
346+
347+ @property
348+ def translated_count(self):
349+ """See `ITranslationStatistics`."""
350+ return self.source.currentcount + self.source.rosettacount
351+
352+ @property
353+ def new_count(self):
354+ """See `ITranslationStatistics`."""
355+ return self.source.rosettacount - self.source.updatescount
356+
357+ @property
358+ def changed_count(self):
359+ """See `ITranslationStatistics`."""
360+ return self.source.updatescount
361+
362+ @property
363+ def unreviewed_count(self):
364+ """See `ITranslationStatistics`."""
365+ return self.source.unreviewed_count
366+
367+
368 class POFile(SQLBase, POFileMixIn):
369 implements(IPOFile)
370
371@@ -570,7 +615,7 @@
372 return u','.join(emails)
373 elif credits_type == TranslationCreditsType.KDE_NAMES:
374 names = []
375-
376+
377 if text is not None:
378 if text == u'':
379 text = SPACE
380@@ -593,7 +638,7 @@
381 text = text[:header_index]
382 else:
383 text += u'\n\n'
384-
385+
386 text += LP_CREDIT_HEADER
387 for contributor in self.contributors:
388 text += ("\n %s %s" %
389@@ -899,6 +944,11 @@
390 self.rosettacount,
391 self.unreviewed_count)
392
393+ @property
394+ def translation_statistics(self):
395+ """See `IPOFile`."""
396+ return POFileStatistics(self)
397+
398 def _appendCompletePluralFormsConditions(self, query,
399 table_name='TranslationMessage'):
400 """Add conditions to implement ITranslationMessage.is_complete in SQL.
401@@ -1349,6 +1399,11 @@
402 return self.potemplate.messageCount()
403
404 @property
405+ def translation_statistics(self):
406+ """See `IPOFile`."""
407+ return POFileStatistics(self)
408+
409+ @property
410 def title(self):
411 """See `IPOFile`."""
412 title = '%s translation of %s' % (
413
414=== added file 'lib/lp/translations/stories/webservice/xx-pofile.txt'
415--- lib/lp/translations/stories/webservice/xx-pofile.txt 1970-01-01 00:00:00 +0000
416+++ lib/lp/translations/stories/webservice/xx-pofile.txt 2010-07-05 21:28:29 +0000
417@@ -0,0 +1,83 @@
418+Translation file webservices
419+============================
420+
421+
422+Getting the attributes of a translation file
423+--------------------------------------------
424+
425+Anonymous users have read access to translation file attributes.
426+
427+ >>> from lazr.restful.testing.webservice import pprint_entry
428+ >>> translation_file = anon_webservice.get(
429+ ... '/ubuntu/hoary/+source/evolution/'
430+ ... '+pots/evolution-2.2/es').jsonBody()
431+ >>> pprint_entry(translation_file)
432+ date_last_updated: u'2005-06-06T20:05:03.244905+00:00'
433+ id: 12
434+ language_link: u'http://.../+languages/es'
435+ last_translator_link: u'http://.../~tsukimi'
436+ owner_link: u'http://.../~ubuntu-translators'
437+ resource_type_link: u'http://.../#translation_file'
438+ self_link:
439+ u'http://.../ubuntu/hoary/+source/evolution/+pots/evolution-2.2/es'
440+ translation_statistics_link:
441+ u'http://.../+source/evolution/+pots/evolution-2.2/es/+statistics'
442+ variant: None
443+
444+
445+Retrieving translation statistics for a translation file
446+--------------------------------------------------------
447+
448+"translation_statistics" attribute from a translation file, will retrieve the
449+translation statistics for this translation file.
450+
451+
452+ >>> from zope.component import getUtility
453+ >>> from zope.security.proxy import removeSecurityProxy
454+ >>> from canonical.launchpad.interfaces.launchpad import (
455+ ... ILaunchpadCelebrities)
456+ >>> from lp.translations.interfaces.potemplate import IPOTemplateSet
457+ >>> login('admin@canonical.com')
458+ >>> hoary = getUtility(ILaunchpadCelebrities).ubuntu.getSeries('hoary')
459+ >>> translation_templates = hoary.getTranslationTemplates()
460+ >>> translation_template = translation_templates[0]
461+ >>> translation_file = removeSecurityProxy(
462+ ... translation_template.getPOFileByLang('es'))
463+ >>> template_name = translation_template.name
464+ >>> package_name = translation_template.translationtarget.name
465+ >>> total_count = translation_template.messageCount()
466+ >>> new_count = (
467+ ... translation_file.rosettacount - translation_file.updatescount)
468+ >>> translated_count = (
469+ ... translation_file.currentcount + translation_file.rosettacount)
470+ >>> unreviewed_count = translation_file.unreviewed_count
471+ >>> changed_count = translation_file.updatescount
472+ >>> logout()
473+
474+ >>> statistics = anon_webservice.get(
475+ ... '/ubuntu/hoary/+source/%s/'
476+ ... '+pots/%s/es/+statistics' % (
477+ ... package_name, template_name)).jsonBody()
478+ >>> print statistics['resource_type_link']
479+ http://.../#translation_statistics
480+ >>> print statistics['language_link']
481+ http://.../+languages/es
482+ >>> statistics['self_link'].find(
483+ ... '/ubuntu/hoary/+source/%s/+pots/%s/es/+statistics' % (
484+ ... package_name, template_name)) != -1
485+ True
486+ >>> statistics['template_link'].find(
487+ ... '/ubuntu/hoary/+source/%s/+pots/%s' % (
488+ ... package_name, template_name)) != -1
489+ True
490+ >>> statistics['changed_count'] == changed_count
491+ True
492+ >>> statistics['new_count'] == new_count
493+ True
494+ >>> statistics['total_count'] == total_count
495+ True
496+ >>> statistics['translated_count'] == translated_count
497+ True
498+ >>> statistics['unreviewed_count'] == unreviewed_count
499+ True
500+