Merge lp:~jtv/launchpad/bug-423705 into lp:launchpad
- bug-423705
- Merge into devel
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Nelson (community) | ui | Approve | |
Abel Deuring (community) | Approve | ||
Review via email: mp+11519@code.launchpad.net |
Commit message
Description of the change
Jeroen T. Vermeulen (jtv) wrote : | # |
Abel Deuring (adeuring) wrote : | # |
Hi Jeroen,
a very nice branch. We discussed two minor changes in IRC, please apply them
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:/
<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:/
<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?)
Preview Diff
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> |
= 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: /launchpad/ pagetitles. py /launchpad/ webapp/ configure. zcml /launchpad/ webapp/ tales.py translations/ browser/ configure. zcml translations/ browser/ person. py translations/ stories/ standalone/ xx-person- activity. txt translations/ templates/ person- navlinks. pt translations/ templates/ person- translation- activity. pt translations/ templates/ person- translations- to-complete- table.pt translations/ templates/ person- translations- to-review- table.pt translations/ templates/ person- translations. pt
lib/canonical
lib/canonical
lib/canonical
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
=== 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