Merge lp:~jcsackett/launchpad/deprecate-official_rosetta into lp:launchpad
- deprecate-official_rosetta
- Merge into devel
Status: | Merged |
---|---|
Approved by: | j.c.sackett |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11520 |
Proposed branch: | lp:~jcsackett/launchpad/deprecate-official_rosetta |
Merge into: | lp:launchpad |
Diff against target: |
3172 lines (+649/-426) 51 files modified
lib/lp/app/enums.py (+6/-1) lib/lp/registry/browser/distribution.py (+2/-1) lib/lp/registry/browser/pillar.py (+11/-8) lib/lp/registry/browser/tests/pillar-views.txt (+4/-3) lib/lp/registry/browser/tests/productseries-views.txt (+6/-4) lib/lp/registry/doc/distribution.txt (+125/-114) lib/lp/registry/doc/product.txt (+62/-44) lib/lp/registry/doc/project.txt (+24/-15) lib/lp/registry/model/projectgroup.py (+4/-1) lib/lp/testing/factory.py (+7/-4) lib/lp/translations/browser/potemplate.py (+4/-2) lib/lp/translations/browser/product.py (+11/-8) lib/lp/translations/browser/tests/language-views.txt (+4/-1) lib/lp/translations/browser/tests/test_breadcrumbs.py (+3/-2) lib/lp/translations/doc/potmsgset.txt (+59/-33) lib/lp/translations/doc/translationimportqueue.txt (+54/-25) lib/lp/translations/doc/translationmessage-destroy.txt (+10/-5) lib/lp/translations/doc/translations-export-to-branch.txt (+10/-6) lib/lp/translations/doc/translationsoverview.txt (+14/-6) lib/lp/translations/model/potemplate.py (+11/-10) lib/lp/translations/model/potmsgset.py (+8/-7) lib/lp/translations/model/translationsoverview.py (+6/-3) lib/lp/translations/model/translationsperson.py (+4/-0) lib/lp/translations/scripts/translations_to_branch.py (+3/-0) lib/lp/translations/stories/buildfarm/xx-build-summary.txt (+8/-4) lib/lp/translations/stories/importqueue/xx-entry-details.txt (+9/-5) lib/lp/translations/stories/productseries/xx-productseries-export-to-branch.txt (+9/-6) lib/lp/translations/stories/productseries/xx-productseries-translations.txt (+5/-3) lib/lp/translations/stories/standalone/custom-language-codes.txt (+5/-3) lib/lp/translations/stories/standalone/xx-potemplate-index.txt (+28/-12) lib/lp/translations/stories/standalone/xx-product-export.txt (+9/-5) lib/lp/translations/stories/standalone/xx-product-translations.txt (+0/-1) lib/lp/translations/stories/standalone/xx-template-description-escaping.txt (+3/-1) lib/lp/translations/stories/translationfocus/xx-product-translationfocus.txt (+5/-3) lib/lp/translations/stories/translationgroups/xx-change-translation-policy.txt (+5/-1) lib/lp/translations/templates/product-portlet-not-using-launchpad.pt (+1/-1) lib/lp/translations/templates/productseries-translations.pt (+1/-1) lib/lp/translations/tests/test_autoapproval.py (+9/-8) lib/lp/translations/tests/test_empty_messages.py (+13/-11) lib/lp/translations/tests/test_hastranslationtemplates.py (+5/-4) lib/lp/translations/tests/test_pofile.py (+17/-14) lib/lp/translations/tests/test_potemplate.py (+3/-2) lib/lp/translations/tests/test_potmsgset.py (+11/-8) lib/lp/translations/tests/test_productserieslanguage.py (+9/-4) lib/lp/translations/tests/test_shared_potemplate.py (+3/-2) lib/lp/translations/tests/test_suggestions.py (+10/-4) lib/lp/translations/tests/test_translatablemessage.py (+9/-7) lib/lp/translations/tests/test_translatedlanguage.py (+5/-2) lib/lp/translations/tests/test_translations_to_review.py (+6/-3) lib/lp/translations/windmill/tests/test_documentation_links.py (+2/-1) lib/lp/translations/windmill/tests/test_import_queue.py (+7/-7) |
To merge this branch: | bzr merge lp:~jcsackett/launchpad/deprecate-official_rosetta |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Leonard Richardson (community) | Approve | ||
Review via email: mp+34229@code.launchpad.net |
Commit message
Replaces use of official_rosetta with translations_usage where possible, so the richer data provided by the enum can be used to drive decisions.
Description of the change
= Summary =
Replaces, where possible, usage of official_rosetta with the translations_usage property.
== Proposed fix ==
Where code uses official_rosetta, use translations_usage instead so that we can take advantage of richer data.
== Pre-implementation notes ==
Spoke with Curtis Hovey (sinzui) and Brad Crittenden (bac).
== Implementation details ==
As in Proposed fix.
SQL queries using official_rosetta have been left alone until data migration occurs.
== Tests ==
No new tests written.
To fully test the refactor:
bin/test -m lib.lp.registry
bin/test -m lib.lp.translations
== Demo and Q/A ==
In Launchpad.dev, nothing should crash when reviewing translations or performing translation related actions.
= Launchpad lint =
This touched enough old files that the lint output is huge. I will fix all valid lint errors before committing, but I didn't want to pollute the diff too much nor make this MP a wall of text.
Preview Diff
1 | === modified file 'lib/lp/app/enums.py' | |||
2 | --- lib/lp/app/enums.py 2010-08-20 20:31:18 +0000 | |||
3 | +++ lib/lp/app/enums.py 2010-09-09 15:34:46 +0000 | |||
4 | @@ -1,11 +1,12 @@ | |||
5 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
6 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
7 | 3 | 3 | ||
9 | 4 | """Enumerations used in the lp/app modules.""" | 4 | """Enumerations and related utilities used in the lp/app modules.""" |
10 | 5 | 5 | ||
11 | 6 | __metaclass__ = type | 6 | __metaclass__ = type |
12 | 7 | __all__ = [ | 7 | __all__ = [ |
13 | 8 | 'ServiceUsage', | 8 | 'ServiceUsage', |
14 | 9 | 'service_uses_launchpad', | ||
15 | 9 | ] | 10 | ] |
16 | 10 | 11 | ||
17 | 11 | from lazr.enum import ( | 12 | from lazr.enum import ( |
18 | @@ -45,3 +46,7 @@ | |||
19 | 45 | 46 | ||
20 | 46 | The pillar does not use this type of service in Launchpad or externally. | 47 | The pillar does not use this type of service in Launchpad or externally. |
21 | 47 | """) | 48 | """) |
22 | 49 | |||
23 | 50 | |||
24 | 51 | def service_uses_launchpad(usage_enum): | ||
25 | 52 | return usage_enum == ServiceUsage.LAUNCHPAD | ||
26 | 48 | 53 | ||
27 | === modified file 'lib/lp/registry/browser/distribution.py' | |||
28 | --- lib/lp/registry/browser/distribution.py 2010-09-03 03:12:39 +0000 | |||
29 | +++ lib/lp/registry/browser/distribution.py 2010-09-09 15:34:46 +0000 | |||
30 | @@ -74,6 +74,7 @@ | |||
31 | 74 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb | 74 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
32 | 75 | from canonical.launchpad.webapp.interfaces import ILaunchBag | 75 | from canonical.launchpad.webapp.interfaces import ILaunchBag |
33 | 76 | from canonical.widgets.image import ImageChangeWidget | 76 | from canonical.widgets.image import ImageChangeWidget |
34 | 77 | from lp.app.enums import service_uses_launchpad | ||
35 | 77 | from lp.answers.browser.faqtarget import FAQTargetNavigationMixin | 78 | from lp.answers.browser.faqtarget import FAQTargetNavigationMixin |
36 | 78 | from lp.answers.browser.questiontarget import ( | 79 | from lp.answers.browser.questiontarget import ( |
37 | 79 | QuestionTargetFacetMixin, | 80 | QuestionTargetFacetMixin, |
38 | @@ -135,7 +136,7 @@ | |||
39 | 135 | if self.context.codehosting_usage == ServiceUsage.LAUNCHPAD: | 136 | if self.context.codehosting_usage == ServiceUsage.LAUNCHPAD: |
40 | 136 | url = canonical_url(self.context, rootsite='code') | 137 | url = canonical_url(self.context, rootsite='code') |
41 | 137 | uses.append(href_template % (url, 'Branches')) | 138 | uses.append(href_template % (url, 'Branches')) |
43 | 138 | if self.context.official_rosetta: | 139 | if service_uses_launchpad(self.context.translations_usage): |
44 | 139 | url = canonical_url(self.context, rootsite='translations') | 140 | url = canonical_url(self.context, rootsite='translations') |
45 | 140 | uses.append(href_template % (url, 'Translations')) | 141 | uses.append(href_template % (url, 'Translations')) |
46 | 141 | 142 | ||
47 | 142 | 143 | ||
48 | === modified file 'lib/lp/registry/browser/pillar.py' | |||
49 | --- lib/lp/registry/browser/pillar.py 2010-09-03 03:12:39 +0000 | |||
50 | +++ lib/lp/registry/browser/pillar.py 2010-09-09 15:34:46 +0000 | |||
51 | @@ -30,7 +30,10 @@ | |||
52 | 30 | nearest, | 30 | nearest, |
53 | 31 | ) | 31 | ) |
54 | 32 | from canonical.launchpad.webapp.tales import MenuAPI | 32 | from canonical.launchpad.webapp.tales import MenuAPI |
56 | 33 | from lp.app.enums import ServiceUsage | 33 | from lp.app.enums import ( |
57 | 34 | ServiceUsage, | ||
58 | 35 | service_uses_launchpad, | ||
59 | 36 | ) | ||
60 | 34 | from lp.app.interfaces.launchpad import IServiceUsage | 37 | from lp.app.interfaces.launchpad import IServiceUsage |
61 | 35 | from lp.registry.browser.structuralsubscription import ( | 38 | from lp.registry.browser.structuralsubscription import ( |
62 | 36 | StructuralSubscriptionMenuMixin, | 39 | StructuralSubscriptionMenuMixin, |
63 | @@ -72,7 +75,7 @@ | |||
64 | 72 | def help_translate(self): | 75 | def help_translate(self): |
65 | 73 | return Link( | 76 | return Link( |
66 | 74 | '', 'Help translate', site='translations', icon='translations', | 77 | '', 'Help translate', site='translations', icon='translations', |
68 | 75 | enabled=self.pillar.official_rosetta) | 78 | enabled=service_uses_launchpad(self.pillar.translations_usage)) |
69 | 76 | 79 | ||
70 | 77 | def submit_code(self): | 80 | def submit_code(self): |
71 | 78 | if self.pillar.codehosting_usage in [ | 81 | if self.pillar.codehosting_usage in [ |
72 | @@ -104,7 +107,7 @@ | |||
73 | 104 | self.official_malone = False | 107 | self.official_malone = False |
74 | 105 | self.official_answers = False | 108 | self.official_answers = False |
75 | 106 | self.official_blueprints = False | 109 | self.official_blueprints = False |
77 | 107 | self.official_rosetta = False | 110 | self.translations_usage = ServiceUsage.UNKNOWN |
78 | 108 | self.codehosting_usage = ServiceUsage.UNKNOWN | 111 | self.codehosting_usage = ServiceUsage.UNKNOWN |
79 | 109 | pillar = nearest(self.context, IPillar) | 112 | pillar = nearest(self.context, IPillar) |
80 | 110 | if IProjectGroup.providedBy(pillar): | 113 | if IProjectGroup.providedBy(pillar): |
81 | @@ -121,7 +124,7 @@ | |||
82 | 121 | self.codehosting_usage = distribution.codehosting_usage | 124 | self.codehosting_usage = distribution.codehosting_usage |
83 | 122 | elif IDistributionSourcePackage.providedBy(self.context): | 125 | elif IDistributionSourcePackage.providedBy(self.context): |
84 | 123 | self.official_blueprints = False | 126 | self.official_blueprints = False |
86 | 124 | self.official_rosetta = False | 127 | self.translations_usage = ServiceUsage.UNKNOWN |
87 | 125 | else: | 128 | else: |
88 | 126 | # The context is used by all apps. | 129 | # The context is used by all apps. |
89 | 127 | pass | 130 | pass |
90 | @@ -136,8 +139,7 @@ | |||
91 | 136 | self.official_answers = True | 139 | self.official_answers = True |
92 | 137 | if pillar.official_blueprints: | 140 | if pillar.official_blueprints: |
93 | 138 | self.official_blueprints = True | 141 | self.official_blueprints = True |
96 | 139 | if pillar.official_rosetta: | 142 | self.translations_usage = IServiceUsage(pillar).translations_usage |
95 | 140 | self.official_rosetta = True | ||
97 | 141 | self.codehosting_usage = IServiceUsage(pillar).codehosting_usage | 143 | self.codehosting_usage = IServiceUsage(pillar).codehosting_usage |
98 | 142 | 144 | ||
99 | 143 | @property | 145 | @property |
100 | @@ -145,8 +147,9 @@ | |||
101 | 145 | """This `IPillar` uses Launchpad.""" | 147 | """This `IPillar` uses Launchpad.""" |
102 | 146 | return ( | 148 | return ( |
103 | 147 | self.official_malone or self.official_answers | 149 | self.official_malone or self.official_answers |
106 | 148 | or self.official_blueprints or self.official_rosetta | 150 | or self.official_blueprints |
107 | 149 | or self.codehosting_usage == ServiceUsage.LAUNCHPAD) | 151 | or service_uses_launchpad(self.translations_usage) |
108 | 152 | or service_uses_launchpad(self.codehosting_usage)) | ||
109 | 150 | 153 | ||
110 | 151 | @property | 154 | @property |
111 | 152 | def enabled_links(self): | 155 | def enabled_links(self): |
112 | 153 | 156 | ||
113 | === modified file 'lib/lp/registry/browser/tests/pillar-views.txt' | |||
114 | --- lib/lp/registry/browser/tests/pillar-views.txt 2010-08-27 17:45:57 +0000 | |||
115 | +++ lib/lp/registry/browser/tests/pillar-views.txt 2010-09-09 15:34:46 +0000 | |||
116 | @@ -35,8 +35,8 @@ | |||
117 | 35 | True | 35 | True |
118 | 36 | >>> view.official_answers | 36 | >>> view.official_answers |
119 | 37 | True | 37 | True |
122 | 38 | >>> view.official_rosetta | 38 | >>> view.translations_usage.name |
123 | 39 | False | 39 | 'UNKNOWN' |
124 | 40 | >>> view.official_blueprints | 40 | >>> view.official_blueprints |
125 | 41 | False | 41 | False |
126 | 42 | >>> view.codehosting_usage.name | 42 | >>> view.codehosting_usage.name |
127 | @@ -230,9 +230,10 @@ | |||
128 | 230 | set the links. Despite the fact that the distribution uses blueprints, | 230 | set the links. Despite the fact that the distribution uses blueprints, |
129 | 231 | and translations those links are not enabled for DistributionSourcePackages. | 231 | and translations those links are not enabled for DistributionSourcePackages. |
130 | 232 | 232 | ||
131 | 233 | >>> from lp.app.enums import ServiceUsage | ||
132 | 233 | >>> login_person(distribution.owner) | 234 | >>> login_person(distribution.owner) |
133 | 234 | >>> distribution.official_blueprints = True | 235 | >>> distribution.official_blueprints = True |
135 | 235 | >>> distribution.official_rosetta = True | 236 | >>> distribution.translations_usage = ServiceUsage.LAUNCHPAD |
136 | 236 | >>> package = factory.makeDistributionSourcePackage( | 237 | >>> package = factory.makeDistributionSourcePackage( |
137 | 237 | ... sourcepackagename="box", | 238 | ... sourcepackagename="box", |
138 | 238 | ... distribution=distribution) | 239 | ... distribution=distribution) |
139 | 239 | 240 | ||
140 | === modified file 'lib/lp/registry/browser/tests/productseries-views.txt' | |||
141 | --- lib/lp/registry/browser/tests/productseries-views.txt 2010-09-03 06:06:40 +0000 | |||
142 | +++ lib/lp/registry/browser/tests/productseries-views.txt 2010-09-09 15:34:46 +0000 | |||
143 | @@ -23,11 +23,12 @@ | |||
144 | 23 | The ProductSeries involvement view uses the ProductSeriesInvolvedMenu when | 23 | The ProductSeries involvement view uses the ProductSeriesInvolvedMenu when |
145 | 24 | rendering links: | 24 | rendering links: |
146 | 25 | 25 | ||
147 | 26 | >>> from lp.app.enums import ServiceUsage | ||
148 | 26 | >>> login_person(product.owner) | 27 | >>> login_person(product.owner) |
149 | 27 | >>> product.official_answers = True | 28 | >>> product.official_answers = True |
150 | 28 | >>> product.official_blueprints = True | 29 | >>> product.official_blueprints = True |
151 | 29 | >>> product.official_malone = True | 30 | >>> product.official_malone = True |
153 | 30 | >>> product.official_rosetta = True | 31 | >>> product.translations_usage = ServiceUsage.LAUNCHPAD |
154 | 31 | >>> view = create_view(series, '+get-involved') | 32 | >>> view = create_view(series, '+get-involved') |
155 | 32 | 33 | ||
156 | 33 | # official_answers is always false for product series. | 34 | # official_answers is always false for product series. |
157 | @@ -37,10 +38,11 @@ | |||
158 | 37 | True | 38 | True |
159 | 38 | >>> print view.official_malone | 39 | >>> print view.official_malone |
160 | 39 | True | 40 | True |
163 | 40 | >>> print view.official_rosetta | 41 | >>> print view.translations_usage.name |
164 | 41 | True | 42 | LAUNCHPAD |
165 | 42 | >>> print view.codehosting_usage.name | 43 | >>> print view.codehosting_usage.name |
166 | 43 | UNKNOWN | 44 | UNKNOWN |
167 | 45 | |||
168 | 44 | >>> for link in view.enabled_links: | 46 | >>> for link in view.enabled_links: |
169 | 45 | ... print link.url | 47 | ... print link.url |
170 | 46 | http://bugs.launchpad.dev/app/simple/+filebug | 48 | http://bugs.launchpad.dev/app/simple/+filebug |
171 | @@ -476,7 +478,7 @@ | |||
172 | 476 | A series cannot be deleted if it is has translation templates. | 478 | A series cannot be deleted if it is has translation templates. |
173 | 477 | 479 | ||
174 | 478 | >>> translated_series = factory.makeProductSeries(product=product) | 480 | >>> translated_series = factory.makeProductSeries(product=product) |
176 | 479 | >>> product.official_rosetta = True | 481 | >>> product.translations_usage = ServiceUsage.LAUNCHPAD |
177 | 480 | >>> po_template = factory.makePOTemplate( | 482 | >>> po_template = factory.makePOTemplate( |
178 | 481 | ... name='gibberish', productseries=translated_series) | 483 | ... name='gibberish', productseries=translated_series) |
179 | 482 | >>> translated_view = create_initialized_view( | 484 | >>> translated_view = create_initialized_view( |
180 | 483 | 485 | ||
181 | === modified file 'lib/lp/registry/doc/distribution.txt' | |||
182 | --- lib/lp/registry/doc/distribution.txt 2010-08-23 00:51:30 +0000 | |||
183 | +++ lib/lp/registry/doc/distribution.txt 2010-09-09 15:34:46 +0000 | |||
184 | @@ -1,4 +1,5 @@ | |||
186 | 1 | = Distributions = | 1 | Distributions |
187 | 2 | ============= | ||
188 | 2 | 3 | ||
189 | 3 | From the DerivationOverview spec | 4 | From the DerivationOverview spec |
190 | 4 | <https://launchpad.canonical.com/DerivationOverview>: | 5 | <https://launchpad.canonical.com/DerivationOverview>: |
191 | @@ -143,7 +144,8 @@ | |||
192 | 143 | False | 144 | False |
193 | 144 | 145 | ||
194 | 145 | 146 | ||
196 | 146 | == Distribution Sorting == | 147 | Distribution Sorting |
197 | 148 | -------------------- | ||
198 | 147 | 149 | ||
199 | 148 | If you ask for all the distributions in the DistributionSet you should get | 150 | If you ask for all the distributions in the DistributionSet you should get |
200 | 149 | Ubuntu (and all flavours of it) first and the rest alphabetically: | 151 | Ubuntu (and all flavours of it) first and the rest alphabetically: |
201 | @@ -164,7 +166,8 @@ | |||
202 | 164 | True | 166 | True |
203 | 165 | 167 | ||
204 | 166 | 168 | ||
206 | 167 | === Searching for DistributionSourcePackages === | 169 | Searching for DistributionSourcePackages |
207 | 170 | ........................................ | ||
208 | 168 | 171 | ||
209 | 169 | The distribution also allows you to look for source packages that match | 172 | The distribution also allows you to look for source packages that match |
210 | 170 | a certain string through the magic of fti. For instance: | 173 | a certain string through the magic of fti. For instance: |
211 | @@ -232,7 +235,8 @@ | |||
212 | 232 | DistributionSourcePackage: alsa-utils | 235 | DistributionSourcePackage: alsa-utils |
213 | 233 | 236 | ||
214 | 234 | 237 | ||
216 | 235 | === Searching for binary packages === | 238 | Searching for binary packages |
217 | 239 | ............................. | ||
218 | 236 | 240 | ||
219 | 237 | There are two useful functions for searching binary packages related | 241 | There are two useful functions for searching binary packages related |
220 | 238 | to the distribution, searchBinaryPackages() and searchBinaryPackagesFTI(). | 242 | to the distribution, searchBinaryPackages() and searchBinaryPackagesFTI(). |
221 | @@ -291,7 +295,8 @@ | |||
222 | 291 | [u'mozilla-firefox'] | 295 | [u'mozilla-firefox'] |
223 | 292 | 296 | ||
224 | 293 | 297 | ||
226 | 294 | === Finding distroseriess and pockets from distribution names === | 298 | Finding distroseriess and pockets from distribution names |
227 | 299 | ......................................................... | ||
228 | 295 | 300 | ||
229 | 296 | A distribution knows what distroseriess it has. Those distroseriess have | 301 | A distribution knows what distroseriess it has. Those distroseriess have |
230 | 297 | pockets which have suffixes used by the archive publisher. Because we | 302 | pockets which have suffixes used by the archive publisher. Because we |
231 | @@ -336,26 +341,27 @@ | |||
232 | 336 | NotFoundError: 'hoary-bullshit' | 341 | NotFoundError: 'hoary-bullshit' |
233 | 337 | 342 | ||
234 | 338 | 343 | ||
236 | 339 | === Upload related stuff === | 344 | Upload related stuff |
237 | 345 | .................... | ||
238 | 340 | 346 | ||
239 | 341 | When uploading to a distribution we need to query its uploaders. Each | 347 | When uploading to a distribution we need to query its uploaders. Each |
240 | 342 | uploader record is in fact an ArchivePermission record that tells us | 348 | uploader record is in fact an ArchivePermission record that tells us |
241 | 343 | what component is uploadable to by what person or group of people. | 349 | what component is uploadable to by what person or group of people. |
242 | 344 | 350 | ||
257 | 345 | >>> from operator import attrgetter | 351 | >>> from operator import attrgetter |
258 | 346 | >>> for permission in sorted( | 352 | >>> for permission in sorted( |
259 | 347 | ... ubuntu.uploaders, key=attrgetter("id")): | 353 | ... ubuntu.uploaders, key=attrgetter("id")): |
260 | 348 | ... assert not permission.archive.is_ppa | 354 | ... assert not permission.archive.is_ppa |
261 | 349 | ... print permission.component.name | 355 | ... print permission.component.name |
262 | 350 | ... print permission.person.displayname | 356 | ... print permission.person.displayname |
263 | 351 | universe | 357 | universe |
264 | 352 | Ubuntu Team | 358 | Ubuntu Team |
265 | 353 | restricted | 359 | restricted |
266 | 354 | Ubuntu Team | 360 | Ubuntu Team |
267 | 355 | main | 361 | main |
268 | 356 | Ubuntu Team | 362 | Ubuntu Team |
269 | 357 | partner | 363 | partner |
270 | 358 | Canonical Partner Developers | 364 | Canonical Partner Developers |
271 | 359 | 365 | ||
272 | 360 | When processing an upload we may want to find a file (E.g. if an | 366 | When processing an upload we may want to find a file (E.g. if an |
273 | 361 | incomplete source is uploaded). | 367 | incomplete source is uploaded). |
274 | @@ -375,7 +381,8 @@ | |||
275 | 375 | AssertionError: searching in an explicitly empty space is pointless | 381 | AssertionError: searching in an explicitly empty space is pointless |
276 | 376 | 382 | ||
277 | 377 | 383 | ||
279 | 378 | === Launchpad Usage === | 384 | Launchpad Usage |
280 | 385 | ............... | ||
281 | 379 | 386 | ||
282 | 380 | A distribution can specify if it uses Malone, Rosetta, or Answers | 387 | A distribution can specify if it uses Malone, Rosetta, or Answers |
283 | 381 | officially. Ubuntu uses all of them: | 388 | officially. Ubuntu uses all of them: |
284 | @@ -385,8 +392,8 @@ | |||
285 | 385 | >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | 392 | >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
286 | 386 | >>> ubuntu.official_malone | 393 | >>> ubuntu.official_malone |
287 | 387 | True | 394 | True |
290 | 388 | >>> ubuntu.official_rosetta | 395 | >>> ubuntu.translations_usage.name |
291 | 389 | True | 396 | 'LAUNCHPAD' |
292 | 390 | >>> ubuntu.official_answers | 397 | >>> ubuntu.official_answers |
293 | 391 | True | 398 | True |
294 | 392 | >>> ubuntu.official_blueprints | 399 | >>> ubuntu.official_blueprints |
295 | @@ -397,12 +404,12 @@ | |||
296 | 397 | >>> print ubuntu.bug_tracking_usage.name | 404 | >>> print ubuntu.bug_tracking_usage.name |
297 | 398 | LAUNCHPAD | 405 | LAUNCHPAD |
298 | 399 | 406 | ||
300 | 400 | While the other attributes track the other official_ attributes. | 407 | While the other attributes track the other official_ attributes. |
301 | 401 | 408 | ||
302 | 402 | >>> print ubuntu.official_rosetta | 409 | >>> print ubuntu.official_rosetta |
303 | 403 | True | 410 | True |
304 | 404 | >>> print ubuntu.translations_usage.name | 411 | >>> print ubuntu.translations_usage.name |
306 | 405 | LAUNCHPAD | 412 | LAUNCHPAD |
307 | 406 | >>> print ubuntu.official_answers | 413 | >>> print ubuntu.official_answers |
308 | 407 | True | 414 | True |
309 | 408 | >>> print ubuntu.answers_usage.name | 415 | >>> print ubuntu.answers_usage.name |
310 | @@ -412,7 +419,8 @@ | |||
311 | 412 | >>> print ubuntu.blueprints_usage.name | 419 | >>> print ubuntu.blueprints_usage.name |
312 | 413 | LAUNCHPAD | 420 | LAUNCHPAD |
313 | 414 | 421 | ||
315 | 415 | If the official_ attributes are False, the usage enums don't know anything. | 422 | If the official_ attributes are False and the enum hasn't been set, |
316 | 423 | the usage enums don't know anything. | ||
317 | 416 | 424 | ||
318 | 417 | >>> login_person(ubuntu.owner.teamowner) | 425 | >>> login_person(ubuntu.owner.teamowner) |
319 | 418 | >>> ubuntu.official_rosetta = False | 426 | >>> ubuntu.official_rosetta = False |
320 | @@ -422,37 +430,35 @@ | |||
321 | 422 | A distribution *cannot* specify that it uses codehosting. Currently there's | 430 | A distribution *cannot* specify that it uses codehosting. Currently there's |
322 | 423 | no way for a distribution to use codehosting. | 431 | no way for a distribution to use codehosting. |
323 | 424 | 432 | ||
330 | 425 | >>> ubuntu.official_codehosting | 433 | >>> from lp.app.enums import ServiceUsage |
325 | 426 | False | ||
326 | 427 | >>> ubuntu.official_codehosting = True | ||
327 | 428 | Traceback (most recent call last): | ||
328 | 429 | ForbiddenAttribute: ('official_codehosting', ...) | ||
329 | 430 | |||
331 | 431 | >>> print ubuntu.codehosting_usage.name | 434 | >>> print ubuntu.codehosting_usage.name |
332 | 432 | NOT_APPLICABLE | 435 | NOT_APPLICABLE |
333 | 436 | >>> ubuntu.codehosting_usage = ServiceUsage.LAUNCHPAD | ||
334 | 437 | Traceback (most recent call last): | ||
335 | 438 | AttributeError: can't set attribute... | ||
336 | 433 | 439 | ||
337 | 434 | While Debian uses none: | 440 | While Debian uses none: |
338 | 435 | 441 | ||
339 | 436 | >>> debian = getUtility(ILaunchpadCelebrities).debian | 442 | >>> debian = getUtility(ILaunchpadCelebrities).debian |
350 | 437 | >>> debian.official_malone | 443 | >>> print debian.bug_tracking_usage.name |
351 | 438 | False | 444 | UNKNOWN |
352 | 439 | >>> debian.official_rosetta | 445 | >>> print debian.translations_usage.name |
353 | 440 | False | 446 | UNKNOWN |
354 | 441 | >>> debian.official_answers | 447 | >>> print debian.answers_usage.name |
355 | 442 | False | 448 | UNKNOWN |
356 | 443 | >>> debian.official_codehosting | 449 | >>> print debian.codehosting_usage.name |
357 | 444 | False | 450 | NOT_APPLICABLE |
358 | 445 | >>> debian.official_blueprints | 451 | >>> print debian.blueprints_usage.name |
359 | 446 | False | 452 | UNKNOWN |
360 | 447 | 453 | ||
361 | 448 | Gentoo only uses Malone | 454 | Gentoo only uses Malone |
362 | 449 | 455 | ||
369 | 450 | >>> print gentoo.official_malone | 456 | >>> print gentoo.bug_tracking_usage.name |
370 | 451 | True | 457 | LAUNCHPAD |
371 | 452 | >>> print gentoo.official_rosetta | 458 | >>> print gentoo.translations_usage.name |
372 | 453 | False | 459 | UNKNOWN |
373 | 454 | >>> print gentoo.official_answers | 460 | >>> print gentoo.answers_usage.name |
374 | 455 | False | 461 | UNKNOWN |
375 | 456 | 462 | ||
376 | 457 | Launchpad admins and the distro owner can set these fields. | 463 | Launchpad admins and the distro owner can set these fields. |
377 | 458 | 464 | ||
378 | @@ -464,9 +470,9 @@ | |||
379 | 464 | >>> debian.official_malone = True | 470 | >>> debian.official_malone = True |
380 | 465 | >>> debian.official_malone | 471 | >>> debian.official_malone |
381 | 466 | True | 472 | True |
385 | 467 | >>> debian.official_rosetta = True | 473 | >>> debian.translations_usage = ServiceUsage.LAUNCHPAD |
386 | 468 | >>> debian.official_rosetta | 474 | >>> debian.translations_usage.name |
387 | 469 | True | 475 | 'LAUNCHPAD' |
388 | 470 | 476 | ||
389 | 471 | >>> debian_owner = factory.makePerson() | 477 | >>> debian_owner = factory.makePerson() |
390 | 472 | >>> debian.owner = debian_owner | 478 | >>> debian.owner = debian_owner |
391 | @@ -484,12 +490,13 @@ | |||
392 | 484 | >>> debian.official_malone = True | 490 | >>> debian.official_malone = True |
393 | 485 | Traceback (most recent call last): | 491 | Traceback (most recent call last): |
394 | 486 | Unauthorized: (..., 'official_malone', 'launchpad.Edit') | 492 | Unauthorized: (..., 'official_malone', 'launchpad.Edit') |
396 | 487 | >>> debian.official_rosetta = True | 493 | >>> debian.translations_usage = ServiceUsage.LAUNCHPAD |
397 | 488 | Traceback (most recent call last): | 494 | Traceback (most recent call last): |
402 | 489 | Unauthorized: (..., 'official_rosetta', 'launchpad.Edit') | 495 | Unauthorized: (..., 'translations_usage', 'launchpad.Edit') |
403 | 490 | 496 | ||
404 | 491 | 497 | ||
405 | 492 | === Specification Listings === | 498 | Specification Listings |
406 | 499 | ...................... | ||
407 | 493 | 500 | ||
408 | 494 | We should be able to get lists of specifications in different states | 501 | We should be able to get lists of specifications in different states |
409 | 495 | related to a distro. | 502 | related to a distro. |
410 | @@ -497,90 +504,93 @@ | |||
411 | 497 | Basically, we can filter by completeness, and by whether or not the spec is | 504 | Basically, we can filter by completeness, and by whether or not the spec is |
412 | 498 | informational. | 505 | informational. |
413 | 499 | 506 | ||
415 | 500 | >>> kubuntu = distroset.getByName("kubuntu") | 507 | >>> kubuntu = distroset.getByName("kubuntu") |
416 | 501 | 508 | ||
418 | 502 | >>> from canonical.launchpad.interfaces import SpecificationFilter | 509 | >>> from canonical.launchpad.interfaces import SpecificationFilter |
419 | 503 | 510 | ||
420 | 504 | First, there should be one informational spec for kubuntu, but it is | 511 | First, there should be one informational spec for kubuntu, but it is |
421 | 505 | complete so it will not show up unless we explicitly ask for complete specs: | 512 | complete so it will not show up unless we explicitly ask for complete specs: |
422 | 506 | 513 | ||
430 | 507 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 514 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
431 | 508 | >>> kubuntu.specifications(filter=filter).count() | 515 | >>> kubuntu.specifications(filter=filter).count() |
432 | 509 | 0 | 516 | 0 |
433 | 510 | >>> filter = [SpecificationFilter.INFORMATIONAL, | 517 | >>> filter = [SpecificationFilter.INFORMATIONAL, |
434 | 511 | ... SpecificationFilter.COMPLETE] | 518 | ... SpecificationFilter.COMPLETE] |
435 | 512 | >>> kubuntu.specifications(filter=filter).count() | 519 | >>> kubuntu.specifications(filter=filter).count() |
436 | 513 | 1 | 520 | 1 |
437 | 514 | 521 | ||
438 | 515 | 522 | ||
439 | 516 | There are 2 completed specs for Kubuntu: | 523 | There are 2 completed specs for Kubuntu: |
440 | 517 | 524 | ||
446 | 518 | >>> filter = [SpecificationFilter.COMPLETE] | 525 | >>> filter = [SpecificationFilter.COMPLETE] |
447 | 519 | >>> for spec in kubuntu.specifications(filter=filter): | 526 | >>> for spec in kubuntu.specifications(filter=filter): |
448 | 520 | ... print spec.name, spec.is_complete | 527 | ... print spec.name, spec.is_complete |
449 | 521 | thinclient-local-devices True | 528 | thinclient-local-devices True |
450 | 522 | usplash-on-hibernation True | 529 | usplash-on-hibernation True |
451 | 523 | 530 | ||
452 | 524 | 531 | ||
453 | 525 | And there are four incomplete specs: | 532 | And there are four incomplete specs: |
454 | 526 | 533 | ||
462 | 527 | >>> filter = [SpecificationFilter.INCOMPLETE] | 534 | >>> filter = [SpecificationFilter.INCOMPLETE] |
463 | 528 | >>> for spec in kubuntu.specifications(filter=filter): | 535 | >>> for spec in kubuntu.specifications(filter=filter): |
464 | 529 | ... print spec.name, spec.is_complete | 536 | ... print spec.name, spec.is_complete |
465 | 530 | cluster-installation False | 537 | cluster-installation False |
466 | 531 | revu False | 538 | revu False |
467 | 532 | kde-desktopfile-langpacks False | 539 | kde-desktopfile-langpacks False |
468 | 533 | krunch-desktop-plan False | 540 | krunch-desktop-plan False |
469 | 534 | 541 | ||
470 | 535 | 542 | ||
471 | 536 | If we ask for all specs, we get them in the order of priority. | 543 | If we ask for all specs, we get them in the order of priority. |
472 | 537 | 544 | ||
482 | 538 | >>> filter = [SpecificationFilter.ALL] | 545 | >>> filter = [SpecificationFilter.ALL] |
483 | 539 | >>> for spec in kubuntu.specifications(filter=filter): | 546 | >>> for spec in kubuntu.specifications(filter=filter): |
484 | 540 | ... print spec.priority.title, spec.name | 547 | ... print spec.priority.title, spec.name |
485 | 541 | Essential cluster-installation | 548 | Essential cluster-installation |
486 | 542 | High revu | 549 | High revu |
487 | 543 | Medium thinclient-local-devices | 550 | Medium thinclient-local-devices |
488 | 544 | Low usplash-on-hibernation | 551 | Low usplash-on-hibernation |
489 | 545 | Undefined kde-desktopfile-langpacks | 552 | Undefined kde-desktopfile-langpacks |
490 | 546 | Not krunch-desktop-plan | 553 | Not krunch-desktop-plan |
491 | 547 | 554 | ||
492 | 548 | 555 | ||
493 | 549 | And if we ask just for specs, we get the incomplete ones. | 556 | And if we ask just for specs, we get the incomplete ones. |
494 | 550 | 557 | ||
501 | 551 | >>> for spec in kubuntu.specifications(): | 558 | >>> for spec in kubuntu.specifications(): |
502 | 552 | ... print spec.name, spec.is_complete | 559 | ... print spec.name, spec.is_complete |
503 | 553 | cluster-installation False | 560 | cluster-installation False |
504 | 554 | revu False | 561 | revu False |
505 | 555 | kde-desktopfile-langpacks False | 562 | kde-desktopfile-langpacks False |
506 | 556 | krunch-desktop-plan False | 563 | krunch-desktop-plan False |
507 | 557 | 564 | ||
508 | 558 | We can filter for specifications that contain specific text: | 565 | We can filter for specifications that contain specific text: |
509 | 559 | 566 | ||
513 | 560 | >>> for spec in kubuntu.specifications(filter=['package']): | 567 | >>> for spec in kubuntu.specifications(filter=['package']): |
514 | 561 | ... print spec.name | 568 | ... print spec.name |
515 | 562 | revu | 569 | revu |
516 | 563 | 570 | ||
517 | 564 | We can get only valid specs (those that are not obsolete or superseded): | 571 | We can get only valid specs (those that are not obsolete or superseded): |
518 | 565 | 572 | ||
537 | 566 | >>> from canonical.launchpad.interfaces import SpecificationDefinitionStatus | 573 | >>> from canonical.launchpad.interfaces import ( |
538 | 567 | >>> login('mark@example.com') | 574 | ... SpecificationDefinitionStatus, |
539 | 568 | >>> for spec in kubuntu.specifications(): | 575 | ... ) |
540 | 569 | ... # Do this here, otherwise, the change will be flush before | 576 | >>> login('mark@example.com') |
541 | 570 | ... # updateLifecycleStatus() acts and an IntegrityError will be | 577 | >>> for spec in kubuntu.specifications(): |
542 | 571 | ... # raised. | 578 | ... # Do this here, otherwise, the change will be flush before |
543 | 572 | ... owner = spec.owner | 579 | ... # updateLifecycleStatus() acts and an IntegrityError will be |
544 | 573 | ... if spec.name in ['cluster-installation', 'revu']: | 580 | ... # raised. |
545 | 574 | ... spec.definition_status = SpecificationDefinitionStatus.OBSOLETE | 581 | ... owner = spec.owner |
546 | 575 | ... if spec.name in ['krunch-desktop-plan']: | 582 | ... if spec.name in ['cluster-installation', 'revu']: |
547 | 576 | ... spec.definition_status = SpecificationDefinitionStatus.SUPERSEDED | 583 | ... spec.definition_status = SpecificationDefinitionStatus.OBSOLETE |
548 | 577 | ... shim = spec.updateLifecycleStatus(owner) | 584 | ... if spec.name in ['krunch-desktop-plan']: |
549 | 578 | >>> for spec in kubuntu.valid_specifications: | 585 | ... spec.definition_status = SpecificationDefinitionStatus.SUPERSEDED |
550 | 579 | ... print spec.name | 586 | ... shim = spec.updateLifecycleStatus(owner) |
551 | 580 | kde-desktopfile-langpacks | 587 | >>> for spec in kubuntu.valid_specifications: |
552 | 581 | 588 | ... print spec.name | |
553 | 582 | 589 | kde-desktopfile-langpacks | |
554 | 583 | == Milestones == | 590 | |
555 | 591 | |||
556 | 592 | Milestones | ||
557 | 593 | ---------- | ||
558 | 584 | 594 | ||
559 | 585 | We can use IDistribution.milestones to get all milestones associated with any | 595 | We can use IDistribution.milestones to get all milestones associated with any |
560 | 586 | series of a distribution. | 596 | series of a distribution. |
561 | @@ -623,7 +633,8 @@ | |||
562 | 623 | [u'3.1', u'3.1-rc1', u'woody-rc1'] | 633 | [u'3.1', u'3.1-rc1', u'woody-rc1'] |
563 | 624 | 634 | ||
564 | 625 | 635 | ||
566 | 626 | == Archives == | 636 | Archives |
567 | 637 | -------- | ||
568 | 627 | 638 | ||
569 | 628 | A distribution archive (primary, partner, debug or copy) can be retrieved | 639 | A distribution archive (primary, partner, debug or copy) can be retrieved |
570 | 629 | by name using IDistribution.getArchive. | 640 | by name using IDistribution.getArchive. |
571 | 630 | 641 | ||
572 | === modified file 'lib/lp/registry/doc/product.txt' | |||
573 | --- lib/lp/registry/doc/product.txt 2010-08-25 15:48:05 +0000 | |||
574 | +++ lib/lp/registry/doc/product.txt 2010-09-09 15:34:46 +0000 | |||
575 | @@ -1,4 +1,5 @@ | |||
577 | 1 | = Product = | 1 | Product |
578 | 2 | ======= | ||
579 | 2 | 3 | ||
580 | 3 | Launchpad keeps track of the "upstream" world as well as the "distro" world. | 4 | Launchpad keeps track of the "upstream" world as well as the "distro" world. |
581 | 4 | The anchorpiece of the "upstream" world is the Product, which is a piece of | 5 | The anchorpiece of the "upstream" world is the Product, which is a piece of |
582 | @@ -162,7 +163,8 @@ | |||
583 | 162 | Obsolete Junk | 163 | Obsolete Junk |
584 | 163 | 164 | ||
585 | 164 | 165 | ||
587 | 165 | == Translatable Products == | 166 | Translatable Products |
588 | 167 | --------------------- | ||
589 | 166 | 168 | ||
590 | 167 | IProductSet will also tell us which products can be translated: | 169 | IProductSet will also tell us which products can be translated: |
591 | 168 | 170 | ||
592 | @@ -217,11 +219,11 @@ | |||
593 | 217 | The packaging table allows us to list source and distro source packages | 219 | The packaging table allows us to list source and distro source packages |
594 | 218 | related to a certain upstream: | 220 | related to a certain upstream: |
595 | 219 | 221 | ||
601 | 220 | >>> alsa = productset.getByName('alsa-utils') | 222 | >>> alsa = productset.getByName('alsa-utils') |
602 | 221 | >>> [(sp.name, sp.distroseries.name) for sp in alsa.sourcepackages] | 223 | >>> [(sp.name, sp.distroseries.name) for sp in alsa.sourcepackages] |
603 | 222 | [(u'alsa-utils', u'sid'), (u'alsa-utils', u'warty')] | 224 | [(u'alsa-utils', u'sid'), (u'alsa-utils', u'warty')] |
604 | 223 | >>> [(sp.name, sp.distribution.name) for sp in alsa.distrosourcepackages] | 225 | >>> [(sp.name, sp.distribution.name) for sp in alsa.distrosourcepackages] |
605 | 224 | [(u'alsa-utils', u'debian'), (u'alsa-utils', u'ubuntu')] | 226 | [(u'alsa-utils', u'debian'), (u'alsa-utils', u'ubuntu')] |
606 | 225 | 227 | ||
607 | 226 | The date_next_suggest_packaging attribute records the date when Launchpad can | 228 | The date_next_suggest_packaging attribute records the date when Launchpad can |
608 | 227 | resume suggesting Ubuntu packages that the project provides. A value of None | 229 | resume suggesting Ubuntu packages that the project provides. A value of None |
609 | @@ -270,7 +272,8 @@ | |||
610 | 270 | >>> from canonical.launchpad.interfaces import IBugTrackerSet | 272 | >>> from canonical.launchpad.interfaces import IBugTrackerSet |
611 | 271 | 273 | ||
612 | 272 | >>> login_person(firefox.owner) | 274 | >>> login_person(firefox.owner) |
614 | 273 | >>> gnome_bugzilla = getUtility(IBugTrackerSet).getByName('gnome-bugzilla') | 275 | >>> bug_tracker_set = getUtility(IBugTrackerSet) |
615 | 276 | >>> gnome_bugzilla = bug_tracker_set.getByName('gnome-bugzilla') | ||
616 | 274 | >>> firefox.project.bugtracker = gnome_bugzilla | 277 | >>> firefox.project.bugtracker = gnome_bugzilla |
617 | 275 | >>> firefox.getExternalBugTracker() is None | 278 | >>> firefox.getExternalBugTracker() is None |
618 | 276 | True | 279 | True |
619 | @@ -307,7 +310,8 @@ | |||
620 | 307 | True | 310 | True |
621 | 308 | 311 | ||
622 | 309 | 312 | ||
624 | 310 | == Answer Tracking == | 313 | Answer Tracking |
625 | 314 | --------------- | ||
626 | 311 | 315 | ||
627 | 312 | Firefox uses the Answer Tracker as the official application to provide | 316 | Firefox uses the Answer Tracker as the official application to provide |
628 | 313 | answers to questions. | 317 | answers to questions. |
629 | @@ -321,7 +325,8 @@ | |||
630 | 321 | False | 325 | False |
631 | 322 | 326 | ||
632 | 323 | 327 | ||
634 | 324 | == Product Creation == | 328 | Product Creation |
635 | 329 | ---------------- | ||
636 | 325 | 330 | ||
637 | 326 | We can create new products with the createProduct() method: | 331 | We can create new products with the createProduct() method: |
638 | 327 | 332 | ||
639 | @@ -374,20 +379,21 @@ | |||
640 | 374 | True | 379 | True |
641 | 375 | 380 | ||
642 | 376 | 381 | ||
644 | 377 | == Specification Listings == | 382 | Specification Listings |
645 | 383 | ---------------------- | ||
646 | 378 | 384 | ||
647 | 379 | We should be able to set whether or not a Product uses specifications | 385 | We should be able to set whether or not a Product uses specifications |
648 | 380 | officially. It defaults to False. | 386 | officially. It defaults to False. |
649 | 381 | 387 | ||
653 | 382 | >>> firefox = productset.getByName('firefox') | 388 | >>> firefox = productset.getByName('firefox') |
654 | 383 | >>> firefox.official_blueprints | 389 | >>> firefox.official_blueprints |
655 | 384 | False | 390 | False |
656 | 385 | 391 | ||
657 | 386 | We can change it to True. | 392 | We can change it to True. |
658 | 387 | 393 | ||
662 | 388 | >>> firefox.official_blueprints = True | 394 | >>> firefox.official_blueprints = True |
663 | 389 | >>> firefox.official_blueprints | 395 | >>> firefox.official_blueprints |
664 | 390 | True | 396 | True |
665 | 391 | 397 | ||
666 | 392 | We should be able to get lists of specifications in different states | 398 | We should be able to get lists of specifications in different states |
667 | 393 | related to a product. | 399 | related to a product. |
668 | @@ -395,39 +401,40 @@ | |||
669 | 395 | Basically, we can filter by completeness, and by whether or not the spec is | 401 | Basically, we can filter by completeness, and by whether or not the spec is |
670 | 396 | informational. | 402 | informational. |
671 | 397 | 403 | ||
674 | 398 | >>> firefox = productset.getByName('firefox') | 404 | >>> firefox = productset.getByName('firefox') |
675 | 399 | >>> from canonical.launchpad.interfaces import SpecificationFilter | 405 | >>> from canonical.launchpad.interfaces import SpecificationFilter |
676 | 400 | 406 | ||
677 | 401 | First, there should be only one informational spec for firefox: | 407 | First, there should be only one informational spec for firefox: |
678 | 402 | 408 | ||
683 | 403 | >>> filter = [SpecificationFilter.INFORMATIONAL] | 409 | >>> filter = [SpecificationFilter.INFORMATIONAL] |
684 | 404 | >>> for spec in firefox.specifications(filter=filter): | 410 | >>> for spec in firefox.specifications(filter=filter): |
685 | 405 | ... print spec.name | 411 | ... print spec.name |
686 | 406 | extension-manager-upgrades | 412 | extension-manager-upgrades |
687 | 407 | 413 | ||
688 | 408 | 414 | ||
689 | 409 | There are no completed specs for firefox: | 415 | There are no completed specs for firefox: |
690 | 410 | 416 | ||
694 | 411 | >>> filter = [SpecificationFilter.COMPLETE] | 417 | >>> filter = [SpecificationFilter.COMPLETE] |
695 | 412 | >>> for spec in firefox.specifications(filter=filter): | 418 | >>> for spec in firefox.specifications(filter=filter): |
696 | 413 | ... print spec.name | 419 | ... print spec.name |
697 | 414 | 420 | ||
698 | 415 | 421 | ||
699 | 416 | And there are five incomplete specs: | 422 | And there are five incomplete specs: |
700 | 417 | 423 | ||
704 | 418 | >>> filter = [SpecificationFilter.INCOMPLETE] | 424 | >>> filter = [SpecificationFilter.INCOMPLETE] |
705 | 419 | >>> firefox.specifications(filter=filter).count() | 425 | >>> firefox.specifications(filter=filter).count() |
706 | 420 | 5 | 426 | 5 |
707 | 421 | 427 | ||
708 | 422 | We can filter for specifications that contain specific text: | 428 | We can filter for specifications that contain specific text: |
709 | 423 | 429 | ||
717 | 424 | >>> for spec in firefox.specifications(filter=['new']): | 430 | >>> for spec in firefox.specifications(filter=['new']): |
718 | 425 | ... print spec.name | 431 | ... print spec.name |
719 | 426 | canvas | 432 | canvas |
720 | 427 | e4x | 433 | e4x |
721 | 428 | 434 | ||
722 | 429 | 435 | ||
723 | 430 | == Milestones == | 436 | Milestones |
724 | 437 | ---------- | ||
725 | 431 | 438 | ||
726 | 432 | We can use IProduct.milestones to get all milestones associated with any | 439 | We can use IProduct.milestones to get all milestones associated with any |
727 | 433 | ProductSeries of a product. | 440 | ProductSeries of a product. |
728 | @@ -470,7 +477,8 @@ | |||
729 | 470 | [u'1.0.0', u'0.9.2', u'0.9.1', u'0.9', u'1.0', u'1.0-rc1'] | 477 | [u'1.0.0', u'0.9.2', u'0.9.1', u'0.9', u'1.0', u'1.0-rc1'] |
730 | 471 | 478 | ||
731 | 472 | 479 | ||
733 | 473 | == Release == | 480 | Release |
734 | 481 | ------- | ||
735 | 474 | 482 | ||
736 | 475 | All the releases for a Product can be retrieved through the releases property. | 483 | All the releases for a Product can be retrieved through the releases property. |
737 | 476 | 484 | ||
738 | @@ -489,7 +497,8 @@ | |||
739 | 489 | 0.9.1 | 497 | 0.9.1 |
740 | 490 | 498 | ||
741 | 491 | 499 | ||
743 | 492 | == Products With Branches == | 500 | Products With Branches |
744 | 501 | ---------------------- | ||
745 | 493 | 502 | ||
746 | 494 | Products are considered to officially support Launchpad as a location | 503 | Products are considered to officially support Launchpad as a location |
747 | 495 | for their branches after a branch is set for the development focus | 504 | for their branches after a branch is set for the development focus |
748 | @@ -568,7 +577,8 @@ | |||
749 | 568 | landscape | 577 | landscape |
750 | 569 | 578 | ||
751 | 570 | 579 | ||
753 | 571 | == Primary translatable == | 580 | Primary translatable |
754 | 581 | -------------------- | ||
755 | 572 | 582 | ||
756 | 573 | Primary translatable series in a product should follow series where | 583 | Primary translatable series in a product should follow series where |
757 | 574 | development is focused on. To be able to do changes to facilitate | 584 | development is focused on. To be able to do changes to facilitate |
758 | @@ -583,12 +593,18 @@ | |||
759 | 583 | >>> from lp.translations.interfaces.potemplate import IPOTemplateSet | 593 | >>> from lp.translations.interfaces.potemplate import IPOTemplateSet |
760 | 584 | >>> potemplate_set = getUtility(IPOTemplateSet) | 594 | >>> potemplate_set = getUtility(IPOTemplateSet) |
761 | 585 | 595 | ||
762 | 596 | We're going to be setting the ServiceUsage values for products, so we | ||
763 | 597 | need those enums. | ||
764 | 598 | |||
765 | 599 | >>> from lp.app.enums import ServiceUsage | ||
766 | 600 | |||
767 | 586 | Firefox has two series, but no translatable series either: | 601 | Firefox has two series, but no translatable series either: |
768 | 587 | 602 | ||
769 | 588 | >>> firefox = productset.getByName('firefox') | 603 | >>> firefox = productset.getByName('firefox') |
770 | 589 | >>> for firefoxseries in firefox.series: | 604 | >>> for firefoxseries in firefox.series: |
773 | 590 | ... print '%s %s' % (firefoxseries.displayname, | 605 | ... print '%s %s' % ( |
774 | 591 | ... list(firefoxseries.getCurrentTranslationTemplates())) | 606 | ... firefoxseries.displayname, |
775 | 607 | ... list(firefoxseries.getCurrentTranslationTemplates())) | ||
776 | 592 | 1.0 [] | 608 | 1.0 [] |
777 | 593 | trunk [] | 609 | trunk [] |
778 | 594 | >>> print firefox.primary_translatable | 610 | >>> print firefox.primary_translatable |
779 | @@ -616,7 +632,7 @@ | |||
780 | 616 | And set that product as using translations officially. We need it so | 632 | And set that product as using translations officially. We need it so |
781 | 617 | translations are available. | 633 | translations are available. |
782 | 618 | 634 | ||
784 | 619 | >>> firefox.official_rosetta = True | 635 | >>> firefox.translations_usage = ServiceUsage.LAUNCHPAD |
785 | 620 | 636 | ||
786 | 621 | The primary_translatable now points at firefox 1.0: | 637 | The primary_translatable now points at firefox 1.0: |
787 | 622 | 638 | ||
788 | @@ -642,7 +658,8 @@ | |||
789 | 642 | 1.0 | 658 | 1.0 |
790 | 643 | 659 | ||
791 | 644 | 660 | ||
793 | 645 | = Series list = | 661 | Series list |
794 | 662 | =========== | ||
795 | 646 | 663 | ||
796 | 647 | The series for a product are returned as a sorted list, with the | 664 | The series for a product are returned as a sorted list, with the |
797 | 648 | exception that the current development focus is first. | 665 | exception that the current development focus is first. |
798 | @@ -697,7 +714,8 @@ | |||
799 | 697 | ... print series.name | 714 | ... print series.name |
800 | 698 | trunk | 715 | trunk |
801 | 699 | 716 | ||
803 | 700 | = Changing ownership = | 717 | Changing ownership |
804 | 718 | ================== | ||
805 | 701 | 719 | ||
806 | 702 | If the owner of a project changes, all series and productreleases | 720 | If the owner of a project changes, all series and productreleases |
807 | 703 | owned by the old owner are transfered to the new owner. | 721 | owned by the old owner are transfered to the new owner. |
808 | 704 | 722 | ||
809 | === modified file 'lib/lp/registry/doc/project.txt' | |||
810 | --- lib/lp/registry/doc/project.txt 2010-06-07 07:52:45 +0000 | |||
811 | +++ lib/lp/registry/doc/project.txt 2010-09-09 15:34:46 +0000 | |||
812 | @@ -1,4 +1,5 @@ | |||
814 | 1 | = ProjectGroups = | 1 | ProjectGroups |
815 | 2 | ============= | ||
816 | 2 | 3 | ||
817 | 3 | A ProjectGroup is a group of Products, making it possible to for | 4 | A ProjectGroup is a group of Products, making it possible to for |
818 | 4 | example see all bugs in the ProjectGroup's Product, or make them share a | 5 | example see all bugs in the ProjectGroup's Product, or make them share a |
819 | @@ -11,7 +12,8 @@ | |||
820 | 11 | >>> projectset = getUtility(IProjectGroupSet) | 12 | >>> projectset = getUtility(IProjectGroupSet) |
821 | 12 | 13 | ||
822 | 13 | 14 | ||
824 | 14 | == Creating new projects == | 15 | Creating new projects |
825 | 16 | --------------------- | ||
826 | 15 | 17 | ||
827 | 16 | When creating a new project there are a bunch of things we need to provide. | 18 | When creating a new project there are a bunch of things we need to provide. |
828 | 17 | While some of them (homepageurl, icon, logo and mugshot) are optional, others | 19 | While some of them (homepageurl, icon, logo and mugshot) are optional, others |
829 | @@ -28,7 +30,8 @@ | |||
830 | 28 | u'project-test' | 30 | u'project-test' |
831 | 29 | 31 | ||
832 | 30 | 32 | ||
834 | 31 | == Looking up existing projects == | 33 | Looking up existing projects |
835 | 34 | ---------------------------- | ||
836 | 32 | 35 | ||
837 | 33 | To fetch a project we use IProjectGroupSet.getByName() or | 36 | To fetch a project we use IProjectGroupSet.getByName() or |
838 | 34 | IProjectGroupSet.__getitem__. The former will, by default, return active and | 37 | IProjectGroupSet.__getitem__. The former will, by default, return active and |
839 | @@ -98,7 +101,8 @@ | |||
840 | 98 | >>> print projectgroups.getByName('gnome', ignore_inactive=True) | 101 | >>> print projectgroups.getByName('gnome', ignore_inactive=True) |
841 | 99 | None | 102 | None |
842 | 100 | 103 | ||
844 | 101 | == Products which are part of a project == | 104 | Products which are part of a project |
845 | 105 | ------------------------------------ | ||
846 | 102 | 106 | ||
847 | 103 | The products which are part of a given project are given by a project's | 107 | The products which are part of a given project are given by a project's |
848 | 104 | .products property. Note that only active products are included and they're | 108 | .products property. Note that only active products are included and they're |
849 | @@ -122,7 +126,8 @@ | |||
850 | 122 | >>> flush_database_updates() | 126 | >>> flush_database_updates() |
851 | 123 | 127 | ||
852 | 124 | 128 | ||
854 | 125 | == Specification Listings == | 129 | Specification Listings |
855 | 130 | ---------------------- | ||
856 | 126 | 131 | ||
857 | 127 | We should be able to generate filtered lists of specs on a project. | 132 | We should be able to generate filtered lists of specs on a project. |
858 | 128 | 133 | ||
859 | @@ -200,7 +205,8 @@ | |||
860 | 200 | e4x | 205 | e4x |
861 | 201 | 206 | ||
862 | 202 | 207 | ||
864 | 203 | == Specification Listings for a ProjectGroupSeries == | 208 | Specification Listings for a ProjectGroupSeries |
865 | 209 | ----------------------------------------------- | ||
866 | 204 | 210 | ||
867 | 205 | An IProjectGroupSeries object can be retrieved by IProjectGroup.getSeries. | 211 | An IProjectGroupSeries object can be retrieved by IProjectGroup.getSeries. |
868 | 206 | 212 | ||
869 | @@ -314,7 +320,8 @@ | |||
870 | 314 | e4x | 320 | e4x |
871 | 315 | 321 | ||
872 | 316 | 322 | ||
874 | 317 | == translatables == | 323 | Translatables |
875 | 324 | ------------- | ||
876 | 318 | 325 | ||
877 | 319 | A project would have IProduct objects that have resources to translate. This | 326 | A project would have IProduct objects that have resources to translate. This |
878 | 320 | method return us the ones that are translatable and officially using Rosetta | 327 | method return us the ones that are translatable and officially using Rosetta |
879 | @@ -349,8 +356,8 @@ | |||
880 | 349 | 356 | ||
881 | 350 | That is using Rosetta officially. | 357 | That is using Rosetta officially. |
882 | 351 | 358 | ||
885 | 352 | >>> evolution.official_rosetta | 359 | >>> print evolution.translations_usage.name |
886 | 353 | True | 360 | LAUNCHPAD |
887 | 354 | 361 | ||
888 | 355 | GNOME project has also another product, netapplet. | 362 | GNOME project has also another product, netapplet. |
889 | 356 | 363 | ||
890 | @@ -361,8 +368,8 @@ | |||
891 | 361 | But it was not returned from 'translatables' method because it's not using | 368 | But it was not returned from 'translatables' method because it's not using |
892 | 362 | Rosetta officially. | 369 | Rosetta officially. |
893 | 363 | 370 | ||
896 | 364 | >>> netapplet.official_rosetta | 371 | >>> print netapplet.translations_usage.name |
897 | 365 | False | 372 | UNKNOWN |
898 | 366 | 373 | ||
899 | 367 | And thus, it doesn't have any translatable series. | 374 | And thus, it doesn't have any translatable series. |
900 | 368 | 375 | ||
901 | @@ -376,7 +383,8 @@ | |||
902 | 376 | 1 | 383 | 1 |
903 | 377 | 384 | ||
904 | 378 | 385 | ||
906 | 379 | == Milestones == | 386 | Milestones |
907 | 387 | ---------- | ||
908 | 380 | 388 | ||
909 | 381 | A project can have virtual milestones. If any of its products has milestones, | 389 | A project can have virtual milestones. If any of its products has milestones, |
910 | 382 | these milestones are also associated with the project. | 390 | these milestones are also associated with the project. |
911 | @@ -398,7 +406,8 @@ | |||
912 | 398 | 1.1. active: True | 406 | 1.1. active: True |
913 | 399 | 1.1 active: True | 407 | 1.1 active: True |
914 | 400 | 408 | ||
916 | 401 | ProjectGroup.all_milestones is a list of all milestones associated with a project. | 409 | ProjectGroup.all_milestones is a list of all milestones associated with a |
917 | 410 | project. | ||
918 | 402 | 411 | ||
919 | 403 | >>> milestones = gnome.all_milestones | 412 | >>> milestones = gnome.all_milestones |
920 | 404 | >>> for milestone in milestones: | 413 | >>> for milestone in milestones: |
921 | @@ -410,8 +419,8 @@ | |||
922 | 410 | 1.1. active: True | 419 | 1.1. active: True |
923 | 411 | 1.1 active: True | 420 | 1.1 active: True |
924 | 412 | 421 | ||
927 | 413 | ProjectGroup.getMilestone(name) returns the project milestone with the name `name' | 422 | ProjectGroup.getMilestone(name) returns the project milestone with the name |
928 | 414 | or None, if no milestone with this name exists. | 423 | `name' or None, if no milestone with this name exists. |
929 | 415 | 424 | ||
930 | 416 | >>> milestone = gnome.getMilestone('1.1') | 425 | >>> milestone = gnome.getMilestone('1.1') |
931 | 417 | >>> print milestone.name | 426 | >>> print milestone.name |
932 | 418 | 427 | ||
933 | === modified file 'lib/lp/registry/model/projectgroup.py' | |||
934 | --- lib/lp/registry/model/projectgroup.py 2010-08-24 19:06:33 +0000 | |||
935 | +++ lib/lp/registry/model/projectgroup.py 2010-09-09 15:34:46 +0000 | |||
936 | @@ -202,6 +202,9 @@ | |||
937 | 202 | 202 | ||
938 | 203 | def translatables(self): | 203 | def translatables(self): |
939 | 204 | """See `IProjectGroup`.""" | 204 | """See `IProjectGroup`.""" |
940 | 205 | # XXX j.c.sackett 2010-08-30 bug=627631 Once data migration has | ||
941 | 206 | # happened for the usage enums, this sql needs to be updated to | ||
942 | 207 | # check for the translations_usage, not official_rosetta. | ||
943 | 205 | return Product.select(''' | 208 | return Product.select(''' |
944 | 206 | Product.project = %s AND | 209 | Product.project = %s AND |
945 | 207 | Product.official_rosetta = TRUE AND | 210 | Product.official_rosetta = TRUE AND |
946 | @@ -271,7 +274,7 @@ | |||
947 | 271 | 274 | ||
948 | 272 | # filter based on completion. see the implementation of | 275 | # filter based on completion. see the implementation of |
949 | 273 | # Specification.is_complete() for more details | 276 | # Specification.is_complete() for more details |
951 | 274 | completeness = Specification.completeness_clause | 277 | completeness = Specification.completeness_clause |
952 | 275 | 278 | ||
953 | 276 | if SpecificationFilter.COMPLETE in filter: | 279 | if SpecificationFilter.COMPLETE in filter: |
954 | 277 | query += ' AND ( %s ) ' % completeness | 280 | query += ' AND ( %s ) ' % completeness |
955 | 278 | 281 | ||
956 | === modified file 'lib/lp/testing/factory.py' | |||
957 | --- lib/lp/testing/factory.py 2010-09-09 14:11:43 +0000 | |||
958 | +++ lib/lp/testing/factory.py 2010-09-09 15:34:46 +0000 | |||
959 | @@ -93,6 +93,7 @@ | |||
960 | 93 | IStoreSelector, | 93 | IStoreSelector, |
961 | 94 | MAIN_STORE, | 94 | MAIN_STORE, |
962 | 95 | ) | 95 | ) |
963 | 96 | from lp.app.enums import ServiceUsage | ||
964 | 96 | from lp.archiveuploader.dscfile import DSCFile | 97 | from lp.archiveuploader.dscfile import DSCFile |
965 | 97 | from lp.archiveuploader.uploadpolicy import BuildDaemonUploadPolicy | 98 | from lp.archiveuploader.uploadpolicy import BuildDaemonUploadPolicy |
966 | 98 | from lp.blueprints.interfaces.specification import ( | 99 | from lp.blueprints.interfaces.specification import ( |
967 | @@ -838,7 +839,7 @@ | |||
968 | 838 | self, name=None, project=None, displayname=None, | 839 | self, name=None, project=None, displayname=None, |
969 | 839 | licenses=None, owner=None, registrant=None, | 840 | licenses=None, owner=None, registrant=None, |
970 | 840 | title=None, summary=None, official_malone=None, | 841 | title=None, summary=None, official_malone=None, |
972 | 841 | official_rosetta=None, bug_supervisor=None): | 842 | translations_usage=None, bug_supervisor=None): |
973 | 842 | """Create and return a new, arbitrary Product.""" | 843 | """Create and return a new, arbitrary Product.""" |
974 | 843 | if owner is None: | 844 | if owner is None: |
975 | 844 | owner = self.makePerson() | 845 | owner = self.makePerson() |
976 | @@ -867,8 +868,9 @@ | |||
977 | 867 | registrant=registrant) | 868 | registrant=registrant) |
978 | 868 | if official_malone is not None: | 869 | if official_malone is not None: |
979 | 869 | removeSecurityProxy(product).official_malone = official_malone | 870 | removeSecurityProxy(product).official_malone = official_malone |
982 | 870 | if official_rosetta is not None: | 871 | if translations_usage is not None: |
983 | 871 | removeSecurityProxy(product).official_rosetta = official_rosetta | 872 | naked_product = removeSecurityProxy(product) |
984 | 873 | naked_product.translations_usage = translations_usage | ||
985 | 872 | if bug_supervisor is not None: | 874 | if bug_supervisor is not None: |
986 | 873 | naked_product = removeSecurityProxy(product) | 875 | naked_product = removeSecurityProxy(product) |
987 | 874 | naked_product.bug_supervisor = bug_supervisor | 876 | naked_product.bug_supervisor = bug_supervisor |
988 | @@ -2176,7 +2178,8 @@ | |||
989 | 2176 | productseries = self.makeProductSeries(owner=owner) | 2178 | productseries = self.makeProductSeries(owner=owner) |
990 | 2177 | # Make it use Translations, otherwise there's little point | 2179 | # Make it use Translations, otherwise there's little point |
991 | 2178 | # to us creating a template for it. | 2180 | # to us creating a template for it. |
993 | 2179 | removeSecurityProxy(productseries).product.official_rosetta = True | 2181 | naked_series = removeSecurityProxy(productseries) |
994 | 2182 | naked_series.product.translations_usage = ServiceUsage.LAUNCHPAD | ||
995 | 2180 | templateset = getUtility(IPOTemplateSet) | 2183 | templateset = getUtility(IPOTemplateSet) |
996 | 2181 | subset = templateset.getSubset( | 2184 | subset = templateset.getSubset( |
997 | 2182 | distroseries, sourcepackagename, productseries) | 2185 | distroseries, sourcepackagename, productseries) |
998 | 2183 | 2186 | ||
999 | === modified file 'lib/lp/translations/browser/potemplate.py' | |||
1000 | --- lib/lp/translations/browser/potemplate.py 2010-08-25 20:04:40 +0000 | |||
1001 | +++ lib/lp/translations/browser/potemplate.py 2010-09-09 15:34:46 +0000 | |||
1002 | @@ -61,6 +61,7 @@ | |||
1003 | 61 | from canonical.launchpad.webapp.launchpadform import ReturnToReferrerMixin | 61 | from canonical.launchpad.webapp.launchpadform import ReturnToReferrerMixin |
1004 | 62 | from canonical.launchpad.webapp.menu import structured | 62 | from canonical.launchpad.webapp.menu import structured |
1005 | 63 | from canonical.lazr.utils import smartquote | 63 | from canonical.lazr.utils import smartquote |
1006 | 64 | from lp.app.enums import service_uses_launchpad | ||
1007 | 64 | from lp.app.errors import NotFoundError | 65 | from lp.app.errors import NotFoundError |
1008 | 65 | from lp.registry.browser.productseries import ProductSeriesFacets | 66 | from lp.registry.browser.productseries import ProductSeriesFacets |
1009 | 66 | from lp.registry.browser.sourcepackage import SourcePackageFacets | 67 | from lp.registry.browser.sourcepackage import SourcePackageFacets |
1010 | @@ -794,9 +795,10 @@ | |||
1011 | 794 | product_or_distro = potemplate.productseries.product | 795 | product_or_distro = potemplate.productseries.product |
1012 | 795 | else: | 796 | else: |
1013 | 796 | product_or_distro = potemplate.distroseries.distribution | 797 | product_or_distro = potemplate.distroseries.distribution |
1015 | 797 | official_rosetta = product_or_distro.official_rosetta | 798 | translations_usage = product_or_distro.translations_usage |
1016 | 798 | 799 | ||
1018 | 799 | if official_rosetta and potemplate.iscurrent: | 800 | if (service_uses_launchpad(translations_usage) and |
1019 | 801 | potemplate.iscurrent): | ||
1020 | 800 | # This template is available for translation. | 802 | # This template is available for translation. |
1021 | 801 | return potemplate | 803 | return potemplate |
1022 | 802 | elif check_permission('launchpad.Edit', potemplate): | 804 | elif check_permission('launchpad.Edit', potemplate): |
1023 | 803 | 805 | ||
1024 | === modified file 'lib/lp/translations/browser/product.py' | |||
1025 | --- lib/lp/translations/browser/product.py 2010-08-24 10:45:57 +0000 | |||
1026 | +++ lib/lp/translations/browser/product.py 2010-09-09 15:34:46 +0000 | |||
1027 | @@ -19,6 +19,7 @@ | |||
1028 | 19 | ) | 19 | ) |
1029 | 20 | from canonical.launchpad.webapp.authorization import check_permission | 20 | from canonical.launchpad.webapp.authorization import check_permission |
1030 | 21 | from canonical.launchpad.webapp.menu import NavigationMenu | 21 | from canonical.launchpad.webapp.menu import NavigationMenu |
1031 | 22 | from lp.app.enums import service_uses_launchpad | ||
1032 | 22 | from lp.registry.browser.product import ProductEditView | 23 | from lp.registry.browser.product import ProductEditView |
1033 | 23 | from lp.registry.interfaces.product import IProduct | 24 | from lp.registry.interfaces.product import IProduct |
1034 | 24 | from lp.registry.interfaces.productseries import IProductSeries | 25 | from lp.registry.interfaces.productseries import IProductSeries |
1035 | @@ -51,12 +52,14 @@ | |||
1036 | 51 | def translationdownload(self): | 52 | def translationdownload(self): |
1037 | 52 | text = 'Download' | 53 | text = 'Download' |
1038 | 53 | preferred_series = self.context.primary_translatable | 54 | preferred_series = self.context.primary_translatable |
1041 | 54 | enabled = (self.context.official_rosetta and | 55 | enabled = (service_uses_launchpad(self.context.translations_usage) |
1042 | 55 | preferred_series is not None) | 56 | and preferred_series is not None) |
1043 | 56 | link = '' | 57 | link = '' |
1044 | 57 | if enabled: | 58 | if enabled: |
1045 | 58 | link = canonical_url( | 59 | link = canonical_url( |
1047 | 59 | preferred_series, rootsite='translations', view_name='+export') | 60 | preferred_series, |
1048 | 61 | rootsite='translations', | ||
1049 | 62 | view_name='+export') | ||
1050 | 60 | text = 'Download "%s"' % preferred_series.name | 63 | text = 'Download "%s"' % preferred_series.name |
1051 | 61 | 64 | ||
1052 | 62 | return Link(link, text, icon='download', enabled=enabled) | 65 | return Link(link, text, icon='download', enabled=enabled) |
1053 | @@ -90,19 +93,19 @@ | |||
1054 | 90 | @cachedproperty | 93 | @cachedproperty |
1055 | 91 | def uses_translations(self): | 94 | def uses_translations(self): |
1056 | 92 | """Whether this product has translatable templates.""" | 95 | """Whether this product has translatable templates.""" |
1059 | 93 | return (self.context.official_rosetta and | 96 | return (service_uses_launchpad(self.context.translations_usage) |
1060 | 94 | self.primary_translatable is not None) | 97 | and self.primary_translatable is not None) |
1061 | 95 | 98 | ||
1062 | 96 | @cachedproperty | 99 | @cachedproperty |
1063 | 97 | def no_translations_available(self): | 100 | def no_translations_available(self): |
1064 | 98 | """Has no translation templates but does support translations.""" | 101 | """Has no translation templates but does support translations.""" |
1067 | 99 | return (self.context.official_rosetta and | 102 | return (service_uses_launchpad(self.context.translations_usage) |
1068 | 100 | self.primary_translatable is None) | 103 | and self.primary_translatable is None) |
1069 | 101 | 104 | ||
1070 | 102 | @cachedproperty | 105 | @cachedproperty |
1071 | 103 | def show_page_content(self): | 106 | def show_page_content(self): |
1072 | 104 | """Whether the main content of the page should be shown.""" | 107 | """Whether the main content of the page should be shown.""" |
1074 | 105 | return (self.context.official_rosetta or | 108 | return (service_uses_launchpad(self.context.translations_usage) or |
1075 | 106 | check_permission("launchpad.TranslationsAdmin", self.context)) | 109 | check_permission("launchpad.TranslationsAdmin", self.context)) |
1076 | 107 | 110 | ||
1077 | 108 | @cachedproperty | 111 | @cachedproperty |
1078 | 109 | 112 | ||
1079 | === modified file 'lib/lp/translations/browser/tests/language-views.txt' | |||
1080 | --- lib/lp/translations/browser/tests/language-views.txt 2010-07-16 16:51:52 +0000 | |||
1081 | +++ lib/lp/translations/browser/tests/language-views.txt 2010-09-09 15:34:46 +0000 | |||
1082 | @@ -143,7 +143,10 @@ | |||
1083 | 143 | 143 | ||
1084 | 144 | Create a product, a template with one msgset and a pofile | 144 | Create a product, a template with one msgset and a pofile |
1085 | 145 | 145 | ||
1087 | 146 | >>> product = factory.makeProduct(official_rosetta=True) | 146 | >>> from lp.app.enums import ServiceUsage |
1088 | 147 | |||
1089 | 148 | >>> product = factory.makeProduct( | ||
1090 | 149 | ... translations_usage=ServiceUsage.LAUNCHPAD) | ||
1091 | 147 | >>> template = factory.makePOTemplate( | 150 | >>> template = factory.makePOTemplate( |
1092 | 148 | ... productseries=product.getSeries('trunk')) | 151 | ... productseries=product.getSeries('trunk')) |
1093 | 149 | >>> potmsgset = factory.makePOTMsgSet(template) | 152 | >>> potmsgset = factory.makePOTMsgSet(template) |
1094 | 150 | 153 | ||
1095 | === modified file 'lib/lp/translations/browser/tests/test_breadcrumbs.py' | |||
1096 | --- lib/lp/translations/browser/tests/test_breadcrumbs.py 2010-08-20 20:31:18 +0000 | |||
1097 | +++ lib/lp/translations/browser/tests/test_breadcrumbs.py 2010-09-09 15:34:46 +0000 | |||
1098 | @@ -6,6 +6,7 @@ | |||
1099 | 6 | from zope.component import getUtility | 6 | from zope.component import getUtility |
1100 | 7 | 7 | ||
1101 | 8 | from canonical.lazr.utils import smartquote | 8 | from canonical.lazr.utils import smartquote |
1102 | 9 | from lp.app.enums import ServiceUsage | ||
1103 | 9 | from lp.services.worlddata.interfaces.language import ILanguageSet | 10 | from lp.services.worlddata.interfaces.language import ILanguageSet |
1104 | 10 | from lp.testing.breadcrumbs import BaseBreadcrumbTestCase | 11 | from lp.testing.breadcrumbs import BaseBreadcrumbTestCase |
1105 | 11 | from lp.testing.factory import remove_security_proxy_and_shout_at_engineer | 12 | from lp.testing.factory import remove_security_proxy_and_shout_at_engineer |
1106 | @@ -152,7 +153,7 @@ | |||
1107 | 152 | def test_potemplate(self): | 153 | def test_potemplate(self): |
1108 | 153 | product = self.factory.makeProduct( | 154 | product = self.factory.makeProduct( |
1109 | 154 | name='crumb-tester', displayname="Crumb Tester", | 155 | name='crumb-tester', displayname="Crumb Tester", |
1111 | 155 | official_rosetta=True) | 156 | translations_usage=ServiceUsage.LAUNCHPAD) |
1112 | 156 | series = self.factory.makeProductSeries( | 157 | series = self.factory.makeProductSeries( |
1113 | 157 | name="test", product=product) | 158 | name="test", product=product) |
1114 | 158 | potemplate = self.factory.makePOTemplate( | 159 | potemplate = self.factory.makePOTemplate( |
1115 | @@ -176,7 +177,7 @@ | |||
1116 | 176 | def test_pofiletranslate(self): | 177 | def test_pofiletranslate(self): |
1117 | 177 | product = self.factory.makeProduct( | 178 | product = self.factory.makeProduct( |
1118 | 178 | name='crumb-tester', displayname="Crumb Tester", | 179 | name='crumb-tester', displayname="Crumb Tester", |
1120 | 179 | official_rosetta=True) | 180 | translations_usage=ServiceUsage.LAUNCHPAD) |
1121 | 180 | series = self.factory.makeProductSeries(name="test", product=product) | 181 | series = self.factory.makeProductSeries(name="test", product=product) |
1122 | 181 | potemplate = self.factory.makePOTemplate(series, name="test-template") | 182 | potemplate = self.factory.makePOTemplate(series, name="test-template") |
1123 | 182 | pofile = self.factory.makePOFile('eo', potemplate) | 183 | pofile = self.factory.makePOFile('eo', potemplate) |
1124 | 183 | 184 | ||
1125 | === modified file 'lib/lp/translations/doc/potmsgset.txt' | |||
1126 | --- lib/lp/translations/doc/potmsgset.txt 2010-09-01 10:03:11 +0000 | |||
1127 | +++ lib/lp/translations/doc/potmsgset.txt 2010-09-09 15:34:46 +0000 | |||
1128 | @@ -1,4 +1,5 @@ | |||
1130 | 1 | = POTMsgSet tests = | 1 | POTMsgSet tests |
1131 | 2 | =============== | ||
1132 | 2 | 3 | ||
1133 | 3 | POTMsgSet represents messages to translate that a POTemplate file has. | 4 | POTMsgSet represents messages to translate that a POTemplate file has. |
1134 | 4 | 5 | ||
1135 | @@ -17,7 +18,9 @@ | |||
1136 | 17 | ... ILanguageSet, IPersonSet, IProductSet) | 18 | ... ILanguageSet, IPersonSet, IProductSet) |
1137 | 18 | 19 | ||
1138 | 19 | >>> potemplate = factory.makePOTemplate() | 20 | >>> potemplate = factory.makePOTemplate() |
1140 | 20 | >>> potmsgset = factory.makePOTMsgSet(potemplate=potemplate, singular="bla") | 21 | >>> potmsgset = factory.makePOTMsgSet( |
1141 | 22 | ... potemplate=potemplate, | ||
1142 | 23 | ... singular="bla") | ||
1143 | 21 | 24 | ||
1144 | 22 | Verify interface. | 25 | Verify interface. |
1145 | 23 | 26 | ||
1146 | @@ -31,7 +34,8 @@ | |||
1147 | 31 | >>> import pytz | 34 | >>> import pytz |
1148 | 32 | 35 | ||
1149 | 33 | 36 | ||
1151 | 34 | == POTMsgSet.is_translation_credit and POTMsgSet.translation_credit_type == | 37 | POTMsgSet.is_translation_credit and POTMsgSet.translation_credit_type |
1152 | 38 | --------------------------------------------------------------------- | ||
1153 | 35 | 39 | ||
1154 | 36 | A POTMsgSet can be translation credits. These have special msgids that may | 40 | A POTMsgSet can be translation credits. These have special msgids that may |
1155 | 37 | differ for historical reason for the same type of credit. The property | 41 | differ for historical reason for the same type of credit. The property |
1156 | @@ -51,7 +55,8 @@ | |||
1157 | 51 | Gnome credits message | 55 | Gnome credits message |
1158 | 52 | 56 | ||
1159 | 53 | 57 | ||
1161 | 54 | == POTMsgSet.normalizeWhitespaces == | 58 | POTMsgSet.normalizeWhitespaces |
1162 | 59 | ------------------------------ | ||
1163 | 55 | 60 | ||
1164 | 56 | This function copies the leading and trailing whitespaces from | 61 | This function copies the leading and trailing whitespaces from |
1165 | 57 | POTMsgSet's msgid into the 'text' argument. | 62 | POTMsgSet's msgid into the 'text' argument. |
1166 | @@ -96,7 +101,8 @@ | |||
1167 | 96 | True | 101 | True |
1168 | 97 | 102 | ||
1169 | 98 | 103 | ||
1171 | 99 | == POTMsgSet.convertDotToSpace == | 104 | POTMsgSet.convertDotToSpace |
1172 | 105 | --------------------------- | ||
1173 | 100 | 106 | ||
1174 | 101 | This method changes the u'\u2022' char by the normal white space. | 107 | This method changes the u'\u2022' char by the normal white space. |
1175 | 102 | 108 | ||
1176 | @@ -126,14 +132,17 @@ | |||
1177 | 126 | u'a string with the char \u2022' | 132 | u'a string with the char \u2022' |
1178 | 127 | 133 | ||
1179 | 128 | 134 | ||
1181 | 129 | == POTMsgSet.normalizeNewLines == | 135 | POTMsgSet.normalizeNewLines |
1182 | 136 | --------------------------- | ||
1183 | 130 | 137 | ||
1184 | 131 | This method syncs the new line chars to use the same as the associated msgid. | 138 | This method syncs the new line chars to use the same as the associated msgid. |
1185 | 132 | 139 | ||
1186 | 133 | As this test is too specific, we are going to change a msgid as we need for | 140 | As this test is too specific, we are going to change a msgid as we need for |
1187 | 134 | every test. | 141 | every test. |
1188 | 135 | 142 | ||
1190 | 136 | >>> potmsgset_windows = factory.makePOTMsgSet(potemplate, singular=u'\r\n') | 143 | >>> potmsgset_windows = factory.makePOTMsgSet( |
1191 | 144 | ... potemplate, | ||
1192 | 145 | ... singular=u'\r\n') | ||
1193 | 137 | >>> potmsgset_unix = factory.makePOTMsgSet(potemplate, singular=u'\n') | 146 | >>> potmsgset_unix = factory.makePOTMsgSet(potemplate, singular=u'\n') |
1194 | 138 | >>> potmsgset_mac = factory.makePOTMsgSet(potemplate, singular=u'\r') | 147 | >>> potmsgset_mac = factory.makePOTMsgSet(potemplate, singular=u'\r') |
1195 | 139 | >>> text_windows = u'\r\n' | 148 | >>> text_windows = u'\r\n' |
1196 | @@ -180,7 +189,8 @@ | |||
1197 | 180 | BrokenTextError: ... | 189 | BrokenTextError: ... |
1198 | 181 | 190 | ||
1199 | 182 | 191 | ||
1201 | 183 | == POTMsgSet.applySanityFixes == | 192 | POTMsgSet.applySanityFixes |
1202 | 193 | -------------------------- | ||
1203 | 184 | 194 | ||
1204 | 185 | This function applies all checks we know to fix broken input | 195 | This function applies all checks we know to fix broken input |
1205 | 186 | 196 | ||
1206 | @@ -199,7 +209,8 @@ | |||
1207 | 199 | u'\nTranslation\nto test\n' | 209 | u'\nTranslation\nto test\n' |
1208 | 200 | 210 | ||
1209 | 201 | 211 | ||
1211 | 202 | == POTMsgSet.updateTranslation == | 212 | POTMsgSet.updateTranslation |
1212 | 213 | --------------------------- | ||
1213 | 203 | 214 | ||
1214 | 204 | This method is the core piece of Translations infrastructure: it | 215 | This method is the core piece of Translations infrastructure: it |
1215 | 205 | updates a single language translation for a POTMsgSet, and modifies a | 216 | updates a single language translation for a POTMsgSet, and modifies a |
1216 | @@ -309,7 +320,8 @@ | |||
1217 | 309 | >>> current.date_created is None | 320 | >>> current.date_created is None |
1218 | 310 | False | 321 | False |
1219 | 311 | 322 | ||
1221 | 312 | === Unsetting a translation from the import === | 323 | Unsetting a translation from the import |
1222 | 324 | ....................................... | ||
1223 | 313 | 325 | ||
1224 | 314 | A translation can be removed from the import by being set to an empty string. | 326 | A translation can be removed from the import by being set to an empty string. |
1225 | 315 | 327 | ||
1226 | @@ -349,7 +361,8 @@ | |||
1227 | 349 | >>> upstream_pofile.updateStatistics() | 361 | >>> upstream_pofile.updateStatistics() |
1228 | 350 | (0, 0, 0, 2) | 362 | (0, 0, 0, 2) |
1229 | 351 | 363 | ||
1231 | 352 | === Activating an existing suggestion === | 364 | Activating an existing suggestion |
1232 | 365 | ................................. | ||
1233 | 353 | 366 | ||
1234 | 354 | Foo Bar is a privileged translator who can do reviews and submit translations | 367 | Foo Bar is a privileged translator who can do reviews and submit translations |
1235 | 355 | directly, while No Privileges user can only submit suggestions. | 368 | directly, while No Privileges user can only submit suggestions. |
1236 | @@ -438,7 +451,8 @@ | |||
1237 | 438 | u'Foo Bar' | 451 | u'Foo Bar' |
1238 | 439 | 452 | ||
1239 | 440 | 453 | ||
1241 | 441 | == Plural forms == | 454 | Plural forms |
1242 | 455 | ------------ | ||
1243 | 442 | 456 | ||
1244 | 443 | Let's focus on handling of messages with plural forms. | 457 | Let's focus on handling of messages with plural forms. |
1245 | 444 | 458 | ||
1246 | @@ -513,7 +527,8 @@ | |||
1247 | 513 | [None, None, None] | 527 | [None, None, None] |
1248 | 514 | 528 | ||
1249 | 515 | 529 | ||
1251 | 516 | === Missing forms === | 530 | Missing forms |
1252 | 531 | ............. | ||
1253 | 517 | 532 | ||
1254 | 518 | Even when a message has a singular and a plural in English, a | 533 | Even when a message has a singular and a plural in English, a |
1255 | 519 | translation does not have to cover all plural forms available in the | 534 | translation does not have to cover all plural forms available in the |
1256 | @@ -538,7 +553,8 @@ | |||
1257 | 538 | False | 553 | False |
1258 | 539 | 554 | ||
1259 | 540 | 555 | ||
1261 | 541 | === Extraneous forms === | 556 | Extraneous forms |
1262 | 557 | ................ | ||
1263 | 542 | 558 | ||
1264 | 543 | It's not normally possible to input more plural forms for a translated | 559 | It's not normally possible to input more plural forms for a translated |
1265 | 544 | message than the language has. But that number is configurable, and can | 560 | message than the language has. But that number is configurable, and can |
1266 | @@ -614,7 +630,8 @@ | |||
1267 | 614 | possible. | 630 | possible. |
1268 | 615 | 631 | ||
1269 | 616 | 632 | ||
1271 | 617 | == isTranslationNewerThan == | 633 | isTranslationNewerThan |
1272 | 634 | ---------------------- | ||
1273 | 618 | 635 | ||
1274 | 619 | This method tells us whether the active translation was reviewed after | 636 | This method tells us whether the active translation was reviewed after |
1275 | 620 | the given timestamp. | 637 | the given timestamp. |
1276 | @@ -633,7 +650,8 @@ | |||
1277 | 633 | False | 650 | False |
1278 | 634 | 651 | ||
1279 | 635 | 652 | ||
1281 | 636 | == External translation suggestions == | 653 | External translation suggestions |
1282 | 654 | -------------------------------- | ||
1283 | 637 | 655 | ||
1284 | 638 | External translation suggestions are current, imported or suggested | 656 | External translation suggestions are current, imported or suggested |
1285 | 639 | translation for exactly the same English string, but in a different | 657 | translation for exactly the same English string, but in a different |
1286 | @@ -670,7 +688,8 @@ | |||
1287 | 670 | ... print line | 688 | ... print line |
1288 | 671 | 689 | ||
1289 | 672 | 690 | ||
1291 | 673 | == POTMsgSet.getExternallyUsedTranslationMessages == | 691 | POTMsgSet.getExternallyUsedTranslationMessages |
1292 | 692 | ---------------------------------------------- | ||
1293 | 674 | 693 | ||
1294 | 675 | On one side, we have a translation template for the evolution product. | 694 | On one side, we have a translation template for the evolution product. |
1295 | 676 | 695 | ||
1296 | @@ -692,10 +711,10 @@ | |||
1297 | 692 | 711 | ||
1298 | 693 | Both, product and distribution use Launchpad Translations. | 712 | Both, product and distribution use Launchpad Translations. |
1299 | 694 | 713 | ||
1304 | 695 | >>> evolution.official_rosetta | 714 | >>> evolution.translations_usage.name |
1305 | 696 | True | 715 | 'LAUNCHPAD' |
1306 | 697 | >>> ubuntu.official_rosetta | 716 | >>> ubuntu.translations_usage.name |
1307 | 698 | True | 717 | 'LAUNCHPAD' |
1308 | 699 | 718 | ||
1309 | 700 | And both translation templates are current | 719 | And both translation templates are current |
1310 | 701 | 720 | ||
1311 | @@ -754,7 +773,9 @@ | |||
1312 | 754 | The same happens if the distribution is not officially using | 773 | The same happens if the distribution is not officially using |
1313 | 755 | translations. | 774 | translations. |
1314 | 756 | 775 | ||
1316 | 757 | >>> ubuntu.official_rosetta = False | 776 | >>> from lp.app.enums import ServiceUsage |
1317 | 777 | |||
1318 | 778 | >>> ubuntu.translations_usage = ServiceUsage.NOT_APPLICABLE | ||
1319 | 758 | 779 | ||
1320 | 759 | # We set the template as current again so we are sure that we don't show | 780 | # We set the template as current again so we are sure that we don't show |
1321 | 760 | # suggestions just due to the change to the official_rosetta flag. | 781 | # suggestions just due to the change to the official_rosetta flag. |
1322 | @@ -767,7 +788,7 @@ | |||
1323 | 767 | 788 | ||
1324 | 768 | And products not using translations officially have the same behaviour. | 789 | And products not using translations officially have the same behaviour. |
1325 | 769 | 790 | ||
1327 | 770 | >>> evolution.official_rosetta = False | 791 | >>> evolution.translations_usage = ServiceUsage.NOT_APPLICABLE |
1328 | 771 | >>> transaction.commit() | 792 | >>> transaction.commit() |
1329 | 772 | >>> suggestions = evo_distro_message.getExternallyUsedTranslationMessages( | 793 | >>> suggestions = evo_distro_message.getExternallyUsedTranslationMessages( |
1330 | 773 | ... spanish) | 794 | ... spanish) |
1331 | @@ -776,12 +797,13 @@ | |||
1332 | 776 | 797 | ||
1333 | 777 | Let's restore the flags for next section. | 798 | Let's restore the flags for next section. |
1334 | 778 | 799 | ||
1337 | 779 | >>> ubuntu.official_rosetta = True | 800 | >>> ubuntu.translations_usage = ServiceUsage.LAUNCHPAD |
1338 | 780 | >>> evolution.official_rosetta = True | 801 | >>> evolution.translations_usage = ServiceUsage.LAUNCHPAD |
1339 | 781 | >>> transaction.commit() | 802 | >>> transaction.commit() |
1340 | 782 | 803 | ||
1341 | 783 | 804 | ||
1343 | 784 | == POTMsgSet.getExternallySuggestedTranslationMessages == | 805 | POTMsgSet.getExternallySuggestedTranslationMessages |
1344 | 806 | --------------------------------------------------- | ||
1345 | 785 | 807 | ||
1346 | 786 | This method returns a set of submissions that have suggested translations | 808 | This method returns a set of submissions that have suggested translations |
1347 | 787 | for the same msgid as the given POTMsgSet across the whole system. | 809 | for the same msgid as the given POTMsgSet across the whole system. |
1348 | @@ -876,7 +898,7 @@ | |||
1349 | 876 | # We set the template as current again so we are sure that we don't show | 898 | # We set the template as current again so we are sure that we don't show |
1350 | 877 | # suggestions just due to the change to the official_rosetta flag. | 899 | # suggestions just due to the change to the official_rosetta flag. |
1351 | 878 | >>> potmsgset_translated.potemplate.iscurrent = True | 900 | >>> potmsgset_translated.potemplate.iscurrent = True |
1353 | 879 | >>> ubuntu.official_rosetta = False | 901 | >>> ubuntu.translations_usage = ServiceUsage.NOT_APPLICABLE |
1354 | 880 | >>> transaction.commit() | 902 | >>> transaction.commit() |
1355 | 881 | 903 | ||
1356 | 882 | >>> wiki_submissions = ( | 904 | >>> wiki_submissions = ( |
1357 | @@ -886,7 +908,8 @@ | |||
1358 | 886 | 0 | 908 | 0 |
1359 | 887 | 909 | ||
1360 | 888 | 910 | ||
1362 | 889 | == POTMsgSet.getCurrentDummyTranslationMessage == | 911 | POTMsgSet.getCurrentDummyTranslationMessage |
1363 | 912 | ------------------------------------------- | ||
1364 | 890 | 913 | ||
1365 | 891 | Sometimes, there are POTMsgSet objects with no translations to a language, | 914 | Sometimes, there are POTMsgSet objects with no translations to a language, |
1366 | 892 | and we need to get dummy objects which emulate them to do read operations. | 915 | and we need to get dummy objects which emulate them to do read operations. |
1367 | @@ -908,7 +931,8 @@ | |||
1368 | 908 | AssertionError: There is already a translation message ... | 931 | AssertionError: There is already a translation message ... |
1369 | 909 | 932 | ||
1370 | 910 | 933 | ||
1372 | 911 | == Suggestions for translator credits == | 934 | Suggestions for translator credits |
1373 | 935 | ---------------------------------- | ||
1374 | 912 | 936 | ||
1375 | 913 | Messages with translator credits are translated automatically by | 937 | Messages with translator credits are translated automatically by |
1376 | 914 | Launchpad, so we should not get any suggestions for them. | 938 | Launchpad, so we should not get any suggestions for them. |
1377 | @@ -936,8 +960,8 @@ | |||
1378 | 936 | 960 | ||
1379 | 937 | Now, let's add 'translation-credits' message to a different POTemplate: | 961 | Now, let's add 'translation-credits' message to a different POTemplate: |
1380 | 938 | 962 | ||
1383 | 939 | >>> new_credits = evolution_potemplate.createMessageSetFromText( | 963 | >>> new_credits = evolution_potemplate.createMessageSetFromText( |
1384 | 940 | ... singular_text=u'translation-credits', plural_text=None) | 964 | ... singular_text=u'translation-credits', plural_text=None) |
1385 | 941 | 965 | ||
1386 | 942 | However, this one doesn't show up as external suggestion for Spanish. | 966 | However, this one doesn't show up as external suggestion for Spanish. |
1387 | 943 | 967 | ||
1388 | @@ -946,7 +970,8 @@ | |||
1389 | 946 | >>> new_credits.getExternallySuggestedTranslationMessages(spanish) | 970 | >>> new_credits.getExternallySuggestedTranslationMessages(spanish) |
1390 | 947 | [] | 971 | [] |
1391 | 948 | 972 | ||
1393 | 949 | == POTMsgSet.setSequence == | 973 | POTMsgSet.setSequence |
1394 | 974 | --------------------- | ||
1395 | 950 | 975 | ||
1396 | 951 | Finally, the new `IPOTMsgSet` should have an entry in the | 976 | Finally, the new `IPOTMsgSet` should have an entry in the |
1397 | 952 | `TranslationTemplateItem` table once we assign a sequence number. | 977 | `TranslationTemplateItem` table once we assign a sequence number. |
1398 | @@ -998,7 +1023,8 @@ | |||
1399 | 998 | 0 | 1023 | 0 |
1400 | 999 | 1024 | ||
1401 | 1000 | 1025 | ||
1403 | 1001 | == POTMsgSet.flags == | 1026 | POTMsgSet.flags |
1404 | 1027 | --------------- | ||
1405 | 1002 | 1028 | ||
1406 | 1003 | The gettext format can associate flags with a POTMsgSet, such as "this | 1029 | The gettext format can associate flags with a POTMsgSet, such as "this |
1407 | 1004 | is a fuzzily matched message" or "this message follows C format-string | 1030 | is a fuzzily matched message" or "this message follows C format-string |
1408 | 1005 | 1031 | ||
1409 | === modified file 'lib/lp/translations/doc/translationimportqueue.txt' | |||
1410 | --- lib/lp/translations/doc/translationimportqueue.txt 2010-07-13 21:49:34 +0000 | |||
1411 | +++ lib/lp/translations/doc/translationimportqueue.txt 2010-09-09 15:34:46 +0000 | |||
1412 | @@ -1,4 +1,5 @@ | |||
1414 | 1 | = TranslationImportQueueEntry = | 1 | TranslationImportQueueEntry |
1415 | 2 | =========================== | ||
1416 | 2 | 3 | ||
1417 | 3 | The TranslationImportQueueEntry is an entry of the queue that will be imported | 4 | The TranslationImportQueueEntry is an entry of the queue that will be imported |
1418 | 4 | into Rosetta. | 5 | into Rosetta. |
1419 | @@ -14,7 +15,8 @@ | |||
1420 | 14 | ... store.find(TranslationImportQueueEntry).remove() | 15 | ... store.find(TranslationImportQueueEntry).remove() |
1421 | 15 | 16 | ||
1422 | 16 | 17 | ||
1424 | 17 | == getGuessedPOFile == | 18 | getGuessedPOFile |
1425 | 19 | ---------------- | ||
1426 | 18 | 20 | ||
1427 | 19 | This property gives us the IPOFile where we think we should import this entry. | 21 | This property gives us the IPOFile where we think we should import this entry. |
1428 | 20 | 22 | ||
1429 | @@ -59,7 +61,8 @@ | |||
1430 | 59 | ... u'po/sr.po', 'foo', True, rosetta_experts, | 61 | ... u'po/sr.po', 'foo', True, rosetta_experts, |
1431 | 60 | ... productseries=evolution_productseries) | 62 | ... productseries=evolution_productseries) |
1432 | 61 | 63 | ||
1434 | 62 | This entry has no information about the IPOFile where it should be attached to: | 64 | This entry has no information about the IPOFile where it should be attached |
1435 | 65 | to: | ||
1436 | 63 | 66 | ||
1437 | 64 | >>> entry.import_into is None | 67 | >>> entry.import_into is None |
1438 | 65 | True | 68 | True |
1439 | @@ -82,7 +85,8 @@ | |||
1440 | 82 | ... sourcepackagename=evolution_sourcepackagename) | 85 | ... sourcepackagename=evolution_sourcepackagename) |
1441 | 83 | >>> transaction.commit() | 86 | >>> transaction.commit() |
1442 | 84 | 87 | ||
1444 | 85 | This entry has no information about the IPOFile where it should be attached to: | 88 | This entry has no information about the IPOFile where it should be attached |
1445 | 89 | to: | ||
1446 | 86 | 90 | ||
1447 | 87 | >>> entry.import_into is None | 91 | >>> entry.import_into is None |
1448 | 88 | True | 92 | True |
1449 | @@ -225,7 +229,8 @@ | |||
1450 | 225 | >>> pofile.path | 229 | >>> pofile.path |
1451 | 226 | u'po/sr.po' | 230 | u'po/sr.po' |
1452 | 227 | 231 | ||
1454 | 228 | === getGuessedPOFile with KDE === | 232 | getGuessedPOFile with KDE |
1455 | 233 | ......................... | ||
1456 | 229 | 234 | ||
1457 | 230 | Official KDE packages have a non standard layout where the .pot files are | 235 | Official KDE packages have a non standard layout where the .pot files are |
1458 | 231 | stored inside the sourcepackage with the binaries that will use it and the | 236 | stored inside the sourcepackage with the binaries that will use it and the |
1459 | @@ -363,7 +368,8 @@ | |||
1460 | 363 | >>> transaction.abort() | 368 | >>> transaction.abort() |
1461 | 364 | 369 | ||
1462 | 365 | 370 | ||
1464 | 366 | === getGuessedPOFile with KOffice === | 371 | getGuessedPOFile with KOffice |
1465 | 372 | ............................. | ||
1466 | 367 | 373 | ||
1467 | 368 | Like official KDE packages, KOffice stores the .pot and .po files in different | 374 | Like official KDE packages, KOffice stores the .pot and .po files in different |
1468 | 369 | packages, the only difference it has is that there is just one source package | 375 | packages, the only difference it has is that there is just one source package |
1469 | @@ -403,7 +409,9 @@ | |||
1470 | 403 | 409 | ||
1471 | 404 | And set this entry as already imported. | 410 | And set this entry as already imported. |
1472 | 405 | 411 | ||
1474 | 406 | >>> koffice_pot_entry.setStatus(RosettaImportStatus.IMPORTED, rosetta_experts) | 412 | >>> koffice_pot_entry.setStatus( |
1475 | 413 | ... RosettaImportStatus.IMPORTED, | ||
1476 | 414 | ... rosetta_experts) | ||
1477 | 407 | >>> flush_database_updates() | 415 | >>> flush_database_updates() |
1478 | 408 | 416 | ||
1479 | 409 | Let's attach a .po file from koffice-l10n | 417 | Let's attach a .po file from koffice-l10n |
1480 | @@ -449,7 +457,8 @@ | |||
1481 | 449 | >>> transaction.abort() | 457 | >>> transaction.abort() |
1482 | 450 | 458 | ||
1483 | 451 | 459 | ||
1485 | 452 | === getGuessedPOFile with .po files in different directories === | 460 | getGuessedPOFile with .po files in different directories |
1486 | 461 | ........................................................ | ||
1487 | 453 | 462 | ||
1488 | 454 | Some packages have translations and templates inside the same package, but | 463 | Some packages have translations and templates inside the same package, but |
1489 | 455 | they don't have them inside the same directory. The layout is: | 464 | they don't have them inside the same directory. The layout is: |
1490 | @@ -500,7 +509,9 @@ | |||
1491 | 500 | 509 | ||
1492 | 501 | And set this entry as already imported. | 510 | And set this entry as already imported. |
1493 | 502 | 511 | ||
1495 | 503 | >>> adept_pot_entry.setStatus(RosettaImportStatus.IMPORTED, rosetta_experts) | 512 | >>> adept_pot_entry.setStatus( |
1496 | 513 | ... RosettaImportStatus.IMPORTED, | ||
1497 | 514 | ... rosetta_experts) | ||
1498 | 504 | >>> flush_database_updates() | 515 | >>> flush_database_updates() |
1499 | 505 | 516 | ||
1500 | 506 | Let's attach a .po file now. | 517 | Let's attach a .po file now. |
1501 | @@ -551,7 +562,9 @@ | |||
1502 | 551 | 562 | ||
1503 | 552 | And set this entry as already imported. | 563 | And set this entry as already imported. |
1504 | 553 | 564 | ||
1506 | 554 | >>> ktorrent_pot_entry.setStatus(RosettaImportStatus.IMPORTED, rosetta_experts) | 565 | >>> ktorrent_pot_entry.setStatus( |
1507 | 566 | ... RosettaImportStatus.IMPORTED, | ||
1508 | 567 | ... rosetta_experts) | ||
1509 | 555 | >>> flush_database_updates() | 568 | >>> flush_database_updates() |
1510 | 556 | 569 | ||
1511 | 557 | Let's attach a .po file now. | 570 | Let's attach a .po file now. |
1512 | @@ -739,7 +752,8 @@ | |||
1513 | 739 | >>> transaction.abort() | 752 | >>> transaction.abort() |
1514 | 740 | 753 | ||
1515 | 741 | 754 | ||
1517 | 742 | == executeOptimisticBlock == | 755 | executeOptimisticBlock |
1518 | 756 | ---------------------- | ||
1519 | 743 | 757 | ||
1520 | 744 | This method looks on the queue to find entries to block based on other .pot | 758 | This method looks on the queue to find entries to block based on other .pot |
1521 | 745 | entries that are stored on the same directory and are already blocked. | 759 | entries that are stored on the same directory and are already blocked. |
1522 | @@ -803,7 +817,8 @@ | |||
1523 | 803 | True | 817 | True |
1524 | 804 | 818 | ||
1525 | 805 | On the other hand, this other one is for the same | 819 | On the other hand, this other one is for the same |
1527 | 806 | distroseries/sourcepackagename than the .pot file we have so it's also blocked. | 820 | distroseries/sourcepackagename than the .pot file we have so it's also |
1528 | 821 | blocked. | ||
1529 | 807 | 822 | ||
1530 | 808 | >>> entry4 = translationimportqueue.get(4) | 823 | >>> entry4 = translationimportqueue.get(4) |
1531 | 809 | >>> entry4.path | 824 | >>> entry4.path |
1532 | @@ -820,7 +835,8 @@ | |||
1533 | 820 | True | 835 | True |
1534 | 821 | 836 | ||
1535 | 822 | 837 | ||
1537 | 823 | == getElapsedTimeText == | 838 | getElapsedTimeText |
1538 | 839 | ----------------- | ||
1539 | 824 | 840 | ||
1540 | 825 | This method returns a string representing the elapsed time since the entry | 841 | This method returns a string representing the elapsed time since the entry |
1541 | 826 | was added to the queue. | 842 | was added to the queue. |
1542 | @@ -860,13 +876,15 @@ | |||
1543 | 860 | '2 days 13 hours 5 minutes ago' | 876 | '2 days 13 hours 5 minutes ago' |
1544 | 861 | 877 | ||
1545 | 862 | 878 | ||
1547 | 863 | = TranslationImportQueue = | 879 | TranslationImportQueue |
1548 | 880 | ====================== | ||
1549 | 864 | 881 | ||
1550 | 865 | The translation import queue is the place where the new translation imports | 882 | The translation import queue is the place where the new translation imports |
1551 | 866 | end before being imported into Rosetta. | 883 | end before being imported into Rosetta. |
1552 | 867 | 884 | ||
1553 | 868 | 885 | ||
1555 | 869 | == getTemplatesOnSameDirectory == | 886 | getTemplatesOnSameDirectory |
1556 | 887 | --------------------------- | ||
1557 | 870 | 888 | ||
1558 | 871 | This method allows us to get the set of .pot files we have on the same | 889 | This method allows us to get the set of .pot files we have on the same |
1559 | 872 | directory that a given entry. | 890 | directory that a given entry. |
1560 | @@ -905,7 +923,8 @@ | |||
1561 | 905 | 0 | 923 | 0 |
1562 | 906 | 924 | ||
1563 | 907 | 925 | ||
1565 | 908 | == getRequestTargets == | 926 | getRequestTargets |
1566 | 927 | ----------------- | ||
1567 | 909 | 928 | ||
1568 | 910 | >>> # Helper functions | 929 | >>> # Helper functions |
1569 | 911 | >>> def get_target_names(status=None): | 930 | >>> def get_target_names(status=None): |
1570 | @@ -1069,7 +1088,8 @@ | |||
1571 | 1069 | firefox Mozilla Firefox | 1088 | firefox Mozilla Firefox |
1572 | 1070 | ubuntu/hoary Hoary | 1089 | ubuntu/hoary Hoary |
1573 | 1071 | 1090 | ||
1575 | 1072 | == addOrUpdateEntry() == | 1091 | addOrUpdateEntry() |
1576 | 1092 | ------------------ | ||
1577 | 1073 | 1093 | ||
1578 | 1074 | addOrUpdateEntry adds a new entry to the import queue so we can handle it | 1094 | addOrUpdateEntry adds a new entry to the import queue so we can handle it |
1579 | 1075 | later with poimport script. | 1095 | later with poimport script. |
1580 | @@ -1264,7 +1284,8 @@ | |||
1581 | 1264 | >>> print entry.content.read() | 1284 | >>> print entry.content.read() |
1582 | 1265 | New bar content | 1285 | New bar content |
1583 | 1266 | 1286 | ||
1585 | 1267 | = Filename filters = | 1287 | Filename filters |
1586 | 1288 | ================ | ||
1587 | 1268 | 1289 | ||
1588 | 1269 | A tarball doesn't always have everything in quite the right place. If | 1290 | A tarball doesn't always have everything in quite the right place. If |
1589 | 1270 | you need to manipulate the file paths within a tarball before the files | 1291 | you need to manipulate the file paths within a tarball before the files |
1590 | @@ -1307,7 +1328,8 @@ | |||
1591 | 1307 | netapplet | None | new-directory/fr.po | 1328 | netapplet | None | new-directory/fr.po |
1592 | 1308 | 1329 | ||
1593 | 1309 | 1330 | ||
1595 | 1310 | = Invalid data = | 1331 | Invalid data |
1596 | 1332 | ============ | ||
1597 | 1311 | 1333 | ||
1598 | 1312 | If administrators fail to correct certain errors in requests while approving | 1334 | If administrators fail to correct certain errors in requests while approving |
1599 | 1313 | them, and the admin user interface mistakenly accepts the approval, we may | 1335 | them, and the admin user interface mistakenly accepts the approval, we may |
1600 | @@ -1385,7 +1407,8 @@ | |||
1601 | 1385 | >>> clear_queue(translationimportqueue) | 1407 | >>> clear_queue(translationimportqueue) |
1602 | 1386 | 1408 | ||
1603 | 1387 | 1409 | ||
1605 | 1388 | == getRequestTargets output ordering == | 1410 | getRequestTargets output ordering |
1606 | 1411 | --------------------------------- | ||
1607 | 1389 | 1412 | ||
1608 | 1390 | The queue is populated with a wild mix of requests: for packages in | 1413 | The queue is populated with a wild mix of requests: for packages in |
1609 | 1391 | different release series of Ubuntu, for packages in different distros, | 1414 | different release series of Ubuntu, for packages in different distros, |
1610 | @@ -1472,7 +1495,8 @@ | |||
1611 | 1472 | evolution Evolution | 1495 | evolution Evolution |
1612 | 1473 | 1496 | ||
1613 | 1474 | 1497 | ||
1615 | 1475 | == cleanUpQueue == | 1498 | cleanUpQueue |
1616 | 1499 | ------------ | ||
1617 | 1476 | 1500 | ||
1618 | 1477 | The queue is cleaned up regularly. | 1501 | The queue is cleaned up regularly. |
1619 | 1478 | 1502 | ||
1620 | @@ -1489,7 +1513,8 @@ | |||
1621 | 1489 | 0 | 1513 | 0 |
1622 | 1490 | 1514 | ||
1623 | 1491 | 1515 | ||
1625 | 1492 | === State and Age === | 1516 | State and Age |
1626 | 1517 | ............. | ||
1627 | 1493 | 1518 | ||
1628 | 1494 | Entries can be cleaned up because they have been in a specific state for | 1519 | Entries can be cleaned up because they have been in a specific state for |
1629 | 1495 | at least a specified period of time. | 1520 | at least a specified period of time. |
1630 | @@ -1516,18 +1541,22 @@ | |||
1631 | 1516 | >>> print_queue_entries(translationimportqueue) | 1541 | >>> print_queue_entries(translationimportqueue) |
1632 | 1517 | 1542 | ||
1633 | 1518 | 1543 | ||
1635 | 1519 | === Deactivated Products === | 1544 | Deactivated Products |
1636 | 1545 | .................... | ||
1637 | 1520 | 1546 | ||
1638 | 1521 | Another reason for deleting entries is that they belong to products that | 1547 | Another reason for deleting entries is that they belong to products that |
1639 | 1522 | have been deactivated. | 1548 | have been deactivated. |
1640 | 1523 | 1549 | ||
1641 | 1524 | A user sets up Jokosher for translation, and uploads a template. | 1550 | A user sets up Jokosher for translation, and uploads a template. |
1642 | 1525 | 1551 | ||
1643 | 1552 | >>> from lp.app.enums import ServiceUsage | ||
1644 | 1553 | |||
1645 | 1526 | >>> jokosher = productset['jokosher'] | 1554 | >>> jokosher = productset['jokosher'] |
1646 | 1527 | >>> jokosher_trunk = jokosher.getSeries('trunk') | 1555 | >>> jokosher_trunk = jokosher.getSeries('trunk') |
1648 | 1528 | >>> jokosher.official_rosetta = True | 1556 | >>> jokosher.translations_usage = ServiceUsage.LAUNCHPAD |
1649 | 1529 | >>> syncUpdate(jokosher) | 1557 | >>> syncUpdate(jokosher) |
1651 | 1530 | >>> jokosher_subset = potemplateset.getSubset(productseries=jokosher_trunk) | 1558 | >>> jokosher_subset = potemplateset.getSubset( |
1652 | 1559 | ... productseries=jokosher_trunk) | ||
1653 | 1531 | >>> template = jokosher_subset.new( | 1560 | >>> template = jokosher_subset.new( |
1654 | 1532 | ... 'jokosher', 'jokosher', 'jokosher.pot', rosetta_experts) | 1561 | ... 'jokosher', 'jokosher', 'jokosher.pot', rosetta_experts) |
1655 | 1533 | >>> syncUpdate(template) | 1562 | >>> syncUpdate(template) |
1656 | 1534 | 1563 | ||
1657 | === modified file 'lib/lp/translations/doc/translationmessage-destroy.txt' | |||
1658 | --- lib/lp/translations/doc/translationmessage-destroy.txt 2009-07-02 17:16:50 +0000 | |||
1659 | +++ lib/lp/translations/doc/translationmessage-destroy.txt 2010-09-09 15:34:46 +0000 | |||
1660 | @@ -1,4 +1,5 @@ | |||
1662 | 1 | == destroySelf == | 1 | destroySelf |
1663 | 2 | =========== | ||
1664 | 2 | 3 | ||
1665 | 3 | (Note: this test runs as rosettaadmin to obtain the necessary | 4 | (Note: this test runs as rosettaadmin to obtain the necessary |
1666 | 4 | privileges) | 5 | privileges) |
1667 | @@ -26,7 +27,8 @@ | |||
1668 | 26 | SQLObjectNotFound:... | 27 | SQLObjectNotFound:... |
1669 | 27 | 28 | ||
1670 | 28 | 29 | ||
1672 | 29 | == POFileTranslator update on remove == | 30 | POFileTranslator update on remove |
1673 | 31 | ================================= | ||
1674 | 30 | 32 | ||
1675 | 31 | In two sharing POTemplates with one shared POTMsgSet with one shared | 33 | In two sharing POTemplates with one shared POTMsgSet with one shared |
1676 | 32 | translation, we get two POFileTranslator records for each of the POFiles. | 34 | translation, we get two POFileTranslator records for each of the POFiles. |
1677 | @@ -35,16 +37,17 @@ | |||
1678 | 35 | >>> # a global 'postgres' permission which allows everything. | 37 | >>> # a global 'postgres' permission which allows everything. |
1679 | 36 | >>> LaunchpadZopelessLayer.switchDbUser('postgres') | 38 | >>> LaunchpadZopelessLayer.switchDbUser('postgres') |
1680 | 37 | >>> from canonical.database.sqlbase import sqlvalues | 39 | >>> from canonical.database.sqlbase import sqlvalues |
1681 | 40 | >>> from lp.app.enums import ServiceUsage | ||
1682 | 38 | >>> from lp.translations.model.pofiletranslator import POFileTranslator | 41 | >>> from lp.translations.model.pofiletranslator import POFileTranslator |
1683 | 39 | >>> from lp.testing.factory import LaunchpadObjectFactory | 42 | >>> from lp.testing.factory import LaunchpadObjectFactory |
1684 | 40 | >>> factory = LaunchpadObjectFactory() | 43 | >>> factory = LaunchpadObjectFactory() |
1685 | 41 | 44 | ||
1687 | 42 | >>> foo = factory.makeProduct() | 45 | >>> foo = factory.makeProduct( |
1688 | 46 | ... translations_usage=ServiceUsage.LAUNCHPAD) | ||
1689 | 43 | >>> foo_devel = factory.makeProductSeries( | 47 | >>> foo_devel = factory.makeProductSeries( |
1690 | 44 | ... name='devel', product=foo) | 48 | ... name='devel', product=foo) |
1691 | 45 | >>> foo_stable = factory.makeProductSeries( | 49 | >>> foo_stable = factory.makeProductSeries( |
1692 | 46 | ... name='stable', product=foo) | 50 | ... name='stable', product=foo) |
1693 | 47 | >>> foo.official_rosetta = True | ||
1694 | 48 | >>> devel_potemplate = factory.makePOTemplate( | 51 | >>> devel_potemplate = factory.makePOTemplate( |
1695 | 49 | ... productseries=foo_devel, name="messages") | 52 | ... productseries=foo_devel, name="messages") |
1696 | 50 | >>> stable_potemplate = factory.makePOTemplate(foo_stable, | 53 | >>> stable_potemplate = factory.makePOTemplate(foo_stable, |
1697 | @@ -56,7 +59,9 @@ | |||
1698 | 56 | >>> potmsgset = factory.makePOTMsgSet(devel_potemplate, sequence=1) | 59 | >>> potmsgset = factory.makePOTMsgSet(devel_potemplate, sequence=1) |
1699 | 57 | >>> potmsgset.setSequence(stable_potemplate, 1) | 60 | >>> potmsgset.setSequence(stable_potemplate, 1) |
1700 | 58 | >>> tm = factory.makeTranslationMessage( | 61 | >>> tm = factory.makeTranslationMessage( |
1702 | 59 | ... pofile=devel_sr_pofile, potmsgset=potmsgset, translations=[u"blah"]) | 62 | ... pofile=devel_sr_pofile, |
1703 | 63 | ... potmsgset=potmsgset, | ||
1704 | 64 | ... translations=[u"blah"]) | ||
1705 | 60 | >>> print POFileTranslator.select( | 65 | >>> print POFileTranslator.select( |
1706 | 61 | ... "latest_message=%s" % sqlvalues(tm)).count() | 66 | ... "latest_message=%s" % sqlvalues(tm)).count() |
1707 | 62 | 2 | 67 | 2 |
1708 | 63 | 68 | ||
1709 | === modified file 'lib/lp/translations/doc/translations-export-to-branch.txt' | |||
1710 | --- lib/lp/translations/doc/translations-export-to-branch.txt 2010-07-20 17:50:45 +0000 | |||
1711 | +++ lib/lp/translations/doc/translations-export-to-branch.txt 2010-09-09 15:34:46 +0000 | |||
1712 | @@ -1,4 +1,5 @@ | |||
1714 | 1 | = Exporting translations to a bzr branch = | 1 | Exporting translations to a bzr branch |
1715 | 2 | ====================================== | ||
1716 | 2 | 3 | ||
1717 | 3 | The translations-export-to-branch script visits all ProductSeries with a | 4 | The translations-export-to-branch script visits all ProductSeries with a |
1718 | 4 | translations_branch set, and for each, exports the series' translations | 5 | translations_branch set, and for each, exports the series' translations |
1719 | @@ -76,10 +77,11 @@ | |||
1720 | 76 | branch. | 77 | branch. |
1721 | 77 | 78 | ||
1722 | 78 | >>> from zope.security.proxy import removeSecurityProxy | 79 | >>> from zope.security.proxy import removeSecurityProxy |
1723 | 80 | >>> from lp.app.enums import ServiceUsage | ||
1724 | 79 | 81 | ||
1725 | 80 | >>> gazblachko = removeSecurityProxy(factory.makeProduct( | 82 | >>> gazblachko = removeSecurityProxy(factory.makeProduct( |
1726 | 81 | ... name='gazblachko', displayname='Gazblachko')) | 83 | ... name='gazblachko', displayname='Gazblachko')) |
1728 | 82 | >>> gazblachko.official_rosetta = True | 84 | >>> gazblachko.translations_usage = ServiceUsage.LAUNCHPAD |
1729 | 83 | 85 | ||
1730 | 84 | >>> branch = removeSecurityProxy(factory.makeBranch( | 86 | >>> branch = removeSecurityProxy(factory.makeBranch( |
1731 | 85 | ... name='gazpo', owner=gazblachko.owner, product=gazblachko)) | 87 | ... name='gazpo', owner=gazblachko.owner, product=gazblachko)) |
1732 | @@ -162,13 +164,13 @@ | |||
1733 | 162 | When Gazblachko stops using Launchpad for Translations, the exports stop | 164 | When Gazblachko stops using Launchpad for Translations, the exports stop |
1734 | 163 | also. | 165 | also. |
1735 | 164 | 166 | ||
1737 | 165 | >>> gazblachko.official_rosetta = False | 167 | >>> gazblachko.translations_usage = ServiceUsage.NOT_APPLICABLE |
1738 | 166 | >>> transaction.commit() | 168 | >>> transaction.commit() |
1739 | 167 | >>> script.main() | 169 | >>> script.main() |
1740 | 168 | INFO Exporting to translations branches. | 170 | INFO Exporting to translations branches. |
1741 | 169 | INFO Processed 0 item(s); 0 failure(s), 0 unpushed branch(es). | 171 | INFO Processed 0 item(s); 0 failure(s), 0 unpushed branch(es). |
1742 | 170 | 172 | ||
1744 | 171 | >>> gazblachko.official_rosetta = True | 173 | >>> gazblachko.translations_usage = ServiceUsage.LAUNCHPAD |
1745 | 172 | >>> transaction.commit() | 174 | >>> transaction.commit() |
1746 | 173 | 175 | ||
1747 | 174 | 176 | ||
1748 | @@ -271,7 +273,8 @@ | |||
1749 | 271 | collected for import yet. | 273 | collected for import yet. |
1750 | 272 | 274 | ||
1751 | 273 | 275 | ||
1753 | 274 | === Branch races === | 276 | Branch races |
1754 | 277 | ............ | ||
1755 | 275 | 278 | ||
1756 | 276 | Any translations coming in through a branch push are safe once they're | 279 | Any translations coming in through a branch push are safe once they're |
1757 | 277 | in the translations import queue. So the race window spans from the | 280 | in the translations import queue. So the race window spans from the |
1758 | @@ -299,7 +302,8 @@ | |||
1759 | 299 | INFO Processed 1 item(s); 1 failure(s), 0 unpushed branch(es). | 302 | INFO Processed 1 item(s); 1 failure(s), 0 unpushed branch(es). |
1760 | 300 | 303 | ||
1761 | 301 | 304 | ||
1763 | 302 | === Pending imports from same branch === | 305 | Pending imports from same branch |
1764 | 306 | ................................ | ||
1765 | 303 | 307 | ||
1766 | 304 | Another race condition is detected by the script itself: there may be | 308 | Another race condition is detected by the script itself: there may be |
1767 | 305 | pending translations BranchJobs on the branch. | 309 | pending translations BranchJobs on the branch. |
1768 | 306 | 310 | ||
1769 | === modified file 'lib/lp/translations/doc/translationsoverview.txt' | |||
1770 | --- lib/lp/translations/doc/translationsoverview.txt 2009-07-24 12:55:03 +0000 | |||
1771 | +++ lib/lp/translations/doc/translationsoverview.txt 2010-09-09 15:34:46 +0000 | |||
1772 | @@ -1,4 +1,5 @@ | |||
1774 | 1 | = TranslationsOverview = | 1 | TranslationsOverview |
1775 | 2 | ==================== | ||
1776 | 2 | 3 | ||
1777 | 3 | This class provides a basic overview of the Launchpad Translations component. | 4 | This class provides a basic overview of the Launchpad Translations component. |
1778 | 4 | It includes data such as projects which have so far received the most | 5 | It includes data such as projects which have so far received the most |
1779 | @@ -45,14 +46,16 @@ | |||
1780 | 45 | 18 | 46 | 18 |
1781 | 46 | 47 | ||
1782 | 47 | 48 | ||
1784 | 48 | == _normalizeSizes == | 49 | _normalizeSizes |
1785 | 50 | --------------- | ||
1786 | 49 | 51 | ||
1787 | 50 | This private method accepts a list of tuples (object, size) and | 52 | This private method accepts a list of tuples (object, size) and |
1788 | 51 | normalizes `size` values into the range [MINIMUM_SIZE, MAXIMUM_SIZE]. | 53 | normalizes `size` values into the range [MINIMUM_SIZE, MAXIMUM_SIZE]. |
1789 | 52 | 54 | ||
1790 | 53 | >>> test_list = [('one', 3), ('two', 0), ('three', 1)] | 55 | >>> test_list = [('one', 3), ('two', 0), ('three', 1)] |
1791 | 54 | >>> from zope.security.proxy import removeSecurityProxy | 56 | >>> from zope.security.proxy import removeSecurityProxy |
1793 | 55 | >>> result = removeSecurityProxy(overview)._normalizeSizes(test_list, 0, 3) | 57 | >>> naked_overview = removeSecurityProxy(overview) |
1794 | 58 | >>> result = naked_overview._normalizeSizes(test_list, 0, 3) | ||
1795 | 56 | >>> for pillar in result: | 59 | >>> for pillar in result: |
1796 | 57 | ... print "%s: %d" % (pillar['pillar'], pillar['weight']) | 60 | ... print "%s: %d" % (pillar['pillar'], pillar['weight']) |
1797 | 58 | one: 18 | 61 | one: 18 |
1798 | @@ -60,7 +63,8 @@ | |||
1799 | 60 | three: 13 | 63 | three: 13 |
1800 | 61 | 64 | ||
1801 | 62 | 65 | ||
1803 | 63 | == Getting the most translated pillars == | 66 | Getting the most translated pillars |
1804 | 67 | ----------------------------------- | ||
1805 | 64 | 68 | ||
1806 | 65 | Method getMostTranslatedPillars() returns a list of dicts listing | 69 | Method getMostTranslatedPillars() returns a list of dicts listing |
1807 | 66 | pillars with most translations karma so far, along with a relative | 70 | pillars with most translations karma so far, along with a relative |
1808 | @@ -104,10 +108,13 @@ | |||
1809 | 104 | 108 | ||
1810 | 105 | Adding a little bit of karma to upstart will put it in the list as well. | 109 | Adding a little bit of karma to upstart will put it in the list as well. |
1811 | 106 | 110 | ||
1812 | 111 | >>> from lp.app.enums import ServiceUsage | ||
1813 | 112 | |||
1814 | 107 | >>> start_karma_update() | 113 | >>> start_karma_update() |
1815 | 108 | >>> upstart = product_set.getByName('upstart') | 114 | >>> upstart = product_set.getByName('upstart') |
1816 | 109 | >>> upstart_id = upstart.id | 115 | >>> upstart_id = upstart.id |
1818 | 110 | >>> removeSecurityProxy(upstart).official_rosetta = True | 116 | >>> naked_upstart = removeSecurityProxy(upstart) |
1819 | 117 | >>> naked_upstart.translations_usage = ServiceUsage.LAUNCHPAD | ||
1820 | 111 | >>> cache_entry = karmacachemanager.new( | 118 | >>> cache_entry = karmacachemanager.new( |
1821 | 112 | ... 50, carlos.id, translations.id, product_id=upstart_id) | 119 | ... 50, carlos.id, translations.id, product_id=upstart_id) |
1822 | 113 | >>> finish_karma_update() | 120 | >>> finish_karma_update() |
1823 | @@ -153,7 +160,8 @@ | |||
1824 | 153 | Ubuntu: 24 | 160 | Ubuntu: 24 |
1825 | 154 | 161 | ||
1826 | 155 | 162 | ||
1828 | 156 | == Zero karma == | 163 | Zero karma |
1829 | 164 | ---------- | ||
1830 | 157 | 165 | ||
1831 | 158 | Sometimes a pillar appears to be listed in the karma cache with zero | 166 | Sometimes a pillar appears to be listed in the karma cache with zero |
1832 | 159 | karma. Our algorithm takes the logarithm of its karma, but it's | 167 | karma. Our algorithm takes the logarithm of its karma, but it's |
1833 | 160 | 168 | ||
1834 | === modified file 'lib/lp/translations/model/potemplate.py' | |||
1835 | --- lib/lp/translations/model/potemplate.py 2010-09-03 03:12:39 +0000 | |||
1836 | +++ lib/lp/translations/model/potemplate.py 2010-09-09 15:34:46 +0000 | |||
1837 | @@ -64,6 +64,7 @@ | |||
1838 | 64 | IMasterStore, | 64 | IMasterStore, |
1839 | 65 | IStore, | 65 | IStore, |
1840 | 66 | ) | 66 | ) |
1841 | 67 | from lp.app.enums import service_uses_launchpad | ||
1842 | 67 | from lp.app.errors import NotFoundError | 68 | from lp.app.errors import NotFoundError |
1843 | 68 | from lp.registry.interfaces.person import validate_public_person | 69 | from lp.registry.interfaces.person import validate_public_person |
1844 | 69 | from lp.registry.model.sourcepackagename import SourcePackageName | 70 | from lp.registry.model.sourcepackagename import SourcePackageName |
1845 | @@ -1322,8 +1323,7 @@ | |||
1846 | 1322 | preferred_matches = [ | 1323 | preferred_matches = [ |
1847 | 1323 | match | 1324 | match |
1848 | 1324 | for match in matches | 1325 | for match in matches |
1851 | 1325 | if match.from_sourcepackagename == sourcepackagename | 1326 | if match.from_sourcepackagename == sourcepackagename] |
1850 | 1326 | ] | ||
1852 | 1327 | 1327 | ||
1853 | 1328 | if len(preferred_matches) == 1: | 1328 | if len(preferred_matches) == 1: |
1854 | 1329 | return preferred_matches[0] | 1329 | return preferred_matches[0] |
1855 | @@ -1378,6 +1378,9 @@ | |||
1856 | 1378 | 1378 | ||
1857 | 1379 | def populateSuggestivePOTemplatesCache(self): | 1379 | def populateSuggestivePOTemplatesCache(self): |
1858 | 1380 | """See `IPOTemplateSet`.""" | 1380 | """See `IPOTemplateSet`.""" |
1859 | 1381 | # XXX j.c.sackett 2010-08-30 bug=627631 Once data migration has | ||
1860 | 1382 | # happened for the usage enums, this sql needs to be updated to | ||
1861 | 1383 | # check for the translations_usage, not official_rosetta. | ||
1862 | 1381 | return IMasterStore(POTemplate).execute(""" | 1384 | return IMasterStore(POTemplate).execute(""" |
1863 | 1382 | INSERT INTO SuggestivePOTemplate ( | 1385 | INSERT INTO SuggestivePOTemplate ( |
1864 | 1383 | SELECT POTemplate.id | 1386 | SELECT POTemplate.id |
1865 | @@ -1437,15 +1440,13 @@ | |||
1866 | 1437 | if self.product: | 1440 | if self.product: |
1867 | 1438 | subsets = [ | 1441 | subsets = [ |
1868 | 1439 | self.potemplateset.getSubset(productseries=series) | 1442 | self.potemplateset.getSubset(productseries=series) |
1871 | 1440 | for series in self.product.series | 1443 | for series in self.product.series] |
1870 | 1441 | ] | ||
1872 | 1442 | else: | 1444 | else: |
1873 | 1443 | subsets = [ | 1445 | subsets = [ |
1874 | 1444 | self.potemplateset.getSubset( | 1446 | self.potemplateset.getSubset( |
1875 | 1445 | distroseries=series, | 1447 | distroseries=series, |
1876 | 1446 | sourcepackagename=self.sourcepackagename) | 1448 | sourcepackagename=self.sourcepackagename) |
1879 | 1447 | for series in self.distribution.series | 1449 | for series in self.distribution.series] |
1878 | 1448 | ] | ||
1880 | 1449 | for subset in subsets: | 1450 | for subset in subsets: |
1881 | 1450 | for template in subset: | 1451 | for template in subset: |
1882 | 1451 | if name_pattern is None or re.match(name_pattern, | 1452 | if name_pattern is None or re.match(name_pattern, |
1883 | @@ -1548,8 +1549,7 @@ | |||
1884 | 1548 | msgset.flags = set([ | 1549 | msgset.flags = set([ |
1885 | 1549 | flag.strip() | 1550 | flag.strip() |
1886 | 1550 | for flag in row.flags_comment.split(',') | 1551 | for flag in row.flags_comment.split(',') |
1889 | 1551 | if flag | 1552 | if flag]) |
1888 | 1552 | ]) | ||
1890 | 1553 | 1553 | ||
1891 | 1554 | # Store the message. | 1554 | # Store the message. |
1892 | 1555 | messages.append(msgset) | 1555 | messages.append(msgset) |
1893 | @@ -1578,8 +1578,9 @@ | |||
1894 | 1578 | collection = self.getTemplatesCollection() | 1578 | collection = self.getTemplatesCollection() |
1895 | 1579 | 1579 | ||
1896 | 1580 | # XXX JeroenVermeulen 2010-07-15 bug=605924: Move the | 1580 | # XXX JeroenVermeulen 2010-07-15 bug=605924: Move the |
1899 | 1581 | # official_rosetta distinction into browser code. | 1581 | # translations_usage distinction into browser code. |
1900 | 1582 | if collection.target_pillar.official_rosetta: | 1582 | pillar = collection.target_pillar |
1901 | 1583 | if service_uses_launchpad(pillar.translations_usage): | ||
1902 | 1583 | return collection.restrictCurrent(current_value) | 1584 | return collection.restrictCurrent(current_value) |
1903 | 1584 | else: | 1585 | else: |
1904 | 1585 | # Product/Distribution does not have translation enabled. | 1586 | # Product/Distribution does not have translation enabled. |
1905 | 1586 | 1587 | ||
1906 | === modified file 'lib/lp/translations/model/potmsgset.py' | |||
1907 | --- lib/lp/translations/model/potmsgset.py 2010-09-06 03:35:47 +0000 | |||
1908 | +++ lib/lp/translations/model/potmsgset.py 2010-09-09 15:34:46 +0000 | |||
1909 | @@ -361,6 +361,9 @@ | |||
1910 | 361 | query = ["(NOT %s)" % in_use_clause] | 361 | query = ["(NOT %s)" % in_use_clause] |
1911 | 362 | query.append('TranslationMessage.language = %s' % sqlvalues(language)) | 362 | query.append('TranslationMessage.language = %s' % sqlvalues(language)) |
1912 | 363 | 363 | ||
1913 | 364 | # XXX j.c.sackett 2010-08-30 bug=627631 Once data migration has | ||
1914 | 365 | # happened for the usage enums, this sql needs to be updated | ||
1915 | 366 | # to check for the translations_usage, not official_rosetta. | ||
1916 | 364 | query.append(''' | 367 | query.append(''' |
1917 | 365 | potmsgset IN ( | 368 | potmsgset IN ( |
1918 | 366 | SELECT POTMsgSet.id | 369 | SELECT POTMsgSet.id |
1919 | @@ -381,7 +384,8 @@ | |||
1920 | 381 | POTMsgSet.id <> %s AND | 384 | POTMsgSet.id <> %s AND |
1921 | 382 | msgid_singular = %s AND | 385 | msgid_singular = %s AND |
1922 | 383 | POTemplate.iscurrent AND | 386 | POTemplate.iscurrent AND |
1924 | 384 | (Product.official_rosetta OR Distribution.official_rosetta) | 387 | (Product.official_rosetta OR |
1925 | 388 | Distribution.official_rosetta) | ||
1926 | 385 | )''' % sqlvalues(self, self.msgid_singular)) | 389 | )''' % sqlvalues(self, self.msgid_singular)) |
1927 | 386 | 390 | ||
1928 | 387 | # Subquery to find the ids of TranslationMessages that are | 391 | # Subquery to find the ids of TranslationMessages that are |
1929 | @@ -396,8 +400,8 @@ | |||
1930 | 396 | for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]) | 400 | for form in xrange(TranslationConstants.MAX_PLURAL_FORMS)]) |
1931 | 397 | ids_query_params = { | 401 | ids_query_params = { |
1932 | 398 | 'msgstrs': msgstrs, | 402 | 'msgstrs': msgstrs, |
1935 | 399 | 'where': ' AND '.join(query) | 403 | 'where': ' AND '.join(query), |
1936 | 400 | } | 404 | } |
1937 | 401 | ids_query = ''' | 405 | ids_query = ''' |
1938 | 402 | SELECT DISTINCT ON (%(msgstrs)s) | 406 | SELECT DISTINCT ON (%(msgstrs)s) |
1939 | 403 | TranslationMessage.id | 407 | TranslationMessage.id |
1940 | @@ -565,8 +569,7 @@ | |||
1941 | 565 | # plural forms. | 569 | # plural forms. |
1942 | 566 | order.extend([ | 570 | order.extend([ |
1943 | 567 | 'msgstr%s NULLS FIRST' % quote(form) | 571 | 'msgstr%s NULLS FIRST' % quote(form) |
1946 | 568 | for form in remaining_plural_forms | 572 | for form in remaining_plural_forms]) |
1945 | 569 | ]) | ||
1947 | 570 | matches = list( | 573 | matches = list( |
1948 | 571 | TranslationMessage.select(' AND '.join(clauses), orderBy=order)) | 574 | TranslationMessage.select(' AND '.join(clauses), orderBy=order)) |
1949 | 572 | 575 | ||
1950 | @@ -722,7 +725,6 @@ | |||
1951 | 722 | if is_imported or new_message == imported_message: | 725 | if is_imported or new_message == imported_message: |
1952 | 723 | new_message.is_imported = True | 726 | new_message.is_imported = True |
1953 | 724 | 727 | ||
1954 | 725 | |||
1955 | 726 | def _isTranslationMessageASuggestion(self, force_suggestion, | 728 | def _isTranslationMessageASuggestion(self, force_suggestion, |
1956 | 727 | pofile, submitter, | 729 | pofile, submitter, |
1957 | 728 | force_edition_rights, is_imported, | 730 | force_edition_rights, is_imported, |
1958 | @@ -1178,4 +1180,3 @@ | |||
1959 | 1178 | """See `IPOTMsgSet`.""" | 1180 | """See `IPOTMsgSet`.""" |
1960 | 1179 | return TranslationTemplateItem.selectBy( | 1181 | return TranslationTemplateItem.selectBy( |
1961 | 1180 | potmsgset=self, orderBy=['id']) | 1182 | potmsgset=self, orderBy=['id']) |
1962 | 1181 | |||
1963 | 1182 | 1183 | ||
1964 | === modified file 'lib/lp/translations/model/translationsoverview.py' | |||
1965 | --- lib/lp/translations/model/translationsoverview.py 2010-08-20 20:31:18 +0000 | |||
1966 | +++ lib/lp/translations/model/translationsoverview.py 2010-09-09 15:34:46 +0000 | |||
1967 | @@ -39,13 +39,15 @@ | |||
1968 | 39 | new_size = int(round( | 39 | new_size = int(round( |
1969 | 40 | real_minimum + | 40 | real_minimum + |
1970 | 41 | (size - offset - real_minimum) * multiplier)) | 41 | (size - offset - real_minimum) * multiplier)) |
1973 | 42 | normalized_sizes.append({'pillar' : pillar, | 42 | normalized_sizes.append({'pillar': pillar, 'weight': new_size}) |
1972 | 43 | 'weight' : new_size }) | ||
1974 | 44 | return normalized_sizes | 43 | return normalized_sizes |
1975 | 45 | 44 | ||
1976 | 46 | def getMostTranslatedPillars(self, limit=50): | 45 | def getMostTranslatedPillars(self, limit=50): |
1977 | 47 | """See `ITranslationsOverview`.""" | 46 | """See `ITranslationsOverview`.""" |
1978 | 48 | 47 | ||
1979 | 48 | # XXX j.c.sackett 2010-08-30 bug=627631 Once data migration has | ||
1980 | 49 | # happened for the usage enums, this sql needs to be updated | ||
1981 | 50 | # to check for the translations_usage, not official_rosetta. | ||
1982 | 49 | query = """ | 51 | query = """ |
1983 | 50 | SELECT LOWER(COALESCE(product_name, distro_name)) AS name, | 52 | SELECT LOWER(COALESCE(product_name, distro_name)) AS name, |
1984 | 51 | product_id, | 53 | product_id, |
1985 | @@ -65,7 +67,8 @@ | |||
1986 | 65 | distribution=distribution.id | 67 | distribution=distribution.id |
1987 | 66 | WHERE category=3 AND | 68 | WHERE category=3 AND |
1988 | 67 | (product IS NOT NULL OR distribution IS NOT NULL) AND | 69 | (product IS NOT NULL OR distribution IS NOT NULL) AND |
1990 | 68 | (product.official_rosetta OR distribution.official_rosetta) | 70 | (product.official_rosetta OR |
1991 | 71 | distribution.official_rosetta) | ||
1992 | 69 | GROUP BY product.displayname, product.id, | 72 | GROUP BY product.displayname, product.id, |
1993 | 70 | distribution.displayname, distribution.id | 73 | distribution.displayname, distribution.id |
1994 | 71 | HAVING SUM(karmavalue) > 0 | 74 | HAVING SUM(karmavalue) > 0 |
1995 | 72 | 75 | ||
1996 | === modified file 'lib/lp/translations/model/translationsperson.py' | |||
1997 | --- lib/lp/translations/model/translationsperson.py 2010-08-27 10:53:40 +0000 | |||
1998 | +++ lib/lp/translations/model/translationsperson.py 2010-09-09 15:34:46 +0000 | |||
1999 | @@ -262,6 +262,10 @@ | |||
2000 | 262 | The added joins may make the overall query non-distinct, so be | 262 | The added joins may make the overall query non-distinct, so be |
2001 | 263 | sure to enforce distinctness. | 263 | sure to enforce distinctness. |
2002 | 264 | """ | 264 | """ |
2003 | 265 | # XXX j.c.sackett 2010-08-30 bug=627631 Once data migration has | ||
2004 | 266 | # happened for the usage enums, this query needs to be updated | ||
2005 | 267 | # to check for the translations_usage, not official_rosetta. | ||
2006 | 268 | |||
2007 | 265 | POTemplateJoin = Join(POTemplate, And( | 269 | POTemplateJoin = Join(POTemplate, And( |
2008 | 266 | POTemplate.id == POFile.potemplateID, | 270 | POTemplate.id == POFile.potemplateID, |
2009 | 267 | POTemplate.iscurrent == True)) | 271 | POTemplate.iscurrent == True)) |
2010 | 268 | 272 | ||
2011 | === modified file 'lib/lp/translations/scripts/translations_to_branch.py' | |||
2012 | --- lib/lp/translations/scripts/translations_to_branch.py 2010-08-20 20:31:18 +0000 | |||
2013 | +++ lib/lp/translations/scripts/translations_to_branch.py 2010-09-09 15:34:46 +0000 | |||
2014 | @@ -306,6 +306,9 @@ | |||
2015 | 306 | 306 | ||
2016 | 307 | self.store = getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR) | 307 | self.store = getUtility(IStoreSelector).get(MAIN_STORE, SLAVE_FLAVOR) |
2017 | 308 | 308 | ||
2018 | 309 | # XXX j.c.sackett 2010-08-30 bug=627631 Once data migration has | ||
2019 | 310 | # happened for the usage enums, this sql needs to be updated to | ||
2020 | 311 | # check for the translations_usage, not official_rosetta. | ||
2021 | 309 | product_join = Join( | 312 | product_join = Join( |
2022 | 310 | ProductSeries, Product, ProductSeries.product == Product.id) | 313 | ProductSeries, Product, ProductSeries.product == Product.id) |
2023 | 311 | productseries = self.store.using(product_join).find( | 314 | productseries = self.store.using(product_join).find( |
2024 | 312 | 315 | ||
2025 | === modified file 'lib/lp/translations/stories/buildfarm/xx-build-summary.txt' | |||
2026 | --- lib/lp/translations/stories/buildfarm/xx-build-summary.txt 2010-07-20 17:50:45 +0000 | |||
2027 | +++ lib/lp/translations/stories/buildfarm/xx-build-summary.txt 2010-09-09 15:34:46 +0000 | |||
2028 | @@ -1,9 +1,11 @@ | |||
2030 | 1 | = TranslationTemplatesBuildJob Build Summary = | 1 | TranslationTemplatesBuildJob Build Summary |
2031 | 2 | ========================================== | ||
2032 | 2 | 3 | ||
2033 | 3 | The builders UI can show TranslationTemplateBuildJobs, although they | 4 | The builders UI can show TranslationTemplateBuildJobs, although they |
2034 | 4 | look a little different from Soyuz-style jobs. | 5 | look a little different from Soyuz-style jobs. |
2035 | 5 | 6 | ||
2037 | 6 | == Setup == | 7 | Setup |
2038 | 8 | ----- | ||
2039 | 7 | 9 | ||
2040 | 8 | Create a builder working on a TranslationTemplatesBuildJob for a branch. | 10 | Create a builder working on a TranslationTemplatesBuildJob for a branch. |
2041 | 9 | 11 | ||
2042 | @@ -13,6 +15,7 @@ | |||
2043 | 13 | >>> from canonical.launchpad.interfaces.librarian import ( | 15 | >>> from canonical.launchpad.interfaces.librarian import ( |
2044 | 14 | ... ILibraryFileAliasSet) | 16 | ... ILibraryFileAliasSet) |
2045 | 15 | >>> from canonical.launchpad.scripts.logger import QuietFakeLogger | 17 | >>> from canonical.launchpad.scripts.logger import QuietFakeLogger |
2046 | 18 | >>> from lp.app.enums import ServiceUsage | ||
2047 | 16 | >>> from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet | 19 | >>> from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet |
2048 | 17 | >>> from lp.testing.factory import ( | 20 | >>> from lp.testing.factory import ( |
2049 | 18 | ... remove_security_proxy_and_shout_at_engineer) | 21 | ... remove_security_proxy_and_shout_at_engineer) |
2050 | @@ -32,7 +35,7 @@ | |||
2051 | 32 | >>> productseries = factory.makeProductSeries(owner=owner) | 35 | >>> productseries = factory.makeProductSeries(owner=owner) |
2052 | 33 | >>> product = productseries.product | 36 | >>> product = productseries.product |
2053 | 34 | >>> naked_product = remove_security_proxy_and_shout_at_engineer(product) | 37 | >>> naked_product = remove_security_proxy_and_shout_at_engineer(product) |
2055 | 35 | >>> naked_product.official_rosetta = True | 38 | >>> naked_product.translations_usage = ServiceUsage.LAUNCHPAD |
2056 | 36 | >>> branch = factory.makeProductBranch(product=product, owner=owner) | 39 | >>> branch = factory.makeProductBranch(product=product, owner=owner) |
2057 | 37 | >>> branch_url = branch.unique_name | 40 | >>> branch_url = branch.unique_name |
2058 | 38 | 41 | ||
2059 | @@ -62,7 +65,8 @@ | |||
2060 | 62 | ... return find_tag_by_id(browser.contents, 'current-build-summary') | 65 | ... return find_tag_by_id(browser.contents, 'current-build-summary') |
2061 | 63 | 66 | ||
2062 | 64 | 67 | ||
2064 | 65 | == Show summary == | 68 | Show summary |
2065 | 69 | ------------ | ||
2066 | 66 | 70 | ||
2067 | 67 | The job's summary shows that what type of job this is. It also links | 71 | The job's summary shows that what type of job this is. It also links |
2068 | 68 | to the branch. | 72 | to the branch. |
2069 | 69 | 73 | ||
2070 | === modified file 'lib/lp/translations/stories/importqueue/xx-entry-details.txt' | |||
2071 | --- lib/lp/translations/stories/importqueue/xx-entry-details.txt 2010-03-11 20:54:36 +0000 | |||
2072 | +++ lib/lp/translations/stories/importqueue/xx-entry-details.txt 2010-09-09 15:34:46 +0000 | |||
2073 | @@ -1,9 +1,11 @@ | |||
2075 | 1 | = Entry details = | 1 | Entry details |
2076 | 2 | ============= | ||
2077 | 2 | 3 | ||
2078 | 3 | The translation import queue entry page shows various details about an | 4 | The translation import queue entry page shows various details about an |
2079 | 4 | entry and its target that may be helpful in queue review. | 5 | entry and its target that may be helpful in queue review. |
2080 | 5 | 6 | ||
2081 | 6 | >>> from zope.security.proxy import removeSecurityProxy | 7 | >>> from zope.security.proxy import removeSecurityProxy |
2082 | 8 | >>> from lp.app.enums import ServiceUsage | ||
2083 | 7 | >>> from lp.translations.model.translationimportqueue import ( | 9 | >>> from lp.translations.model.translationimportqueue import ( |
2084 | 8 | ... TranslationImportQueue) | 10 | ... TranslationImportQueue) |
2085 | 9 | 11 | ||
2086 | @@ -11,8 +13,8 @@ | |||
2087 | 11 | 13 | ||
2088 | 12 | >>> login(ANONYMOUS) | 14 | >>> login(ANONYMOUS) |
2089 | 13 | >>> queue = TranslationImportQueue() | 15 | >>> queue = TranslationImportQueue() |
2092 | 14 | >>> product = factory.makeProduct() | 16 | >>> product = factory.makeProduct( |
2093 | 15 | >>> removeSecurityProxy(product).official_rosetta = True | 17 | ... translations_usage=ServiceUsage.LAUNCHPAD) |
2094 | 16 | >>> trunk = product.getSeries('trunk') | 18 | >>> trunk = product.getSeries('trunk') |
2095 | 17 | >>> uploader = factory.makePerson() | 19 | >>> uploader = factory.makePerson() |
2096 | 18 | >>> entry = queue.addOrUpdateEntry( | 20 | >>> entry = queue.addOrUpdateEntry( |
2097 | @@ -47,7 +49,8 @@ | |||
2098 | 47 | http://...foo.pot | 49 | http://...foo.pot |
2099 | 48 | 50 | ||
2100 | 49 | 51 | ||
2102 | 50 | == Existing templates == | 52 | Existing templates |
2103 | 53 | ------------------ | ||
2104 | 51 | 54 | ||
2105 | 52 | If there are translatable templates in the series, this will be stated | 55 | If there are translatable templates in the series, this will be stated |
2106 | 53 | and there will be a link to the templates list. | 56 | and there will be a link to the templates list. |
2107 | @@ -81,7 +84,8 @@ | |||
2108 | 81 | ... | 84 | ... |
2109 | 82 | 85 | ||
2110 | 83 | 86 | ||
2112 | 84 | == Source packages == | 87 | Source packages |
2113 | 88 | --------------- | ||
2114 | 85 | 89 | ||
2115 | 86 | The portlet shows different (well, less) information for uploads | 90 | The portlet shows different (well, less) information for uploads |
2116 | 87 | attached to distribution packages. | 91 | attached to distribution packages. |
2117 | 88 | 92 | ||
2118 | === modified file 'lib/lp/translations/stories/productseries/xx-productseries-export-to-branch.txt' | |||
2119 | --- lib/lp/translations/stories/productseries/xx-productseries-export-to-branch.txt 2009-09-02 16:35:54 +0000 | |||
2120 | +++ lib/lp/translations/stories/productseries/xx-productseries-export-to-branch.txt 2010-09-09 15:34:46 +0000 | |||
2121 | @@ -1,15 +1,16 @@ | |||
2123 | 1 | = ProductSeries Translations Branch = | 1 | ProductSeries Translations Branch |
2124 | 2 | ================================= | ||
2125 | 2 | 3 | ||
2126 | 3 | If a ProductSeries has its translations_branch set, Launchpad will | 4 | If a ProductSeries has its translations_branch set, Launchpad will |
2127 | 4 | periodically commit snapshots of the series' translations to that | 5 | periodically commit snapshots of the series' translations to that |
2128 | 5 | branch. | 6 | branch. |
2129 | 6 | 7 | ||
2131 | 7 | >>> from zope.security.proxy import removeSecurityProxy | 8 | >>> from lp.app.enums import ServiceUsage |
2132 | 8 | 9 | ||
2133 | 9 | >>> login(ANONYMOUS) | 10 | >>> login(ANONYMOUS) |
2134 | 10 | >>> owner = factory.makePerson(email='x@example.com', password='****') | 11 | >>> owner = factory.makePerson(email='x@example.com', password='****') |
2137 | 11 | >>> product = factory.makeProduct(owner=owner) | 12 | >>> product = factory.makeProduct(owner=owner, |
2138 | 12 | >>> removeSecurityProxy(product).official_rosetta = True | 13 | ... translations_usage=ServiceUsage.LAUNCHPAD) |
2139 | 13 | >>> productseries = product.getSeries('trunk') | 14 | >>> productseries = product.getSeries('trunk') |
2140 | 14 | >>> branch = factory.makeBranch(product=product, owner=owner) | 15 | >>> branch = factory.makeBranch(product=product, owner=owner) |
2141 | 15 | >>> branch_name = branch.name | 16 | >>> branch_name = branch.name |
2142 | @@ -99,7 +100,8 @@ | |||
2143 | 99 | </div> | 100 | </div> |
2144 | 100 | 101 | ||
2145 | 101 | 102 | ||
2147 | 102 | == Disabling exports == | 103 | Disabling exports |
2148 | 104 | ----------------- | ||
2149 | 103 | 105 | ||
2150 | 104 | The field can also be cleared in order to disable the exports. | 106 | The field can also be cleared in order to disable the exports. |
2151 | 105 | 107 | ||
2152 | @@ -125,7 +127,8 @@ | |||
2153 | 125 | None | 127 | None |
2154 | 126 | 128 | ||
2155 | 127 | 129 | ||
2157 | 128 | == Security == | 130 | Security |
2158 | 131 | -------- | ||
2159 | 129 | 132 | ||
2160 | 130 | You can only set the translations_branch to a branch that you own. | 133 | You can only set the translations_branch to a branch that you own. |
2161 | 131 | Otherwise you'd be giving Launchpad a blanket license to commit | 134 | Otherwise you'd be giving Launchpad a blanket license to commit |
2162 | 132 | 135 | ||
2163 | === modified file 'lib/lp/translations/stories/productseries/xx-productseries-translations.txt' | |||
2164 | --- lib/lp/translations/stories/productseries/xx-productseries-translations.txt 2010-03-31 20:25:33 +0000 | |||
2165 | +++ lib/lp/translations/stories/productseries/xx-productseries-translations.txt 2010-09-09 15:34:46 +0000 | |||
2166 | @@ -5,9 +5,10 @@ | |||
2167 | 5 | a single product series, or instructions on how to set up a series for | 5 | a single product series, or instructions on how to set up a series for |
2168 | 6 | translation. | 6 | translation. |
2169 | 7 | 7 | ||
2170 | 8 | >>> from lp.app.enums import ServiceUsage | ||
2171 | 8 | >>> login('foo.bar@canonical.com') | 9 | >>> login('foo.bar@canonical.com') |
2174 | 9 | >>> frobnicator = factory.makeProduct(name='frobnicator') | 10 | >>> frobnicator = factory.makeProduct(name='frobnicator', |
2175 | 10 | >>> frobnicator.official_rosetta = True | 11 | ... translations_usage=ServiceUsage.LAUNCHPAD) |
2176 | 11 | >>> frobnicator_trunk = frobnicator.getSeries('trunk') | 12 | >>> frobnicator_trunk = frobnicator.getSeries('trunk') |
2177 | 12 | >>> frobnicator_trunk_url = canonical_url( | 13 | >>> frobnicator_trunk_url = canonical_url( |
2178 | 13 | ... frobnicator_trunk, rootsite='translations') | 14 | ... frobnicator_trunk, rootsite='translations') |
2179 | @@ -148,7 +149,8 @@ | |||
2180 | 148 | 149 | ||
2181 | 149 | # Use the raw DB object to bypass the security proxy. | 150 | # Use the raw DB object to bypass the security proxy. |
2182 | 150 | >>> from lp.registry.model.product import Product | 151 | >>> from lp.registry.model.product import Product |
2184 | 151 | >>> Product.byName('bazaar').official_rosetta = False | 152 | >>> product = Product.byName('bazaar') |
2185 | 153 | >>> product.translations_usage = ServiceUsage.NOT_APPLICABLE | ||
2186 | 152 | 154 | ||
2187 | 153 | When the owner now visits the upload page for trunk, there's a notice. | 155 | When the owner now visits the upload page for trunk, there's a notice. |
2188 | 154 | 156 | ||
2189 | 155 | 157 | ||
2190 | === modified file 'lib/lp/translations/stories/standalone/custom-language-codes.txt' | |||
2191 | --- lib/lp/translations/stories/standalone/custom-language-codes.txt 2010-03-11 20:54:36 +0000 | |||
2192 | +++ lib/lp/translations/stories/standalone/custom-language-codes.txt 2010-09-09 15:34:46 +0000 | |||
2193 | @@ -11,11 +11,11 @@ | |||
2194 | 11 | Custom language codes are attached to either a product or a source | 11 | Custom language codes are attached to either a product or a source |
2195 | 12 | package. | 12 | package. |
2196 | 13 | 13 | ||
2197 | 14 | >>> import re | ||
2198 | 15 | >>> from zope.component import getUtility | 14 | >>> from zope.component import getUtility |
2199 | 16 | >>> from zope.security.proxy import removeSecurityProxy | 15 | >>> from zope.security.proxy import removeSecurityProxy |
2200 | 17 | >>> from canonical.launchpad.interfaces.launchpad import ( | 16 | >>> from canonical.launchpad.interfaces.launchpad import ( |
2201 | 18 | ... ILaunchpadCelebrities) | 17 | ... ILaunchpadCelebrities) |
2202 | 18 | >>> from lp.app.enums import ServiceUsage | ||
2203 | 19 | 19 | ||
2204 | 20 | >>> def find_custom_language_codes_link(browser): | 20 | >>> def find_custom_language_codes_link(browser): |
2205 | 21 | ... """Find reference to custom language codes on a page.""" | 21 | ... """Find reference to custom language codes on a page.""" |
2206 | @@ -29,7 +29,8 @@ | |||
2207 | 29 | ... getUtility(ILaunchpadCelebrities).rosetta_experts) | 29 | ... getUtility(ILaunchpadCelebrities).rosetta_experts) |
2208 | 30 | >>> product = factory.makeProduct(displayname="Foo", owner=owner) | 30 | >>> product = factory.makeProduct(displayname="Foo", owner=owner) |
2209 | 31 | >>> trunk = product.getSeries('trunk') | 31 | >>> trunk = product.getSeries('trunk') |
2211 | 32 | >>> removeSecurityProxy(product).official_rosetta = True | 32 | >>> naked_product = removeSecurityProxy(product) |
2212 | 33 | >>> naked_product.translations_usage = ServiceUsage.LAUNCHPAD | ||
2213 | 33 | >>> template = factory.makePOTemplate(productseries=trunk) | 34 | >>> template = factory.makePOTemplate(productseries=trunk) |
2214 | 34 | >>> product_page = canonical_url(product, rootsite='translations') | 35 | >>> product_page = canonical_url(product, rootsite='translations') |
2215 | 35 | >>> logout() | 36 | >>> logout() |
2216 | @@ -198,7 +199,8 @@ | |||
2217 | 198 | >>> sourcepackagename = SourcePackageName(name='bar') | 199 | >>> sourcepackagename = SourcePackageName(name='bar') |
2218 | 199 | >>> package = factory.makeSourcePackage( | 200 | >>> package = factory.makeSourcePackage( |
2219 | 200 | ... sourcepackagename=sourcepackagename, distroseries=distroseries) | 201 | ... sourcepackagename=sourcepackagename, distroseries=distroseries) |
2221 | 201 | >>> removeSecurityProxy(distro).official_rosetta = True | 202 | >>> naked_distro = removeSecurityProxy(distro) |
2222 | 203 | >>> naked_distro.translations_usage = ServiceUsage.LAUNCHPAD | ||
2223 | 202 | >>> other_series = factory.makeDistroRelease(distribution=distro) | 204 | >>> other_series = factory.makeDistroRelease(distribution=distro) |
2224 | 203 | >>> template = factory.makePOTemplate( | 205 | >>> template = factory.makePOTemplate( |
2225 | 204 | ... distroseries=package.distroseries, | 206 | ... distroseries=package.distroseries, |
2226 | 205 | 207 | ||
2227 | === modified file 'lib/lp/translations/stories/standalone/xx-potemplate-index.txt' | |||
2228 | --- lib/lp/translations/stories/standalone/xx-potemplate-index.txt 2010-02-16 21:21:14 +0000 | |||
2229 | +++ lib/lp/translations/stories/standalone/xx-potemplate-index.txt 2010-09-09 15:34:46 +0000 | |||
2230 | @@ -6,7 +6,7 @@ | |||
2231 | 6 | ----------- | 6 | ----------- |
2232 | 7 | 7 | ||
2233 | 8 | The index page for a POTemplate lists all available translations | 8 | The index page for a POTemplate lists all available translations |
2235 | 9 | for a source package. No Privileges Person visits the | 9 | for a source package. No Privileges Person visits the |
2236 | 10 | evolution-2.2 POTemplate page. | 10 | evolution-2.2 POTemplate page. |
2237 | 11 | 11 | ||
2238 | 12 | >>> anon_browser.open("http://translations.launchpad.dev/" | 12 | >>> anon_browser.open("http://translations.launchpad.dev/" |
2239 | @@ -85,7 +85,7 @@ | |||
2240 | 85 | </p> | 85 | </p> |
2241 | 86 | 86 | ||
2242 | 87 | 87 | ||
2244 | 88 | DistroSeries and ProductSeries links to related templates | 88 | DistroSeries and ProductSeries links to related templates |
2245 | 89 | --------------------------------------------------------- | 89 | --------------------------------------------------------- |
2246 | 90 | 90 | ||
2247 | 91 | We are presented not only with links to alternate templates from the same | 91 | We are presented not only with links to alternate templates from the same |
2248 | @@ -117,8 +117,8 @@ | |||
2249 | 117 | A source package with five templates is created. | 117 | A source package with five templates is created. |
2250 | 118 | 118 | ||
2251 | 119 | >>> from zope.component import getUtility | 119 | >>> from zope.component import getUtility |
2254 | 120 | >>> from canonical.launchpad.interfaces.launchpad import ( | 120 | >>> from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
2255 | 121 | ... ILaunchpadCelebrities) | 121 | |
2256 | 122 | >>> login('admin@canonical.com') | 122 | >>> login('admin@canonical.com') |
2257 | 123 | >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu | 123 | >>> ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
2258 | 124 | >>> hoary = ubuntu.getSeries('hoary') | 124 | >>> hoary = ubuntu.getSeries('hoary') |
2259 | @@ -212,8 +212,10 @@ | |||
2260 | 212 | >>> from zope.component import getUtility | 212 | >>> from zope.component import getUtility |
2261 | 213 | >>> from canonical.launchpad.interfaces.launchpad import ( | 213 | >>> from canonical.launchpad.interfaces.launchpad import ( |
2262 | 214 | ... ILaunchpadCelebrities) | 214 | ... ILaunchpadCelebrities) |
2263 | 215 | >>> from lp.app.enums import ServiceUsage | ||
2264 | 215 | >>> login('admin@canonical.com') | 216 | >>> login('admin@canonical.com') |
2266 | 216 | >>> product = factory.makeProduct(name="fusa", official_rosetta=True) | 217 | >>> product = factory.makeProduct(name="fusa", |
2267 | 218 | ... translations_usage=ServiceUsage.LAUNCHPAD) | ||
2268 | 217 | >>> product_trunk = product.getSeries('trunk') | 219 | >>> product_trunk = product.getSeries('trunk') |
2269 | 218 | >>> template = factory.makePOTemplate( | 220 | >>> template = factory.makePOTemplate( |
2270 | 219 | ... productseries=product_trunk, name='first') | 221 | ... productseries=product_trunk, name='first') |
2271 | @@ -253,7 +255,9 @@ | |||
2272 | 253 | Anonymous visitors see only a list of all existing templates, with no | 255 | Anonymous visitors see only a list of all existing templates, with no |
2273 | 254 | administration or download/upload links. | 256 | administration or download/upload links. |
2274 | 255 | 257 | ||
2276 | 256 | >>> anon_browser.open('http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | 258 | >>> anon_browser.open( |
2277 | 259 | ... 'http://translations.launchpad.dev/' | ||
2278 | 260 | ... 'ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | ||
2279 | 257 | >>> anon_browser.getLink('upload') | 261 | >>> anon_browser.getLink('upload') |
2280 | 258 | Traceback (most recent call last): | 262 | Traceback (most recent call last): |
2281 | 259 | ... | 263 | ... |
2282 | @@ -267,7 +271,9 @@ | |||
2283 | 267 | As an authenticated user, you should see the download link, | 271 | As an authenticated user, you should see the download link, |
2284 | 268 | but not the one for uploading file to this potemplate. | 272 | but not the one for uploading file to this potemplate. |
2285 | 269 | 273 | ||
2287 | 270 | >>> user_browser.open('http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | 274 | >>> user_browser.open( |
2288 | 275 | ... 'http://translations.launchpad.dev/' | ||
2289 | 276 | ... 'ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | ||
2290 | 271 | >>> user_browser.getLink('upload') | 277 | >>> user_browser.getLink('upload') |
2291 | 272 | Traceback (most recent call last): | 278 | Traceback (most recent call last): |
2292 | 273 | ... | 279 | ... |
2293 | @@ -281,27 +287,37 @@ | |||
2294 | 281 | Beside administering this template, "Change permissions" | 287 | Beside administering this template, "Change permissions" |
2295 | 282 | and "Change details" should be also accessible. | 288 | and "Change details" should be also accessible. |
2296 | 283 | 289 | ||
2298 | 284 | >>> admin_browser.open('http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | 290 | >>> admin_browser.open( |
2299 | 291 | ... 'http://translations.launchpad.dev/' | ||
2300 | 292 | ... 'ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | ||
2301 | 285 | >>> admin_browser.getLink('upload').click() | 293 | >>> admin_browser.getLink('upload').click() |
2302 | 286 | >>> print admin_browser.url | 294 | >>> print admin_browser.url |
2303 | 287 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+upload | 295 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+upload |
2304 | 288 | 296 | ||
2306 | 289 | >>> admin_browser.open('http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | 297 | >>> admin_browser.open( |
2307 | 298 | ... 'http://translations.launchpad.dev/' | ||
2308 | 299 | ... 'ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | ||
2309 | 290 | >>> admin_browser.getLink('download').click() | 300 | >>> admin_browser.getLink('download').click() |
2310 | 291 | >>> print admin_browser.url | 301 | >>> print admin_browser.url |
2311 | 292 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+export | 302 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+export |
2312 | 293 | 303 | ||
2314 | 294 | >>> admin_browser.open('http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | 304 | >>> admin_browser.open( |
2315 | 305 | ... 'http://translations.launchpad.dev/' | ||
2316 | 306 | ... 'ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | ||
2317 | 295 | >>> admin_browser.getLink('Administer this template').click() | 307 | >>> admin_browser.getLink('Administer this template').click() |
2318 | 296 | >>> print admin_browser.url | 308 | >>> print admin_browser.url |
2319 | 297 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+admin | 309 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+admin |
2320 | 298 | 310 | ||
2322 | 299 | >>> admin_browser.open('http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | 311 | >>> admin_browser.open( |
2323 | 312 | ... 'http://translations.launchpad.dev/' | ||
2324 | 313 | ... 'ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | ||
2325 | 300 | >>> admin_browser.getLink('Change details').click() | 314 | >>> admin_browser.getLink('Change details').click() |
2326 | 301 | >>> print admin_browser.url | 315 | >>> print admin_browser.url |
2327 | 302 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+edit | 316 | http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/+edit |
2328 | 303 | 317 | ||
2330 | 304 | >>> admin_browser.open('http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | 318 | >>> admin_browser.open( |
2331 | 319 | ... 'http://translations.launchpad.dev/' | ||
2332 | 320 | ... 'ubuntu/hoary/+source/evolution/+pots/evolution-2.2') | ||
2333 | 305 | >>> admin_browser.getLink('Change permissions').click() | 321 | >>> admin_browser.getLink('Change permissions').click() |
2334 | 306 | >>> print admin_browser.url | 322 | >>> print admin_browser.url |
2335 | 307 | http://translations.launchpad.dev/ubuntu/+settings | 323 | http://translations.launchpad.dev/ubuntu/+settings |
2336 | 308 | 324 | ||
2337 | === modified file 'lib/lp/translations/stories/standalone/xx-product-export.txt' | |||
2338 | --- lib/lp/translations/stories/standalone/xx-product-export.txt 2009-09-18 15:42:19 +0000 | |||
2339 | +++ lib/lp/translations/stories/standalone/xx-product-export.txt 2010-09-09 15:34:46 +0000 | |||
2340 | @@ -1,4 +1,5 @@ | |||
2342 | 1 | = Downloading Product Series Translations = | 1 | Downloading Product Series Translations |
2343 | 2 | ======================================= | ||
2344 | 2 | 3 | ||
2345 | 3 | Products and product series that use Translations offer complete | 4 | Products and product series that use Translations offer complete |
2346 | 4 | translation downloads. | 5 | translation downloads. |
2347 | @@ -33,16 +34,18 @@ | |||
2348 | 33 | Your request has been received. Expect to receive an email shortly. | 34 | Your request has been received. Expect to receive an email shortly. |
2349 | 34 | 35 | ||
2350 | 35 | 36 | ||
2352 | 36 | == Use of Launchpad Translations == | 37 | Use of Launchpad Translations |
2353 | 38 | ----------------------------- | ||
2354 | 37 | 39 | ||
2355 | 38 | The Download link is not shown if the product does not use Launchpad | 40 | The Download link is not shown if the product does not use Launchpad |
2356 | 39 | Translations. | 41 | Translations. |
2357 | 40 | 42 | ||
2358 | 41 | # Use the DB classes directly to avoid having to setup a zope interaction | 43 | # Use the DB classes directly to avoid having to setup a zope interaction |
2359 | 42 | # (i.e. login()) and bypass the security proxy. | 44 | # (i.e. login()) and bypass the security proxy. |
2360 | 45 | >>> from lp.app.enums import ServiceUsage | ||
2361 | 43 | >>> from lp.registry.model.product import Product | 46 | >>> from lp.registry.model.product import Product |
2362 | 44 | >>> product = Product.byName('evolution') | 47 | >>> product = Product.byName('evolution') |
2364 | 45 | >>> product.official_rosetta = False | 48 | >>> product.translations_usage = ServiceUsage.NOT_APPLICABLE |
2365 | 46 | >>> product.sync() | 49 | >>> product.sync() |
2366 | 47 | >>> user_browser.open('http://translations.launchpad.dev/evolution') | 50 | >>> user_browser.open('http://translations.launchpad.dev/evolution') |
2367 | 48 | >>> user_browser.getLink('download') | 51 | >>> user_browser.getLink('download') |
2368 | @@ -51,14 +54,15 @@ | |||
2369 | 51 | LinkNotFoundError | 54 | LinkNotFoundError |
2370 | 52 | 55 | ||
2371 | 53 | >>> # Restore previous state for subsequent tests, and verify | 56 | >>> # Restore previous state for subsequent tests, and verify |
2373 | 54 | >>> product.official_rosetta = True | 57 | >>> product.translations_usage = ServiceUsage.LAUNCHPAD |
2374 | 55 | >>> product.sync() | 58 | >>> product.sync() |
2375 | 56 | >>> user_browser.open('http://translations.launchpad.dev/evolution') | 59 | >>> user_browser.open('http://translations.launchpad.dev/evolution') |
2376 | 57 | >>> user_browser.getLink('download') is not None | 60 | >>> user_browser.getLink('download') is not None |
2377 | 58 | True | 61 | True |
2378 | 59 | 62 | ||
2379 | 60 | 63 | ||
2381 | 61 | == Authorization == | 64 | Authorization |
2382 | 65 | ------------- | ||
2383 | 62 | 66 | ||
2384 | 63 | Only logged-in users get the option to request downloads. | 67 | Only logged-in users get the option to request downloads. |
2385 | 64 | 68 | ||
2386 | 65 | 69 | ||
2387 | === modified file 'lib/lp/translations/stories/standalone/xx-product-translations.txt' | |||
2388 | --- lib/lp/translations/stories/standalone/xx-product-translations.txt 2010-08-25 00:01:57 +0000 | |||
2389 | +++ lib/lp/translations/stories/standalone/xx-product-translations.txt 2010-09-09 15:34:46 +0000 | |||
2390 | @@ -1,4 +1,3 @@ | |||
2391 | 1 | ==================== | ||
2392 | 2 | Product Translations | 1 | Product Translations |
2393 | 3 | ==================== | 2 | ==================== |
2394 | 4 | 3 | ||
2395 | 5 | 4 | ||
2396 | === modified file 'lib/lp/translations/stories/standalone/xx-template-description-escaping.txt' | |||
2397 | --- lib/lp/translations/stories/standalone/xx-template-description-escaping.txt 2009-09-14 15:41:21 +0000 | |||
2398 | +++ lib/lp/translations/stories/standalone/xx-template-description-escaping.txt 2010-09-09 15:34:46 +0000 | |||
2399 | @@ -1,12 +1,14 @@ | |||
2400 | 1 | >>> import re | 1 | >>> import re |
2401 | 2 | >>> from zope.security.proxy import removeSecurityProxy | 2 | >>> from zope.security.proxy import removeSecurityProxy |
2402 | 3 | >>> from lp.app.enums import ServiceUsage | ||
2403 | 3 | 4 | ||
2404 | 4 | >>> login('foo.bar@canonical.com') | 5 | >>> login('foo.bar@canonical.com') |
2405 | 5 | >>> package = factory.makeSourcePackage() | 6 | >>> package = factory.makeSourcePackage() |
2406 | 6 | >>> template = removeSecurityProxy(factory.makePOTemplate( | 7 | >>> template = removeSecurityProxy(factory.makePOTemplate( |
2407 | 7 | ... distroseries=package.distroseries, | 8 | ... distroseries=package.distroseries, |
2408 | 8 | ... sourcepackagename=package.sourcepackagename)) | 9 | ... sourcepackagename=package.sourcepackagename)) |
2410 | 9 | >>> template.distroseries.distribution.official_rosetta = True | 10 | >>> distribution = template.distroseries.distribution |
2411 | 11 | >>> distribution.translations_usage = ServiceUsage.LAUNCHPAD | ||
2412 | 10 | >>> template.distroseries.hide_all_translations = False | 12 | >>> template.distroseries.hide_all_translations = False |
2413 | 11 | >>> template.description = "See http://example.com/ for an example!" | 13 | >>> template.description = "See http://example.com/ for an example!" |
2414 | 12 | >>> package_url = canonical_url(package, rootsite='translations') | 14 | >>> package_url = canonical_url(package, rootsite='translations') |
2415 | 13 | 15 | ||
2416 | === modified file 'lib/lp/translations/stories/translationfocus/xx-product-translationfocus.txt' | |||
2417 | --- lib/lp/translations/stories/translationfocus/xx-product-translationfocus.txt 2010-01-20 20:21:42 +0000 | |||
2418 | +++ lib/lp/translations/stories/translationfocus/xx-product-translationfocus.txt 2010-09-09 15:34:46 +0000 | |||
2419 | @@ -1,9 +1,10 @@ | |||
2420 | 1 | The translation focus of a product can be explicitly set to a specific series. | 1 | The translation focus of a product can be explicitly set to a specific series. |
2421 | 2 | When not set, launchpad recommends the development focus to translate. | 2 | When not set, launchpad recommends the development focus to translate. |
2422 | 3 | 3 | ||
2423 | 4 | >>> from lp.app.enums import ServiceUsage | ||
2424 | 4 | >>> login('admin@canonical.com') | 5 | >>> login('admin@canonical.com') |
2425 | 5 | >>> fooproject = factory.makeProduct(name="fooproject") | 6 | >>> fooproject = factory.makeProduct(name="fooproject") |
2427 | 6 | >>> fooproject.official_rosetta = True | 7 | >>> fooproject.translations_usage = ServiceUsage.LAUNCHPAD |
2428 | 7 | >>> fooproject_trunk = fooproject.getSeries("trunk") | 8 | >>> fooproject_trunk = fooproject.getSeries("trunk") |
2429 | 8 | >>> fooproject_url = canonical_url( | 9 | >>> fooproject_url = canonical_url( |
2430 | 9 | ... fooproject, rootsite="translations") | 10 | ... fooproject, rootsite="translations") |
2431 | @@ -25,7 +26,8 @@ | |||
2432 | 25 | ... | 26 | ... |
2433 | 26 | IndexError: list index out of range | 27 | IndexError: list index out of range |
2434 | 27 | 28 | ||
2436 | 28 | == Setting the translation focus == | 29 | Setting the translation focus |
2437 | 30 | ============================= | ||
2438 | 29 | 31 | ||
2439 | 30 | >>> login('admin@canonical.com') | 32 | >>> login('admin@canonical.com') |
2440 | 31 | >>> from zope.security.proxy import removeSecurityProxy | 33 | >>> from zope.security.proxy import removeSecurityProxy |
2441 | @@ -35,7 +37,7 @@ | |||
2442 | 35 | >>> pofile = factory.makePOFile("pt_BR", potemplate=pot_main) | 37 | >>> pofile = factory.makePOFile("pt_BR", potemplate=pot_main) |
2443 | 36 | >>> logout() | 38 | >>> logout() |
2444 | 37 | 39 | ||
2446 | 38 | When the translation focus is not set, Launchpad suggests the | 40 | When the translation focus is not set, Launchpad suggests the |
2447 | 39 | development focus as the current series to be translated. | 41 | development focus as the current series to be translated. |
2448 | 40 | It needs to be translatable. | 42 | It needs to be translatable. |
2449 | 41 | 43 | ||
2450 | 42 | 44 | ||
2451 | === modified file 'lib/lp/translations/stories/translationgroups/xx-change-translation-policy.txt' | |||
2452 | --- lib/lp/translations/stories/translationgroups/xx-change-translation-policy.txt 2010-02-16 21:21:14 +0000 | |||
2453 | +++ lib/lp/translations/stories/translationgroups/xx-change-translation-policy.txt 2010-09-09 15:34:46 +0000 | |||
2454 | @@ -4,11 +4,15 @@ | |||
2455 | 4 | A product owner, Rosetta expert, and Ubuntu translations coordinator | 4 | A product owner, Rosetta expert, and Ubuntu translations coordinator |
2456 | 5 | browser is created. | 5 | browser is created. |
2457 | 6 | 6 | ||
2458 | 7 | >>> from lp.app.enums import ServiceUsage | ||
2459 | 8 | |||
2460 | 7 | >>> login('admin@canonical.com') | 9 | >>> login('admin@canonical.com') |
2461 | 8 | >>> product_owner = factory.makePerson( | 10 | >>> product_owner = factory.makePerson( |
2462 | 9 | ... email="po@ex.com", password="test") | 11 | ... email="po@ex.com", password="test") |
2463 | 10 | >>> chestii = factory.makeProduct( | 12 | >>> chestii = factory.makeProduct( |
2465 | 11 | ... name='chestii', owner=product_owner, official_rosetta=True) | 13 | ... name='chestii', |
2466 | 14 | ... owner=product_owner, | ||
2467 | 15 | ... translations_usage=ServiceUsage.LAUNCHPAD) | ||
2468 | 12 | >>> logout() | 16 | >>> logout() |
2469 | 13 | >>> dtc_browser = setupDTCBrowser() | 17 | >>> dtc_browser = setupDTCBrowser() |
2470 | 14 | >>> re_browser = setupRosettaExpertBrowser() | 18 | >>> re_browser = setupRosettaExpertBrowser() |
2471 | 15 | 19 | ||
2472 | === modified file 'lib/lp/translations/templates/product-portlet-not-using-launchpad.pt' | |||
2473 | --- lib/lp/translations/templates/product-portlet-not-using-launchpad.pt 2010-03-15 20:17:21 +0000 | |||
2474 | +++ lib/lp/translations/templates/product-portlet-not-using-launchpad.pt 2010-09-09 15:34:46 +0000 | |||
2475 | @@ -5,7 +5,7 @@ | |||
2476 | 5 | omit-tag=""> | 5 | omit-tag=""> |
2477 | 6 | 6 | ||
2478 | 7 | <div id="not-translated-in-launchpad" | 7 | <div id="not-translated-in-launchpad" |
2480 | 8 | tal:condition="not: context/official_rosetta"> | 8 | tal:condition="not: context/translations_usage/enumvalue:LAUNCHPAD"> |
2481 | 9 | <strong> | 9 | <strong> |
2482 | 10 | This project is not using Launchpad for translations. | 10 | This project is not using Launchpad for translations. |
2483 | 11 | </strong> | 11 | </strong> |
2484 | 12 | 12 | ||
2485 | === modified file 'lib/lp/translations/templates/productseries-translations.pt' | |||
2486 | --- lib/lp/translations/templates/productseries-translations.pt 2009-12-16 15:21:36 +0000 | |||
2487 | +++ lib/lp/translations/templates/productseries-translations.pt 2010-09-09 15:34:46 +0000 | |||
2488 | @@ -30,7 +30,7 @@ | |||
2489 | 30 | <a href="https://help.launchpad.net/Translations/YourProject">start | 30 | <a href="https://help.launchpad.net/Translations/YourProject">start |
2490 | 31 | translating your project</a>, | 31 | translating your project</a>, |
2491 | 32 | <tal:uses-translations condition="not: | 32 | <tal:uses-translations condition="not: |
2493 | 33 | context/product/official_rosetta"> | 33 | context/product/translations_usage/enumvalue:LAUNCHPAD"> |
2494 | 34 | you should enable translations in your project settings, and | 34 | you should enable translations in your project settings, and |
2495 | 35 | </tal:uses-translations> | 35 | </tal:uses-translations> |
2496 | 36 | you can either | 36 | you can either |
2497 | 37 | 37 | ||
2498 | === modified file 'lib/lp/translations/tests/test_autoapproval.py' | |||
2499 | --- lib/lp/translations/tests/test_autoapproval.py 2010-08-20 20:31:18 +0000 | |||
2500 | +++ lib/lp/translations/tests/test_autoapproval.py 2010-09-09 15:34:46 +0000 | |||
2501 | @@ -23,6 +23,7 @@ | |||
2502 | 23 | from canonical.launchpad.interfaces.lpstorm import IMasterStore | 23 | from canonical.launchpad.interfaces.lpstorm import IMasterStore |
2503 | 24 | from canonical.launchpad.webapp.testing import verifyObject | 24 | from canonical.launchpad.webapp.testing import verifyObject |
2504 | 25 | from canonical.testing import LaunchpadZopelessLayer | 25 | from canonical.testing import LaunchpadZopelessLayer |
2505 | 26 | from lp.app.enums import ServiceUsage | ||
2506 | 26 | from lp.registry.interfaces.series import SeriesStatus | 27 | from lp.registry.interfaces.series import SeriesStatus |
2507 | 27 | from lp.registry.model.distribution import Distribution | 28 | from lp.registry.model.distribution import Distribution |
2508 | 28 | from lp.registry.model.sourcepackagename import ( | 29 | from lp.registry.model.sourcepackagename import ( |
2509 | @@ -714,8 +715,8 @@ | |||
2510 | 714 | # _get_pofile_from_language will find an enabled template, and | 715 | # _get_pofile_from_language will find an enabled template, and |
2511 | 715 | # return either an existing POFile for the given language, or a | 716 | # return either an existing POFile for the given language, or a |
2512 | 716 | # newly created one. | 717 | # newly created one. |
2515 | 717 | product = self.factory.makeProduct() | 718 | product = self.factory.makeProduct( |
2516 | 718 | product.official_rosetta = True | 719 | translations_usage=ServiceUsage.LAUNCHPAD) |
2517 | 719 | trunk = product.getSeries('trunk') | 720 | trunk = product.getSeries('trunk') |
2518 | 720 | template = self.factory.makePOTemplate( | 721 | template = self.factory.makePOTemplate( |
2519 | 721 | productseries=trunk, translation_domain='domain') | 722 | productseries=trunk, translation_domain='domain') |
2520 | @@ -732,8 +733,8 @@ | |||
2521 | 732 | # _get_pofile_from_language will not consider a disabled | 733 | # _get_pofile_from_language will not consider a disabled |
2522 | 733 | # template as an auto-approval target, and so will not return a | 734 | # template as an auto-approval target, and so will not return a |
2523 | 734 | # POFile for it. | 735 | # POFile for it. |
2526 | 735 | product = self.factory.makeProduct() | 736 | product = self.factory.makeProduct( |
2527 | 736 | product.official_rosetta = True | 737 | translations_usage=ServiceUsage.LAUNCHPAD) |
2528 | 737 | trunk = product.getSeries('trunk') | 738 | trunk = product.getSeries('trunk') |
2529 | 738 | template = self.factory.makePOTemplate( | 739 | template = self.factory.makePOTemplate( |
2530 | 739 | productseries=trunk, translation_domain='domain') | 740 | productseries=trunk, translation_domain='domain') |
2531 | @@ -750,8 +751,8 @@ | |||
2532 | 750 | # When the template has translation credits, a new dummy translation | 751 | # When the template has translation credits, a new dummy translation |
2533 | 751 | # is created in the new POFile. Since this is running with gardener | 752 | # is created in the new POFile. Since this is running with gardener |
2534 | 752 | # privileges, we need to check that this works, too. | 753 | # privileges, we need to check that this works, too. |
2537 | 753 | product = self.factory.makeProduct() | 754 | product = self.factory.makeProduct( |
2538 | 754 | product.official_rosetta = True | 755 | translations_usage=ServiceUsage.LAUNCHPAD) |
2539 | 755 | trunk = product.getSeries('trunk') | 756 | trunk = product.getSeries('trunk') |
2540 | 756 | template = self.factory.makePOTemplate( | 757 | template = self.factory.makePOTemplate( |
2541 | 757 | productseries=trunk, translation_domain='domain') | 758 | productseries=trunk, translation_domain='domain') |
2542 | @@ -778,8 +779,8 @@ | |||
2543 | 778 | 779 | ||
2544 | 779 | def _makeProductEntry(self, path='foo.pot', status=None): | 780 | def _makeProductEntry(self, path='foo.pot', status=None): |
2545 | 780 | """Simulate upload for a product.""" | 781 | """Simulate upload for a product.""" |
2548 | 781 | product = self.factory.makeProduct() | 782 | product = self.factory.makeProduct( |
2549 | 782 | product.official_rosetta = True | 783 | translations_usage=ServiceUsage.LAUNCHPAD) |
2550 | 783 | trunk = product.getSeries('trunk') | 784 | trunk = product.getSeries('trunk') |
2551 | 784 | entry = self.queue.addOrUpdateEntry( | 785 | entry = self.queue.addOrUpdateEntry( |
2552 | 785 | path, '# contents', False, product.owner, productseries=trunk) | 786 | path, '# contents', False, product.owner, productseries=trunk) |
2553 | 786 | 787 | ||
2554 | === modified file 'lib/lp/translations/tests/test_empty_messages.py' | |||
2555 | --- lib/lp/translations/tests/test_empty_messages.py 2010-08-20 20:31:18 +0000 | |||
2556 | +++ lib/lp/translations/tests/test_empty_messages.py 2010-09-09 15:34:46 +0000 | |||
2557 | @@ -4,17 +4,17 @@ | |||
2558 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
2559 | 5 | 5 | ||
2560 | 6 | from datetime import datetime | 6 | from datetime import datetime |
2561 | 7 | import unittest | ||
2562 | 8 | 7 | ||
2563 | 9 | from pytz import timezone | 8 | from pytz import timezone |
2564 | 10 | from zope.component import getUtility | 9 | from zope.component import getUtility |
2565 | 11 | 10 | ||
2566 | 12 | from canonical.testing import LaunchpadZopelessLayer | 11 | from canonical.testing import LaunchpadZopelessLayer |
2567 | 12 | from lp.app.enums import ServiceUsage | ||
2568 | 13 | from lp.services.worlddata.interfaces.language import ILanguageSet | 13 | from lp.services.worlddata.interfaces.language import ILanguageSet |
2573 | 14 | from lp.testing.factory import LaunchpadObjectFactory | 14 | from lp.testing import TestCaseWithFactory |
2574 | 15 | 15 | ||
2575 | 16 | 16 | ||
2576 | 17 | class TestTranslationEmptyMessages(unittest.TestCase): | 17 | class TestTranslationEmptyMessages(TestCaseWithFactory): |
2577 | 18 | """Test behaviour of empty translation messages.""" | 18 | """Test behaviour of empty translation messages.""" |
2578 | 19 | 19 | ||
2579 | 20 | layer = LaunchpadZopelessLayer | 20 | layer = LaunchpadZopelessLayer |
2580 | @@ -23,13 +23,15 @@ | |||
2581 | 23 | """Set up context to test in.""" | 23 | """Set up context to test in.""" |
2582 | 24 | # Pretend we have a product being translated to Serbian. | 24 | # Pretend we have a product being translated to Serbian. |
2583 | 25 | # This is where we are going to be importing translations to. | 25 | # This is where we are going to be importing translations to. |
2589 | 26 | factory = LaunchpadObjectFactory() | 26 | super(TestTranslationEmptyMessages, self).setUp() |
2590 | 27 | self.factory = factory | 27 | product = self.factory.makeProduct( |
2591 | 28 | self.productseries = factory.makeProductSeries() | 28 | translations_usage=ServiceUsage.LAUNCHPAD) |
2592 | 29 | self.productseries.product.official_rosetta = True | 29 | self.productseries = self.factory.makeProductSeries(product=product) |
2593 | 30 | self.potemplate = factory.makePOTemplate(self.productseries) | 30 | self.potemplate = self.factory.makePOTemplate(self.productseries) |
2594 | 31 | self.serbian = getUtility(ILanguageSet).getLanguageByCode('sr') | 31 | self.serbian = getUtility(ILanguageSet).getLanguageByCode('sr') |
2596 | 32 | self.pofile_sr = factory.makePOFile('sr', potemplate=self.potemplate) | 32 | self.pofile_sr = self.factory.makePOFile( |
2597 | 33 | 'sr', | ||
2598 | 34 | potemplate=self.potemplate) | ||
2599 | 33 | self.now = datetime.now(timezone('UTC')) | 35 | self.now = datetime.now(timezone('UTC')) |
2600 | 34 | 36 | ||
2601 | 35 | def test_NoEmptyImporedTranslation(self): | 37 | def test_NoEmptyImporedTranslation(self): |
2602 | 36 | 38 | ||
2603 | === modified file 'lib/lp/translations/tests/test_hastranslationtemplates.py' | |||
2604 | --- lib/lp/translations/tests/test_hastranslationtemplates.py 2010-08-20 20:31:18 +0000 | |||
2605 | +++ lib/lp/translations/tests/test_hastranslationtemplates.py 2010-09-09 15:34:46 +0000 | |||
2606 | @@ -6,6 +6,7 @@ | |||
2607 | 6 | from zope.interface.verify import verifyObject | 6 | from zope.interface.verify import verifyObject |
2608 | 7 | 7 | ||
2609 | 8 | from canonical.testing import ZopelessDatabaseLayer | 8 | from canonical.testing import ZopelessDatabaseLayer |
2610 | 9 | from lp.app.enums import ServiceUsage | ||
2611 | 9 | from lp.testing import TestCaseWithFactory | 10 | from lp.testing import TestCaseWithFactory |
2612 | 10 | from lp.translations.interfaces.potemplate import IHasTranslationTemplates | 11 | from lp.translations.interfaces.potemplate import IHasTranslationTemplates |
2613 | 11 | from lp.translations.interfaces.translationfileformat import ( | 12 | from lp.translations.interfaces.translationfileformat import ( |
2614 | @@ -152,7 +153,7 @@ | |||
2615 | 152 | 153 | ||
2616 | 153 | # A product or distribution that doesn't use Launchpad for | 154 | # A product or distribution that doesn't use Launchpad for |
2617 | 154 | # translations has no current templates. | 155 | # translations has no current templates. |
2619 | 155 | self.product_or_distro.official_rosetta = False | 156 | self.product_or_distro.translations_usage = ServiceUsage.EXTERNAL |
2620 | 156 | self.assertFalse(self.container.has_current_translation_templates) | 157 | self.assertFalse(self.container.has_current_translation_templates) |
2621 | 157 | 158 | ||
2622 | 158 | def test_getTranslationTemplateFormats(self): | 159 | def test_getTranslationTemplateFormats(self): |
2623 | @@ -205,7 +206,7 @@ | |||
2624 | 205 | super(TestProductSeriesHasTranslationTemplates, self).setUp() | 206 | super(TestProductSeriesHasTranslationTemplates, self).setUp() |
2625 | 206 | self.container = self.factory.makeProductSeries() | 207 | self.container = self.factory.makeProductSeries() |
2626 | 207 | self.product_or_distro = self.container.product | 208 | self.product_or_distro = self.container.product |
2628 | 208 | self.product_or_distro.official_rosetta = True | 209 | self.product_or_distro.translations_usage = ServiceUsage.LAUNCHPAD |
2629 | 209 | 210 | ||
2630 | 210 | 211 | ||
2631 | 211 | class TestSourcePackageHasTranslationTemplates( | 212 | class TestSourcePackageHasTranslationTemplates( |
2632 | @@ -223,7 +224,7 @@ | |||
2633 | 223 | super(TestSourcePackageHasTranslationTemplates, self).setUp() | 224 | super(TestSourcePackageHasTranslationTemplates, self).setUp() |
2634 | 224 | self.container = self.factory.makeSourcePackage() | 225 | self.container = self.factory.makeSourcePackage() |
2635 | 225 | self.product_or_distro = self.container.distroseries.distribution | 226 | self.product_or_distro = self.container.distroseries.distribution |
2637 | 226 | self.product_or_distro.official_rosetta = True | 227 | self.product_or_distro.translations_usage = ServiceUsage.LAUNCHPAD |
2638 | 227 | 228 | ||
2639 | 228 | 229 | ||
2640 | 229 | class TestDistroSeriesHasTranslationTemplates( | 230 | class TestDistroSeriesHasTranslationTemplates( |
2641 | @@ -243,4 +244,4 @@ | |||
2642 | 243 | super(TestDistroSeriesHasTranslationTemplates, self).setUp() | 244 | super(TestDistroSeriesHasTranslationTemplates, self).setUp() |
2643 | 244 | self.container = self.factory.makeDistroRelease() | 245 | self.container = self.factory.makeDistroRelease() |
2644 | 245 | self.product_or_distro = self.container.distribution | 246 | self.product_or_distro = self.container.distribution |
2646 | 246 | self.product_or_distro.official_rosetta = True | 247 | self.product_or_distro.translations_usage = ServiceUsage.LAUNCHPAD |
2647 | 247 | 248 | ||
2648 | === modified file 'lib/lp/translations/tests/test_pofile.py' | |||
2649 | --- lib/lp/translations/tests/test_pofile.py 2010-09-03 14:38:20 +0000 | |||
2650 | +++ lib/lp/translations/tests/test_pofile.py 2010-09-09 15:34:46 +0000 | |||
2651 | @@ -24,6 +24,7 @@ | |||
2652 | 24 | LaunchpadZopelessLayer, | 24 | LaunchpadZopelessLayer, |
2653 | 25 | ZopelessDatabaseLayer, | 25 | ZopelessDatabaseLayer, |
2654 | 26 | ) | 26 | ) |
2655 | 27 | from lp.app.enums import ServiceUsage | ||
2656 | 27 | from lp.testing import TestCaseWithFactory | 28 | from lp.testing import TestCaseWithFactory |
2657 | 28 | from lp.translations.interfaces.pofile import IPOFileSet | 29 | from lp.translations.interfaces.pofile import IPOFileSet |
2658 | 29 | from lp.translations.interfaces.translatablemessage import ( | 30 | from lp.translations.interfaces.translatablemessage import ( |
2659 | @@ -46,12 +47,13 @@ | |||
2660 | 46 | # Create a product with two series and a shared POTemplate | 47 | # Create a product with two series and a shared POTemplate |
2661 | 47 | # in different series ('devel' and 'stable'). | 48 | # in different series ('devel' and 'stable'). |
2662 | 48 | super(TestTranslationSharedPOFile, self).setUp() | 49 | super(TestTranslationSharedPOFile, self).setUp() |
2664 | 49 | self.foo = self.factory.makeProduct(name='foo') | 50 | self.foo = self.factory.makeProduct( |
2665 | 51 | name='foo', | ||
2666 | 52 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
2667 | 50 | self.foo_devel = self.factory.makeProductSeries( | 53 | self.foo_devel = self.factory.makeProductSeries( |
2668 | 51 | name='devel', product=self.foo) | 54 | name='devel', product=self.foo) |
2669 | 52 | self.foo_stable = self.factory.makeProductSeries( | 55 | self.foo_stable = self.factory.makeProductSeries( |
2670 | 53 | name='stable', product=self.foo) | 56 | name='stable', product=self.foo) |
2671 | 54 | self.foo.official_rosetta = True | ||
2672 | 55 | 57 | ||
2673 | 56 | # POTemplate is 'shared' if it has the same name ('messages'). | 58 | # POTemplate is 'shared' if it has the same name ('messages'). |
2674 | 57 | self.devel_potemplate = self.factory.makePOTemplate( | 59 | self.devel_potemplate = self.factory.makePOTemplate( |
2675 | @@ -76,7 +78,8 @@ | |||
2676 | 76 | 'http://translations.launchpad.dev/foo/devel/+pots/messages/sr', | 78 | 'http://translations.launchpad.dev/foo/devel/+pots/messages/sr', |
2677 | 77 | canonical_url(self.devel_sr_pofile)) | 79 | canonical_url(self.devel_sr_pofile)) |
2678 | 78 | self.assertEqual( | 80 | self.assertEqual( |
2680 | 79 | 'http://translations.launchpad.dev/foo/devel/+pots/messages/sr/+details', | 81 | ('http://translations.launchpad.dev/' |
2681 | 82 | 'foo/devel/+pots/messages/sr/+details'), | ||
2682 | 80 | canonical_url(self.devel_sr_pofile, view_name="+details")) | 83 | canonical_url(self.devel_sr_pofile, view_name="+details")) |
2683 | 81 | 84 | ||
2684 | 82 | def test_findPOTMsgSetsContaining(self): | 85 | def test_findPOTMsgSetsContaining(self): |
2685 | @@ -879,12 +882,12 @@ | |||
2686 | 879 | # Create a product with two series and a shared POTemplate | 882 | # Create a product with two series and a shared POTemplate |
2687 | 880 | # in different series ('devel' and 'stable'). | 883 | # in different series ('devel' and 'stable'). |
2688 | 881 | super(TestSharedPOFileCreation, self).setUp() | 884 | super(TestSharedPOFileCreation, self).setUp() |
2690 | 882 | self.foo = self.factory.makeProduct() | 885 | self.foo = self.factory.makeProduct( |
2691 | 886 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
2692 | 883 | self.foo_devel = self.factory.makeProductSeries( | 887 | self.foo_devel = self.factory.makeProductSeries( |
2693 | 884 | name='devel', product=self.foo) | 888 | name='devel', product=self.foo) |
2694 | 885 | self.foo_stable = self.factory.makeProductSeries( | 889 | self.foo_stable = self.factory.makeProductSeries( |
2695 | 886 | name='stable', product=self.foo) | 890 | name='stable', product=self.foo) |
2696 | 887 | self.foo.official_rosetta = True | ||
2697 | 888 | 891 | ||
2698 | 889 | def test_pofile_creation_shared(self): | 892 | def test_pofile_creation_shared(self): |
2699 | 890 | # When a pofile is created in a POTemplate it is also created in | 893 | # When a pofile is created in a POTemplate it is also created in |
2700 | @@ -1009,12 +1012,12 @@ | |||
2701 | 1009 | # Create a product with two series and a shared POTemplate | 1012 | # Create a product with two series and a shared POTemplate |
2702 | 1010 | # in different series ('devel' and 'stable'). | 1013 | # in different series ('devel' and 'stable'). |
2703 | 1011 | super(TestTranslationPOFilePOTMsgSetOrdering, self).setUp() | 1014 | super(TestTranslationPOFilePOTMsgSetOrdering, self).setUp() |
2705 | 1012 | self.foo = self.factory.makeProduct() | 1015 | self.foo = self.factory.makeProduct( |
2706 | 1016 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
2707 | 1013 | self.foo_devel = self.factory.makeProductSeries( | 1017 | self.foo_devel = self.factory.makeProductSeries( |
2708 | 1014 | name='devel', product=self.foo) | 1018 | name='devel', product=self.foo) |
2709 | 1015 | self.foo_stable = self.factory.makeProductSeries( | 1019 | self.foo_stable = self.factory.makeProductSeries( |
2710 | 1016 | name='stable', product=self.foo) | 1020 | name='stable', product=self.foo) |
2711 | 1017 | self.foo.official_rosetta = True | ||
2712 | 1018 | 1021 | ||
2713 | 1019 | # POTemplate is 'shared' if it has the same name ('messages'). | 1022 | # POTemplate is 'shared' if it has the same name ('messages'). |
2714 | 1020 | self.devel_potemplate = self.factory.makePOTemplate( | 1023 | self.devel_potemplate = self.factory.makePOTemplate( |
2715 | @@ -1288,8 +1291,8 @@ | |||
2716 | 1288 | # We create a product with two series, and attach | 1291 | # We create a product with two series, and attach |
2717 | 1289 | # a POTemplate and Serbian POFile to each, making | 1292 | # a POTemplate and Serbian POFile to each, making |
2718 | 1290 | # sure they share translations (potemplates have the same name). | 1293 | # sure they share translations (potemplates have the same name). |
2721 | 1291 | product = self.factory.makeProduct() | 1294 | product = self.factory.makeProduct( |
2722 | 1292 | product.official_rosetta = True | 1295 | translations_usage=ServiceUsage.LAUNCHPAD) |
2723 | 1293 | series1 = self.factory.makeProductSeries(product=product, | 1296 | series1 = self.factory.makeProductSeries(product=product, |
2724 | 1294 | name='one') | 1297 | name='one') |
2725 | 1295 | series2 = self.factory.makeProductSeries(product=product, | 1298 | series2 = self.factory.makeProductSeries(product=product, |
2726 | @@ -1324,8 +1327,8 @@ | |||
2727 | 1324 | # This is a test for bug #414832 which caused sharing POFiles | 1327 | # This is a test for bug #414832 which caused sharing POFiles |
2728 | 1325 | # of the touched POFile not to be returned if they had | 1328 | # of the touched POFile not to be returned if they had |
2729 | 1326 | # IDs smaller than the touched POFile. | 1329 | # IDs smaller than the touched POFile. |
2732 | 1327 | product = self.factory.makeProduct() | 1330 | product = self.factory.makeProduct( |
2733 | 1328 | product.official_rosetta = True | 1331 | translations_usage=ServiceUsage.LAUNCHPAD) |
2734 | 1329 | series1 = self.factory.makeProductSeries(product=product, | 1332 | series1 = self.factory.makeProductSeries(product=product, |
2735 | 1330 | name='one') | 1333 | name='one') |
2736 | 1331 | series2 = self.factory.makeProductSeries(product=product, | 1334 | series2 = self.factory.makeProductSeries(product=product, |
2737 | @@ -1357,7 +1360,7 @@ | |||
2738 | 1357 | # POFile to each, making sure they share translations | 1360 | # POFile to each, making sure they share translations |
2739 | 1358 | # (potemplates have the same name). | 1361 | # (potemplates have the same name). |
2740 | 1359 | distro = self.factory.makeDistribution() | 1362 | distro = self.factory.makeDistribution() |
2742 | 1360 | distro.official_rosetta = True | 1363 | distro.translations_usage = ServiceUsage.LAUNCHPAD |
2743 | 1361 | series1 = self.factory.makeDistroRelease(distribution=distro, | 1364 | series1 = self.factory.makeDistroRelease(distribution=distro, |
2744 | 1362 | name='one') | 1365 | name='one') |
2745 | 1363 | sourcepackagename = self.factory.makeSourcePackageName() | 1366 | sourcepackagename = self.factory.makeSourcePackageName() |
2746 | @@ -1395,9 +1398,9 @@ | |||
2747 | 1395 | # Make sure POFiles which are in different products | 1398 | # Make sure POFiles which are in different products |
2748 | 1396 | # are not returned even though they have the same potemplate name. | 1399 | # are not returned even though they have the same potemplate name. |
2749 | 1397 | series1 = self.factory.makeProductSeries(name='one') | 1400 | series1 = self.factory.makeProductSeries(name='one') |
2751 | 1398 | series1.product.official_rosetta = True | 1401 | series1.product.translations_usage = ServiceUsage.LAUNCHPAD |
2752 | 1399 | series2 = self.factory.makeProductSeries(name='two') | 1402 | series2 = self.factory.makeProductSeries(name='two') |
2754 | 1400 | series2.product.official_rosetta = True | 1403 | series1.product.translations_usage = ServiceUsage.LAUNCHPAD |
2755 | 1401 | self.assertNotEqual(series1.product, series2.product) | 1404 | self.assertNotEqual(series1.product, series2.product) |
2756 | 1402 | 1405 | ||
2757 | 1403 | potemplate1 = self.factory.makePOTemplate(name='shared', | 1406 | potemplate1 = self.factory.makePOTemplate(name='shared', |
2758 | 1404 | 1407 | ||
2759 | === modified file 'lib/lp/translations/tests/test_potemplate.py' | |||
2760 | --- lib/lp/translations/tests/test_potemplate.py 2010-08-20 20:31:18 +0000 | |||
2761 | +++ lib/lp/translations/tests/test_potemplate.py 2010-09-09 15:34:46 +0000 | |||
2762 | @@ -7,6 +7,7 @@ | |||
2763 | 7 | from zope.security.proxy import removeSecurityProxy | 7 | from zope.security.proxy import removeSecurityProxy |
2764 | 8 | 8 | ||
2765 | 9 | from canonical.testing import DatabaseFunctionalLayer | 9 | from canonical.testing import DatabaseFunctionalLayer |
2766 | 10 | from lp.app.enums import ServiceUsage | ||
2767 | 10 | from lp.registry.interfaces.distribution import IDistributionSet | 11 | from lp.registry.interfaces.distribution import IDistributionSet |
2768 | 11 | from lp.services.worlddata.interfaces.language import ILanguageSet | 12 | from lp.services.worlddata.interfaces.language import ILanguageSet |
2769 | 12 | from lp.testing import TestCaseWithFactory | 13 | from lp.testing import TestCaseWithFactory |
2770 | @@ -327,8 +328,8 @@ | |||
2771 | 327 | 328 | ||
2772 | 328 | def setUp(self): | 329 | def setUp(self): |
2773 | 329 | super(TestTemplatePrecedence, self).setUp(user='mark@example.com') | 330 | super(TestTemplatePrecedence, self).setUp(user='mark@example.com') |
2776 | 330 | self.product = self.factory.makeProduct() | 331 | self.product = self.factory.makeProduct( |
2777 | 331 | self.product.official_rosetta = True | 332 | translations_usage=ServiceUsage.LAUNCHPAD) |
2778 | 332 | self.trunk = self.product.getSeries('trunk') | 333 | self.trunk = self.product.getSeries('trunk') |
2779 | 333 | self.one_dot_oh = self.factory.makeProductSeries( | 334 | self.one_dot_oh = self.factory.makeProductSeries( |
2780 | 334 | product=self.product, name='one') | 335 | product=self.product, name='one') |
2781 | 335 | 336 | ||
2782 | === modified file 'lib/lp/translations/tests/test_potmsgset.py' | |||
2783 | --- lib/lp/translations/tests/test_potmsgset.py 2010-08-20 20:31:18 +0000 | |||
2784 | +++ lib/lp/translations/tests/test_potmsgset.py 2010-09-09 15:34:46 +0000 | |||
2785 | @@ -20,6 +20,7 @@ | |||
2786 | 20 | 20 | ||
2787 | 21 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities | 21 | from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
2788 | 22 | from canonical.testing import ZopelessDatabaseLayer | 22 | from canonical.testing import ZopelessDatabaseLayer |
2789 | 23 | from lp.app.enums import ServiceUsage | ||
2790 | 23 | from lp.registry.interfaces.person import IPersonSet | 24 | from lp.registry.interfaces.person import IPersonSet |
2791 | 24 | from lp.registry.interfaces.product import IProductSet | 25 | from lp.registry.interfaces.product import IProductSet |
2792 | 25 | from lp.services.worlddata.interfaces.language import ILanguageSet | 26 | from lp.services.worlddata.interfaces.language import ILanguageSet |
2793 | @@ -45,12 +46,12 @@ | |||
2794 | 45 | # Create a product with two series and a shared POTemplate | 46 | # Create a product with two series and a shared POTemplate |
2795 | 46 | # in different series ('devel' and 'stable'). | 47 | # in different series ('devel' and 'stable'). |
2796 | 47 | super(TestTranslationSharedPOTMsgSets, self).setUp() | 48 | super(TestTranslationSharedPOTMsgSets, self).setUp() |
2798 | 48 | self.foo = self.factory.makeProduct() | 49 | self.foo = self.factory.makeProduct( |
2799 | 50 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
2800 | 49 | self.foo_devel = self.factory.makeProductSeries( | 51 | self.foo_devel = self.factory.makeProductSeries( |
2801 | 50 | name='devel', product=self.foo) | 52 | name='devel', product=self.foo) |
2802 | 51 | self.foo_stable = self.factory.makeProductSeries( | 53 | self.foo_stable = self.factory.makeProductSeries( |
2803 | 52 | name='stable', product=self.foo) | 54 | name='stable', product=self.foo) |
2804 | 53 | self.foo.official_rosetta = True | ||
2805 | 54 | 55 | ||
2806 | 55 | # POTemplate is 'shared' if it has the same name ('messages'). | 56 | # POTemplate is 'shared' if it has the same name ('messages'). |
2807 | 56 | self.devel_potemplate = self.factory.makePOTemplate( | 57 | self.devel_potemplate = self.factory.makePOTemplate( |
2808 | @@ -324,7 +325,8 @@ | |||
2809 | 324 | # Create an external POTemplate with a POTMsgSet using | 325 | # Create an external POTemplate with a POTMsgSet using |
2810 | 325 | # the same English string as the one in self.potmsgset. | 326 | # the same English string as the one in self.potmsgset. |
2811 | 326 | external_template = self.factory.makePOTemplate() | 327 | external_template = self.factory.makePOTemplate() |
2813 | 327 | external_template.productseries.product.official_rosetta = True | 328 | product = external_template.productseries.product |
2814 | 329 | product.translations_usage = ServiceUsage.LAUNCHPAD | ||
2815 | 328 | external_potmsgset = self.factory.makePOTMsgSet( | 330 | external_potmsgset = self.factory.makePOTMsgSet( |
2816 | 329 | external_template, | 331 | external_template, |
2817 | 330 | singular=self.potmsgset.singular_text) | 332 | singular=self.potmsgset.singular_text) |
2818 | @@ -383,7 +385,8 @@ | |||
2819 | 383 | # Create an external POTemplate with a POTMsgSet using | 385 | # Create an external POTemplate with a POTMsgSet using |
2820 | 384 | # the same English string as the one in self.potmsgset. | 386 | # the same English string as the one in self.potmsgset. |
2821 | 385 | external_template = self.factory.makePOTemplate() | 387 | external_template = self.factory.makePOTemplate() |
2823 | 386 | external_template.productseries.product.official_rosetta = True | 388 | product = external_template.productseries.product |
2824 | 389 | product.translations_usage = ServiceUsage.LAUNCHPAD | ||
2825 | 387 | external_potmsgset = self.factory.makePOTMsgSet( | 390 | external_potmsgset = self.factory.makePOTMsgSet( |
2826 | 388 | external_template, | 391 | external_template, |
2827 | 389 | singular=self.potmsgset.singular_text) | 392 | singular=self.potmsgset.singular_text) |
2828 | @@ -738,10 +741,10 @@ | |||
2829 | 738 | # create TranslationMessage objects. | 741 | # create TranslationMessage objects. |
2830 | 739 | super(TestPOTMsgSetSuggestions, self).setUp() | 742 | super(TestPOTMsgSetSuggestions, self).setUp() |
2831 | 740 | self.now = self.gen_now().next | 743 | self.now = self.gen_now().next |
2833 | 741 | self.foo = self.factory.makeProduct() | 744 | self.foo = self.factory.makeProduct( |
2834 | 745 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
2835 | 742 | self.foo_main = self.factory.makeProductSeries( | 746 | self.foo_main = self.factory.makeProductSeries( |
2836 | 743 | name='main', product=self.foo) | 747 | name='main', product=self.foo) |
2837 | 744 | self.foo.official_rosetta = True | ||
2838 | 745 | 748 | ||
2839 | 746 | self.potemplate = self.factory.makePOTemplate( | 749 | self.potemplate = self.factory.makePOTemplate( |
2840 | 747 | productseries=self.foo_main, name="messages") | 750 | productseries=self.foo_main, name="messages") |
2841 | @@ -926,10 +929,10 @@ | |||
2842 | 926 | # create TranslationMessage objects. | 929 | # create TranslationMessage objects. |
2843 | 927 | super(TestPOTMsgSetResetTranslation, self).setUp() | 930 | super(TestPOTMsgSetResetTranslation, self).setUp() |
2844 | 928 | self.now = self.gen_now().next | 931 | self.now = self.gen_now().next |
2846 | 929 | self.foo = self.factory.makeProduct() | 932 | self.foo = self.factory.makeProduct( |
2847 | 933 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
2848 | 930 | self.foo_main = self.factory.makeProductSeries( | 934 | self.foo_main = self.factory.makeProductSeries( |
2849 | 931 | name='main', product=self.foo) | 935 | name='main', product=self.foo) |
2850 | 932 | self.foo.official_rosetta = True | ||
2851 | 933 | 936 | ||
2852 | 934 | self.potemplate = self.factory.makePOTemplate( | 937 | self.potemplate = self.factory.makePOTemplate( |
2853 | 935 | productseries=self.foo_main, name="messages") | 938 | productseries=self.foo_main, name="messages") |
2854 | 936 | 939 | ||
2855 | === modified file 'lib/lp/translations/tests/test_productserieslanguage.py' | |||
2856 | --- lib/lp/translations/tests/test_productserieslanguage.py 2010-08-20 20:31:18 +0000 | |||
2857 | +++ lib/lp/translations/tests/test_productserieslanguage.py 2010-09-09 15:34:46 +0000 | |||
2858 | @@ -10,6 +10,7 @@ | |||
2859 | 10 | from zope.security.proxy import removeSecurityProxy | 10 | from zope.security.proxy import removeSecurityProxy |
2860 | 11 | 11 | ||
2861 | 12 | from canonical.testing import ZopelessDatabaseLayer | 12 | from canonical.testing import ZopelessDatabaseLayer |
2862 | 13 | from lp.app.enums import ServiceUsage | ||
2863 | 13 | from lp.services.worlddata.interfaces.language import ILanguageSet | 14 | from lp.services.worlddata.interfaces.language import ILanguageSet |
2864 | 14 | from lp.testing import TestCaseWithFactory | 15 | from lp.testing import TestCaseWithFactory |
2865 | 15 | from lp.translations.interfaces.productserieslanguage import ( | 16 | from lp.translations.interfaces.productserieslanguage import ( |
2866 | @@ -26,8 +27,10 @@ | |||
2867 | 26 | def setUp(self): | 27 | def setUp(self): |
2868 | 27 | # Create a productseries that uses translations. | 28 | # Create a productseries that uses translations. |
2869 | 28 | TestCaseWithFactory.setUp(self) | 29 | TestCaseWithFactory.setUp(self) |
2872 | 29 | self.productseries = self.factory.makeProductSeries() | 30 | product = self.factory.makeProduct( |
2873 | 30 | self.productseries.product.official_rosetta = True | 31 | translations_usage=ServiceUsage.LAUNCHPAD) |
2874 | 32 | self.productseries = self.factory.makeProductSeries( | ||
2875 | 33 | product=product) | ||
2876 | 31 | 34 | ||
2877 | 32 | def test_no_templates_no_translation(self): | 35 | def test_no_templates_no_translation(self): |
2878 | 33 | # There are no templates and no translations. | 36 | # There are no templates and no translations. |
2879 | @@ -125,8 +128,10 @@ | |||
2880 | 125 | def setUp(self): | 128 | def setUp(self): |
2881 | 126 | # Create a productseries that uses translations. | 129 | # Create a productseries that uses translations. |
2882 | 127 | TestCaseWithFactory.setUp(self) | 130 | TestCaseWithFactory.setUp(self) |
2885 | 128 | self.productseries = self.factory.makeProductSeries() | 131 | product = self.factory.makeProduct( |
2886 | 129 | self.productseries.product.official_rosetta = True | 132 | translations_usage=ServiceUsage.LAUNCHPAD) |
2887 | 133 | self.productseries = self.factory.makeProductSeries( | ||
2888 | 134 | product=product) | ||
2889 | 130 | self.psl_set = getUtility(IProductSeriesLanguageSet) | 135 | self.psl_set = getUtility(IProductSeriesLanguageSet) |
2890 | 131 | self.language = getUtility(ILanguageSet).getLanguageByCode('sr') | 136 | self.language = getUtility(ILanguageSet).getLanguageByCode('sr') |
2891 | 132 | 137 | ||
2892 | 133 | 138 | ||
2893 | === modified file 'lib/lp/translations/tests/test_shared_potemplate.py' | |||
2894 | --- lib/lp/translations/tests/test_shared_potemplate.py 2010-08-20 20:31:18 +0000 | |||
2895 | +++ lib/lp/translations/tests/test_shared_potemplate.py 2010-09-09 15:34:46 +0000 | |||
2896 | @@ -10,6 +10,7 @@ | |||
2897 | 10 | from zope.security.proxy import removeSecurityProxy | 10 | from zope.security.proxy import removeSecurityProxy |
2898 | 11 | 11 | ||
2899 | 12 | from canonical.testing import ZopelessDatabaseLayer | 12 | from canonical.testing import ZopelessDatabaseLayer |
2900 | 13 | from lp.app.enums import ServiceUsage | ||
2901 | 13 | from lp.testing.factory import LaunchpadObjectFactory | 14 | from lp.testing.factory import LaunchpadObjectFactory |
2902 | 14 | 15 | ||
2903 | 15 | 16 | ||
2904 | @@ -24,12 +25,12 @@ | |||
2905 | 24 | # in different series ('devel' and 'stable'). | 25 | # in different series ('devel' and 'stable'). |
2906 | 25 | factory = LaunchpadObjectFactory() | 26 | factory = LaunchpadObjectFactory() |
2907 | 26 | self.factory = factory | 27 | self.factory = factory |
2909 | 27 | self.foo = factory.makeProduct() | 28 | self.foo = self.factory.makeProduct( |
2910 | 29 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
2911 | 28 | self.foo_devel = factory.makeProductSeries( | 30 | self.foo_devel = factory.makeProductSeries( |
2912 | 29 | name='devel', product=self.foo) | 31 | name='devel', product=self.foo) |
2913 | 30 | self.foo_stable = factory.makeProductSeries( | 32 | self.foo_stable = factory.makeProductSeries( |
2914 | 31 | name='stable', product=self.foo) | 33 | name='stable', product=self.foo) |
2915 | 32 | self.foo.official_rosetta = True | ||
2916 | 33 | 34 | ||
2917 | 34 | # POTemplate is a 'sharing' one if it has the same name ('messages'). | 35 | # POTemplate is a 'sharing' one if it has the same name ('messages'). |
2918 | 35 | self.devel_potemplate = factory.makePOTemplate( | 36 | self.devel_potemplate = factory.makePOTemplate( |
2919 | 36 | 37 | ||
2920 | === modified file 'lib/lp/translations/tests/test_suggestions.py' | |||
2921 | --- lib/lp/translations/tests/test_suggestions.py 2010-08-20 20:31:18 +0000 | |||
2922 | +++ lib/lp/translations/tests/test_suggestions.py 2010-09-09 15:34:46 +0000 | |||
2923 | @@ -17,6 +17,7 @@ | |||
2924 | 17 | 17 | ||
2925 | 18 | from canonical.config import config | 18 | from canonical.config import config |
2926 | 19 | from canonical.testing import LaunchpadZopelessLayer | 19 | from canonical.testing import LaunchpadZopelessLayer |
2927 | 20 | from lp.app.enums import ServiceUsage | ||
2928 | 20 | from lp.services.worlddata.interfaces.language import ILanguageSet | 21 | from lp.services.worlddata.interfaces.language import ILanguageSet |
2929 | 21 | from lp.testing.factory import LaunchpadObjectFactory | 22 | from lp.testing.factory import LaunchpadObjectFactory |
2930 | 22 | from lp.translations.interfaces.translationmessage import ( | 23 | from lp.translations.interfaces.translationmessage import ( |
2931 | @@ -36,10 +37,14 @@ | |||
2932 | 36 | # suggestions for the other. | 37 | # suggestions for the other. |
2933 | 37 | factory = LaunchpadObjectFactory() | 38 | factory = LaunchpadObjectFactory() |
2934 | 38 | self.factory = factory | 39 | self.factory = factory |
2939 | 39 | self.foo_trunk = factory.makeProductSeries() | 40 | foo_product = factory.makeProduct( |
2940 | 40 | self.bar_trunk = factory.makeProductSeries() | 41 | translations_usage=ServiceUsage.LAUNCHPAD) |
2941 | 41 | self.foo_trunk.product.official_rosetta = True | 42 | bar_product = factory.makeProduct( |
2942 | 42 | self.bar_trunk.product.official_rosetta = True | 43 | translations_usage=ServiceUsage.LAUNCHPAD) |
2943 | 44 | self.foo_trunk = factory.makeProductSeries( | ||
2944 | 45 | product=foo_product) | ||
2945 | 46 | self.bar_trunk = factory.makeProductSeries( | ||
2946 | 47 | product=bar_product) | ||
2947 | 43 | self.foo_template = factory.makePOTemplate(self.foo_trunk) | 48 | self.foo_template = factory.makePOTemplate(self.foo_trunk) |
2948 | 44 | self.bar_template = factory.makePOTemplate(self.bar_trunk) | 49 | self.bar_template = factory.makePOTemplate(self.bar_trunk) |
2949 | 45 | self.nl = getUtility(ILanguageSet).getLanguageByCode('nl') | 50 | self.nl = getUtility(ILanguageSet).getLanguageByCode('nl') |
2950 | @@ -222,5 +227,6 @@ | |||
2951 | 222 | "TranslationMessage with errors is not correctly" | 227 | "TranslationMessage with errors is not correctly" |
2952 | 223 | "marked as such in the database.") | 228 | "marked as such in the database.") |
2953 | 224 | 229 | ||
2954 | 230 | |||
2955 | 225 | def test_suite(): | 231 | def test_suite(): |
2956 | 226 | return unittest.TestLoader().loadTestsFromName(__name__) | 232 | return unittest.TestLoader().loadTestsFromName(__name__) |
2957 | 227 | 233 | ||
2958 | === modified file 'lib/lp/translations/tests/test_translatablemessage.py' | |||
2959 | --- lib/lp/translations/tests/test_translatablemessage.py 2010-08-20 20:31:18 +0000 | |||
2960 | +++ lib/lp/translations/tests/test_translatablemessage.py 2010-09-09 15:34:46 +0000 | |||
2961 | @@ -15,6 +15,7 @@ | |||
2962 | 15 | import transaction | 15 | import transaction |
2963 | 16 | 16 | ||
2964 | 17 | from canonical.testing import ZopelessDatabaseLayer | 17 | from canonical.testing import ZopelessDatabaseLayer |
2965 | 18 | from lp.app.enums import ServiceUsage | ||
2966 | 18 | from lp.testing import TestCaseWithFactory | 19 | from lp.testing import TestCaseWithFactory |
2967 | 19 | from lp.translations.model.translatablemessage import TranslatableMessage | 20 | from lp.translations.model.translatablemessage import TranslatableMessage |
2968 | 20 | 21 | ||
2969 | @@ -31,8 +32,8 @@ | |||
2970 | 31 | `POTMsgSet`, as well as a Esperanto translation. | 32 | `POTMsgSet`, as well as a Esperanto translation. |
2971 | 32 | """ | 33 | """ |
2972 | 33 | super(TestTranslatableMessageBase, self).setUp() | 34 | super(TestTranslatableMessageBase, self).setUp() |
2975 | 34 | self.product = self.factory.makeProduct() | 35 | self.product = self.factory.makeProduct( |
2976 | 35 | self.product.official_rosetta = True | 36 | translations_usage=ServiceUsage.LAUNCHPAD) |
2977 | 36 | self.trunk = self.product.getSeries('trunk') | 37 | self.trunk = self.product.getSeries('trunk') |
2978 | 37 | self.potemplate = self.factory.makePOTemplate( | 38 | self.potemplate = self.factory.makePOTemplate( |
2979 | 38 | productseries=self.trunk) | 39 | productseries=self.trunk) |
2980 | @@ -137,7 +138,8 @@ | |||
2981 | 137 | super(TestTranslatableMessageExternal, self).setUp() | 138 | super(TestTranslatableMessageExternal, self).setUp() |
2982 | 138 | common_msgid = self.potmsgset.singular_text | 139 | common_msgid = self.potmsgset.singular_text |
2983 | 139 | self.external_potemplate = self.factory.makePOTemplate() | 140 | self.external_potemplate = self.factory.makePOTemplate() |
2985 | 140 | self.external_potemplate.productseries.product.official_rosetta = True | 141 | product = self.external_potemplate.productseries.product |
2986 | 142 | product.translations_usage = ServiceUsage.LAUNCHPAD | ||
2987 | 141 | self.external_potmsgset = self.factory.makePOTMsgSet( | 143 | self.external_potmsgset = self.factory.makePOTMsgSet( |
2988 | 142 | potemplate=self.external_potemplate, | 144 | potemplate=self.external_potemplate, |
2989 | 143 | singular=common_msgid, sequence=1) | 145 | singular=common_msgid, sequence=1) |
2990 | @@ -175,24 +177,24 @@ | |||
2991 | 175 | super(TestTranslatableMessageSuggestions, self).setUp() | 177 | super(TestTranslatableMessageSuggestions, self).setUp() |
2992 | 176 | self.now = self.gen_now().next | 178 | self.now = self.gen_now().next |
2993 | 177 | self.suggestion1 = self._createTranslation(date_updated=self.now()) | 179 | self.suggestion1 = self._createTranslation(date_updated=self.now()) |
2995 | 178 | self.current = self._createTranslation(is_current=True, | 180 | self.current = self._createTranslation(is_current=True, |
2996 | 179 | date_updated=self.now()) | 181 | date_updated=self.now()) |
2997 | 180 | self.suggestion2 = self._createTranslation(date_updated=self.now()) | 182 | self.suggestion2 = self._createTranslation(date_updated=self.now()) |
2998 | 181 | self.message = TranslatableMessage(self.potmsgset, self.pofile) | 183 | self.message = TranslatableMessage(self.potmsgset, self.pofile) |
2999 | 182 | 184 | ||
3000 | 183 | def test_getAllSuggestions(self): | 185 | def test_getAllSuggestions(self): |
3002 | 184 | # There are three different methods to return | 186 | # There are three different methods to return |
3003 | 185 | suggestions = self.message.getAllSuggestions() | 187 | suggestions = self.message.getAllSuggestions() |
3004 | 186 | self.assertContentEqual([self.suggestion1, self.suggestion2], | 188 | self.assertContentEqual([self.suggestion1, self.suggestion2], |
3005 | 187 | suggestions) | 189 | suggestions) |
3006 | 188 | 190 | ||
3007 | 189 | def test_getDismissedSuggestions(self): | 191 | def test_getDismissedSuggestions(self): |
3009 | 190 | # There are three different methods to return | 192 | # There are three different methods to return |
3010 | 191 | suggestions = self.message.getDismissedSuggestions() | 193 | suggestions = self.message.getDismissedSuggestions() |
3011 | 192 | self.assertContentEqual([self.suggestion1], suggestions) | 194 | self.assertContentEqual([self.suggestion1], suggestions) |
3012 | 193 | 195 | ||
3013 | 194 | def test_getUnreviewedSuggestions(self): | 196 | def test_getUnreviewedSuggestions(self): |
3015 | 195 | # There are three different methods to return | 197 | # There are three different methods to return |
3016 | 196 | suggestions = self.message.getUnreviewedSuggestions() | 198 | suggestions = self.message.getUnreviewedSuggestions() |
3017 | 197 | self.assertContentEqual([self.suggestion2], suggestions) | 199 | self.assertContentEqual([self.suggestion2], suggestions) |
3018 | 198 | 200 | ||
3019 | 199 | 201 | ||
3020 | === modified file 'lib/lp/translations/tests/test_translatedlanguage.py' | |||
3021 | --- lib/lp/translations/tests/test_translatedlanguage.py 2010-08-20 20:31:18 +0000 | |||
3022 | +++ lib/lp/translations/tests/test_translatedlanguage.py 2010-09-09 15:34:46 +0000 | |||
3023 | @@ -8,6 +8,7 @@ | |||
3024 | 8 | from zope.security.proxy import removeSecurityProxy | 8 | from zope.security.proxy import removeSecurityProxy |
3025 | 9 | 9 | ||
3026 | 10 | from canonical.testing import ZopelessDatabaseLayer | 10 | from canonical.testing import ZopelessDatabaseLayer |
3027 | 11 | from lp.app.enums import ServiceUsage | ||
3028 | 11 | from lp.testing import TestCaseWithFactory | 12 | from lp.testing import TestCaseWithFactory |
3029 | 12 | from lp.translations.interfaces.productserieslanguage import ( | 13 | from lp.translations.interfaces.productserieslanguage import ( |
3030 | 13 | IProductSeriesLanguageSet, | 14 | IProductSeriesLanguageSet, |
3031 | @@ -24,8 +25,10 @@ | |||
3032 | 24 | def setUp(self): | 25 | def setUp(self): |
3033 | 25 | # Create a productseries that uses translations. | 26 | # Create a productseries that uses translations. |
3034 | 26 | TestCaseWithFactory.setUp(self) | 27 | TestCaseWithFactory.setUp(self) |
3037 | 27 | self.productseries = self.factory.makeProductSeries() | 28 | product = self.factory.makeProduct( |
3038 | 28 | self.productseries.product.official_rosetta = True | 29 | translations_usage = ServiceUsage.LAUNCHPAD) |
3039 | 30 | self.productseries = self.factory.makeProductSeries( | ||
3040 | 31 | product=product) | ||
3041 | 29 | self.parent = self.productseries | 32 | self.parent = self.productseries |
3042 | 30 | self.psl_set = getUtility(IProductSeriesLanguageSet) | 33 | self.psl_set = getUtility(IProductSeriesLanguageSet) |
3043 | 31 | self.language = self.factory.makeLanguage('sr@test') | 34 | self.language = self.factory.makeLanguage('sr@test') |
3044 | 32 | 35 | ||
3045 | === modified file 'lib/lp/translations/tests/test_translations_to_review.py' | |||
3046 | --- lib/lp/translations/tests/test_translations_to_review.py 2010-08-20 20:31:18 +0000 | |||
3047 | +++ lib/lp/translations/tests/test_translations_to_review.py 2010-09-09 15:34:46 +0000 | |||
3048 | @@ -16,6 +16,7 @@ | |||
3049 | 16 | from zope.security.proxy import removeSecurityProxy | 16 | from zope.security.proxy import removeSecurityProxy |
3050 | 17 | 17 | ||
3051 | 18 | from canonical.testing import DatabaseFunctionalLayer | 18 | from canonical.testing import DatabaseFunctionalLayer |
3052 | 19 | from lp.app.enums import ServiceUsage | ||
3053 | 19 | from lp.services.worlddata.model.language import LanguageSet | 20 | from lp.services.worlddata.model.language import LanguageSet |
3054 | 20 | from lp.testing import TestCaseWithFactory | 21 | from lp.testing import TestCaseWithFactory |
3055 | 21 | from lp.translations.interfaces.translationsperson import ITranslationsPerson | 22 | from lp.translations.interfaces.translationsperson import ITranslationsPerson |
3056 | @@ -28,6 +29,7 @@ | |||
3057 | 28 | 29 | ||
3058 | 29 | class ReviewTestMixin: | 30 | class ReviewTestMixin: |
3059 | 30 | """Base for testing which translations a reviewer can review.""" | 31 | """Base for testing which translations a reviewer can review.""" |
3060 | 32 | |||
3061 | 31 | def setUpMixin(self, for_product=True): | 33 | def setUpMixin(self, for_product=True): |
3062 | 32 | """Set up test environment. | 34 | """Set up test environment. |
3063 | 33 | 35 | ||
3064 | @@ -68,7 +70,7 @@ | |||
3065 | 68 | transaction.commit() | 70 | transaction.commit() |
3066 | 69 | 71 | ||
3067 | 70 | self.supercontext.translationgroup = self.translationgroup | 72 | self.supercontext.translationgroup = self.translationgroup |
3069 | 71 | self.supercontext.official_rosetta = True | 73 | self.supercontext.translations_usage = ServiceUsage.LAUNCHPAD |
3070 | 72 | 74 | ||
3071 | 73 | self.potemplate = self.factory.makePOTemplate( | 75 | self.potemplate = self.factory.makePOTemplate( |
3072 | 74 | productseries=self.productseries, distroseries=self.distroseries, | 76 | productseries=self.productseries, distroseries=self.distroseries, |
3073 | @@ -111,6 +113,7 @@ | |||
3074 | 111 | 113 | ||
3075 | 112 | Can be applied to product or distribution setups. | 114 | Can be applied to product or distribution setups. |
3076 | 113 | """ | 115 | """ |
3077 | 116 | |||
3078 | 114 | def test_OneFileToReview(self): | 117 | def test_OneFileToReview(self): |
3079 | 115 | # In the base case, the method finds one POFile for self.person | 118 | # In the base case, the method finds one POFile for self.person |
3080 | 116 | # to review. | 119 | # to review. |
3081 | @@ -131,7 +134,7 @@ | |||
3082 | 131 | def test_getReviewableTranslationFiles_not_translating_in_launchpad(self): | 134 | def test_getReviewableTranslationFiles_not_translating_in_launchpad(self): |
3083 | 132 | # We don't see products/distros that don't use Launchpad for | 135 | # We don't see products/distros that don't use Launchpad for |
3084 | 133 | # translations. | 136 | # translations. |
3086 | 134 | self.supercontext.official_rosetta = False | 137 | self.supercontext.translations_usage = ServiceUsage.NOT_APPLICABLE |
3087 | 135 | self.assertEqual(self._getReviewables(), []) | 138 | self.assertEqual(self._getReviewables(), []) |
3088 | 136 | 139 | ||
3089 | 137 | def test_getReviewableTranslationFiles_non_reviewer(self): | 140 | def test_getReviewableTranslationFiles_non_reviewer(self): |
3090 | @@ -200,7 +203,7 @@ | |||
3091 | 200 | other_pofile = removeSecurityProxy(other_pofile) | 203 | other_pofile = removeSecurityProxy(other_pofile) |
3092 | 201 | 204 | ||
3093 | 202 | product = other_pofile.potemplate.productseries.product | 205 | product = other_pofile.potemplate.productseries.product |
3095 | 203 | product.official_rosetta = True | 206 | product.translations_usage = ServiceUsage.LAUNCHPAD |
3096 | 204 | 207 | ||
3097 | 205 | if with_unreviewed: | 208 | if with_unreviewed: |
3098 | 206 | other_pofile.unreviewed_count = 1 | 209 | other_pofile.unreviewed_count = 1 |
3099 | 207 | 210 | ||
3100 | === modified file 'lib/lp/translations/windmill/tests/test_documentation_links.py' | |||
3101 | --- lib/lp/translations/windmill/tests/test_documentation_links.py 2010-08-20 20:31:18 +0000 | |||
3102 | +++ lib/lp/translations/windmill/tests/test_documentation_links.py 2010-09-09 15:34:46 +0000 | |||
3103 | @@ -9,6 +9,7 @@ | |||
3104 | 9 | from zope.security.proxy import removeSecurityProxy | 9 | from zope.security.proxy import removeSecurityProxy |
3105 | 10 | 10 | ||
3106 | 11 | from canonical.launchpad.windmill.testing import lpuser | 11 | from canonical.launchpad.windmill.testing import lpuser |
3107 | 12 | from lp.app.enums import ServiceUsage | ||
3108 | 12 | from lp.testing import WindmillTestCase | 13 | from lp.testing import WindmillTestCase |
3109 | 13 | from lp.translations.windmill.testing import TranslationsWindmillLayer | 14 | from lp.translations.windmill.testing import TranslationsWindmillLayer |
3110 | 14 | 15 | ||
3111 | @@ -52,7 +53,7 @@ | |||
3112 | 52 | project = self.factory.makeProduct( | 53 | project = self.factory.makeProduct( |
3113 | 53 | name='test-product', | 54 | name='test-product', |
3114 | 54 | displayname='Test Product', | 55 | displayname='Test Product', |
3116 | 55 | official_rosetta=True) | 56 | translations_usage=ServiceUsage.LAUNCHPAD) |
3117 | 56 | removeSecurityProxy(project).translationgroup = group | 57 | removeSecurityProxy(project).translationgroup = group |
3118 | 57 | 58 | ||
3119 | 58 | potemplate = self.createPOTemplateWithPOTMsgSets( | 59 | potemplate = self.createPOTemplateWithPOTMsgSets( |
3120 | 59 | 60 | ||
3121 | === modified file 'lib/lp/translations/windmill/tests/test_import_queue.py' | |||
3122 | --- lib/lp/translations/windmill/tests/test_import_queue.py 2010-08-20 20:31:18 +0000 | |||
3123 | +++ lib/lp/translations/windmill/tests/test_import_queue.py 2010-09-09 15:34:46 +0000 | |||
3124 | @@ -8,7 +8,6 @@ | |||
3125 | 8 | 8 | ||
3126 | 9 | import transaction | 9 | import transaction |
3127 | 10 | from zope.component import getUtility | 10 | from zope.component import getUtility |
3128 | 11 | from zope.security.proxy import removeSecurityProxy | ||
3129 | 12 | 11 | ||
3130 | 13 | from canonical.launchpad.webapp import canonical_url | 12 | from canonical.launchpad.webapp import canonical_url |
3131 | 14 | from canonical.launchpad.windmill.testing import lpuser | 13 | from canonical.launchpad.windmill.testing import lpuser |
3132 | @@ -18,6 +17,7 @@ | |||
3133 | 18 | SLEEP, | 17 | SLEEP, |
3134 | 19 | ) | 18 | ) |
3135 | 20 | from canonical.launchpad.windmill.testing.lpuser import login_person | 19 | from canonical.launchpad.windmill.testing.lpuser import login_person |
3136 | 20 | from lp.app.enums import ServiceUsage | ||
3137 | 21 | from lp.testing import WindmillTestCase | 21 | from lp.testing import WindmillTestCase |
3138 | 22 | from lp.translations.interfaces.translationimportqueue import ( | 22 | from lp.translations.interfaces.translationimportqueue import ( |
3139 | 23 | ITranslationImportQueue, | 23 | ITranslationImportQueue, |
3140 | @@ -41,8 +41,8 @@ | |||
3141 | 41 | 'field.potemplate', | 41 | 'field.potemplate', |
3142 | 42 | 'field.potemplate_name', | 42 | 'field.potemplate_name', |
3143 | 43 | 'field.language', | 43 | 'field.language', |
3146 | 44 | ] | 44 | ], |
3147 | 45 | } | 45 | } |
3148 | 46 | SELECT_FIELDS = [ | 46 | SELECT_FIELDS = [ |
3149 | 47 | 'field.potemplate', | 47 | 'field.potemplate', |
3150 | 48 | 'field.language', | 48 | 'field.language', |
3151 | @@ -55,8 +55,7 @@ | |||
3152 | 55 | input_tag = 'input' | 55 | input_tag = 'input' |
3153 | 56 | return ( | 56 | return ( |
3154 | 57 | u"//tr[contains(@class,'unseen')]" | 57 | u"//tr[contains(@class,'unseen')]" |
3157 | 58 | u"//%s[@id='%s']" % (input_tag, field_id) | 58 | u"//%s[@id='%s']" % (input_tag, field_id)) |
3156 | 59 | ) | ||
3158 | 60 | 59 | ||
3159 | 61 | def _assertAllFieldsVisible(self, client, fields): | 60 | def _assertAllFieldsVisible(self, client, fields): |
3160 | 62 | """Assert that all given fields are visible. | 61 | """Assert that all given fields are visible. |
3161 | @@ -279,8 +278,9 @@ | |||
3162 | 279 | name="hubert", displayname="Hubert Hunt", password="test", | 278 | name="hubert", displayname="Hubert Hunt", password="test", |
3163 | 280 | email="hubert@example.com") | 279 | email="hubert@example.com") |
3164 | 281 | # Create a project and an import entry with it. | 280 | # Create a project and an import entry with it. |
3167 | 282 | product = self.factory.makeProduct(owner=hubert) | 281 | product = self.factory.makeProduct( |
3168 | 283 | removeSecurityProxy(product).official_rosetta = True | 282 | owner=hubert, |
3169 | 283 | translations_usage=ServiceUsage.LAUNCHPAD) | ||
3170 | 284 | productseries = product.getSeries('trunk') | 284 | productseries = product.getSeries('trunk') |
3171 | 285 | queue = getUtility(ITranslationImportQueue) | 285 | queue = getUtility(ITranslationImportQueue) |
3172 | 286 | potemplate = self.factory.makePOTemplate(productseries=productseries) | 286 | potemplate = self.factory.makePOTemplate(productseries=productseries) |
Needs bugs for the two problems marked with XXXes (lines 422 et al, and line 453). Other than that, it looks good.