Merge lp://qastaging/~henninge/launchpad/bug-128324 into lp://qastaging/launchpad
- bug-128324
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Henning Eggers |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp://qastaging/~henninge/launchpad/bug-128324 |
Merge into: | lp://qastaging/launchpad |
Diff against target: |
588 lines 8 files modified
lib/lp/testing/factory.py (+2/-4) lib/lp/translations/doc/potmsgset.txt (+7/-69) lib/lp/translations/interfaces/potemplate.py (+15/-7) lib/lp/translations/model/potemplate.py (+14/-6) lib/lp/translations/tests/test_pofile.py (+48/-12) lib/lp/translations/tests/test_potmsgset.py (+95/-1) lib/lp/translations/tests/test_shared_potemplate.py (+11/-38) lib/lp/translations/tests/test_vpoexport.py (+0/-62) |
To merge this branch: | bzr merge lp://qastaging/~henninge/launchpad/bug-128324 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeroen T. Vermeulen (community) | Approve | ||
Review via email: mp+13946@code.qastaging.launchpad.net |
Commit message
Description of the change
Henning Eggers (henninge) wrote : | # |
Henning Eggers (henninge) wrote : | # |
I missed a test...
Directly related:
bin/test -vvt potmsgset.txt -t TestPOTMsgSetTr
Indirectly related:
bin/test -vvt TestTranslation
Jeroen T. Vermeulen (jtv) wrote : | # |
Looks good; I particularly like the tech debt payoff component in this branch.
It's not really explicit, but I take it the "half" of the bug that you're not solving here is the one where you mark credits as translated when you create a new POFile. If so, there really ought to be a separate bug about that. Could you see to it?
One nit: _launchpad_
Jeroen
Preview Diff
1 | === modified file 'lib/lp/testing/factory.py' |
2 | --- lib/lp/testing/factory.py 2009-10-23 13:51:40 +0000 |
3 | +++ lib/lp/testing/factory.py 2009-10-26 15:28:11 +0000 |
4 | @@ -1566,14 +1566,12 @@ |
5 | create_sharing=create_sharing) |
6 | |
7 | def makePOTMsgSet(self, potemplate, singular=None, plural=None, |
8 | - context=None, sequence=None): |
9 | + context=None, sequence=0): |
10 | """Make a new `POTMsgSet` in the given template.""" |
11 | if singular is None and plural is None: |
12 | singular = self.getUniqueString() |
13 | potmsgset = potemplate.createMessageSetFromText( |
14 | - singular, plural, context=context) |
15 | - if sequence is not None: |
16 | - potmsgset.setSequence(potemplate, sequence) |
17 | + singular, plural, context, sequence) |
18 | naked_potmsgset = removeSecurityProxy(potmsgset) |
19 | naked_potmsgset.sync() |
20 | return potmsgset |
21 | |
22 | === modified file 'lib/lp/translations/doc/potmsgset.txt' |
23 | --- lib/lp/translations/doc/potmsgset.txt 2009-10-22 15:51:58 +0000 |
24 | +++ lib/lp/translations/doc/potmsgset.txt 2009-10-26 15:28:11 +0000 |
25 | @@ -34,79 +34,17 @@ |
26 | is_translation_credit indicates if the POTMsgSet is translation credits. The |
27 | property translation_credit_type contains the type of translation credits. |
28 | |
29 | - >>> def print_credits(credits): |
30 | - ... print credits.is_translation_credit |
31 | - ... print credits.translation_credits_type.title |
32 | - |
33 | - >>> print_credits(factory.makePOTMsgSet(potemplate)) |
34 | + >>> print potmsgset.is_translation_credit |
35 | False |
36 | + >>> print potmsgset.translation_credits_type.title |
37 | Not a translation credits message |
38 | |
39 | - >>> print_credits(factory.makePOTMsgSet( |
40 | - ... potemplate, singular=u'translator-credits')) |
41 | - True |
42 | - Gnome credits message |
43 | - |
44 | - >>> print_credits(factory.makePOTMsgSet( |
45 | - ... potemplate, singular=u'translation-credits')) |
46 | - True |
47 | - Gnome credits message |
48 | - |
49 | - >>> print_credits(factory.makePOTMsgSet( |
50 | - ... potemplate, |
51 | - ... singular=u'Your emails', context=u'EMAIL OF TRANSLATORS')) |
52 | - True |
53 | - KDE emails credits message |
54 | - |
55 | - >>> print_credits(factory.makePOTMsgSet( |
56 | - ... potemplate, singular=u'_: EMAIL OF TRANSLATORS\nYour emails')) |
57 | - True |
58 | - KDE emails credits message |
59 | - |
60 | - |
61 | -== POTMsgSet.setTranslationCreditsToTranslated == |
62 | - |
63 | -If a message is a translation credits message, its translations must be set |
64 | -to some dummy value so that they are counted as "translated" and don't |
65 | -mess up the statistics. |
66 | - |
67 | - >>> eo_pofile = factory.makePOFile('eo', potemplate=potemplate) |
68 | - >>> eo_language = eo_pofile.language |
69 | - >>> gnome_credits = factory.makePOTMsgSet( |
70 | + >>> credits = factory.makePOTMsgSet( |
71 | ... potemplate, singular=u'translator-credits') |
72 | - >>> current = gnome_credits.getCurrentTranslationMessage(potemplate, |
73 | - ... eo_language) |
74 | - >>> print current |
75 | - None |
76 | - >>> login("foo.bar@canonical.com") |
77 | - >>> gnome_credits.setTranslationCreditsToTranslated(eo_pofile) |
78 | - >>> current = gnome_credits.getCurrentTranslationMessage(potemplate, |
79 | - ... eo_language) |
80 | - >>> print current.msgstr0.translation |
81 | - This is a dummy translation so that the credits are counted as translated. |
82 | - |
83 | -An imported translation credits message will already contain a translation |
84 | -and is therefore left untouched. |
85 | - |
86 | - >>> from zope.security.proxy import removeSecurityProxy |
87 | - >>> sr_pofile = removeSecurityProxy(factory.makePOFile('sr', potemplate=potemplate)) |
88 | - >>> sr_language = sr_pofile.language |
89 | - >>> sr_credits = factory.makeTranslationMessage( |
90 | - ... potmsgset=gnome_credits, pofile=sr_pofile, is_imported=True, |
91 | - ... translations=[u"Some translations credits for Serbian."]) |
92 | - >>> gnome_credits.setTranslationCreditsToTranslated(sr_pofile) |
93 | - >>> current = gnome_credits.getCurrentTranslationMessage(potemplate, |
94 | - ... sr_language) |
95 | - >>> print current.msgstr0.translation |
96 | - Some translations credits for Serbian. |
97 | - |
98 | -Normal messages will be left untouched, too. |
99 | - |
100 | - >>> potmsgset.setTranslationCreditsToTranslated(sr_language) |
101 | - >>> current = potmsgset.getCurrentTranslationMessage(potemplate, |
102 | - ... sr_pofile) |
103 | - >>> print current |
104 | - None |
105 | + >>> print credits.is_translation_credit |
106 | + True |
107 | + >>> print credits.translation_credits_type.title |
108 | + Gnome credits message |
109 | |
110 | |
111 | == POTMsgSet.normalizeWhitespaces == |
112 | |
113 | === modified file 'lib/lp/translations/interfaces/potemplate.py' |
114 | --- lib/lp/translations/interfaces/potemplate.py 2009-10-23 21:50:23 +0000 |
115 | +++ lib/lp/translations/interfaces/potemplate.py 2009-10-26 15:28:11 +0000 |
116 | @@ -463,27 +463,35 @@ |
117 | """ |
118 | |
119 | def createPOTMsgSetFromMsgIDs(msgid_singular, msgid_plural=None, |
120 | - context=None): |
121 | + context=None, sequence=0): |
122 | """Creates a new template message in the database. |
123 | |
124 | :param msgid_singular: A reference to a singular msgid. |
125 | :param msgid_plural: A reference to a plural msgid. Can be None |
126 | - if the message is not a plural message. |
127 | + if the message is not a plural message. |
128 | :param context: A context for the template message differentiating |
129 | - it from other template messages with exactly the same `msgid`. |
130 | + it from other template messages with exactly the same `msgid`. |
131 | + :param sequence: The sequence number of this POTMsgSet within this |
132 | + POTemplate. If 0, it is considered obsolete. |
133 | :return: The newly created message set. |
134 | """ |
135 | |
136 | - def createMessageSetFromText(singular_text, plural_text, context=None): |
137 | + def createMessageSetFromText(singular_text, plural_text, |
138 | + context=None, sequence=0): |
139 | """Creates a new template message in the database using strings. |
140 | |
141 | Similar to createMessageSetFromMessageID, but takes text objects |
142 | (unicode or string) along with textual context, rather than a |
143 | message IDs. |
144 | |
145 | - For non-plural messages, plural_text should be None. |
146 | - |
147 | - Returns the newly created message set. |
148 | + :param singular_text: The string for the singular msgid. |
149 | + :param msgid_plural: The string for the plural msgid. Must be None |
150 | + if the message is not a plural message. |
151 | + :param context: A context for the template message differentiating |
152 | + it from other template messages with exactly the same `msgid`. |
153 | + :param sequence: The sequence number of this POTMsgSet within this |
154 | + POTemplate. If 0, it is considered obsolete. |
155 | + :return: The newly created message set. |
156 | """ |
157 | |
158 | def getOrCreateSharedPOTMsgSet(singular_text, plural_text, context=None): |
159 | |
160 | === modified file 'lib/lp/translations/model/potemplate.py' |
161 | --- lib/lp/translations/model/potemplate.py 2009-10-23 21:50:23 +0000 |
162 | +++ lib/lp/translations/model/potemplate.py 2009-10-26 15:28:11 +0000 |
163 | @@ -799,9 +799,9 @@ |
164 | return DummyPOFile(self, language, variant=variant, owner=requester) |
165 | |
166 | def createPOTMsgSetFromMsgIDs(self, msgid_singular, msgid_plural=None, |
167 | - context=None): |
168 | + context=None, sequence=0): |
169 | """See `IPOTemplate`.""" |
170 | - return POTMsgSet( |
171 | + potmsgset = POTMsgSet( |
172 | context=context, |
173 | msgid_singular=msgid_singular, |
174 | msgid_plural=msgid_plural, |
175 | @@ -812,6 +812,15 @@ |
176 | sourcecomment=None, |
177 | flagscomment=None) |
178 | |
179 | + potmsgset.setSequence(self, sequence) |
180 | + if potmsgset.is_translation_credit: |
181 | + for language in self.languages(): |
182 | + pofile = self.getPOFileByLang(language.code) |
183 | + if pofile is not None: |
184 | + potmsgset.setTranslationCreditsToTranslated(pofile) |
185 | + |
186 | + return potmsgset |
187 | + |
188 | def getOrCreatePOMsgID(self, text): |
189 | """Creates or returns existing POMsgID for given `text`.""" |
190 | try: |
191 | @@ -824,7 +833,7 @@ |
192 | return msgid |
193 | |
194 | def createMessageSetFromText(self, singular_text, plural_text, |
195 | - context=None): |
196 | + context=None, sequence=0): |
197 | """See `IPOTemplate`.""" |
198 | |
199 | msgid_singular = self.getOrCreatePOMsgID(singular_text) |
200 | @@ -837,7 +846,7 @@ |
201 | " primary msgid and context '%r'" % context) |
202 | |
203 | return self.createPOTMsgSetFromMsgIDs(msgid_singular, msgid_plural, |
204 | - context) |
205 | + context, sequence) |
206 | |
207 | def getOrCreateSharedPOTMsgSet(self, singular_text, plural_text, |
208 | context=None): |
209 | @@ -851,8 +860,7 @@ |
210 | context, sharing_templates=True) |
211 | if potmsgset is None: |
212 | potmsgset = self.createMessageSetFromText( |
213 | - singular_text, plural_text, context) |
214 | - potmsgset.setSequence(self, 0) |
215 | + singular_text, plural_text, context, sequence=0) |
216 | return potmsgset |
217 | |
218 | def importFromQueue(self, entry_to_import, logger=None, txn=None): |
219 | |
220 | === modified file 'lib/lp/translations/tests/test_pofile.py' |
221 | --- lib/lp/translations/tests/test_pofile.py 2009-10-20 19:34:26 +0000 |
222 | +++ lib/lp/translations/tests/test_pofile.py 2009-10-26 15:28:11 +0000 |
223 | @@ -926,6 +926,14 @@ |
224 | self.credits_potmsgset = self.factory.makePOTMsgSet( |
225 | potemplate=self.potemplate, singular=u'translator-credits') |
226 | |
227 | + def compose_launchpad_credits_text(self, imported_credits_text): |
228 | + return u"%s\n\nLaunchpad Contributions:\n %s" % ( |
229 | + imported_credits_text, |
230 | + "\n ".join(["%s %s" % (person.displayname, |
231 | + canonical_url(person)) |
232 | + for person in self.pofile.contributors]) |
233 | + ) |
234 | + |
235 | def test_prepareTranslationCredits_extending(self): |
236 | # This test ensures that continuous updates to the translation credits |
237 | # don't result in duplicate entries. |
238 | @@ -933,10 +941,6 @@ |
239 | person = self.factory.makePerson() |
240 | |
241 | imported_credits_text = u"Imported Contributor <name@project.org>" |
242 | - launchpad_credits_text = ( |
243 | - u"%s\n\nLaunchpad Contributions:\n %s %s" % ( |
244 | - imported_credits_text, person.displayname, |
245 | - canonical_url(person))) |
246 | |
247 | # Import a translation credits message to 'translator-credits'. |
248 | self.factory.makeTranslationMessage( |
249 | @@ -954,7 +958,9 @@ |
250 | # The first translation credits export. |
251 | credits_text = self.pofile.prepareTranslationCredits( |
252 | self.credits_potmsgset) |
253 | - self.assertEquals(launchpad_credits_text, credits_text) |
254 | + self.assertEquals( |
255 | + self.compose_launchpad_credits_text(imported_credits_text), |
256 | + credits_text) |
257 | |
258 | # Now, re-import this generated message. |
259 | self.factory.makeTranslationMessage( |
260 | @@ -965,7 +971,9 @@ |
261 | |
262 | credits_text = self.pofile.prepareTranslationCredits( |
263 | self.credits_potmsgset) |
264 | - self.assertEquals(launchpad_credits_text, credits_text) |
265 | + self.assertEquals( |
266 | + self.compose_launchpad_credits_text(imported_credits_text), |
267 | + credits_text) |
268 | |
269 | |
270 | class TestTranslationPOFilePOTMsgSetOrdering(TestCaseWithFactory): |
271 | @@ -1487,21 +1495,49 @@ |
272 | |
273 | layer = ZopelessDatabaseLayer |
274 | |
275 | + # The sequence number 0 is put at the beginning of the data to verify that |
276 | + # it really gets sorted to the end. |
277 | + TEST_MESSAGES = [ |
278 | + {'msgid':'computer', 'string':'komputilo', 'sequence':0}, |
279 | + {'msgid':'mouse', 'string':'muso', 'sequence':0}, |
280 | + {'msgid':'Good morning', 'string':'Bonan matenon', 'sequence':2}, |
281 | + {'msgid':'Thank you', 'string':'Dankon', 'sequence':1}, |
282 | + ] |
283 | + EXPECTED_SEQUENCE = [1, 2, 0, 0] |
284 | + |
285 | def setUp(self): |
286 | # Create a POFile to calculate statistics on. |
287 | super(TestPOFile, self).setUp() |
288 | - self.pofile = self.factory.makePOFile('sr') |
289 | + self.pofile = self.factory.makePOFile('eo') |
290 | self.potemplate = self.pofile.potemplate |
291 | |
292 | - # Create a single POTMsgSet that is used across all tests. |
293 | - self.potmsgset = self.factory.makePOTMsgSet(self.potemplate, |
294 | - sequence=1) |
295 | - |
296 | def test_makeTranslatableMessage(self): |
297 | # TranslatableMessages can be created from the PO file |
298 | - message = self.pofile.makeTranslatableMessage(self.potmsgset) |
299 | + potmsgset = self.factory.makePOTMsgSet(self.potemplate, |
300 | + sequence=1) |
301 | + message = self.pofile.makeTranslatableMessage(potmsgset) |
302 | verifyObject(ITranslatableMessage, message) |
303 | |
304 | + def _createMessageSet(self, testmsg): |
305 | + # Create a message set from the test data. |
306 | + pomsgset = self.factory.makePOTMsgSet( |
307 | + self.potemplate, testmsg['msgid'], sequence=testmsg['sequence']) |
308 | + pomsgset.updateTranslation( |
309 | + self.pofile, self.pofile.owner, |
310 | + {0:testmsg['string'],}, |
311 | + True, None, force_edition_rights=True) |
312 | + |
313 | + def test_getTranslationRows_sequence(self): |
314 | + # Test for correct sorting of obsolete messages (where sequence=0). |
315 | + msgsets = [ |
316 | + self._createMessageSet(msg) for msg in self.TEST_MESSAGES] |
317 | + for rownum, row in enumerate( |
318 | + self.pofile.getTranslationRows()): |
319 | + self.failUnlessEqual( |
320 | + row.sequence, self.EXPECTED_SEQUENCE[rownum], |
321 | + "getTranslationRows does not sort obsolete messages " |
322 | + "(sequence=0) to the end of the file.") |
323 | + |
324 | |
325 | def test_suite(): |
326 | return unittest.TestLoader().loadTestsFromName(__name__) |
327 | |
328 | === modified file 'lib/lp/translations/tests/test_potmsgset.py' |
329 | --- lib/lp/translations/tests/test_potmsgset.py 2009-08-26 16:24:02 +0000 |
330 | +++ lib/lp/translations/tests/test_potmsgset.py 2009-10-26 15:28:11 +0000 |
331 | @@ -20,7 +20,7 @@ |
332 | from lp.registry.interfaces.person import IPersonSet |
333 | from lp.services.worlddata.interfaces.language import ILanguageSet |
334 | from lp.translations.interfaces.potmsgset import ( |
335 | - POTMsgSetInIncompatibleTemplatesError) |
336 | + POTMsgSetInIncompatibleTemplatesError, TranslationCreditsType) |
337 | from lp.translations.interfaces.translationfileformat import ( |
338 | TranslationFileFormat) |
339 | from lp.translations.interfaces.translationmessage import TranslationConflict |
340 | @@ -1078,5 +1078,99 @@ |
341 | self.assertFalse(tm2.is_imported) |
342 | |
343 | |
344 | +class TestPOTMsgSetTranslationCredits(TestCaseWithFactory): |
345 | + """Test methods related to TranslationCredits.""" |
346 | + |
347 | + layer = ZopelessDatabaseLayer |
348 | + |
349 | + def setUp(self): |
350 | + super(TestPOTMsgSetTranslationCredits, self).setUp() |
351 | + self.potemplate = self.factory.makePOTemplate() |
352 | + |
353 | + def test_creation_credits(self): |
354 | + # Upon creation of a translation credits message, |
355 | + # dummy translations are inserted for each POFile. |
356 | + eo_pofile = self.factory.makePOFile('eo', potemplate=self.potemplate) |
357 | + sr_pofile = self.factory.makePOFile('sr', potemplate=self.potemplate) |
358 | + |
359 | + credits = self.factory.makePOTMsgSet( |
360 | + self.potemplate, u'translator-credits', sequence=1) |
361 | + |
362 | + eo_translation = credits.getCurrentTranslationMessage( |
363 | + self.potemplate, eo_pofile.language) |
364 | + self.assertIsNot(None, eo_translation, |
365 | + "Translation credits are not translated upon creation.") |
366 | + |
367 | + sr_translation = credits.getCurrentTranslationMessage( |
368 | + self.potemplate, sr_pofile.language) |
369 | + self.assertIsNot(None, sr_translation, |
370 | + "Translation credits are not translated upon " |
371 | + "creation in 2nd POFile.") |
372 | + |
373 | + def test_creation_not_translated(self): |
374 | + # Normal messages do not receive a dummy translation. |
375 | + eo_pofile = self.factory.makePOFile('eo', potemplate=self.potemplate) |
376 | + |
377 | + potmsgset = self.factory.makePOTMsgSet(self.potemplate, sequence=1) |
378 | + eo_translation = potmsgset.getCurrentTranslationMessage( |
379 | + self.potemplate, eo_pofile.language) |
380 | + self.assertIs(None, eo_translation) |
381 | + |
382 | + def test_creation_not_imported(self): |
383 | + # Dummy translation for translation credits are not created as |
384 | + # imported and can therefore be overwritten by later imports. |
385 | + eo_pofile = self.factory.makePOFile('eo', potemplate=self.potemplate) |
386 | + imported_credits = u'Imported credits.' |
387 | + |
388 | + credits = self.factory.makePOTMsgSet( |
389 | + self.potemplate, u'translator-credits', sequence=1) |
390 | + translation = self.factory.makeTranslationMessage(eo_pofile, credits, |
391 | + translations=[imported_credits], is_imported=True) |
392 | + |
393 | + eo_translation = credits.getCurrentTranslationMessage( |
394 | + self.potemplate, eo_pofile.language) |
395 | + self.assertEqual(imported_credits, eo_translation.msgstr0.translation, |
396 | + "Imported translation credits do not replace dummy credits.") |
397 | + |
398 | + def test_translation_credits_gnome(self): |
399 | + # Detect all known variations of Gnome translator credits. |
400 | + gnome_credits = [ |
401 | + u'translator-credits', |
402 | + u'translator_credits', |
403 | + u'translation-credits', |
404 | + ] |
405 | + for sequence, credits_string in enumerate(gnome_credits): |
406 | + credits = self.factory.makePOTMsgSet( |
407 | + self.potemplate, credits_string, sequence=sequence+1) |
408 | + self.assertTrue(credits.is_translation_credit) |
409 | + self.assertEqual(TranslationCreditsType.GNOME, |
410 | + credits.translation_credits_type) |
411 | + |
412 | + def test_translation_credits_kde(self): |
413 | + # Detect all known variations of KDE translator credits. |
414 | + kde_credits = [ |
415 | + (u'Your emails', u'EMAIL OF TRANSLATORS', |
416 | + TranslationCreditsType.KDE_EMAILS), |
417 | + (u'Your names', u'NAME OF TRANSLATORS', |
418 | + TranslationCreditsType.KDE_NAMES), |
419 | + ] |
420 | + sequence = 0 |
421 | + for credits_string, context, credits_type in kde_credits: |
422 | + sequence += 1 |
423 | + credits = self.factory.makePOTMsgSet( |
424 | + self.potemplate, credits_string, |
425 | + context=context, sequence=sequence) |
426 | + self.assertTrue(credits.is_translation_credit) |
427 | + self.assertEqual(credits_type, credits.translation_credits_type) |
428 | + |
429 | + # Old KDE style. |
430 | + sequence += 1 |
431 | + credits = self.factory.makePOTMsgSet( |
432 | + self.potemplate, u'_: %s\n%s' % (context, credits_string), |
433 | + sequence=sequence) |
434 | + self.assertTrue(credits.is_translation_credit) |
435 | + self.assertEqual(credits_type, credits.translation_credits_type) |
436 | + |
437 | + |
438 | def test_suite(): |
439 | return unittest.TestLoader().loadTestsFromName(__name__) |
440 | |
441 | === modified file 'lib/lp/translations/tests/test_shared_potemplate.py' |
442 | --- lib/lp/translations/tests/test_shared_potemplate.py 2009-07-17 00:26:05 +0000 |
443 | +++ lib/lp/translations/tests/test_shared_potemplate.py 2009-10-26 15:28:11 +0000 |
444 | @@ -53,32 +53,20 @@ |
445 | |
446 | def test_getPOTMsgSetByMsgIDText(self): |
447 | potmsgset = self.factory.makePOTMsgSet(self.devel_potemplate, |
448 | - singular="Open file") |
449 | - |
450 | - # It's still not present in the PO template. |
451 | - read_potmsgset = self.devel_potemplate.getPOTMsgSetByMsgIDText( |
452 | - "Open file") |
453 | - self.assertEquals(read_potmsgset, None) |
454 | - |
455 | - # To actually insert it into a POTemplate, it needs |
456 | - # a sequence to be set. |
457 | - potmsgset.setSequence(self.devel_potemplate, 2) |
458 | + singular="Open file", |
459 | + sequence=2) |
460 | + |
461 | + # We can retrieve the potmsgset by its ID text. |
462 | read_potmsgset = self.devel_potemplate.getPOTMsgSetByMsgIDText( |
463 | "Open file") |
464 | self.assertEquals(potmsgset, read_potmsgset) |
465 | |
466 | def test_getPOTMsgSetBySequence(self): |
467 | - potmsgset = self.factory.makePOTMsgSet(self.devel_potemplate) |
468 | sequence = self.factory.getUniqueInteger() |
469 | - |
470 | - # It's still not present in the PO template. |
471 | - read_potmsgset = self.devel_potemplate.getPOTMsgSetBySequence( |
472 | - sequence) |
473 | - self.assertEquals(read_potmsgset, None) |
474 | - |
475 | - # Now we set the appropriate sequence in a potemplate and see that |
476 | - # it works. |
477 | - potmsgset.setSequence(self.devel_potemplate, sequence) |
478 | + potmsgset = self.factory.makePOTMsgSet(self.devel_potemplate, |
479 | + sequence=sequence) |
480 | + |
481 | + # We can retrieve the potmsgset by its sequence. |
482 | read_potmsgset = self.devel_potemplate.getPOTMsgSetBySequence( |
483 | sequence) |
484 | self.assertEquals(potmsgset, read_potmsgset) |
485 | @@ -89,16 +77,11 @@ |
486 | self.assertEquals(read_potmsgset, None) |
487 | |
488 | def test_getPOTMsgSetByID(self): |
489 | - potmsgset = self.factory.makePOTMsgSet(self.devel_potemplate) |
490 | + potmsgset = self.factory.makePOTMsgSet(self.devel_potemplate, |
491 | + sequence=3) |
492 | id = potmsgset.id |
493 | |
494 | - # It's still not present in the PO template. |
495 | - read_potmsgset = self.devel_potemplate.getPOTMsgSetByID(id) |
496 | - self.assertEquals(read_potmsgset, None) |
497 | - |
498 | - # Now we set the appropriate sequence in a potemplate and see that |
499 | - # we can get it by ID. |
500 | - potmsgset.setSequence(self.devel_potemplate, 3) |
501 | + # We can retrieve the potmsgset by its ID. |
502 | read_potmsgset = self.devel_potemplate.getPOTMsgSetByID(id) |
503 | self.assertEquals(potmsgset, read_potmsgset) |
504 | |
505 | @@ -122,16 +105,6 @@ |
506 | present_msgid_singular, present_msgid_plural, present_context) |
507 | self.assertEquals(has_message_id, True) |
508 | |
509 | - # A new POTMsgSet that is not part of the POTemplate cannot |
510 | - # be gotten using hasMessageID on a POTemplate. |
511 | - absent_potmsgset = self.factory.makePOTMsgSet(self.devel_potemplate) |
512 | - absent_msgid_singular = absent_potmsgset.msgid_singular |
513 | - absent_msgid_plural = absent_potmsgset.msgid_plural |
514 | - absent_context = absent_potmsgset.msgid_plural |
515 | - has_message_id = naked_potemplate.hasMessageID( |
516 | - absent_msgid_singular, absent_msgid_plural, absent_context) |
517 | - self.assertEquals(has_message_id, False) |
518 | - |
519 | def test_hasPluralMessage(self): |
520 | naked_potemplate = removeSecurityProxy(self.devel_potemplate) |
521 | |
522 | |
523 | === removed file 'lib/lp/translations/tests/test_vpoexport.py' |
524 | --- lib/lp/translations/tests/test_vpoexport.py 2009-07-22 11:52:40 +0000 |
525 | +++ lib/lp/translations/tests/test_vpoexport.py 1970-01-01 00:00:00 +0000 |
526 | @@ -1,62 +0,0 @@ |
527 | -# Copyright 2009 Canonical Ltd. This software is licensed under the |
528 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
529 | - |
530 | -"""PO file export view tests.""" |
531 | - |
532 | -__metaclass__ = type |
533 | - |
534 | -import unittest |
535 | -import transaction |
536 | - |
537 | -from lp.testing.factory import LaunchpadObjectFactory |
538 | -from canonical.testing import LaunchpadZopelessLayer |
539 | - |
540 | -# The sequence number 0 is put at the beginning of the data to verify that |
541 | -# it really gets sorted to the end. |
542 | -TEST_MESSAGES = [ |
543 | - {'msgid':'computer', 'string':'komputilo', 'sequence':0}, |
544 | - {'msgid':'mouse', 'string':'muso', 'sequence':0}, |
545 | - {'msgid':'Good morning', 'string':'Bonan matenon', 'sequence':2}, |
546 | - {'msgid':'Thank you', 'string':'Dankon', 'sequence':1}, |
547 | - ] |
548 | -EXPECTED_SEQUENCE = [1, 2, 0, 0] |
549 | - |
550 | -class VPOExportSetTestCase(unittest.TestCase): |
551 | - """Test the PO file export view.""" |
552 | - layer = LaunchpadZopelessLayer |
553 | - |
554 | - def _createMessageSet(self, testmsg): |
555 | - # Create a message set from the test data. |
556 | - msgset = self.potemplate.createMessageSetFromText( |
557 | - testmsg['msgid'], None) |
558 | - msgset.setSequence(self.potemplate, testmsg['sequence']) |
559 | - msgset.updateTranslation( |
560 | - self.pofile, self.submitter_person, |
561 | - {0:testmsg['string'],}, |
562 | - True, None, force_edition_rights=True) |
563 | - |
564 | - def setUp(self): |
565 | - factory = LaunchpadObjectFactory() |
566 | - |
567 | - # Create a PO file and fill with test data. |
568 | - self.potemplate = factory.makePOTemplate() |
569 | - self.pofile = factory.makePOFile('eo', self.potemplate) |
570 | - self.submitter_person = factory.makePerson() |
571 | - self.msgsets = [ |
572 | - self._createMessageSet(msg) for msg in TEST_MESSAGES] |
573 | - |
574 | - transaction.commit() |
575 | - |
576 | - def test_getTranslationRows_sequence(self): |
577 | - # Test for correct sorting of obsolete messages (where sequence=0). |
578 | - for rownum, row in enumerate( |
579 | - self.pofile.getTranslationRows()): |
580 | - self.failUnlessEqual( |
581 | - row.sequence, EXPECTED_SEQUENCE[rownum], |
582 | - "VPOExportSet does not sort obsolete messages (sequence=0) " |
583 | - "to the end of the file.") |
584 | - |
585 | -def test_suite(): |
586 | - suite = unittest.TestSuite() |
587 | - suite.addTest(unittest.makeSuite(VPOExportSetTestCase)) |
588 | - return suite |
= Details =
See bug 128324.
This branch only contains half the fix as proposed in the bug. It adds the creation of dummy translations to the creation of POTMsgSets. The question of where the creation of POTMsgSets actually happens lead to some more related changes so that it is best to land this part separately now.
A POTMsgSet is created by POTemplate. createPOTMsgSet FromMsgIDs( ) whose only call site is in POTemplate. createMessageSe tFromText( ). This used to create an "unbound" POTMsgSet that is not linked to a POTemplate by a TranslationTemp lateItem instance. This had to be done by a subsequent call to setSequence.
Having identified createPOTMsgSet FromMsgIDs as the place where POTMsgSets are born, I thought that might be a good place to put the "create dummy translations for all pofiles that belong to this potemplate". But wait, the POTMsgSet had not yet officially been linked to the POTemplate, so setting translations in its POFile seems premature.
The first obvious solution was to do it in setSequence but that seemed to be too much because that methods gets called a lot when re-importing templates where the order has changed.
So really the question is: Should unbound POTMsgSets exist at all? My answer is a clear: No, there is no point in having them. The logical solution is to set the sequence to 0 in createPOTMsgSet FromMsgIDs which the only production call site for createMessageSe tFromText had done anyway.
So it was only the makePOTMsgSet factory method that needed to be adjusted too and any test that depended on this missfeature. Luckily they were few.
== Implementation details == setTranslationC reditsToTransla ted separately does not make sense anymore because the factory method will already call it. So it is now tested as part of the creation test.
I decided to move some tests from the doctest to the unit tests for better coverage. Also, testing POTMsgSet.
One of the call sites for createMessageSe tFromText was in the old test_vpoexport.py whose content I could move to test_pofile.py completely, thereby removing this relict.
== Test ==
Run the new tests and those affected by the change. I ran all of lp.translations tests to find out which were affected by the test. (A full ec2 test run has taken place since then, too.)
bin/test -vvt potmsgset.txt -t TestTranslation Credits -t getTranslationR ows_sequence -t shared_potemplate
== QA/Demo ==
1. Download an existing potemplate that does not have translator-credits.
2. Add translator-credits to the template and import it again.
3. Filter for untranslated messages in any of the languages that this template has translations in.
4. The translator-credits message should not appear among the untranslated messages.
= Launchpad lint =
Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.
Linting changed files: testing/ factory. py translations/ doc/potmsgset. txt translations/ interfaces/ potemplate. py translations/ model/potemplat e.py translations/ tests/test_ pofile. py translations/ tests/test_ potmsgset. py translations/ tests/test_ shared_ potemplate. py
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
== Pyli...