Merge lp:~jtv/launchpad/bug-423705 into lp:launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Merged at revision: not available
Proposed branch: lp:~jtv/launchpad/bug-423705
Merge into: lp:launchpad
Diff against target: None lines
To merge this branch: bzr merge lp:~jtv/launchpad/bug-423705
Reviewer Review Type Date Requested Status
Michael Nelson (community) ui Approve
Abel Deuring (community) Approve
Review via email: mp+11519@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

= Bug 423705: 3.0 Person Translations page =

This branch converts the Person page in Translations to the 3.0 style.
It also transforms the translation activity (previously "history")
listing on that page into something more like what we drew up in Buenos
Aires (minus the squiggles where the straight lines were supposed to be
:-)

The activity listing no longer floods the page with your complete
translation history; the full list has moved to a new "activity" page.
The person page now only shows the latest 10 entries.

What you see on the new page is a bit more detailed than the short list,
but also less detailed than what the existing Person page shows. The
reason is that it originally had a mixed bag of purposes, including
helping people reach the translations they've been working on. But for
that we now have the "translations you need to review" and "translations
you can help complete" listings.

I tried to get a two-column layout working for this page, but couldn't
because the elements on the page are much too variable. Each of the
portlets is conditional, all with different conditions. No static
layout is going to make that work well for even a reasonable number of
cases.

== Test ==

Best to run all Translations stories, as I did, but in particular:
{{{
./bin/test -vv -t xx-person-activity
}}}

== Demo and Q/A ==

For a nicely filled example, go to Carlos' home page:

    https://translations.launchpad.dev/~carlos

It gets better if you look at the same page but logged in as Carlos
(<email address hidden> / test).

From there, click on the "See all" link on the right, at the bottom of
the activity list. That takes you to the new, batched full activity
listing.

Also look at an empty page:

    https://translations.launchpad.dev/~salgado

And finally, there's the warning if you haven't set your preferred
languages. Log in as Brad (<email address hidden> / test) and visit Brad's
Translations page:

    https://translations.launchpad.dev/~bac

The "Please set them now" link will take you to the settings page where
you can select preferred languages.

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

Linting changed files:
  lib/canonical/launchpad/pagetitles.py
  lib/canonical/launchpad/webapp/configure.zcml
  lib/canonical/launchpad/webapp/tales.py
  lib/lp/translations/browser/configure.zcml
  lib/lp/translations/browser/person.py
  lib/lp/translations/stories/standalone/xx-person-activity.txt
  lib/lp/translations/templates/person-navlinks.pt
  lib/lp/translations/templates/person-translation-activity.pt
  lib/lp/translations/templates/person-translations-to-complete-table.pt
  lib/lp/translations/templates/person-translations-to-review-table.pt
  lib/lp/translations/templates/person-translations.pt

=== Pylint notices ===

lib/canonical/launchpad/webapp/tales.py
    21: [F0401] Unable to import 'lazr.enum' (No module named enum)
}}}

I'm not planning to do anything about that last one.

Jeroen

Revision history for this message
Abel Deuring (adeuring) wrote :

Hi Jeroen,

a very nice branch. We discussed two minor changes in IRC, please apply them

review: Approve
Revision history for this message
Michael Nelson (michael.nelson) wrote :

Great work Jeroen!

The index page looks great!

Note: RE the icons not displaying, I'd say you just need to add icon='info' to your menu 'Link's.

We agreed it would be good to perhaps not include the edit translation guidelines here on the index page, but are not including it as part of this update.

<jtv> Anyone free to give me a UI review for https://code.edge.launchpad.net/~jtv/launchpad/bug-423705/+merge/11519 ? noodles775 maybe?
<noodles775> jtv: I could - but I just saw that barry will be around on ocr soon - would you mind if I leave it to him?
<jtv> noodles775: I _hate_ to nag (well, except end-users) but this branch has been sitting on the review queue for a while, been accidentally removed from it, put back etc. If barry has no time, that pushes this to next week.
* jtv bats eyelids at noodles
<noodles775> jtv: ah, do you need to leave soon?
<jtv> noodles775: ideally, yes, though I don't think it's particularly likely :-)
<noodles775> OK, looking now...
<jtv> noodles775: great, thanks!
<noodles775> jtv: just noticed that I think you're doing something similar to https://launchpad.dev/~carlos/+related-software
<noodles775> with the 'sub-menu'...
<noodles775> The only difference being the icons?
<noodles775> jtv: btw, the index page looks great!
<jtv> noodles775: actually I copied the whole idea from there. :) _Keine_ _blasse_ _Ahnung_ why those icons don't appear for me. :(
<noodles775> heh
<jtv> noodles775: (glad you like the page btw)
<noodles775> jtv: I'm not sure about having the full translation groups table there? Well, at least the edit translation guidelines link... what do you think? I just noticed if you edit the translation guideline you obviously don't end up back on the same page...
<noodles775> But then again, I guess that's similar to clicking on the needs [link]2 strings reviewed[/link]
<jtv> noodles775: it's one of those things I would've liked to update, but avoided on the "timely and within the review limit beats perfect" principle.
<noodles775> jtv: yep, sure.
<jtv> noodles775: I do agree it can do with a makeover though
<jtv> (Or since this is all just outward appearance, is it really a combover?)

