launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #02749
[Merge] lp:~abentley/launchpad/translation-splitting into lp:launchpad
Aaron Bentley has proposed merging lp:~abentley/launchpad/translation-splitting into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~abentley/launchpad/translation-splitting/+merge/50949
= Summary =
Allow un-merging translations for a ProductSeries and SourcePackage.
When ProductSeries and SourcePackages are linked via a Packaging, their translations are shared. However, if the Packaging is destroyed, they need to stop sharing. This branch provides a mechanism for doing the splitting. Running a Job when the Packaging is destroyed is left for a follow-on branch.
== Proposed fix ==
Implement a TranslationSplitter.
== Pre-implementation notes ==
Discussed with henninge
== Implementation details ==
The TranslationSplitter
- Finds the shared POTMsgSets
- Creates a new POTMsgSet (via the new clone method) for the SourcePackage's template.
- Moves diverged TranslationMessages associated with the SourcePackage to the new POTMsgSet.
- Copies shared TranslationMessages (via the new clone method) to the new POTMsgSet.
== Tests ==
bin/test -v translationsplitter
== Demo and Q/A ==
None.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/translations/utilities/translationsplitter.py
lib/lp/translations/interfaces/translationmessage.py
lib/lp/translations/interfaces/potmsgset.py
lib/lp/translations/interfaces/translationtemplateitem.py
lib/lp/translations/tests/test_translationmessage.py
lib/lp/testing/factory.py
lib/lp/translations/tests/test_potmsgset.py
lib/lp/translations/configure.zcml
lib/lp/translations/tests/test_translationsplitter.py
lib/lp/translations/model/potmsgset.py
lib/lp/translations/model/potemplate.py
lib/lp/translations/model/translationmessage.py
--
https://code.launchpad.net/~abentley/launchpad/translation-splitting/+merge/50949
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/translation-splitting into lp:launchpad.
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2011-02-19 13:26:27 +0000
+++ lib/lp/testing/factory.py 2011-02-23 16:37:30 +0000
@@ -2720,15 +2720,27 @@
return potemplate.newPOFile(language_code,
create_sharing=create_sharing)
- def makePOTMsgSet(self, potemplate, singular=None, plural=None,
- context=None, sequence=None):
+ def makePOTMsgSet(self, potemplate=None, singular=None, plural=None,
+ context=None, sequence=None, commenttext=None,
+ filereferences=None, sourcecomment=None,
+ flagscomment=None):
"""Make a new `POTMsgSet` in the given template."""
+ if potemplate is None:
+ potemplate = self.makePOTemplate()
if singular is None and plural is None:
singular = self.getUniqueString()
if sequence is None:
sequence = self.getUniqueInteger()
potmsgset = potemplate.createMessageSetFromText(
singular, plural, context, sequence)
+ if commenttext is not None:
+ potmsgset.commenttext = commenttext
+ if filereferences is not None:
+ potmsgset.filereferences = filereferences
+ if sourcecomment is not None:
+ potmsgset.sourcecomment = sourcecomment
+ if flagscomment is not None:
+ potmsgset.flagscomment = flagscomment
removeSecurityProxy(potmsgset).sync()
return potmsgset
@@ -2791,7 +2803,8 @@
translations=None, diverged=False,
current_other=False,
date_created=None, date_reviewed=None,
- language=None, side=None):
+ language=None, side=None,
+ potemplate=None):
"""Create a `TranslationMessage` and make it current.
By default the message will only be current on the side (Ubuntu
@@ -2819,6 +2832,8 @@
:param date_reviewed: Force a specific review date instead of 'now'.
:param language: `Language` to use for the POFile
:param side: The `TranslationSide` this translation should be for.
+ :param potemplate: If provided, the POTemplate to use when creating
+ the POFile.
"""
assert not (diverged and current_other), (
"A diverged message can't be current on the other side.")
@@ -2827,9 +2842,14 @@
assert None in (side, pofile), (
'Cannot specify both side and pofile.')
if pofile is None:
- pofile = self.makePOFile(language=language, side=side)
+ pofile = self.makePOFile(
+ language=language, side=side, potemplate=potemplate)
+ else:
+ assert potemplate is None, (
+ 'Cannot specify both pofile and potemplate')
+ potemplate = pofile.potemplate
if potmsgset is None:
- potmsgset = self.makePOTMsgSet(pofile.potemplate)
+ potmsgset = self.makePOTMsgSet(potemplate)
if translator is None:
translator = self.makePerson()
if reviewer is None:
=== modified file 'lib/lp/translations/configure.zcml'
--- lib/lp/translations/configure.zcml 2010-12-23 22:12:49 +0000
+++ lib/lp/translations/configure.zcml 2011-02-23 16:37:30 +0000
@@ -383,6 +383,7 @@
class="lp.translations.model.translationtemplateitem.TranslationTemplateItem">
<allow
interface="lp.translations.interfaces.translationtemplateitem.ITranslationTemplateItem"/>
+ <require permission="launchpad.Admin" set_attributes="potmsgset"/>
</class>
<!-- ProductSeriesLanguage -->
=== modified file 'lib/lp/translations/interfaces/potmsgset.py'
--- lib/lp/translations/interfaces/potmsgset.py 2011-02-17 14:16:17 +0000
+++ lib/lp/translations/interfaces/potmsgset.py 2011-02-23 16:37:30 +0000
@@ -128,6 +128,9 @@
queries that search for credits messages.
"""))
+ def clone():
+ """Return a new copy of this POTMsgSet."""
+
def getCurrentTranslationMessageOrDummy(pofile):
"""Return the current `TranslationMessage`, or a dummy.
=== modified file 'lib/lp/translations/interfaces/translationmessage.py'
--- lib/lp/translations/interfaces/translationmessage.py 2011-02-05 15:24:50 +0000
+++ lib/lp/translations/interfaces/translationmessage.py 2011-02-23 16:37:30 +0000
@@ -123,7 +123,7 @@
potmsgset = Object(
title=_("The template message that this translation is for"),
- readonly=True, required=True, schema=IPOTMsgSet)
+ readonly=False, required=True, schema=IPOTMsgSet)
date_created = Datetime(
title=_("The date we saw this translation first"),
@@ -260,6 +260,13 @@
It must not be referenced by any other object.
"""
+ def clone(potmsgset):
+ """Create a copy of this message associated with a different MsgSet.
+
+ potemplate of the clone is always None. Aside from this, all values
+ should be the same.
+ """
+
def approve(pofile, reviewer, share_with_other_side=False,
lock_timestamp=None):
"""Approve this suggestion, making it a current translation."""
=== modified file 'lib/lp/translations/interfaces/translationtemplateitem.py'
--- lib/lp/translations/interfaces/translationtemplateitem.py 2010-08-20 20:31:18 +0000
+++ lib/lp/translations/interfaces/translationtemplateitem.py 2011-02-23 16:37:30 +0000
@@ -37,4 +37,4 @@
potmsgset = Object(
title=_("The template message that this translation is for"),
- readonly=True, required=True, schema=IPOTMsgSet)
+ readonly=False, required=True, schema=IPOTMsgSet)
=== modified file 'lib/lp/translations/model/potemplate.py'
--- lib/lp/translations/model/potemplate.py 2011-02-22 20:43:35 +0000
+++ lib/lp/translations/model/potemplate.py 2011-02-23 16:37:30 +0000
@@ -853,7 +853,8 @@
return potmsgset
- def getOrCreatePOMsgID(self, text):
+ @staticmethod
+ def getOrCreatePOMsgID(text):
"""Creates or returns existing POMsgID for given `text`."""
try:
msgid = POMsgID.byMsgid(text)
=== modified file 'lib/lp/translations/model/potmsgset.py'
--- lib/lp/translations/model/potmsgset.py 2011-02-17 14:18:27 +0000
+++ lib/lp/translations/model/potmsgset.py 2011-02-23 16:37:30 +0000
@@ -148,6 +148,17 @@
credits_message_ids = credits_message_info.keys()
+ def clone(self):
+ return POTMsgSet(
+ context=self.context,
+ msgid_singular=self.msgid_singular,
+ msgid_plural=self.msgid_plural,
+ commenttext=self.commenttext,
+ filereferences=self.filereferences,
+ sourcecomment=self.sourcecomment,
+ flagscomment=self.flagscomment,
+ )
+
def _conflictsExistingSourceFileFormats(self, source_file_format=None):
"""Return whether `source_file_format` conflicts with existing ones
for this `POTMsgSet`.
@@ -1165,6 +1176,7 @@
if translation_template_item is not None:
# Update the sequence for the translation template item.
translation_template_item.sequence = sequence
+ return translation_template_item
elif sequence >= 0:
# Introduce this new entry into the TranslationTemplateItem for
# later usage.
@@ -1179,7 +1191,7 @@
"Attempt to add a POTMsgSet into a POTemplate which "
"has a conflicting value for uses_english_msgids.")
- TranslationTemplateItem(
+ return TranslationTemplateItem(
potemplate=potemplate,
sequence=sequence,
potmsgset=self)
@@ -1187,7 +1199,7 @@
# There is no entry for this potmsgset in TranslationTemplateItem
# table, neither we need to create one, given that the sequence is
# less than zero.
- pass
+ return None
def getSequence(self, potemplate):
"""See `IPOTMsgSet`."""
=== modified file 'lib/lp/translations/model/translationmessage.py'
--- lib/lp/translations/model/translationmessage.py 2011-02-04 23:51:50 +0000
+++ lib/lp/translations/model/translationmessage.py 2011-02-23 16:37:30 +0000
@@ -485,6 +485,21 @@
return twins.order_by(TranslationMessage.id).first()
+ def clone(self, potmsgset):
+ clone = TranslationMessage(
+ potmsgset=potmsgset, submitter=self.submitter, origin=self.origin,
+ language=self.language, date_created=self.date_created,
+ reviewer=self.reviewer, date_reviewed=self.date_reviewed,
+ msgstr0=self.msgstr0, msgstr1=self.msgstr1,
+ msgstr2=self.msgstr2, msgstr3=self.msgstr3,
+ msgstr4=self.msgstr4, msgstr5=self.msgstr5,
+ comment=self.comment, validation_status=self.validation_status,
+ is_current_ubuntu=self.is_current_ubuntu,
+ is_current_upstream=self.is_current_upstream,
+ was_obsolete_in_last_import=self.was_obsolete_in_last_import,
+ )
+ return clone
+
class TranslationMessageSet:
"""See `ITranslationMessageSet`."""
=== modified file 'lib/lp/translations/tests/test_potmsgset.py'
--- lib/lp/translations/tests/test_potmsgset.py 2011-02-18 16:47:52 +0000
+++ lib/lp/translations/tests/test_potmsgset.py 2011-02-23 16:37:30 +0000
@@ -1880,3 +1880,33 @@
found = potmsgset.findTranslationMessage(
pofile, translations=translations, prefer_shared=True)
self.assertEqual(shared, found)
+
+
+class TestClone(TestCaseWithFactory):
+ """Test the clone() method."""
+
+ layer = ZopelessDatabaseLayer
+
+ def test_clone(self):
+ """Cloning a POTMsgSet should produce a near-identical copy."""
+ msgset = self.factory.makePOTMsgSet(
+ context=self.factory.getUniqueString('context'),
+ plural=self.factory.getUniqueString('plural'),
+ singular=self.factory.getUniqueString('singular'),
+ commenttext=self.factory.getUniqueString('comment'),
+ filereferences=self.factory.getUniqueString('filereferences'),
+ sourcecomment=self.factory.getUniqueString('sourcecomment'),
+ flagscomment=self.factory.getUniqueString('flagscomment'),
+ )
+ new_msgset = msgset.clone()
+ naked_msgset = removeSecurityProxy(msgset)
+ naked_new_msgset = removeSecurityProxy(new_msgset)
+ self.assertNotEqual(msgset.id, new_msgset.id)
+ self.assertEqual(msgset.context, new_msgset.context)
+ self.assertEqual(msgset.msgid_singular, new_msgset.msgid_singular)
+ self.assertEqual(msgset.msgid_plural, new_msgset.msgid_plural)
+ self.assertEqual(
+ msgset.commenttext, new_msgset.commenttext)
+ self.assertEqual(msgset.filereferences, new_msgset.filereferences)
+ self.assertEqual(msgset.sourcecomment, new_msgset.sourcecomment)
+ self.assertEqual(msgset.flagscomment, new_msgset.flagscomment)
=== modified file 'lib/lp/translations/tests/test_translationmessage.py'
--- lib/lp/translations/tests/test_translationmessage.py 2011-02-17 21:41:31 +0000
+++ lib/lp/translations/tests/test_translationmessage.py 2011-02-23 16:37:30 +0000
@@ -786,6 +786,38 @@
tm.potmsgset.setSequence(pofile.potemplate, 0)
self.assertEquals(None, tm.getOnePOFile())
+ def test_clone(self):
+ """Cloning a translation should produce a near-identical copy."""
+ translations = [self.factory.getUniqueString() for x in range(6)]
+ tm = self.factory.makeCurrentTranslationMessage(
+ date_created=self.factory.getUniqueDate(),
+ translations=translations, current_other=True)
+ tm.comment = self.factory.getUniqueString()
+ tm.was_obsolete_in_last_import = True
+ potmsgset = self.factory.makePOTMsgSet()
+ clone = tm.clone(potmsgset)
+ self.assertNotEqual(tm.id, clone.id)
+ self.assertIs(None, clone.potemplate)
+ self.assertEqual(potmsgset, clone.potmsgset)
+ self.assertEqual(tm.submitter, clone.submitter)
+ self.assertEqual(tm.language, clone.language)
+ self.assertEqual(tm.origin, clone.origin)
+ self.assertEqual(tm.date_created, clone.date_created)
+ self.assertEqual(tm.reviewer, clone.reviewer)
+ self.assertEqual(tm.date_reviewed, clone.date_reviewed)
+ self.assertEqual(tm.msgstr0, clone.msgstr0)
+ self.assertEqual(tm.msgstr1, clone.msgstr1)
+ self.assertEqual(tm.msgstr2, clone.msgstr2)
+ self.assertEqual(tm.msgstr3, clone.msgstr3)
+ self.assertEqual(tm.msgstr4, clone.msgstr4)
+ self.assertEqual(tm.msgstr5, clone.msgstr5)
+ self.assertEqual(tm.comment, clone.comment)
+ self.assertEqual(tm.validation_status, clone.validation_status)
+ self.assertEqual(tm.is_current_ubuntu, clone.is_current_ubuntu)
+ self.assertEqual(tm.is_current_upstream, clone.is_current_upstream)
+ self.assertEqual(
+ tm.was_obsolete_in_last_import, clone.was_obsolete_in_last_import)
+
class TestTranslationMessageFindIdenticalMessage(TestCaseWithFactory):
"""Tests for `TranslationMessage.findIdenticalMessage`."""
=== added file 'lib/lp/translations/tests/test_translationsplitter.py'
--- lib/lp/translations/tests/test_translationsplitter.py 1970-01-01 00:00:00 +0000
+++ lib/lp/translations/tests/test_translationsplitter.py 2011-02-23 16:37:30 +0000
@@ -0,0 +1,145 @@
+# Copyright 2011 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+__metaclass__ = type
+
+
+from zope.security.proxy import removeSecurityProxy
+
+from canonical.testing.layers import ZopelessDatabaseLayer
+from lp.testing import TestCaseWithFactory
+from lp.translations.interfaces.side import (
+ TranslationSide,
+ )
+from lp.translations.utilities.translationsplitter import (
+ TranslationSplitter,
+ )
+
+
+class TestTranslationSplitter(TestCaseWithFactory):
+
+ layer = ZopelessDatabaseLayer
+
+ def useInTemplate(self, potmsgset, potemplate):
+ return potmsgset.setSequence(
+ potemplate, self.factory.getUniqueInteger())
+
+ def test_findShared_requires_both(self):
+ """Results are only included when both sides have the POTMsgSet."""
+ upstream_template = self.factory.makePOTemplate(
+ side=TranslationSide.UPSTREAM)
+ productseries = upstream_template.productseries
+ ubuntu_template = self.factory.makePOTemplate(
+ side=TranslationSide.UBUNTU)
+ package = ubuntu_template.sourcepackage
+ potmsgset = self.factory.makePOTMsgSet(upstream_template, sequence=1)
+ splitter = TranslationSplitter(productseries, package)
+ self.assertContentEqual([], splitter.findShared())
+ (upstream_item,) = potmsgset.getAllTranslationTemplateItems()
+ ubuntu_item = self.useInTemplate(potmsgset, ubuntu_template)
+ self.assertContentEqual(
+ [(upstream_item, ubuntu_item)], splitter.findShared())
+ removeSecurityProxy(upstream_item).destroySelf()
+ self.assertContentEqual([], splitter.findShared())
+
+ def makeTranslationSplitter(self):
+ return TranslationSplitter(
+ self.factory.makeProductSeries(),
+ self.factory.makeSourcePackage())
+
+ def makeSharedPOTMsgSet(self, splitter):
+ upstream_template = self.factory.makePOTemplate(
+ productseries=splitter.productseries)
+ potmsgset = self.factory.makePOTMsgSet(
+ upstream_template, sequence=self.factory.getUniqueInteger())
+ (upstream_item,) = potmsgset.getAllTranslationTemplateItems()
+ ubuntu_template = self.factory.makePOTemplate(
+ sourcepackage=splitter.sourcepackage)
+ ubuntu_item = self.useInTemplate(potmsgset, ubuntu_template)
+ return upstream_item, ubuntu_item
+
+ def test_findSharedGroupsPOTMsgSet(self):
+ """POTMsgSets are correctly grouped."""
+ splitter = self.makeTranslationSplitter()
+ self.makeSharedPOTMsgSet(splitter)
+ self.makeSharedPOTMsgSet(splitter)
+ for num, (upstream, ubuntu) in enumerate(splitter.findShared()):
+ self.assertEqual(upstream.potmsgset, ubuntu.potmsgset)
+ self.assertEqual(1, num)
+
+ def test_splitPOTMsgSet(self):
+ """Splitting a POTMsgSet clones it and updates TemplateItem."""
+ splitter = self.makeTranslationSplitter()
+ upstream_item, ubuntu_item = self.makeSharedPOTMsgSet(splitter)
+ ubuntu_template = ubuntu_item.potemplate
+ ubuntu_sequence = ubuntu_item.sequence
+ new_potmsgset = splitter.splitPOTMsgSet(ubuntu_item)
+ self.assertEqual(new_potmsgset, ubuntu_item.potmsgset)
+
+ def test_migrateTranslations_diverged_upstream(self):
+ """Diverged upstream translation stays put."""
+ splitter = self.makeTranslationSplitter()
+ upstream_item, ubuntu_item = self.makeSharedPOTMsgSet(splitter)
+ upstream_message = self.factory.makeCurrentTranslationMessage(
+ potmsgset=upstream_item.potmsgset,
+ potemplate=upstream_item.potemplate, diverged=True)
+ splitter.splitPOTMsgSet(ubuntu_item)
+ upstream_translation = splitter.migrateTranslations(
+ upstream_item.potmsgset, ubuntu_item)
+ self.assertEqual(
+ upstream_message,
+ upstream_item.potmsgset.getAllTranslationMessages().one())
+ self.assertIs(
+ None, ubuntu_item.potmsgset.getAllTranslationMessages().one())
+
+ def test_migrateTranslations_diverged_ubuntu(self):
+ """Diverged ubuntu translation moves."""
+ splitter = self.makeTranslationSplitter()
+ upstream_item, ubuntu_item = self.makeSharedPOTMsgSet(splitter)
+ ubuntu_message = self.factory.makeCurrentTranslationMessage(
+ potmsgset=ubuntu_item.potmsgset,
+ potemplate=ubuntu_item.potemplate, diverged=True)
+ splitter.splitPOTMsgSet(ubuntu_item)
+ upstream_translation = splitter.migrateTranslations(
+ upstream_item.potmsgset, ubuntu_item)
+ self.assertEqual(
+ ubuntu_message,
+ ubuntu_item.potmsgset.getAllTranslationMessages().one())
+ self.assertIs(
+ None,
+ upstream_item.potmsgset.getAllTranslationMessages().one())
+
+ def test_migrateTranslations_shared(self):
+ """Shared translation is copied."""
+ splitter = self.makeTranslationSplitter()
+ upstream_item, ubuntu_item = self.makeSharedPOTMsgSet(splitter)
+ self.factory.makeCurrentTranslationMessage(
+ potmsgset=upstream_item.potmsgset)
+ splitter.splitPOTMsgSet(ubuntu_item)
+ splitter.migrateTranslations(upstream_item.potmsgset, ubuntu_item)
+ (upstream_translation,) = (
+ upstream_item.potmsgset.getAllTranslationMessages())
+ (ubuntu_translation,) = (
+ ubuntu_item.potmsgset.getAllTranslationMessages())
+ self.assertEqual(
+ ubuntu_translation.translations,
+ upstream_translation.translations)
+
+ def test_split_translations(self):
+ """Split translations splits POTMsgSet and TranslationMessage."""
+ splitter = self.makeTranslationSplitter()
+ upstream_item, ubuntu_item = self.makeSharedPOTMsgSet(splitter)
+ upstream_message = self.factory.makeCurrentTranslationMessage(
+ potmsgset=upstream_item.potmsgset,
+ potemplate=upstream_item.potemplate)
+ splitter.split()
+ self.assertNotEqual(
+ list(upstream_item.potemplate), list(ubuntu_item.potemplate))
+ self.assertNotEqual(
+ list(upstream_item.potmsgset.getAllTranslationMessages()),
+ list(ubuntu_item.potmsgset.getAllTranslationMessages()),
+ )
+ self.assertEqual(
+ upstream_item.potmsgset.getAllTranslationMessages().count(),
+ ubuntu_item.potmsgset.getAllTranslationMessages().count(),
+ )
=== added file 'lib/lp/translations/utilities/translationsplitter.py'
--- lib/lp/translations/utilities/translationsplitter.py 1970-01-01 00:00:00 +0000
+++ lib/lp/translations/utilities/translationsplitter.py 2011-02-23 16:37:30 +0000
@@ -0,0 +1,86 @@
+# Copyright 2011 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+__metaclass__ = type
+
+
+from storm.locals import ClassAlias, Store
+
+from lp.translations.model.potemplate import POTemplate
+from lp.translations.model.translationtemplateitem import (
+ TranslationTemplateItem,
+ )
+
+
+class TranslationSplitter:
+ """Split translations for a productseries, sourcepackage pair.
+
+ If a productseries and sourcepackage were linked in error, and then
+ unlinked, they may still share some translations. This class breaks those
+ associations.
+ """
+
+ def __init__(self, productseries, sourcepackage):
+ """Constructor.
+
+ :param productseries: The `ProductSeries` to split from.
+ :param sourcepackage: The `SourcePackage` to split from.
+ """
+ self.productseries = productseries
+ self.sourcepackage = sourcepackage
+
+ def findShared(self):
+ """Provide tuples of upstream, ubuntu for each shared POTMsgSet."""
+ store = Store.of(self.productseries)
+ UpstreamItem = ClassAlias(TranslationTemplateItem, 'UpstreamItem')
+ UpstreamTemplate = ClassAlias(POTemplate, 'UpstreamTemplate')
+ UbuntuItem = ClassAlias(TranslationTemplateItem, 'UbuntuItem')
+ UbuntuTemplate = ClassAlias(POTemplate, 'UbuntuTemplate')
+ return store.find(
+ (UpstreamItem, UbuntuItem),
+ UpstreamItem.potmsgsetID == UbuntuItem.potmsgsetID,
+ UbuntuItem.potemplateID == UbuntuTemplate.id,
+ UbuntuTemplate.sourcepackagenameID ==
+ self.sourcepackage.sourcepackagename.id,
+ UbuntuTemplate.distroseriesID ==
+ self.sourcepackage.distroseries.id,
+ UpstreamItem.potemplateID == UpstreamTemplate.id,
+ UpstreamTemplate.productseriesID == self.productseries.id,
+ )
+
+ @staticmethod
+ def splitPOTMsgSet(ubuntu_item):
+ """Split the POTMsgSet for TranslationTemplateItem.
+
+ The specified `TranslationTemplateItem` will have a new `POTMsgSet`
+ that is a clone of the old one. All other TranslationTemplateItems
+ will continue to use the old POTMsgSet.
+
+ :param ubuntu_item: The `TranslationTemplateItem` to use.
+ """
+ new_potmsgset = ubuntu_item.potmsgset.clone()
+ ubuntu_item.potmsgset = new_potmsgset
+ return new_potmsgset
+
+ @staticmethod
+ def migrateTranslations(upstream_msgset, ubuntu_item):
+ """Migrate the translations between potemplates.
+
+ :param upstream_msgset: The `POTMsgSet` to copy or move translations
+ from.
+ :param ubuntu_item: The target `TranslationTemplateItem`.
+ ubuntu_item.potmsgset is the msgset to attach translations to and
+ ubuntu_item.potemplate is used to determine whether to move a
+ diverged translation.
+ """
+ for message in upstream_msgset.getAllTranslationMessages():
+ if message.potemplate == ubuntu_item.potemplate:
+ message.potmsgset = ubuntu_item.potmsgset
+ elif not message.is_diverged:
+ message.clone(ubuntu_item.potmsgset)
+
+ def split(self):
+ """Split the translations for the ProductSeries and SourcePackage."""
+ for upstream_item, ubuntu_item in self.findShared():
+ self.splitPOTMsgSet(ubuntu_item)
+ self.migrateTranslations(upstream_item.potmsgset, ubuntu_item)