Merge lp:~henninge/launchpad/bug-488765-oops-translations into lp:launchpad
- bug-488765-oops-translations
- Merge into devel
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Henning Eggers | ||||||||
Approved revision: | not available | ||||||||
Merged at revision: | not available | ||||||||
Proposed branch: | lp:~henninge/launchpad/bug-488765-oops-translations | ||||||||
Merge into: | lp:launchpad | ||||||||
Diff against target: |
236 lines (+88/-51) 4 files modified
lib/lp/translations/browser/product.py (+22/-25) lib/lp/translations/browser/tests/test_product_view.py (+2/-1) lib/lp/translations/stories/standalone/xx-product-translations.txt (+54/-15) lib/lp/translations/templates/product-translations.pt (+10/-10) |
||||||||
To merge this branch: | bzr merge lp:~henninge/launchpad/bug-488765-oops-translations | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guilherme Salgado (community) | code | Approve | |
Canonical Launchpad Engineering | code | Pending | |
Review via email: mp+17396@code.launchpad.net |
Commit message
Fixed Product:
Description of the change
Henning Eggers (henninge) wrote : | # |
Guilherme Salgado (salgado) wrote : | # |
Hi Henning,
I have just a few suggestions to improve this branch a bit.
review needs-fixing
On Thu, 2010-01-14 at 17:22 +0000, Henning Eggers wrote:
> = Bug 488765 =
>
> A product has an attribute primary_
> product series or source package that should be translated. Returning
> source packages here seems to be a newer feature that broke a
> product's +translations page if the primary_
> package because the template assumed it's a product series.
>
> == Proposed fx ==
>
> I filed bug 507534 about that behaviour and fixed the page by
> filtering out source packages in the view so that only product series
> are displayed by the template.
>
> I also discovered that bug 371632 can be fixed with this.
>
> == Implementation details ==
>
> lib/lp/
>
> * The view already had a property "primary_
> obviously unused and returned a dictionary. I re-used it to return the
> primary_
> series.
>
> lib/lp/
>
> * The part that only checked for up/download links was expanded to
> check for the whole recommendation section. This way it can be tested
> for complete absence if no primary_
>
> * This test did reproducce the error because evolution is linked to a
> translatable source package in the sample data, so
> Product.
> templates in the product series have been disabled.
>
> * Disabling all the templates is a bit of noise but needed to
> reproduce the error.
>
> * Appended a test to show the notice when no translations are
> available.
>
> lib/lp/
>
> * Use view/primary_
>
> * Changed some ids and classes needed for testing.
>
> * Added notice for when no translations are available.
>
> * Changed conditions so that page is never empty.
>
>
> == Test ==
>
> bin/test -vvct product-
>
> == Demo/QA ==
>
> On launchpad.dev:
> 1. Disable all templates for evolution trunk.
> 2. Got to https:/
> 3. You should not get an oops but a notice that there are no
> translations for this project.
>
> To reproduce on staging you'll need a project that is linked to a
> source pacakage with translations.
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -89,28 +89,14 @@
>
> @cachedproperty
> def primary_
> - """Return a dictionary with the info for a primary translatable.
> -
> - If there is no primary translatable object, returns an empty
> - dictionary.
> -
> - The dictionary has the keys:
> - * 'title': The title of the translatable object.
> - * 'potemplates': a set of PO Templates for this object.
> - * 'base_url': The base URL to reach the base URL for this object.
...
Henning Eggers (henninge) wrote : | # |
Am 15.01.2010 13:06, Guilherme Salgado schrieb:
> Review: Needs Fixing
> Hi Henning,
>
> I have just a few suggestions to improve this branch a bit.
Cool, thanks for doing the review.
>> === modified file 'lib/lp/
>> + if not isinstance(
>
> You can use zope.security.
> remove the security proxy.
Cool, I didn't know about this.
>
> Actually, you should use IProductSeries.
> would allow you to not import ProductSeries here, as that must not be
> done. I wonder why the import fascist doesn't emit a warning about this
> import...
Yes, you are right on both accounts. I changed it to use providedBy.
>> === modified file 'lib/lp/
>> +A series is not translatable if all templates are disabled. We need to jump
>> +through some hoops to create that situation.
>> +
>> + >>> login('<email address hidden>')
>> + >>> from zope.component import getUtility
>> + >>> from lp.registry.
>> + >>> evotrunk = getUtility(
>> + ... 'evolution'
>> + >>> from lp.translations
>> + >>> potemplates = getUtility(
>> + ... productseries=
>> + >>> for potemplate in potemplates:
>> + ... potemplate.
>> + >>> logout()
>> + >>> admin_browser.
>> + >>> print find_translatio
>> + None
>
> I think it'd be nice to show here that the product has a translatable
> source package and explain that is only in that case that we don't show
> recommendations. It's also important to do that because the test
> assumes there's a translatable source package associated to evolution
> (as you described in the cover letter), but the test itself doesn't make
> it clear nor does it assert that.
Ah, that is not quite right. We don't show the recommendation even if
there is source package because atm we cannot treat a source package
like a product series in this respect. That will have to be fixed in
another branch (bug 507534).
I added a test that shows that the series has translatable source
package. This situation is what triggered the oops that this branch is
fixing but the display of recommendations is independent of a
translatable source package.
>
>> +
>> +Instead a notice is displayed that the product has no translations.
>> +
>> + >>> notice = first_tag_
>> + >>> print extract_
>> + There are no translations for this project.
>>
>
>> === modified file 'lib/lp/
>> --- lib/lp/
>> +++ lib/lp/
>> @@ -14,7 +14,7 @@
>> </div>
>>
>> <div metal:fill-
>> - tal:define=
1 | === modified file 'lib/lp/translations/browser/product.py' | |||
2 | --- lib/lp/translations/browser/product.py 2010-01-15 07:39:43 +0000 | |||
3 | +++ lib/lp/translations/browser/product.py 2010-01-15 14:37:06 +0000 | |||
4 | @@ -11,14 +11,12 @@ | |||
5 | 11 | 'ProductView', | 11 | 'ProductView', |
6 | 12 | ] | 12 | ] |
7 | 13 | 13 | ||
8 | 14 | from zope.security.proxy import removeSecurityProxy | ||
9 | 15 | |||
10 | 16 | from canonical.cachedproperty import cachedproperty | 14 | from canonical.cachedproperty import cachedproperty |
11 | 17 | from canonical.launchpad.webapp import ( | 15 | from canonical.launchpad.webapp import ( |
12 | 18 | LaunchpadView, Link, canonical_url, enabled_with_permission) | 16 | LaunchpadView, Link, canonical_url, enabled_with_permission) |
13 | 17 | from canonical.launchpad.webapp.authorization import check_permission | ||
14 | 19 | from canonical.launchpad.webapp.menu import NavigationMenu | 18 | from canonical.launchpad.webapp.menu import NavigationMenu |
17 | 20 | from lp.registry.interfaces.product import IProduct | 19 | from lp.registry.interfaces.product import IProduct, IProductSeries |
16 | 21 | from lp.registry.model.productseries import ProductSeries | ||
18 | 22 | from lp.registry.browser.product import ProductEditView | 20 | from lp.registry.browser.product import ProductEditView |
19 | 23 | from lp.translations.browser.translations import TranslationsMixin | 21 | from lp.translations.browser.translations import TranslationsMixin |
20 | 24 | 22 | ||
21 | @@ -85,7 +83,20 @@ | |||
22 | 85 | @cachedproperty | 83 | @cachedproperty |
23 | 86 | def uses_translations(self): | 84 | def uses_translations(self): |
24 | 87 | """Whether this product has translatable templates.""" | 85 | """Whether this product has translatable templates.""" |
26 | 88 | return (self.context.official_rosetta and self.primary_translatable) | 86 | return (self.context.official_rosetta and |
27 | 87 | self.primary_translatable is not None) | ||
28 | 88 | |||
29 | 89 | @cachedproperty | ||
30 | 90 | def no_translations_available(self): | ||
31 | 91 | """Has no translation templates but does support translations.""" | ||
32 | 92 | return (self.context.official_rosetta and | ||
33 | 93 | self.primary_translatable is None) | ||
34 | 94 | |||
35 | 95 | @cachedproperty | ||
36 | 96 | def show_page_content(self): | ||
37 | 97 | """Whether the main content of the page should be shown.""" | ||
38 | 98 | return (self.context.official_rosetta or | ||
39 | 99 | check_permission("launchpad.TranslationsAdmin", self.context)) | ||
40 | 89 | 100 | ||
41 | 90 | @cachedproperty | 101 | @cachedproperty |
42 | 91 | def primary_translatable(self): | 102 | def primary_translatable(self): |
43 | @@ -93,7 +104,7 @@ | |||
44 | 93 | """ | 104 | """ |
45 | 94 | translatable = self.context.primary_translatable | 105 | translatable = self.context.primary_translatable |
46 | 95 | 106 | ||
48 | 96 | if not isinstance(removeSecurityProxy(translatable), ProductSeries): | 107 | if not IProductSeries.providedBy(translatable): |
49 | 97 | return None | 108 | return None |
50 | 98 | 109 | ||
51 | 99 | return translatable | 110 | return translatable |
52 | 100 | 111 | ||
53 | === modified file 'lib/lp/translations/stories/standalone/xx-product-translations.txt' | |||
54 | --- lib/lp/translations/stories/standalone/xx-product-translations.txt 2010-01-14 17:03:56 +0000 | |||
55 | +++ lib/lp/translations/stories/standalone/xx-product-translations.txt 2010-01-15 13:56:37 +0000 | |||
56 | @@ -222,6 +222,15 @@ | |||
57 | 222 | >>> print find_translation_recommendation(admin_browser) | 222 | >>> print find_translation_recommendation(admin_browser) |
58 | 223 | None | 223 | None |
59 | 224 | 224 | ||
60 | 225 | At the moment, translatable source packages are not recommended, although | ||
61 | 226 | the product is linked to one. | ||
62 | 227 | |||
63 | 228 | >>> source_package = find_tag_by_id( | ||
64 | 229 | ... admin_browser.contents, 'portlet-translatable-packages') | ||
65 | 230 | >>> print extract_text(source_package) | ||
66 | 231 | All translatable distribution packages | ||
67 | 232 | “evolution” source package in Hoary | ||
68 | 233 | |||
69 | 225 | Instead a notice is displayed that the product has no translations. | 234 | Instead a notice is displayed that the product has no translations. |
70 | 226 | 235 | ||
71 | 227 | >>> notice = first_tag_by_class(admin_browser.contents, 'notice') | 236 | >>> notice = first_tag_by_class(admin_browser.contents, 'notice') |
72 | 228 | 237 | ||
73 | === modified file 'lib/lp/translations/templates/product-translations.pt' | |||
74 | --- lib/lp/translations/templates/product-translations.pt 2010-01-15 07:39:43 +0000 | |||
75 | +++ lib/lp/translations/templates/product-translations.pt 2010-01-15 14:39:59 +0000 | |||
76 | @@ -14,8 +14,7 @@ | |||
77 | 14 | </div> | 14 | </div> |
78 | 15 | 15 | ||
79 | 16 | <div metal:fill-slot="main" | 16 | <div metal:fill-slot="main" |
82 | 17 | tal:define="official_rosetta context/official_rosetta; | 17 | tal:define="admin_user context/required:launchpad.TranslationsAdmin"> |
81 | 18 | admin_user context/required:launchpad.TranslationsAdmin"> | ||
83 | 19 | <div class="translation-help-links"> | 18 | <div class="translation-help-links"> |
84 | 20 | <a href="https://help.launchpad.net/Translations" | 19 | <a href="https://help.launchpad.net/Translations" |
85 | 21 | id="link-to-translations-help" | 20 | id="link-to-translations-help" |
86 | @@ -27,13 +26,12 @@ | |||
87 | 27 | <tal:official_use replace=" | 26 | <tal:official_use replace=" |
88 | 28 | structure | 27 | structure |
89 | 29 | context/@@+portlet-not-using-launchpad"/> | 28 | context/@@+portlet-not-using-launchpad"/> |
91 | 30 | <div tal:condition="python:not view.uses_translations and official_rosetta"> | 29 | <div tal:condition="view/no_translations_available"> |
92 | 31 | There are no translations for this project. | 30 | There are no translations for this project. |
93 | 32 | </div> | 31 | </div> |
94 | 33 | </div> | 32 | </div> |
95 | 34 | 33 | ||
98 | 35 | <tal:uses-translations | 34 | <tal:page_content condition="view/show_page_content"> |
97 | 36 | condition="python:official_rosetta or admin_user"> | ||
99 | 37 | <tal:translatable define="target view/primary_translatable"> | 35 | <tal:translatable define="target view/primary_translatable"> |
100 | 38 | 36 | ||
101 | 39 | <div class="yui-g"> | 37 | <div class="yui-g"> |
102 | @@ -100,7 +98,7 @@ | |||
103 | 100 | <div tal:replace="structure context/@@+rosetta-status-legend" /> | 98 | <div tal:replace="structure context/@@+rosetta-status-legend" /> |
104 | 101 | </div> | 99 | </div> |
105 | 102 | </tal:translatable> | 100 | </tal:translatable> |
107 | 103 | </tal:uses-translations> | 101 | </tal:page_content> |
108 | 104 | </div> | 102 | </div> |
109 | 105 | </body> | 103 | </body> |
110 | 106 | </html> | 104 | </html> |
Guilherme Salgado (salgado) : | # |
Preview Diff
1 | === modified file 'lib/lp/translations/browser/product.py' | |||
2 | --- lib/lp/translations/browser/product.py 2009-10-26 18:40:04 +0000 | |||
3 | +++ lib/lp/translations/browser/product.py 2010-01-16 08:51:16 +0000 | |||
4 | @@ -11,14 +11,12 @@ | |||
5 | 11 | 'ProductView', | 11 | 'ProductView', |
6 | 12 | ] | 12 | ] |
7 | 13 | 13 | ||
8 | 14 | from zope.security.proxy import removeSecurityProxy | ||
9 | 15 | |||
10 | 16 | from canonical.cachedproperty import cachedproperty | 14 | from canonical.cachedproperty import cachedproperty |
11 | 17 | from canonical.launchpad.webapp import ( | 15 | from canonical.launchpad.webapp import ( |
12 | 18 | LaunchpadView, Link, canonical_url, enabled_with_permission) | 16 | LaunchpadView, Link, canonical_url, enabled_with_permission) |
13 | 17 | from canonical.launchpad.webapp.authorization import check_permission | ||
14 | 19 | from canonical.launchpad.webapp.menu import NavigationMenu | 18 | from canonical.launchpad.webapp.menu import NavigationMenu |
17 | 20 | from lp.registry.interfaces.product import IProduct | 19 | from lp.registry.interfaces.product import IProduct, IProductSeries |
16 | 21 | from lp.registry.model.productseries import ProductSeries | ||
18 | 22 | from lp.registry.browser.product import ProductEditView | 20 | from lp.registry.browser.product import ProductEditView |
19 | 23 | from lp.translations.browser.translations import TranslationsMixin | 21 | from lp.translations.browser.translations import TranslationsMixin |
20 | 24 | 22 | ||
21 | @@ -85,32 +83,31 @@ | |||
22 | 85 | @cachedproperty | 83 | @cachedproperty |
23 | 86 | def uses_translations(self): | 84 | def uses_translations(self): |
24 | 87 | """Whether this product has translatable templates.""" | 85 | """Whether this product has translatable templates.""" |
26 | 88 | return (self.context.official_rosetta and self.primary_translatable) | 86 | return (self.context.official_rosetta and |
27 | 87 | self.primary_translatable is not None) | ||
28 | 88 | |||
29 | 89 | @cachedproperty | ||
30 | 90 | def no_translations_available(self): | ||
31 | 91 | """Has no translation templates but does support translations.""" | ||
32 | 92 | return (self.context.official_rosetta and | ||
33 | 93 | self.primary_translatable is None) | ||
34 | 94 | |||
35 | 95 | @cachedproperty | ||
36 | 96 | def show_page_content(self): | ||
37 | 97 | """Whether the main content of the page should be shown.""" | ||
38 | 98 | return (self.context.official_rosetta or | ||
39 | 99 | check_permission("launchpad.TranslationsAdmin", self.context)) | ||
40 | 89 | 100 | ||
41 | 90 | @cachedproperty | 101 | @cachedproperty |
42 | 91 | def primary_translatable(self): | 102 | def primary_translatable(self): |
52 | 92 | """Return a dictionary with the info for a primary translatable. | 103 | """Return the context's primary translatable if it's a product series. |
44 | 93 | |||
45 | 94 | If there is no primary translatable object, returns an empty | ||
46 | 95 | dictionary. | ||
47 | 96 | |||
48 | 97 | The dictionary has the keys: | ||
49 | 98 | * 'title': The title of the translatable object. | ||
50 | 99 | * 'potemplates': a set of PO Templates for this object. | ||
51 | 100 | * 'base_url': The base URL to reach the base URL for this object. | ||
53 | 101 | """ | 104 | """ |
54 | 102 | translatable = self.context.primary_translatable | 105 | translatable = self.context.primary_translatable |
66 | 103 | naked_translatable = removeSecurityProxy(translatable) | 106 | |
67 | 104 | 107 | if not IProductSeries.providedBy(translatable): | |
68 | 105 | if (translatable is None or | 108 | return None |
69 | 106 | not isinstance(naked_translatable, ProductSeries)): | 109 | |
70 | 107 | return {} | 110 | return translatable |
60 | 108 | |||
61 | 109 | return { | ||
62 | 110 | 'title': translatable.title, | ||
63 | 111 | 'potemplates': translatable.getCurrentTranslationTemplates(), | ||
64 | 112 | 'base_url': canonical_url(translatable) | ||
65 | 113 | } | ||
71 | 114 | 111 | ||
72 | 115 | @cachedproperty | 112 | @cachedproperty |
73 | 116 | def untranslatable_series(self): | 113 | def untranslatable_series(self): |
74 | 117 | 114 | ||
75 | === modified file 'lib/lp/translations/browser/tests/test_product_view.py' | |||
76 | --- lib/lp/translations/browser/tests/test_product_view.py 2009-07-17 02:25:09 +0000 | |||
77 | +++ lib/lp/translations/browser/tests/test_product_view.py 2010-01-16 08:51:16 +0000 | |||
78 | @@ -36,7 +36,8 @@ | |||
79 | 36 | pot = self.factory.makePOTemplate( | 36 | pot = self.factory.makePOTemplate( |
80 | 37 | distroseries=sourcepackage.distroseries, | 37 | distroseries=sourcepackage.distroseries, |
81 | 38 | sourcepackagename=sourcepackage.sourcepackagename) | 38 | sourcepackagename=sourcepackage.sourcepackagename) |
83 | 39 | self.assertEquals(self.view.primary_translatable, {}) | 39 | self.assertEquals(None, self.view.primary_translatable) |
84 | 40 | 40 | ||
85 | 41 | def test_suite(): | 41 | def test_suite(): |
86 | 42 | return unittest.TestLoader().loadTestsFromName(__name__) | 42 | return unittest.TestLoader().loadTestsFromName(__name__) |
87 | 43 | |||
88 | 43 | 44 | ||
89 | === modified file 'lib/lp/translations/stories/standalone/xx-product-translations.txt' | |||
90 | --- lib/lp/translations/stories/standalone/xx-product-translations.txt 2009-11-01 20:18:32 +0000 | |||
91 | +++ lib/lp/translations/stories/standalone/xx-product-translations.txt 2010-01-16 08:51:16 +0000 | |||
92 | @@ -168,32 +168,71 @@ | |||
93 | 168 | Language Untranslated Unreviewed Changed | 168 | Language Untranslated Unreviewed Changed |
94 | 169 | 169 | ||
95 | 170 | 170 | ||
103 | 171 | == Download and upload links == | 171 | == Translation recommendation == |
104 | 172 | 172 | ||
105 | 173 | A logged-in user is invited to download translations. | 173 | The page mentions which product series should be translated. |
106 | 174 | 174 | ||
107 | 175 | >>> def find_download_upload_invitation(browser): | 175 | >>> def find_translation_recommendation(browser): |
108 | 176 | ... """Find the text inviting the user to upload or download.""" | 176 | ... """Find the text recommending to translate.""" |
109 | 177 | ... tag = find_tag_by_id(browser.contents, 'downloadupload') | 177 | ... tag = find_tag_by_id( |
110 | 178 | ... browser.contents, 'translation-recommendation') | ||
111 | 178 | ... if tag is None: | 179 | ... if tag is None: |
112 | 179 | ... return None | 180 | ... return None |
113 | 180 | ... return extract_text(tag.renderContents()) | 181 | ... return extract_text(tag.renderContents()) |
114 | 181 | 182 | ||
115 | 182 | >>> product_url = 'http://translations.launchpad.dev/evolution' | 183 | >>> product_url = 'http://translations.launchpad.dev/evolution' |
116 | 183 | 184 | ||
117 | 185 | That's all an anonymous user will see. | ||
118 | 186 | |||
119 | 187 | >>> anon_browser.open(product_url) | ||
120 | 188 | >>> print find_translation_recommendation(anon_browser) | ||
121 | 189 | Launchpad currently recommends translating Evolution trunk series. | ||
122 | 190 | |||
123 | 191 | A logged-in user is also invited to download translations. | ||
124 | 192 | |||
125 | 184 | >>> user_browser.open(product_url) | 193 | >>> user_browser.open(product_url) |
127 | 185 | >>> print find_download_upload_invitation(user_browser) | 194 | >>> print find_translation_recommendation(user_browser) |
128 | 195 | Launchpad currently recommends translating Evolution trunk series. | ||
129 | 186 | You can also download translations for trunk. | 196 | You can also download translations for trunk. |
130 | 187 | 197 | ||
131 | 188 | An anonymous user does not see this invitation. | ||
132 | 189 | |||
133 | 190 | >>> anon_browser.open(product_url) | ||
134 | 191 | >>> print find_download_upload_invitation(anon_browser) | ||
135 | 192 | None | ||
136 | 193 | |||
137 | 194 | A user with upload rights sees the invitation not just to download but | 198 | A user with upload rights sees the invitation not just to download but |
138 | 195 | to upload as well. | 199 | to upload as well. |
139 | 196 | 200 | ||
140 | 197 | >>> admin_browser.open(product_url) | 201 | >>> admin_browser.open(product_url) |
142 | 198 | >>> print find_download_upload_invitation(admin_browser) | 202 | >>> print find_translation_recommendation(admin_browser) |
143 | 203 | Launchpad currently recommends translating Evolution trunk series. | ||
144 | 199 | You can also download or upload translations for trunk. | 204 | You can also download or upload translations for trunk. |
145 | 205 | |||
146 | 206 | If there is no translatable series, no such recommendation is displayed. | ||
147 | 207 | A series is not translatable if all templates are disabled. We need to jump | ||
148 | 208 | through some hoops to create that situation. | ||
149 | 209 | |||
150 | 210 | >>> login('foo.bar@canonical.com') | ||
151 | 211 | >>> from zope.component import getUtility | ||
152 | 212 | >>> from lp.registry.interfaces.product import IProductSet | ||
153 | 213 | >>> evotrunk = getUtility(IProductSet).getByName( | ||
154 | 214 | ... 'evolution').getSeries('trunk') | ||
155 | 215 | >>> from lp.translations.interfaces.potemplate import IPOTemplateSet | ||
156 | 216 | >>> potemplates = getUtility(IPOTemplateSet).getSubset( | ||
157 | 217 | ... productseries=evotrunk, iscurrent=True) | ||
158 | 218 | >>> for potemplate in potemplates: | ||
159 | 219 | ... potemplate.iscurrent = False | ||
160 | 220 | >>> logout() | ||
161 | 221 | >>> admin_browser.open(product_url) | ||
162 | 222 | >>> print find_translation_recommendation(admin_browser) | ||
163 | 223 | None | ||
164 | 224 | |||
165 | 225 | At the moment, translatable source packages are not recommended, although | ||
166 | 226 | the product is linked to one. | ||
167 | 227 | |||
168 | 228 | >>> source_package = find_tag_by_id( | ||
169 | 229 | ... admin_browser.contents, 'portlet-translatable-packages') | ||
170 | 230 | >>> print extract_text(source_package) | ||
171 | 231 | All translatable distribution packages | ||
172 | 232 | “evolution” source package in Hoary | ||
173 | 233 | |||
174 | 234 | Instead a notice is displayed that the product has no translations. | ||
175 | 235 | |||
176 | 236 | >>> notice = first_tag_by_class(admin_browser.contents, 'notice') | ||
177 | 237 | >>> print extract_text(notice) | ||
178 | 238 | There are no translations for this project. | ||
179 | 200 | 239 | ||
180 | === modified file 'lib/lp/translations/templates/product-translations.pt' | |||
181 | --- lib/lp/translations/templates/product-translations.pt 2009-12-16 15:21:36 +0000 | |||
182 | +++ lib/lp/translations/templates/product-translations.pt 2010-01-16 08:51:16 +0000 | |||
183 | @@ -14,8 +14,7 @@ | |||
184 | 14 | </div> | 14 | </div> |
185 | 15 | 15 | ||
186 | 16 | <div metal:fill-slot="main" | 16 | <div metal:fill-slot="main" |
189 | 17 | tal:define="uses_translations view/uses_translations; | 17 | tal:define="admin_user context/required:launchpad.TranslationsAdmin"> |
188 | 18 | admin_user context/required:launchpad.TranslationsAdmin"> | ||
190 | 19 | <div class="translation-help-links"> | 18 | <div class="translation-help-links"> |
191 | 20 | <a href="https://help.launchpad.net/Translations" | 19 | <a href="https://help.launchpad.net/Translations" |
192 | 21 | id="link-to-translations-help" | 20 | id="link-to-translations-help" |
193 | @@ -23,26 +22,27 @@ | |||
194 | 23 | </a> | 22 | </a> |
195 | 24 | <div></div><!-- to clear-up all floats --> | 23 | <div></div><!-- to clear-up all floats --> |
196 | 25 | </div> | 24 | </div> |
198 | 26 | <div class="top-portlet"> | 25 | <div class="top-portlet notice"> |
199 | 27 | <tal:official_use replace=" | 26 | <tal:official_use replace=" |
200 | 28 | structure | 27 | structure |
201 | 29 | context/@@+portlet-not-using-launchpad"/> | 28 | context/@@+portlet-not-using-launchpad"/> |
202 | 29 | <div tal:condition="view/no_translations_available"> | ||
203 | 30 | There are no translations for this project. | ||
204 | 31 | </div> | ||
205 | 30 | </div> | 32 | </div> |
206 | 31 | 33 | ||
210 | 32 | <tal:uses-translations | 34 | <tal:page_content condition="view/show_page_content"> |
211 | 33 | condition="python:uses_translations or admin_user"> | 35 | <tal:translatable define="target view/primary_translatable"> |
209 | 34 | <tal:translatable define="target context/primary_translatable"> | ||
212 | 35 | 36 | ||
213 | 36 | <div class="yui-g"> | 37 | <div class="yui-g"> |
214 | 37 | <div class="yui-u first"> | 38 | <div class="yui-u first"> |
215 | 38 | <div class="portlet"> | 39 | <div class="portlet"> |
216 | 39 | <h3>Translation details</h3> | 40 | <h3>Translation details</h3> |
218 | 40 | <p tal:condition="target"> | 41 | <p tal:condition="target" id="translation-recommendation"> |
219 | 41 | Launchpad currently recommends translating | 42 | Launchpad currently recommends translating |
220 | 42 | <tal:target replace="structure target/fmt:link" | 43 | <tal:target replace="structure target/fmt:link" |
221 | 43 | >trunk</tal:target>. | 44 | >trunk</tal:target>. |
224 | 44 | <span id="downloadupload" | 45 | <span tal:condition="context/required:launchpad.AnyPerson"> |
223 | 45 | tal:condition="context/required:launchpad.AnyPerson"> | ||
225 | 46 | You can also | 46 | You can also |
226 | 47 | <a tal:attributes="href target/fmt:url/+export" | 47 | <a tal:attributes="href target/fmt:url/+export" |
227 | 48 | >download</a> | 48 | >download</a> |
228 | @@ -98,7 +98,7 @@ | |||
229 | 98 | <div tal:replace="structure context/@@+rosetta-status-legend" /> | 98 | <div tal:replace="structure context/@@+rosetta-status-legend" /> |
230 | 99 | </div> | 99 | </div> |
231 | 100 | </tal:translatable> | 100 | </tal:translatable> |
233 | 101 | </tal:uses-translations> | 101 | </tal:page_content> |
234 | 102 | </div> | 102 | </div> |
235 | 103 | </body> | 103 | </body> |
236 | 104 | </html> | 104 | </html> |
= Bug 488765 =
A product has an attribute primary_ translatable that returns the product series or source package that should be translated. Returning source packages here seems to be a newer feature that broke a product's +translations page if the primary_ translatable was a source package because the template assumed it's a product series.
== Proposed fx ==
I filed bug 507534 about that behaviour and fixed the page by filtering out source packages in the view so that only product series are displayed by the template.
I also discovered that bug 371632 can be fixed with this.
== Implementation details ==
lib/lp/ translations/ browser/ product. py
* The view already had a property "primary_ translatable" that was obviously unused and returned a dictionary. I re-used it to return the primary_ translatable of the context or None if it is not a product series.
lib/lp/ translations/ stories/ standalone/ xx-product- translations. txt
* The part that only checked for up/download links was expanded to check for the whole recommendation section. This way it can be tested for complete absence if no primary_ translatable is available.
* This test did reproducce the error because evolution is linked to a translatable source package in the sample data, so Product. primary_ translatable returns a source package when all templates in the product series have been disabled.
* Disabling all the templates is a bit of noise but needed to reproduce the error.
* Appended a test to show the notice when no translations are available.
lib/lp/ translations/ templates/ product- translations. pt
* Use view/primary_ translatable instead of context's.
* Changed some ids and classes needed for testing.
* Added notice for when no translations are available.
* Changed conditions so that page is never empty.
== Test ==
bin/test -vvct product- translations
== Demo/QA ==
On launchpad.dev: /translations. launchpad. dev/evolution
1. Disable all templates for evolution trunk.
2. Got to https:/
3. You should not get an oops but a notice that there are no translations for this project.
To reproduce on staging you'll need a project that is linked to a source pacakage with translations.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: translations/ browser/ product. py translations/ stories/ standalone/ xx-product- translations. txt translations/ templates/ product- translations. pt
lib/lp/
lib/lp/
lib/lp/