review: Approve (ui)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/pagetitles.py'
2--- lib/canonical/launchpad/pagetitles.py 2009-09-10 01:35:03 +0000
3+++ lib/canonical/launchpad/pagetitles.py 2009-09-10 10:09:18 +0000
4@@ -739,8 +739,6 @@
5
6 person_specworkload = ContextDisplayName('Blueprint workload for %s')
7
8-person_translations = ContextDisplayName('Translations related to %s')
9-
10 person_translations_to_review = ContextDisplayName(
11 'Translations for review by %s')
12
13
14=== modified file 'lib/canonical/launchpad/webapp/configure.zcml'
15--- lib/canonical/launchpad/webapp/configure.zcml 2009-09-01 08:37:31 +0000
16+++ lib/canonical/launchpad/webapp/configure.zcml 2009-09-09 11:45:55 +0000
17@@ -513,6 +513,12 @@
18 name="fmt"
19 />
20 <adapter
21+ for="lp.translations.interfaces.pofile.IPOFile"
22+ provides="zope.traversing.interfaces.IPathAdapter"
23+ factory="canonical.launchpad.webapp.tales.POFileFormatterAPI"
24+ name="fmt"
25+ />
26+ <adapter
27 for="*"
28 provides="zope.traversing.interfaces.IPathAdapter"
29 factory="canonical.launchpad.webapp.tales.PermissionRequiredQuery"
30
31=== modified file 'lib/canonical/launchpad/webapp/tales.py'
32--- lib/canonical/launchpad/webapp/tales.py 2009-09-07 12:16:29 +0000
33+++ lib/canonical/launchpad/webapp/tales.py 2009-09-09 11:45:55 +0000
34@@ -3181,3 +3181,27 @@
35 def displayname(self, view_name, rootsite=None):
36 """Return the displayname as a string."""
37 return self._context.title
38+
39+
40+class POFileFormatterAPI(ObjectFormatterAPI):
41+ """Adapter for `IPOFile` objects to a formatted string."""
42+
43+ traversable_names = {
44+ 'link': 'link',
45+ 'url': 'url',
46+ 'displayname': 'displayname',
47+ }
48+
49+ def url(self, view_name=None, rootsite='translations'):
50+ """See `ObjectFormatterAPI`."""
51+ return super(POFileFormatterAPI, self).url(view_name, rootsite)
52+
53+ def link(self, view_name, rootsite='translations'):
54+ """See `ObjectFormatterAPI`."""
55+ pofile = self._context
56+ url = self.url(view_name, rootsite)
57+ return u'<a href="%s">%s</a>' % (url, cgi.escape(pofile.title))
58+
59+ def displayname(self, view_name, rootsite=None):
60+ """Return the displayname as a string."""
61+ return self._context.title
62
63=== modified file 'lib/lp/translations/browser/configure.zcml'
64--- lib/lp/translations/browser/configure.zcml 2009-09-01 11:09:53 +0000
65+++ lib/lp/translations/browser/configure.zcml 2009-09-10 10:09:18 +0000
66@@ -709,7 +709,6 @@
67 <browser:page
68 for="lp.registry.interfaces.person.IPerson"
69 name="+licensing"
70- facet="translations"
71 class="
72 lp.translations.browser.person.PersonTranslationRelicensingView"
73 permission="launchpad.Edit"
74@@ -719,12 +718,24 @@
75 for="lp.registry.interfaces.person.IPerson"
76 name="+imports"
77 class="lp.translations.browser.hastranslationimports.HasTranslationImportsView"
78- facet="translations"
79 permission="zope.Public"
80 template="../templates/hastranslationimports-index.pt"
81 layer="canonical.launchpad.layers.TranslationsLayer"/>
82 <browser:page
83 for="lp.registry.interfaces.person.IPerson"
84+ class="lp.translations.browser.person.PersonTranslationView"
85+ permission="zope.Public"
86+ name="+person-navlinks"
87+ template="../templates/person-navlinks.pt"/>
88+ <browser:page
89+ for="lp.registry.interfaces.person.IPerson"
90+ name="+activity"
91+ class="lp.translations.browser.person.TranslationActivityView"
92+ permission="zope.Public"
93+ template="../templates/person-translation-activity.pt"
94+ layer="canonical.launchpad.layers.TranslationsLayer"/>
95+ <browser:page
96+ for="lp.registry.interfaces.person.IPerson"
97 name="+translations-to-review"
98 class="lp.translations.browser.person.PersonTranslationView"
99 permission="zope.Public"
100
101=== modified file 'lib/lp/translations/browser/person.py'
102--- lib/lp/translations/browser/person.py 2009-09-09 16:49:35 +0000
103+++ lib/lp/translations/browser/person.py 2009-09-10 11:56:21 +0000
104@@ -8,13 +8,16 @@
105 __all__ = [
106 'PersonTranslationView',
107 'PersonTranslationRelicensingView',
108+ 'TranslationActivityView',
109 ]
110
111 from datetime import datetime, timedelta
112 import pytz
113 import urllib
114+
115 from zope.app.form.browser import TextWidget
116 from zope.component import getUtility
117+from zope.interface import implements, Interface
118
119 from canonical.launchpad import _
120 from canonical.launchpad.webapp.interfaces import ILaunchBag
121@@ -25,7 +28,6 @@
122 from canonical.launchpad.webapp.batching import BatchNavigator
123 from canonical.launchpad.webapp.publisher import LaunchpadView
124 from canonical.widgets import LaunchpadRadioWidget
125-from lp.registry.interfaces.person import IPerson
126 from lp.registry.interfaces.sourcepackage import ISourcePackage
127 from lp.translations.browser.translationlinksaggregator import (
128 TranslationLinksAggregator)
129@@ -89,18 +91,56 @@
130 return pofile.untranslatedCount()
131
132
133+def compose_pofile_filter_url(pofile, person):
134+ """Compose URL for `Person`'s contributions to `POFile`."""
135+ person_name = urllib.urlencode({'person': person.name})
136+ return canonical_url(pofile) + "/+filter?%s" % person_name
137+
138+
139+class ActivityDescriptor:
140+ """Description of a past translation activity."""
141+
142+ date = None
143+ title = None
144+ url = None
145+
146+ def __init__(self, person, pofiletranslator):
147+ """Describe a past translation activity by `person`.
148+
149+ :param person: The `Person` whose activity is being described.
150+ :param pofiletranslator: A `POFileTranslator` record for
151+ `person`.
152+ """
153+ assert person == pofiletranslator.person, (
154+ "This POFileTranslator record is for the wrong person.")
155+
156+ self.date = pofiletranslator.date_last_touched
157+
158+ pofile = pofiletranslator.pofile
159+
160+ self.title = pofile.potemplate.translationtarget.title
161+ self.url = compose_pofile_filter_url(pofile, person)
162+
163+
164 def person_is_reviewer(person):
165 """Is `person` a translations reviewer?"""
166 groups = ITranslationsPerson(person).translation_groups
167 return groups.any() is not None
168
169
170+class IPersonTranslationsMenu(Interface):
171+ """Marker interface for `Person` Translations navigation menu."""
172+
173+
174 class PersonTranslationsMenu(NavigationMenu):
175
176- usedfor = IPerson
177+ usedfor = IPersonTranslationsMenu
178 facet = 'translations'
179 links = ('overview', 'licensing', 'imports', 'translations_to_review')
180- title = "Related pages"
181+
182+ @property
183+ def person(self):
184+ return self.context.context
185
186 def overview(self):
187 text = 'Overview'
188@@ -112,37 +152,45 @@
189
190 def licensing(self):
191 text = 'Translations licensing'
192- enabled = (self.context == self.user)
193+ enabled = (self.person == self.user)
194 return Link('+licensing', text, enabled=enabled)
195
196 def translations_to_review(self):
197 text = 'Translations to review'
198- enabled = person_is_reviewer(self.context)
199+ enabled = person_is_reviewer(self.person)
200 return Link('+translations-to-review', text, enabled=enabled)
201
202
203 class PersonTranslationView(LaunchpadView):
204 """View for translation-related Person pages."""
205+ implements(IPersonTranslationsMenu)
206
207- _pofiletranslator_cache = None
208+ reviews_to_show = 10
209
210 def __init__(self, *args, **kwargs):
211 super(PersonTranslationView, self).__init__(*args, **kwargs)
212 now = datetime.now(pytz.timezone('UTC'))
213 self.history_horizon = now - timedelta(90, 0, 0)
214
215- @cachedproperty
216- def batchnav(self):
217+ @property
218+ def page_title(self):
219+ return "Translations related to %s" % self.context.displayname
220+
221+ @cachedproperty
222+ def recent_activity(self):
223+ """Recent translation activity by this person."""
224+ entries = ITranslationsPerson(self.context).translation_history[:10]
225+ return [ActivityDescriptor(self.context, entry) for entry in entries]
226+
227+ @cachedproperty
228+ def latest_activity(self):
229+ """Single latest translation activity by this person."""
230 translations_person = ITranslationsPerson(self.context)
231- batchnav = BatchNavigator(
232- translations_person.translation_history, self.request)
233-
234- pofiletranslatorset = getUtility(IPOFileTranslatorSet)
235- batch = batchnav.currentBatch()
236- self._pofiletranslator_cache = (
237- pofiletranslatorset.prefetchPOFileTranslatorRelations(batch))
238-
239- return batchnav
240+ latest = list(translations_person.translation_history[:1])
241+ if len(latest) == 0:
242+ return None
243+ else:
244+ return ActivityDescriptor(self.context, latest[0])
245
246 @cachedproperty
247 def translation_groups(self):
248@@ -156,11 +204,6 @@
249 translations_person = ITranslationsPerson(self.context)
250 return list(translations_person.translators)
251
252- @cachedproperty
253- def person_filter_querystring(self):
254- """Return person's name appropriate for including in links."""
255- return urllib.urlencode({'person': self.context.name})
256-
257 @property
258 def person_is_reviewer(self):
259 """Is this person in a translation group?"""
260@@ -429,3 +472,29 @@
261 "Unknown allow_relicensing value: %r" % allow_relicensing)
262 self.next_url = self.getSafeRedirectURL(data['back_to'])
263
264+
265+class TranslationActivityView(LaunchpadView):
266+ """View for person's activity listing."""
267+
268+ _pofiletranslator_cache = None
269+
270+ @property
271+ def page_title(self):
272+ return "Translation activity by %s" % self.context.displayname
273+
274+ @cachedproperty
275+ def batchnav(self):
276+ """Iterate over person's translation_history."""
277+ translations_person = ITranslationsPerson(self.context)
278+ batchnav = BatchNavigator(
279+ translations_person.translation_history, self.request)
280+
281+ pofiletranslatorset = getUtility(IPOFileTranslatorSet)
282+ batch = batchnav.currentBatch()
283+ self._pofiletranslator_cache = (
284+ pofiletranslatorset.prefetchPOFileTranslatorRelations(batch))
285+
286+ return batchnav
287+
288+ def composeURL(self, pofile):
289+ return compose_pofile_filter_url(pofile, self.context)
290
291=== renamed file 'lib/lp/translations/stories/standalone/xx-person-translations.txt' => 'lib/lp/translations/stories/standalone/xx-person-activity.txt'
292--- lib/lp/translations/stories/standalone/xx-person-translations.txt 2009-09-01 09:51:12 +0000
293+++ lib/lp/translations/stories/standalone/xx-person-activity.txt 2009-09-10 11:56:21 +0000
294@@ -1,13 +1,13 @@
295-Test that the person's translation history page displays the latest
296-translations and translation groups related to the person in question.
297+Person's translation activity
298+=============================
299+
300+A person's translation activity page displays the translations that the
301+person has contributed to.
302+
303+Here the person whose activity we're going to look at is Carlos.
304
305 >>> anon_browser.open(
306- ... "http://translations.launchpad.dev/people/carlos/+translations")
307-
308- >>> header = find_tag_by_id(
309- ... anon_browser.contents, 'translation-history-header')
310- >>> print extract_text(header)
311- Applications and packages translated
312+ ... "http://translations.launchpad.dev/people/carlos/+activity")
313
314 The user can see in the page navigation that Carlos has so far worked
315 on six files, five of which are shown on this page.
316@@ -20,74 +20,60 @@
317
318 # Prints a heading and formatted list of POFiles and latest submissions.
319 >>> import re
320- >>> def print_list_of_contributions(listing):
321- ... listing_head = listing.findAll('thead')[0].findAll('tr')[0]
322- ... heading_cells = listing_head.findAll('th')
323- ... print "%-24s %-8s %-8s %-26s" % (
324- ... extract_text(heading_cells[0]),
325- ... extract_text(heading_cells[1])[:6] + '...',
326- ... extract_text(heading_cells[2])[:6] + '...',
327- ... extract_text(heading_cells[3]))
328- ... listing_body = listing.find('tbody')
329- ... for row in listing_body.findAll('tr'):
330- ... cells = row.findAll('td')
331- ... pofile = extract_text(cells[0])
332- ... if len(pofile) > 24:
333- ... pofile = pofile[:21] + '...'
334- ... untranslated = extract_text(cells[1])
335- ... needs_review = extract_text(cells[2])
336- ... message = re.sub(' +', ' ', extract_text(cells[3]))
337- ... if len(message) > 26:
338- ... message = message[:23] + '...'
339- ... print "%-24s %-10s %-10s %-26s" % (
340- ... pofile, untranslated, needs_review, message)
341-
342- >>> listing = find_tags_by_class(anon_browser.contents, 'listing')[0]
343- >>> print_list_of_contributions(listing)
344- Translation file Untra... Need... Latest translation
345- English (en) translat... 6 0 2007-07-12 auto, esddsp...
346- Spanish (es) translat... 3 0 2007-04-07 _: EMAIL OF ...
347- Spanish (es) translat... 0 0 2007-01-24 test man pag...
348- Spanish (es) translat... 14 2 2006-12-22 have lalalala
349- Japanese (ja) transla... 21 0 2005-10-11 %d contact %...
350-
351-When the user clicks one of the entries, he is shown a page listing
352-all translations done by Carlos in this file.
353+ >>> def print_activity_list(listing):
354+ ... for row in listing.findAll('tr'):
355+ ... print extract_text(row)
356+
357+ >>> listing = find_tag_by_id(anon_browser.contents, 'activity-table')
358+ >>> print_activity_list(listing)
359+ 2007-07-12
360+ English (en) translation of pkgconf-mozilla in Ubuntu Hoary package
361+ "mozilla"
362+ 2007-04-07
363+ Spanish (es) translation of alsa-utils in alsa-utils trunk
364+ 2007-01-24
365+ Spanish (es) translation of man in Ubuntu Hoary package "evolution"
366+ 2006-12-22
367+ Spanish (es) translation of evolution-2.2 in Evolution trunk
368+ 2005-10-11
369+ Japanese (ja) translation of evolution-2.2 in Ubuntu Hoary package
370+ "evolution"
371+
372+Clicking one of the entries takes you to a page listing all of Carlos'
373+contributions to the selected translation.
374
375 >>> alsa_utils_link = 'Spanish (es) translation of alsa-utils in alsa-utils trunk'
376 >>> anon_browser.getLink(alsa_utils_link).click()
377- >>> anon_browser.title
378- 'Translations by Carlos...of alsa-utils...'
379-
380-From the full listing of all contributions, Carlos can jump to the pages
381-containing only untranslated or only translations that need reviewing.
382-
383- >>> anon_browser.goBack()
384- >>> untranslated_link = find_tags_by_class(anon_browser.contents,
385- ... 'untranslated-count')[1]
386- >>> extract_link_from_tag(untranslated_link)
387- u'/alsa-utils/trunk/+pots/alsa-utils/es/+translate?show=untranslated'
388-
389- >>> unreviewed_link = find_tags_by_class(anon_browser.contents,
390- ... 'unreviewed-count')[1]
391- >>> extract_link_from_tag(unreviewed_link)
392- u'/alsa-utils/trunk/+pots/alsa-utils/es/+translate?show=new_suggestions'
393-
394-A person is created with a name containing characters that need escaping
395-before being used in query strings.
396+ >>> print anon_browser.title
397+ Translations by Carlos...of alsa-utils...
398+
399+
400+URL-escaped user names
401+----------------------
402+
403+Since the user's name is included in the URL, and user names can contain
404+some slightly weird characters, it is escaped especially for this usage.
405+
406+For instance, here's a user called a+b.
407
408 >>> login('carlos@canonical.com')
409- >>> foobar = factory.makePerson(name='foo+bar', email='blah@test.com')
410- >>> message = factory.makeTranslationMessage(translator=foobar)
411- >>> person_url = canonical_url(foobar, rootsite='translations')
412+ >>> ab = factory.makePerson(name='a+b')
413+ >>> message = factory.makeTranslationMessage(translator=ab)
414+ >>> person_url = canonical_url(ab, rootsite='translations')
415 >>> logout()
416
417-When that person goes to see the translations she has done, she sees
418-a correctly encoded link to a filtered PO file page.
419-
420- >>> user_browser.open(person_url)
421- >>> table = first_tag_by_class(user_browser.contents, 'listing')
422- >>> tbody = table.find('tbody')
423- >>> link = tbody.find('a')
424- >>> link['href'].split('/')[-1]
425- u'+filter?person=foo%2Bbar'
426+When a+b goes to see the translations she has done, she sees a correctly
427+encoded link to a filtered PO file page.
428+
429+ >>> user_browser.open(person_url + '/+activity')
430+ >>> table = find_tag_by_id(user_browser.contents, 'activity-table')
431+ >>> link = table.find('a')
432+ >>> url = link['href']
433+ >>> print url.split('/')[-1]
434+ +filter?person=a%2Bb
435+
436+Because of this, the link actually works.
437+
438+ >>> user_browser.open(url.encode('ascii'))
439+ >>> print user_browser.title
440+ Translations by ...
441
442=== added file 'lib/lp/translations/templates/person-navlinks.pt'
443--- lib/lp/translations/templates/person-navlinks.pt 1970-01-01 00:00:00 +0000
444+++ lib/lp/translations/templates/person-navlinks.pt 2009-09-10 11:56:21 +0000
445@@ -0,0 +1,21 @@
446+<tal:root
447+ xmlns:tal="http://xml.zope.org/namespaces/tal"
448+ xmlns:metal="http://xml.zope.org/namespaces/metal"
449+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
450+ omit-tag="">
451+
452+ <ul id="navlinks" class="horizontal">
453+ <li>
454+ <a tal:replace="structure view/menu:navigation/overview/render"/>
455+ </li>
456+ <li>
457+ <a tal:replace="structure view/menu:navigation/licensing/render"/>
458+ </li>
459+ <li>
460+ <a tal:replace="structure view/menu:navigation/imports/render"/>
461+ </li>
462+ <li>
463+ <a tal:replace="structure view/menu:navigation/translations_to_review/render"/>
464+ </li>
465+ </ul>
466+</tal:root>
467
468=== added file 'lib/lp/translations/templates/person-translation-activity.pt'
469--- lib/lp/translations/templates/person-translation-activity.pt 1970-01-01 00:00:00 +0000
470+++ lib/lp/translations/templates/person-translation-activity.pt 2009-09-10 11:53:09 +0000
471@@ -0,0 +1,41 @@
472+<html
473+ xmlns="http://www.w3.org/1999/xhtml"
474+ xmlns:tal="http://xml.zope.org/namespaces/tal"
475+ xmlns:metal="http://xml.zope.org/namespaces/metal"
476+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
477+ metal:use-macro="view/macro:page/main_only"
478+>
479+<body>
480+ <div metal:fill-slot="main">
481+ <div class="top-portlet" style="max-width: 800px">
482+ <p>
483+ <tal:person replace="structure context/fmt:link">R. Viewer</tal:person>
484+ has contributed to the following translations.
485+ </p>
486+
487+ <div class="lesser" id="top-navigation">
488+ <tal:navigation content="structure view/batchnav/@@+navigation-links-upper" />
489+ </div>
490+
491+ <table class="listing" id="activity-table">
492+ <tr tal:repeat="record view/batchnav/currentBatch">
493+ <td tal:attributes="title record/date_last_touched/fmt:datetime"
494+ tal:content="record/date_last_touched/fmt:approximatedate">
495+ 2009-10-28
496+ </td>
497+ <td>
498+ <a tal:attributes="href python:view.composeURL(record.pofile)"
499+ tal:content="record/pofile/title">
500+ Greek (el) translations of alsa-utils in alsa-utils trunk
501+ </a>
502+ </td>
503+ </tr>
504+ </table>
505+
506+ <div class="lesser">
507+ <tal:navigation content="structure view/batchnav/@@+navigation-links-lower" />
508+ </div>
509+ </div>
510+ </div>
511+</body>
512+</html>
513
514=== modified file 'lib/lp/translations/templates/person-translations-to-complete-table.pt'
515--- lib/lp/translations/templates/person-translations-to-complete-table.pt 2009-08-28 09:44:31 +0000
516+++ lib/lp/translations/templates/person-translations-to-complete-table.pt 2009-09-09 09:51:14 +0000
517@@ -4,7 +4,7 @@
518 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
519 omit-tag="">
520
521-<table class="listing" id="translations-to-complete-table">
522+<table class="summary" id="translations-to-complete-table">
523 <tr tal:repeat="target_info view/top_projects_and_packages_to_translate">
524 <td>
525 <tal:product condition="target_info/is_product"
526
527=== modified file 'lib/lp/translations/templates/person-translations-to-review-table.pt'
528--- lib/lp/translations/templates/person-translations-to-review-table.pt 2009-08-12 07:59:37 +0000
529+++ lib/lp/translations/templates/person-translations-to-review-table.pt 2009-09-09 09:51:14 +0000
530@@ -4,7 +4,7 @@
531 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
532 omit-tag="">
533
534-<table class="listing" id="translations-to-review-table">
535+<table class="summary" id="translations-to-review-table">
536 <tr tal:repeat="target_info view/top_projects_and_packages_to_review">
537 <td>
538 <tal:product condition="target_info/is_product"
539
540=== modified file 'lib/lp/translations/templates/person-translations.pt'
541--- lib/lp/translations/templates/person-translations.pt 2009-09-09 16:49:35 +0000
542+++ lib/lp/translations/templates/person-translations.pt 2009-09-10 11:53:09 +0000
543@@ -3,35 +3,56 @@
544 xmlns:tal="http://xml.zope.org/namespaces/tal"
545 xmlns:metal="http://xml.zope.org/namespaces/metal"
546 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
547+ metal:use-macro="view/macro:page/main_only"
548 i18n:domain="launchpad"
549- xml:lang="en"
550- lang="en"
551- dir="ltr"
552- metal:use-macro="view/macro:page/onecolumn"
553 >
554
555 <body>
556
557-<h1>Translations related to <tal:name content="context/displayname" /></h1>
558+<div metal:fill-slot="heading">
559+ <h1 tal:content="view/page_title" />
560+</div>
561
562 <div metal:fill-slot="main">
563+ <div class="top-portlet">
564+ <tal:navlinks replace="structure context/@@+person-navlinks" />
565+ </div>
566
567 <tal:me condition="view/person_includes_me">
568- <p tal:condition="view/requires_preferred_languages" id="no-languages">
569+ <div tal:condition="view/requires_preferred_languages"
570+ class="portlet"
571+ id="no-languages">
572 You have not selected your preferred languages. Please
573 <a href="/+editmylanguages" id="set-languages">set them now</a>.
574- </p>
575+ </div>
576+ </tal:me>
577+
578+ <div class="portlet">
579+ <tal:active tal:condition="view/latest_activity">
580+ Last translation activity by
581+ <tal:name replace="context/displayname">Foo Bar</tal:name>
582+ was
583+ <tal:date replace="view/latest_activity/date/fmt:displaydate">
584+ on 2009-10-12</tal:date>.
585+ </tal:active>
586+ <tal:inactive tal:condition="not: view/latest_activity">
587+ No translation activities recorded for
588+ <tal:name replace="context/displayname">Foo Bar</tal:name>.
589+ </tal:inactive>
590+ </div>
591+
592+ <tal:me condition="view/person_includes_me">
593 <tal:reviewer condition="view/person_is_reviewer">
594- <div id="translations-to-review-section" style="max-width:800px">
595- <span style="float:right">
596- <a href="http://help.launchpad.net/Translations/Reviewing">
597- Why is this important?
598- </a>
599- </span>
600+ <div id="translations-to-review-section" class="portlet">
601 <h2>Translations you need to review</h2>
602+ <span style="display:block; text-align:right">
603+ <a href="http://help.launchpad.net/Translations/Reviewing">
604+ Why is this important?
605+ </a>
606+ </span>
607 <metal:translations-to-review
608 tal:replace="structure context/@@+translations-to-review-table" />
609- <span style="float:right"
610+ <span style="display:block; text-align:right"
611 tal:condition="python: view.num_projects_and_packages_to_review > 1">
612 <a href="+translations-to-review" id="translations-to-review-link">
613 See all
614@@ -42,9 +63,11 @@
615 </span>
616 </div>
617 </tal:reviewer>
618+ </tal:me>
619
620+ <tal:me condition="view/person_includes_me">
621 <tal:translator condition="view/person_is_translator">
622- <div id="translations-to-complete-section" style="max-width:800px">
623+ <div id="translations-to-complete-section" class="portlet">
624 <h2>Translations you can help complete</h2>
625 <metal:translations-to-complete
626 tal:replace="structure context/@@+translations-to-complete-table" />
627@@ -52,87 +75,40 @@
628 </tal:translator>
629 </tal:me>
630
631-
632- <h2 id="translation-history-header">Applications and packages translated</h2>
633-
634- <tal:block define="history view/batchnav/currentBatch">
635-
636- <tal:block condition="history">
637-
638- <div class="lesser" id="top-navigation">
639- <tal:navigation content="structure view/batchnav/@@+navigation-links-upper" />
640- </div>
641-
642- <table class="listing" style="max-width:800px">
643- <thead>
644- <tr>
645- <th>Translation file</th>
646- <th>Untranslated</th>
647- <th>Need review</th>
648- <th>Latest translation</th>
649- </tr>
650- </thead>
651- <tbody>
652- <tr tal:repeat="record history">
653- <tal:block define="translationmessage record/latest_message">
654- <td><a tal:content="record/pofile/title"
655- tal:attributes="href string:${record/pofile/fmt:url}/+filter?${view/person_filter_querystring}">foo bar in package bla</a>
656- </td>
657- <td><a tal:content="record/pofile/untranslatedCount"
658- tal:attributes="href string:${record/pofile/fmt:url}/+translate?show=untranslated"
659- class="untranslated-count"
660- >17</a>
661- </td>
662- <td><a tal:content="record/pofile/unreviewedCount"
663- tal:attributes="href string:${record/pofile/fmt:url}/+translate?show=new_suggestions"
664- class="unreviewed-count"
665- >17</a>
666- </td>
667- <td style="padding-left: 2em;">
668- <em
669- tal:attributes="title record/date_last_touched/fmt:datetime"
670- tal:content="record/date_last_touched/fmt:approximatedate"
671- style="margin-left: -2em;" />
672- <div tal:content="translationmessage/potmsgset/singular_text" />
673- <div
674- tal:condition="python:not(view.should_display_message(translationmessage))">
675- <strong>For privacy reasons this translation is not visible to
676- anonymous visitors. To see it,
677- <a href="+login">log in</a> first.</strong></div>
678- <div
679- tal:condition="python:view.should_display_message(translationmessage)">
680- <tal:block
681- tal:condition="translationmessage/msgstr0"
682- tal:content="translationmessage/msgstr0/translation" />
683- </div>
684- </td>
685- </tal:block>
686- </tr>
687- </tbody>
688- </table>
689-
690- <div class="lesser">
691- <tal:navigation content="structure view/batchnav/@@+navigation-links-lower" />
692- </div>
693-
694- </tal:block>
695-
696- <tal:block condition="not: history">
697- <p><i>No translations recorded from
698- <span tal:replace="context/displayname">Foo Bar</span>.</i></p>
699+ <tal:block tal:define="activities view/recent_activity">
700+ <tal:block condition="activities">
701+ <div class="portlet">
702+ <h2>Activity</h2>
703+ <p>
704+ These are the translations that
705+ <tal:name replace="context/displayname">Foo Bar</tal:name>
706+ last worked on:
707+ </p>
708+ <table class="summary">
709+ <tr tal:repeat="activity activities">
710+ <td tal:attributes="title activity/date/fmt:datetime"
711+ tal:content="activity/date/fmt:approximatedate">
712+ 2009-08-15
713+ </td>
714+ <td>
715+ <a tal:content="activity/title"
716+ tal:attributes="href activity/url">foo bar in package bla</a>
717+ </td>
718+ </tr>
719+ </table>
720+ <span style="display:block; text-align:right">
721+ <a href="+activity">See all</a>
722+ </span>
723+ </div>
724 </tal:block>
725 </tal:block>
726
727- <tal:block condition="view/translation_groups">
728-
729+ <div tal:condition="view/translation_groups" class="portlet">
730 <h2>Translation Groups</h2>
731-
732 <span tal:replace="context/displayname">Mark Shuttleworth</span> is
733 a member of the following translation groups:
734
735- <table class="listing"
736- id="translation-group-memberships"
737- style="max-width:800px">
738+ <table class="listing" id="translation-group-memberships">
739 <thead>
740 <tr>
741 <th>Translation group</th>
742@@ -158,9 +134,7 @@
743 </tr>
744 </tbody>
745 </table>
746-
747- </tal:block>
748-
749+ </div>
750 </div>
751 </body>
752 </html>