← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~henninge/launchpad/devel-translation-fixing5 into lp:launchpad

 

Henning Eggers has proposed merging lp:~henninge/launchpad/devel-translation-fixing5 into lp:launchpad with lp:~henninge/launchpad/abentley-translation-fixing4 as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #708028 Remove updateTranslation method
  https://bugs.launchpad.net/bugs/708028

For more details, see:
https://code.launchpad.net/~henninge/launchpad/devel-translation-fixing5/+merge/47597

= Summary =

Remove updateTranslation, that old monster, and all of its evil allies.

Admittedly, this is a humongous branch but it consists mostly of removal.

== Proposed fix ==

Replace remaining call sites of updateTranslation and get.*TranslationMessage
with their modern counterparts. Then delete the lot. Profit.

== Pre-implementation notes ==

This is a long-awaited step as part of the upstream-translations-sharing
feature.

== Implementation details ==

I had hoped to present a removal-only branch but there were some left-overs
that needed fixing. Let me draw your attention to them.

scripts/message_sharing_migration.py
I renamed imported to upststream and current to ubuntu. This is really to be
fixed as bug 708298 but I wanted it to be consistent with the test change.

scripts/tests/test_message_sharing_migration.py
As has been the case with a lot of other tests, this one just needed to be
"turned around", i.e. all occurrences of is_current_upstream and
is_current_ubuntu swapped. The script is using a product for testing and
for products is_current_upstream is the "real" is_current. I you can 
follow me ...

stories/standalone/xx-translationmessage-translate.txt
There is no factory method to create an "other side" message because really
you should simply be creating that on the other side. But sometimes it is
just easier to flip the flags manually as needed to be done here.
Unfortunately I discovered a bug here that makes the UI not work as
expected.

tests/test_potmsgset.py
Same as before, flags needed to be flipped manually. Also, I couldn't
restrain myself from removing some sample data (Serbian).

utilities/tests/import-flags.txt
This test was in the wrong place and therefore not being called. When being
run, it failed. Since these tests are now covered elsewhere, it could be
removed.

== Tests ==

Better run all translation tests to be sure.

test -vvcm lp.translations

== Demo and Q/A ==

No real Q/A needed. Everything should continue to work as before.


= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/translations/scripts/tests/test_remove_translations.py
  lib/lp/translations/interfaces/translationmessage.py
  lib/lp/translations/scripts/tests/test_message_sharing_migration.py
  lib/lp/translations/interfaces/potmsgset.py
  lib/lp/translations/scripts/message_sharing_migration.py
  lib/lp/translations/tests/test_pofile.py
  lib/lp/translations/tests/test_translationmessage.py
  lib/lp/testing/factory.py
  lib/lp/translations/doc/distroseries-translations-copy.txt
  lib/lp/translations/tests/test_potmsgset.py
  lib/lp/translations/model/potmsgset.py
  lib/lp/translations/doc/rosetta-translation.txt
  lib/lp/translations/doc/potmsgset.txt
  lib/lp/translations/model/translationmessage.py
  lib/lp/translations/stories/standalone/xx-translationmessage-translate.txt
-- 
https://code.launchpad.net/~henninge/launchpad/devel-translation-fixing5/+merge/47597
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~henninge/launchpad/devel-translation-fixing5 into lp:launchpad.
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py	2011-01-26 22:23:52 +0000
+++ lib/lp/testing/factory.py	2011-01-26 22:24:37 +0000
@@ -2567,35 +2567,6 @@
 
         return pofile, potmsgset
 
-    def makeTranslationMessage(self, pofile=None, potmsgset=None,
-                               translator=None, suggestion=False,
-                               reviewer=None, translations=None,
-                               lock_timestamp=None, date_updated=None,
-                               is_current_upstream=False, force_shared=False,
-                               force_diverged=False):
-        """Make a new `TranslationMessage` in the given PO file."""
-        if pofile is None:
-            pofile = self.makePOFile('sr')
-        if potmsgset is None:
-            potmsgset = self.makePOTMsgSet(pofile.potemplate, sequence=1)
-        if translator is None:
-            translator = self.makePerson()
-        if translations is None:
-            translations = [self.getUniqueString()]
-        translation_message = potmsgset.updateTranslation(
-            pofile, translator, translations,
-            is_current_upstream=is_current_upstream,
-            lock_timestamp=lock_timestamp, force_suggestion=suggestion,
-            force_shared=force_shared, force_diverged=force_diverged)
-        if date_updated is not None:
-            naked_translation_message = removeSecurityProxy(
-                translation_message)
-            naked_translation_message.date_created = date_updated
-            if translation_message.reviewer is not None:
-                naked_translation_message.date_reviewed = date_updated
-            naked_translation_message.sync()
-        return translation_message
-
     def makeTranslationsDict(self, translations=None):
         """Make sure translations are stored in a dict, e.g. {0: "foo"}.
 
@@ -2632,19 +2603,6 @@
             naked_translation_message.sync()
         return translation_message
 
-    def makeSharedTranslationMessage(self, pofile=None, potmsgset=None,
-                                     translator=None, suggestion=False,
-                                     reviewer=None, translations=None,
-                                     date_updated=None,
-                                     is_current_upstream=False):
-        translation_message = self.makeTranslationMessage(
-            pofile=pofile, potmsgset=potmsgset, translator=translator,
-            suggestion=suggestion, reviewer=reviewer,
-            is_current_upstream=is_current_upstream,
-            translations=translations, date_updated=date_updated,
-            force_shared=True)
-        return translation_message
-
     def makeCurrentTranslationMessage(self, pofile=None, potmsgset=None,
                                       translator=None, reviewer=None,
                                       translations=None, diverged=False,
@@ -2652,11 +2610,6 @@
                                       date_created=None, date_reviewed=None):
         """Create a `TranslationMessage` and make it current.
 
-        This is similar to `makeTranslationMessage`, except:
-         * It doesn't create suggestions.
-         * It doesn't rely on the obsolescent updateTranslation.
-         * It activates the message on the correct translation side.
-
         By default the message will only be current on the side (Ubuntu
         or upstream) that `pofile` is on.
 

=== modified file 'lib/lp/translations/interfaces/potmsgset.py'
--- lib/lp/translations/interfaces/potmsgset.py	2011-01-26 22:23:52 +0000
+++ lib/lp/translations/interfaces/potmsgset.py	2011-01-26 22:24:37 +0000
@@ -142,15 +142,6 @@
             `self` in `pofile`.
         """
 
-    def getCurrentTranslationMessage(potemplate, language):
-        """Returns a TranslationMessage marked as being currently used.
-
-        Diverged messages are preferred.
-        """
-
-    def getSharedTranslationMessage(language):
-        """Returns a shared TranslationMessage."""
-
     def getOtherTranslation(language, side):
         """Returns the TranslationMessage that is current on the other side.
 
@@ -227,44 +218,6 @@
         otherwise.
         """
 
-    def updateTranslation(pofile, submitter, new_translations,
-                          is_current_upstream, lock_timestamp,
-                          force_shared=False, force_diverged=False,
-                          force_suggestion=False, ignore_errors=False,
-                          force_edition_rights=False, allow_credits=False):
-        """Update or create a translation message using `new_translations`.
-
-        This method is Launchpad Translations's sliderule: it does
-        everything, nobody fully understands it all, and we intend to
-        replace it with a range of less flexible tools.
-
-        :param pofile: a `POFile` to add `new_translations` to.
-        :param submitter: author of the translations.
-        :param new_translations: a dictionary of plural forms, with the
-            integer plural form number as the key and the translation as the
-            value.
-        :param is_current_upstream: indicates whether this update is
-            imported from a packaged po file.
-        :param lock_timestamp: The timestamp when we checked the values we
-            want to update.
-        :param force_suggestion: Whether to force translation to be
-            a suggestion, even if submitted by an editor.
-        :param ignore_errors: A flag that controls whether the translations
-            should be stored even when an error is detected.
-        :param force_edition_rights: A flag that 'forces' handling this
-            submission as coming from an editor, even if `submitter` is not.
-        :param allow_credits: Override the protection of translation credits
-            message.
-
-        If there is an error with the translations and ignore_errors is not
-        True or it's not a fuzzy submit, raises GettextValidationError.
-
-        :return: a modified or newly created translation message; or None if
-            no message is to be updated.  This can happen when updating a
-            translation credits message without the is_current_upstream
-            parameter set.
-        """
-
     def validateTranslations(translations):
         """Validate `translations` against gettext.
 
@@ -321,13 +274,6 @@
             that this change is based on.
         """
 
-    def old_resetCurrentTranslation(pofile, lock_timestamp):
-        """Reset a translation.
-
-        OBSOLETE in Recife.  In the new model, use the new
-        `resetCurrentTranslation` implementation instead.
-        """
-
     def resetCurrentTranslation(pofile, lock_timestamp=None,
                                 share_with_other_side=False):
         """Turn the current translation back into a suggestion.

=== modified file 'lib/lp/translations/interfaces/translationmessage.py'
--- lib/lp/translations/interfaces/translationmessage.py	2010-12-02 16:13:51 +0000
+++ lib/lp/translations/interfaces/translationmessage.py	2011-01-26 22:24:37 +0000
@@ -19,7 +19,6 @@
     List,
     Object,
     Text,
-    TextLine,
     )
 
 from canonical.launchpad import _
@@ -290,20 +289,6 @@
             happened.  Defaults to "now."
         """
 
-    def makeCurrentUbuntu(new_value=True):
-        """Set the `is_current_ubuntu` flag.
-
-        If setting to True, clears the flag on any competing
-        TranslationMessages.
-        """
-
-    def makeCurrentUpstream(new_value=True):
-        """Set the `is_current_upstream` flag.
-
-        If setting to True, clears the flag on any competing
-        TranslationMessages.
-        """
-
 
 class ITranslationMessageSuggestions(Interface):
     """Suggested `ITranslationMessage`s for a `POTMsgSet`.

=== modified file 'lib/lp/translations/model/potmsgset.py'
--- lib/lp/translations/model/potmsgset.py	2011-01-26 22:23:52 +0000
+++ lib/lp/translations/model/potmsgset.py	2011-01-26 22:24:37 +0000
@@ -36,7 +36,6 @@
 from canonical.config import config
 from canonical.database.constants import (
     DEFAULT,
-    UTC_NOW,
     )
 from canonical.database.sqlbase import (
     cursor,
@@ -47,8 +46,6 @@
 from canonical.launchpad.helpers import shortlist
 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
 from canonical.launchpad.interfaces.lpstorm import ISlaveStore
-from canonical.launchpad.readonly import is_read_only
-from lp.app.errors import UnexpectedFormData
 from lp.services.propertycache import get_property_cache
 from lp.translations.interfaces.potmsgset import (
     BrokenTextError,
@@ -83,7 +80,6 @@
     TranslationTemplateItem,
     )
 from lp.translations.utilities.validate import (
-    GettextValidationError,
     validate_translation,
     )
 
@@ -282,49 +278,6 @@
             current.setPOFile(pofile)
             return current
 
-    def _getUsedTranslationMessage(self, potemplate, language, current=True):
-        """Get a translation message which is either used in
-        Launchpad (current=True) or in an import (current=False).
-
-        Prefers a diverged message if present.
-        """
-        # Change 'is_current IS TRUE' and 'is_imported IS TRUE' conditions
-        # carefully: they need to match condition specified in indexes,
-        # or Postgres may not pick them up (in complicated queries,
-        # Postgres query optimizer sometimes does text-matching of indexes).
-        if current:
-            used_clause = 'is_current_ubuntu IS TRUE'
-        else:
-            used_clause = 'is_current_upstream IS TRUE'
-        if potemplate is None:
-            template_clause = 'TranslationMessage.potemplate IS NULL'
-        else:
-            template_clause = (
-                '(TranslationMessage.potemplate IS NULL OR '
-                ' TranslationMessage.potemplate=%s)' % sqlvalues(potemplate))
-        clauses = [
-            'potmsgset = %s' % sqlvalues(self),
-            used_clause,
-            template_clause,
-            'TranslationMessage.language = %s' % sqlvalues(language)]
-
-        order_by = '-COALESCE(potemplate, -1)'
-
-        # This should find at most two messages: zero or one shared
-        # message, and zero or one diverged one.
-        return TranslationMessage.selectFirst(
-            ' AND '.join(clauses), orderBy=[order_by])
-
-    def getCurrentTranslationMessage(self, potemplate, language):
-        """See `IPOTMsgSet`."""
-        return self._getUsedTranslationMessage(
-            potemplate, language, current=True)
-
-    def getSharedTranslationMessage(self, language):
-        """See `IPOTMsgSet`."""
-        return self._getUsedTranslationMessage(
-            None, language, current=True)
-
     def getOtherTranslation(self, language, side):
         """See `IPOTMsgSet`."""
         traits = getUtility(
@@ -510,60 +463,11 @@
             date_updated = current.date_reviewed
         return (date_updated is not None and date_updated > timestamp)
 
-    def _sanitizeTranslations(self, translations, pluralforms):
-        """Sanitize `translations` using self.applySanityFixes.
-
-        If there is no certain pluralform in `translations`, set it to None.
-        If there are `translations` with greater pluralforms than allowed,
-        sanitize and keep them.
-        """
-        # Strip any trailing or leading whitespace, and normalize empty
-        # translations to None.
-        sanitized_translations = {}
-        for pluralform in range(pluralforms):
-            if pluralform < len(translations):
-                sanitized_translations[pluralform] = self.applySanityFixes(
-                    translations[pluralform])
-            else:
-                sanitized_translations[pluralform] = None
-        # Unneeded plural forms are stored as well (needed since we may
-        # have incorrect plural form data, so we can just reactivate them
-        # once we fix the plural information for the language)
-        for index, value in enumerate(translations):
-            if index not in sanitized_translations:
-                sanitized_translations[index] = self.applySanityFixes(value)
-
-        return sanitized_translations
-
     def validateTranslations(self, translations):
         """See `IPOTMsgSet`."""
         validate_translation(
             self.singular_text, self.plural_text, translations, self.flags)
 
-    def _validate_translations(self, translations, ignore_errors):
-        """Validate all the `translations` and return a validation_status."""
-        # By default all translations are correct.
-        validation_status = TranslationValidationStatus.OK
-
-        # Validate the translation we got from the translation form
-        # to know if gettext is unhappy with the input.
-        try:
-            self.validateTranslations(translations)
-        except GettextValidationError:
-            if ignore_errors:
-                # The translations are stored anyway, but we set them as
-                # broken.
-                validation_status = TranslationValidationStatus.UNKNOWNERROR
-            else:
-                # Check to know if there is any translation.
-                if any(translations.values()):
-                    # Partial translations cannot be stored, the
-                    # exception is raised again and handled outside
-                    # this method.
-                    raise
-
-        return validation_status
-
     def _findPOTranslations(self, translations):
         """Find all POTranslation records for passed `translations`."""
         potranslations = {}
@@ -646,327 +550,6 @@
         else:
             return None
 
-    def _makeTranslationMessageCurrent(self, pofile, new_message,
-                                       upstream_message, is_current_upstream,
-                                       submitter, force_shared=False,
-                                       force_diverged=False):
-        """Make the given translation message the current one."""
-        current_message = self.getCurrentTranslationMessage(
-            pofile.potemplate, pofile.language)
-
-        # Converging from a diverged to a shared translation:
-        # when the new translation matches a shared one (iscurrent,
-        # potemplate==None), and a current translation is diverged
-        # (potemplate != None), then we want to remove divergence.
-        converge_shared = force_shared
-        if (not force_diverged and
-            (current_message is None or
-             ((new_message.potemplate is None and
-                new_message.is_current_ubuntu) and
-              (current_message.potemplate is not None)))):
-            converge_shared = True
-
-        make_current = False
-
-        if is_current_upstream:
-            # A new imported message is made current
-            # if there is no existing current message
-            # or if there was no previous imported message
-            # or if the current message came from import
-            # or if current message is empty (deactivated translation),
-            # or if current message is the same as new message,
-            # or, if we are forcing a diverged imported translation.
-            # Empty imported translations should not replace
-            # non-empty imported translations.
-            if (current_message is None or
-                upstream_message is None or
-                (current_message.is_current_upstream and
-                 (current_message.is_empty or not new_message.is_empty)) or
-                current_message.is_empty or
-                (current_message == new_message) or
-                (force_diverged and not new_message.is_empty)):
-                make_current = True
-
-                # Don't update the submitter and date changed
-                # if there was no current message and an empty
-                # message is submitted.
-                if (not (current_message is None and
-                         new_message.is_empty)):
-                    pofile.lasttranslator = submitter
-                    pofile.date_changed = UTC_NOW
-
-        else:
-            # Non-imported translations.
-            make_current = True
-            pofile.lasttranslator = submitter
-            pofile.date_changed = UTC_NOW
-
-            if new_message.origin == RosettaTranslationOrigin.ROSETTAWEB:
-                # The submitted translation came from our UI, we give
-                # give karma to the submitter of that translation.
-                new_message.submitter.assignKarma(
-                    'translationsuggestionapproved',
-                    product=pofile.potemplate.product,
-                    distribution=pofile.potemplate.distribution,
-                    sourcepackagename=pofile.potemplate.sourcepackagename)
-
-            # If the current message has been changed, and it was submitted
-            # by a different person than is now doing the review (i.e.
-            # `submitter`), then give this reviewer karma as well.
-            if new_message != current_message:
-                if new_message.submitter != submitter:
-                    submitter.assignKarma(
-                        'translationreview',
-                        product=pofile.potemplate.product,
-                        distribution=pofile.potemplate.distribution,
-                        sourcepackagename=pofile.potemplate.sourcepackagename)
-
-                new_message.markReviewed(submitter, UTC_NOW)
-                pofile.date_changed = UTC_NOW
-                pofile.lasttranslator = submitter
-
-        unmark_upstream = (
-            make_current and
-            upstream_message is not None and (
-                is_current_upstream or upstream_message == new_message))
-        if unmark_upstream:
-            # Unmark previous imported translation as 'imported'.
-            was_diverged_to = upstream_message.potemplate
-            if (was_diverged_to is not None or
-                (was_diverged_to is None and
-                 new_message == current_message and
-                 new_message.potemplate is not None)):
-                # If imported message was diverged,
-                # or if it was shared, but there was
-                # a diverged current message that is
-                # now being imported, previous imported
-                # message is neither imported nor current
-                # anymore.
-                upstream_message.is_current_upstream = False
-                upstream_message.is_current_ubuntu = False
-                upstream_message.potemplate = None
-                if upstream_message != new_message:
-                    Store.of(upstream_message).add_flush_order(
-                        upstream_message, new_message)
-            if not (force_diverged or force_shared):
-                # If there was an imported message, keep the same
-                # divergence/shared state unless something was forced.
-                if (new_message.is_current_upstream and
-                    new_message.potemplate is None):
-                    # If we are reverting imported message to
-                    # a shared imported message, do not
-                    # set it as diverged anymore.
-                    was_diverged_to = None
-                new_message.potemplate = was_diverged_to
-
-        # Change actual is_current_ubuntu flag only if it validates ok.
-        if new_message.validation_status == TranslationValidationStatus.OK:
-            if make_current:
-                if (current_message is not None and
-                    current_message.potemplate is not None):
-                    # Deactivate previous diverged message.
-                    current_message.is_current_ubuntu = False
-                    if current_message != new_message:
-                        Store.of(current_message).add_flush_order(
-                            current_message, new_message)
-
-                    # Do not "converge" a diverged imported message since
-                    # there might be another shared imported message.
-                    if not current_message.is_current_upstream:
-                        current_message.potemplate = None
-                    if not converge_shared:
-                        force_diverged = True
-                if force_diverged:
-                    # Make the message diverged.
-                    new_message.potemplate = pofile.potemplate
-                else:
-                    # Either converge_shared==True, or a new message.
-                    new_message.potemplate = None
-
-                new_message.makeCurrentUbuntu()
-            else:
-                new_message.potemplate = None
-        if is_current_upstream or new_message == upstream_message:
-            new_message.makeCurrentUpstream()
-
-    def _isTranslationMessageASuggestion(self, force_suggestion,
-                                         pofile, submitter,
-                                         force_edition_rights,
-                                         is_current_upstream, lock_timestamp):
-        # Whether a message should be saved as a suggestion and
-        # whether we should display a warning when an older translation is
-        # submitted.
-        # Returns a pair of (just_a_suggestion, warn_about_lock_timestamp).
-
-        if force_suggestion:
-            return True, False
-
-        # Is the submitter allowed to edit translations?
-        is_editor = (force_edition_rights or
-                     pofile.canEditTranslations(submitter))
-
-        if is_read_only():
-            # This can happen if the request was just in time to slip
-            # past the read-only check before the gate closed.  If it
-            # does, that screws up the privileges checks below since
-            # nobody has translation privileges in read-only mode.
-            raise UnexpectedFormData(
-                "Sorry, Launchpad is in read-only mode right now.")
-
-        if is_current_upstream and not is_editor:
-            raise AssertionError(
-                'Only an editor can submit is_current_upstream translations.')
-
-        assert is_editor or pofile.canAddSuggestions(submitter), (
-            '%s cannot add suggestions here.' % submitter.displayname)
-
-        # If not an editor, default to submitting a suggestion only.
-        just_a_suggestion = not is_editor
-        warn_about_lock_timestamp = False
-
-        # Our current submission is newer than 'lock_timestamp'
-        # and we try to change it, so just add a suggestion.
-        if (not just_a_suggestion and not is_current_upstream and
-            self.isTranslationNewerThan(pofile, lock_timestamp)):
-            just_a_suggestion = True
-            warn_about_lock_timestamp = True
-
-        return just_a_suggestion, warn_about_lock_timestamp
-
-    def allTranslationsAreEmpty(self, translations):
-        """Return true if all translations are empty strings or None."""
-        has_translations = False
-        for pluralform in translations:
-            translation = translations[pluralform]
-            if (translation is not None and translation != u""):
-                has_translations = True
-                break
-        return not has_translations
-
-    def updateTranslation(self, pofile, submitter, new_translations,
-                          is_current_upstream, lock_timestamp,
-                          force_shared=False, force_diverged=False,
-                          force_suggestion=False, ignore_errors=False,
-                          force_edition_rights=False, allow_credits=False):
-        """See `IPOTMsgSet`."""
-
-        just_a_suggestion, warn_about_lock_timestamp = (
-            self._isTranslationMessageASuggestion(force_suggestion,
-                                                  pofile, submitter,
-                                                  force_edition_rights,
-                                                  is_current_upstream,
-                                                  lock_timestamp))
-
-        # If the update is on the translation credits message, yet
-        # update is not is_current_upstream, silently return.
-        deny_credits = (not allow_credits and
-                        self.is_translation_credit and
-                        not is_current_upstream)
-        if deny_credits:
-            return None
-
-        # Sanitize translations
-        sanitized_translations = self._sanitizeTranslations(
-            new_translations, pofile.plural_forms)
-        # Check that the translations are correct.
-        validation_status = self._validate_translations(
-            sanitized_translations, ignore_errors)
-
-        # Find all POTranslation records for strings we need.
-        potranslations = self._findPOTranslations(sanitized_translations)
-
-        # Find an existing TranslationMessage with exactly the same set
-        # of translations.  None if there is no such message and needs to be
-        # created.
-        matching_message = self._findMatchingTranslationMessage(
-            pofile, potranslations, prefer_shared=True)
-
-        match_is_upstream = (
-            matching_message is not None and
-            matching_message.is_current_upstream)
-        if is_current_upstream or match_is_upstream:
-            upstream_message = self.getCurrentTranslation(
-                pofile.potemplate, pofile.language, TranslationSide.UPSTREAM)
-        else:
-            upstream_message = None
-
-        if matching_message is None:
-            # Creating a new message.
-
-            if is_current_upstream:
-                origin = RosettaTranslationOrigin.SCM
-            else:
-                origin = RosettaTranslationOrigin.ROSETTAWEB
-
-            assert TranslationConstants.MAX_PLURAL_FORMS == 6, (
-                "Change this code to support %d plural forms."
-                % TranslationConstants.MAX_PLURAL_FORMS)
-
-            if (is_current_upstream and
-                self.allTranslationsAreEmpty(sanitized_translations)):
-                # Don't create empty is_current_upstream translations
-                if upstream_message is not None:
-                    upstream_message.is_current_upstream = False
-                    if upstream_message.is_current_ubuntu:
-                        upstream_message.is_current_ubuntu = False
-                return None
-            else:
-                # The pofile=pofile is only needed until 10.09 rollout.
-                matching_message = TranslationMessage(
-                    potmsgset=self,
-                    potemplate=pofile.potemplate,
-                    language=pofile.language,
-                    origin=origin,
-                    submitter=submitter,
-                    msgstr0=potranslations[0],
-                    msgstr1=potranslations[1],
-                    msgstr2=potranslations[2],
-                    msgstr3=potranslations[3],
-                    msgstr4=potranslations[4],
-                    msgstr5=potranslations[5],
-                    validation_status=validation_status)
-
-                if just_a_suggestion:
-                    # Adds suggestion karma: editors get their translations
-                    # automatically approved, so they get 'reviewer' karma
-                    # instead.
-                    submitter.assignKarma(
-                        'translationsuggestionadded',
-                        product=pofile.potemplate.product,
-                        distribution=pofile.potemplate.distribution,
-                        sourcepackagename=pofile.potemplate.sourcepackagename)
-        else:
-            # There is an existing matching message. Update it as needed.
-            # Also update validation status if needed
-            matching_message.validation_status = validation_status
-
-        if just_a_suggestion:
-            # An existing message is just a suggestion, warn if needed.
-            if warn_about_lock_timestamp:
-                raise TranslationConflict(
-                    'The new translations were saved as suggestions to '
-                    'avoid possible conflicts. Please review them.')
-        else:
-            # Makes the new_message current if needed and also
-            # assigns karma for translation approval.
-            self._makeTranslationMessageCurrent(
-                pofile, matching_message, upstream_message,
-                is_current_upstream, submitter,
-                force_shared=force_shared, force_diverged=force_diverged)
-
-        # We need this sync so we don't set self.isfuzzy to the wrong
-        # value because cache problems. See bug #102382 as an example of what
-        # happened without having this flag + broken code. Our tests were not
-        # able to find the problem.
-        # XXX CarlosPerelloMarin 2007-11-14 Is there any way to avoid the
-        # sync() call and leave it as syncUpdate? Without it we have cache
-        # problems with workflows like the ones in
-        # xx-pofile-translate-gettext-error-middle-page.txt so we don't see
-        # the successful submissions when there are other errors in the same
-        # page.
-        matching_message.sync()
-        return matching_message
-
     def submitSuggestion(self, pofile, submitter, new_translations):
         """See `IPOTMsgSet`."""
         if self.is_translation_credit:
@@ -1390,29 +973,6 @@
 
         return message
 
-    def old_resetCurrentTranslation(self, pofile, lock_timestamp):
-        """See `POTMsgSet`.
-
-        This message is OBSOLETE in the Recife feature branch.  It's
-        still here only until we replace its one call with the new
-        method.
-        """
-        assert lock_timestamp is not None, "No lock timestamp given."
-        current = self.getCurrentTranslationMessage(
-            pofile.potemplate, pofile.language)
-        if current is None:
-            return
-
-        # Check for translation conflicts and update the required
-        # attributes.
-        self._maybeRaiseTranslationConflict(current, lock_timestamp)
-        current.is_current_ubuntu = False
-        # Converge the current translation only if it is diverged and
-        # not current upstream.
-        if current.is_diverged and not current.is_current_upstream:
-            current.potemplate = None
-        pofile.markChanged()
-
     def resetCurrentTranslation(self, pofile, lock_timestamp=None,
                                 share_with_other_side=False):
         """See `IPOTMsgSet`."""

=== modified file 'lib/lp/translations/model/translationmessage.py'
--- lib/lp/translations/model/translationmessage.py	2011-01-26 22:23:52 +0000
+++ lib/lp/translations/model/translationmessage.py	2011-01-26 22:24:37 +0000
@@ -190,14 +190,6 @@
         # This object is already non persistent, so nothing needs to be done.
         return
 
-    def makeCurrentUbuntu(self, new_value=True):
-        """See `ITranslationMessage`."""
-        self.is_current_ubuntu = new_value
-
-    def makeCurrentUpstream(self, new_value=True):
-        """See `ITranslationMessage`."""
-        self.is_current_upstream = new_value
-
     def getSharedEquivalent(self):
         """See `ITranslationMessage`."""
         raise NotImplementedError()
@@ -472,36 +464,6 @@
 
         return twins.order_by(TranslationMessage.id).first()
 
-    def makeCurrentUbuntu(self, new_value=True):
-        """See `ITranslationMessage`."""
-        if new_value and not self.is_current_ubuntu:
-            incumbent = self.potmsgset.getCurrentTranslation(
-                self.potemplate, self.language, TranslationSide.UBUNTU)
-            if incumbent == self:
-                return
-            if (incumbent is not None and
-                incumbent.potemplate == self.potemplate):
-                # The incumbent is in the way.  Clear its flag.
-                incumbent.is_current_ubuntu = False
-                Store.of(self).add_flush_order(incumbent, self)
-
-        self.is_current_ubuntu = new_value
-
-    def makeCurrentUpstream(self, new_value=True):
-        """See `ITranslationMessage`."""
-        if new_value and not self.is_current_upstream:
-            incumbent = self.potmsgset.getCurrentTranslationMessage(
-                self.potemplate, self.language, TranslationSide.UPSTREAM)
-            if incumbent == self:
-                return
-            if (incumbent is not None and
-                incumbent.potemplate == self.potemplate):
-                # The incumbent is in the way.  Clear its flag.
-                incumbent.is_current_upstream = False
-                Store.of(self).add_flush_order(incumbent, self)
-
-        self.is_current_upstream = new_value
-
 
 class TranslationMessageSet:
     """See `ITranslationMessageSet`."""

=== modified file 'lib/lp/translations/scripts/message_sharing_migration.py'
--- lib/lp/translations/scripts/message_sharing_migration.py	2011-01-26 22:23:52 +0000
+++ lib/lp/translations/scripts/message_sharing_migration.py	2011-01-26 22:24:37 +0000
@@ -100,7 +100,7 @@
         merge_pofiletranslators(item.potmsgset, representative_template)
 
 
-def filter_clashes(clashing_current, clashing_imported, twin):
+def filter_clashes(clashing_ubuntu, clashing_upstream, twin):
     """Filter clashes for harmless clashes with an identical message.
 
     Takes the three forms of clashes a message can have in a context
@@ -116,11 +116,11 @@
     This function returns the same tuple but with these "harmless"
     clashes eliminated.
     """
-    if clashing_current == twin:
-        clashing_current = None
-    if clashing_imported == twin:
-        clashing_imported = None
-    return clashing_current, clashing_imported, twin
+    if clashing_ubuntu == twin:
+        clashing_ubuntu = None
+    if clashing_upstream == twin:
+        clashing_upstream = None
+    return clashing_ubuntu, clashing_upstream, twin
 
 
 def sacrifice_flags(message, incumbents=None):
@@ -592,32 +592,32 @@
         environment already has a current message for that language, or
         similar for the message being imported.
 
-        :return: a tuple of a clashing current message or None, a
-            clashing imported message or None, and a message that is
+        :return: a tuple of a clashing ubuntu message or None, a
+            clashing upstream message or None, and a message that is
             identical to the one you passed in, if present.
         """
-        clashing_current = None
+        clashing_ubuntu = None
         if message.is_current_ubuntu:
             found = target_potmsgset.getCurrentTranslation(
                 potemplate=target_potemplate, language=message.language,
                 side=TranslationSide.UBUNTU)
             if found is not None and found.potemplate == target_potemplate:
-                clashing_current = found
+                clashing_ubuntu = found
 
-        clashing_imported = None
+        clashing_upstream = None
         if message.is_current_upstream:
             found = target_potmsgset.getCurrentTranslation(
                 potemplate=target_potemplate, language=message.language,
                 side=TranslationSide.UPSTREAM)
             if found is not None and found.potemplate == target_potemplate:
-                clashing_imported = found
+                clashing_upstream = found
 
         twin = message.findIdenticalMessage(
             target_potmsgset, target_potemplate)
 
-        # Clashes with a twin message not real clashes: in such cases the
+        # Clashes with a twin message are not real clashes: in such cases the
         # message can be merged into the twin without problems.
-        return filter_clashes(clashing_current, clashing_imported, twin)
+        return filter_clashes(clashing_ubuntu, clashing_upstream, twin)
 
     def _saveByDiverging(self, message, target_potmsgset, source_potmsgset):
         """Avoid a TranslationMessage clash during POTMsgSet merge.

=== modified file 'lib/lp/translations/scripts/tests/test_message_sharing_migration.py'
--- lib/lp/translations/scripts/tests/test_message_sharing_migration.py	2010-12-16 13:25:54 +0000
+++ lib/lp/translations/scripts/tests/test_message_sharing_migration.py	2011-01-26 22:24:37 +0000
@@ -166,13 +166,14 @@
 
     def _makeTranslationMessage(self, pofile, potmsgset, text, diverged):
         """Set a translation for given message in given translation."""
-        message = self.factory.makeTranslationMessage(
-            pofile=pofile, potmsgset=potmsgset, translations=[text],
-            translator=pofile.owner)
         if diverged:
-            message.potemplate = pofile.potemplate
+            message = self.factory.makeDivergedTranslationMessage(
+                pofile=pofile, potmsgset=potmsgset, translations=[text],
+                translator=pofile.owner)
         else:
-            message.potemplate = None
+            message = self.factory.makeCurrentTranslationMessage(
+                pofile=pofile, potmsgset=potmsgset, translations=[text],
+                translator=pofile.owner)
 
         return message
 
@@ -208,8 +209,8 @@
 
     def _getMessage(self, potmsgset, template):
         """Get TranslationMessage for given POTMsgSet in given template."""
-        message = potmsgset.getCurrentTranslationMessage(
-            potemplate=template, language=self.dutch)
+        message = potmsgset.getCurrentTranslation(
+            template, self.dutch, template.translation_side)
         if not message:
             # No diverged message here, so check for a shared one.
             message = potmsgset.getSharedTranslation(
@@ -263,8 +264,8 @@
         # templates even if their POTMsgSets are merged.
         trunk_message, stable_message = self._makeTranslationMessages(
             'bar', 'splat', trunk_diverged=True, stable_diverged=True)
-        trunk_message.is_current_ubuntu = True
-        stable_message.is_current_ubuntu = True
+        trunk_message.is_current_upstream = True
+        stable_message.is_current_upstream = True
 
         self.script._mergePOTMsgSets(self.templates)
 
@@ -277,8 +278,8 @@
         # translations in the merged templates.
         trunk_message, stable_message = self._makeTranslationMessages(
             'bar', 'bar', trunk_diverged=False, stable_diverged=False)
-        trunk_message.is_current_ubuntu = True
-        stable_message.is_current_ubuntu = True
+        trunk_message.is_current_upstream = True
+        stable_message.is_current_upstream = True
 
         self.script._mergePOTMsgSets(self.templates)
 
@@ -290,8 +291,8 @@
         # shared.  The translation that "loses out" becomes diverged.
         trunk_message, stable_message = self._makeTranslationMessages(
             'bar2', 'splat2', trunk_diverged=False, stable_diverged=False)
-        trunk_message.is_current_ubuntu = True
-        stable_message.is_current_ubuntu = True
+        trunk_message.is_current_upstream = True
+        stable_message.is_current_upstream = True
 
         self.script._mergePOTMsgSets(self.templates)
 
@@ -313,8 +314,8 @@
         # Identical suggestions can be merged without breakage.
         trunk_message, stable_message = self._makeTranslationMessages(
             'bar', 'bar', trunk_diverged=False, stable_diverged=False)
-        trunk_message.is_current_ubuntu = False
-        stable_message.is_current_ubuntu = False
+        trunk_message.is_current_upstream = False
+        stable_message.is_current_upstream = False
 
         self.script._mergePOTMsgSets(self.templates)
 
@@ -327,8 +328,8 @@
         # the most representative shared translation wins.
         trunk_message, stable_message = self._makeTranslationMessages(
             'foe', 'barr', trunk_diverged=False, stable_diverged=False)
-        trunk_message.is_current_ubuntu = True
-        stable_message.is_current_ubuntu = True
+        trunk_message.is_current_upstream = True
+        stable_message.is_current_upstream = True
 
         self.script._mergePOTMsgSets(self.templates)
 
@@ -346,12 +347,12 @@
         # translation for the same message.
         trunk_message, stable_message = self._makeTranslationMessages(
             'smurf', 'smurf', trunk_diverged=False, stable_diverged=False)
-        trunk_message.is_current_ubuntu = False
-        stable_message.is_current_ubuntu = True
+        trunk_message.is_current_upstream = False
+        stable_message.is_current_upstream = True
 
         current_message = self._makeTranslationMessage(
             self.trunk_pofile, trunk_message.potmsgset, 'bzo', False)
-        current_message.is_current_ubuntu = True
+        current_message.is_current_upstream = True
 
         self.assertEqual(self._getTranslations(), ('bzo', 'smurf'))
 
@@ -449,8 +450,8 @@
         trunk_message, stable_message = self._makeTranslationMessages(
             'gah', 'ulp', trunk_diverged=False, stable_diverged=True)
 
-        trunk_message.is_current_ubuntu = False
-        stable_message.is_current_ubuntu = False
+        trunk_message.is_current_upstream = False
+        stable_message.is_current_upstream = False
 
         self.script._mergePOTMsgSets(self.templates)
         self.script._mergeTranslationMessages(self.templates)
@@ -486,7 +487,7 @@
         # this implies that it gains one).
         trunk_message, stable_message = self._makeTranslationMessages(
             'n', 'n', trunk_diverged=False, stable_diverged=True)
-        stable_message.is_current_ubuntu = False
+        stable_message.is_current_upstream = False
 
         self.assertEqual(self._getTranslations(), ('n', None))
 
@@ -500,7 +501,7 @@
         trunk_message, stable_message = self._getMessages()
         self.assertEqual(trunk_message, stable_message)
         self.assertEqual(trunk_message.potemplate, None)
-        self.assertTrue(trunk_message.is_current_ubuntu)
+        self.assertTrue(trunk_message.is_current_upstream)
 
         # Redundant messages are deleted.
         tms = trunk_message.potmsgset.getAllTranslationMessages()
@@ -573,12 +574,12 @@
         # TranslationMessages that might get in the way of merging.
         trunk_message, stable_message = self._makeTranslationMessages(
             'snaggle', 'snaggle')
-        trunk_message.is_current_ubuntu = False
+        trunk_message.is_current_upstream = False
         trunk_message.sync()
 
         potmsgset = trunk_message.potmsgset
 
-        stable_message.is_current_upstream = True
+        stable_message.is_current_ubuntu = True
         stable_message.potemplate = trunk_message.potemplate
         stable_message.potmsgset = potmsgset
         stable_message.sync()
@@ -595,13 +596,13 @@
         # The duplicates have been cleaned up.
         self.assertEqual(potmsgset.getAllTranslationMessages().count(), 1)
 
-        # The is_current_ubuntu and is_current_upstream flags from the
+        # The is_current_upstream and is_current_ubuntu flags from the
         # duplicate messages have been merged into a single message,
         # current in both ubuntu and upstream.
 
         message = self._getMessage(potmsgset, self.trunk_template)
+        self.assertTrue(message.is_current_upstream)
         self.assertTrue(message.is_current_ubuntu)
-        self.assertTrue(message.is_current_upstream)
 
     def test_ScrubPOTMsgSetTranslationsWithoutDuplication(self):
         # _scrubPOTMsgSetTranslations eliminates duplicated
@@ -618,7 +619,7 @@
 
     def test_ScrubPOTMsgSetTranslationsWithDuplication(self):
         # If there are duplicate TranslationMessages, one inherits all
-        # their is_current_ubuntu/is_is_current_upstream flags and the
+        # their is_current_upstream/is_is_current_ubuntu flags and the
         # others disappear.
         # XXX JeroenVermeulen 2009-06-15
         # spec=message-sharing-prevent-duplicates: We're going to have a
@@ -627,8 +628,8 @@
         # retired.
         message1, message2 = self._makeTranslationMessages(
             'tigidou', 'tigidou', trunk_diverged=True, stable_diverged=True)
-        message2.is_current_ubuntu = False
-        message2.is_current_upstream = True
+        message2.is_current_upstream = False
+        message2.is_current_ubuntu = True
         message2.potmsgset = self.trunk_potmsgset
         message2.potemplate = self.trunk_template
         ids = (message1.id, message2.id)
@@ -643,44 +644,44 @@
         # The remaining message combines the flags from both its
         # predecessors.
         self.assertEqual(
-            (message.is_current_ubuntu, message.is_current_upstream),
+            (message.is_current_upstream, message.is_current_ubuntu),
             (True, True))
 
     def test_FindCurrentClash(self):
         # _findClashes finds messages that would be "in the way" (as far
-        # as the is_current_ubuntu/is_current_upstream flags are
+        # as the is_current_upstream/is_current_ubuntu flags are
         # concerned) if we try to move a message to another template and
         # potmsgset.
         trunk_message, stable_message = self._makeTranslationMessages(
             'ex', 'why', trunk_diverged=False, stable_diverged=False)
-        current_clash, imported_clash, twin = self.script._findClashes(
+        ubuntu_clash, upstream_clash, twin = self.script._findClashes(
             stable_message, self.trunk_potmsgset, None)
 
         # Moving stable_message fully into trunk would clash with
         # trunk_message.
-        self.assertEqual(current_clash, trunk_message)
+        self.assertEqual(upstream_clash, trunk_message)
 
-        # There's no conflict for the is_current_upstream flag.
-        self.assertEqual(imported_clash, None)
+        # There's no conflict for the is_current_ubuntu flag.
+        self.assertEqual(ubuntu_clash, None)
 
         # Nor does stable_message have a twin in trunk.
         self.assertEqual(twin, None)
 
-    def test_FindImportedClash(self):
-        # Finding is_current_upstream clashes works just like finding
-        # is_current_ubuntu clashes.
+    def test_FindUbuntuClash(self):
+        # Finding is_current_ubuntu clashes works just like finding
+        # is_current_upstream clashes.
         trunk_message, stable_message = self._makeTranslationMessages(
             'ex', 'why', trunk_diverged=False, stable_diverged=False)
 
         for message in (trunk_message, stable_message):
-            message.is_current_ubuntu = False
-            message.is_current_upstream = True
+            message.is_current_upstream = False
+            message.is_current_ubuntu = True
 
-        current_clash, imported_clash, twin = self.script._findClashes(
+        ubuntu_clash, upstream_clash, twin = self.script._findClashes(
             stable_message, self.trunk_potmsgset, None)
 
-        self.assertEqual(current_clash, None)
-        self.assertEqual(imported_clash, trunk_message)
+        self.assertEqual(upstream_clash, None)
+        self.assertEqual(ubuntu_clash, trunk_message)
         self.assertEqual(twin, None)
 
     def test_FindTwin(self):
@@ -688,13 +689,13 @@
         # translations, for the same language.
         trunk_message, stable_message = self._makeTranslationMessages(
             'klob', 'klob', trunk_diverged=False, stable_diverged=False)
-        trunk_message.is_current_ubuntu = False
+        trunk_message.is_current_upstream = False
 
-        current_clash, imported_clash, twin = self.script._findClashes(
+        ubuntu_clash, upstream_clash, twin = self.script._findClashes(
             stable_message, self.trunk_potmsgset, None)
 
-        self.assertEqual(current_clash, None)
-        self.assertEqual(imported_clash, None)
+        self.assertEqual(upstream_clash, None)
+        self.assertEqual(ubuntu_clash, None)
         self.assertEqual(twin, trunk_message)
 
     def test_FindClashesWithTwin(self):
@@ -703,11 +704,11 @@
         trunk_message, stable_message = self._makeTranslationMessages(
             'sniw', 'sniw', trunk_diverged=False, stable_diverged=False)
 
-        current_clash, imported_clash, twin = self.script._findClashes(
+        ubuntu_clash, upstream_clash, twin = self.script._findClashes(
             stable_message, self.trunk_potmsgset, None)
 
-        self.assertEqual(current_clash, None)
-        self.assertEqual(imported_clash, None)
+        self.assertEqual(upstream_clash, None)
+        self.assertEqual(ubuntu_clash, None)
         self.assertEqual(twin, trunk_message)
 
     def test_FindClashesWithNonTwin(self):
@@ -715,15 +716,15 @@
         # same place.
         trunk_message, stable_message = self._makeTranslationMessages(
             'sniw', 'sniw', trunk_diverged=False, stable_diverged=False)
-        trunk_message.is_current_ubuntu = False
+        trunk_message.is_current_upstream = False
         current_message = self._makeTranslationMessage(
             self.trunk_pofile, self.trunk_potmsgset, 'gah', False)
 
-        current_clash, imported_clash, twin = self.script._findClashes(
+        ubuntu_clash, upstream_clash, twin = self.script._findClashes(
             stable_message, self.trunk_potmsgset, None)
 
-        self.assertEqual(current_clash, current_message)
-        self.assertEqual(imported_clash, None)
+        self.assertEqual(upstream_clash, current_message)
+        self.assertEqual(ubuntu_clash, None)
         self.assertEqual(twin, trunk_message)
 
 

=== modified file 'lib/lp/translations/stories/standalone/xx-translationmessage-translate.txt'
--- lib/lp/translations/stories/standalone/xx-translationmessage-translate.txt	2011-01-26 22:23:52 +0000
+++ lib/lp/translations/stories/standalone/xx-translationmessage-translate.txt	2011-01-26 22:24:37 +0000
@@ -554,21 +554,22 @@
     >>> potmsgset = evolution_potemplate.getPOTMsgSetByMsgIDText(' cards')
     >>> spanish = evolution_pofile.language
 
-    >>> imported = potmsgset.getCurrentTranslation(
+    >>> upstream_message = potmsgset.getCurrentTranslation(
     ...     evolution_potemplate, spanish,
     ...     side=TranslationSide.UPSTREAM)
-    >>> imported.translations
+    >>> upstream_message.translations
     [u' tarjetas']
 
 We replace it with an empty, imported translation:
 
-    >>> import datetime, pytz
-    >>> UTC = pytz.timezone('UTC')
-    >>> translation_message = potmsgset.updateTranslation(
-    ...     evolution_pofile, carlos, {0: u''}, is_current_upstream=True,
-    ...     lock_timestamp=datetime.datetime.now(UTC))
-    >>> print translation_message
-    None
+    >>> empty_upstream_message = factory.makeSuggestion(
+    ...     potmsgset=potmsgset, pofile=evolution_pofile, translator=carlos,
+    ...     translations={0: u''})
+    >>> from zope.security.proxy import removeSecurityProxy
+    >>> removeSecurityProxy(upstream_message).is_current_upstream = False
+    >>> removeSecurityProxy(empty_upstream_message).is_current_upstream = True
+    >>> empty_upstream_message.translations
+    [u'']
 
     >>> logout()
 
@@ -578,8 +579,14 @@
     >>> browser.open('http://translations.launchpad.dev/ubuntu/hoary/'
     ...              '+source/evolution/+pots/evolution-2.2/es/5/+translate')
     >>> packaged = find_tag_by_id(browser.contents, 'msgset_134_other')
-    >>> print packaged
-    None
+
+XXX: 2011-01-25 henninge, bug=707825: This should either display nothing or
+a string like "(no translation)". This documents the current behavior although
+it would be different if the translation had been properly reset. Also the
+wording here ("packaged") needs to be adapted.
+
+    >>> print extract_text(packaged)
+    In upstream:
 
 
 Shared and diverged translations

=== modified file 'lib/lp/translations/tests/test_potmsgset.py'
--- lib/lp/translations/tests/test_potmsgset.py	2011-01-26 22:23:52 +0000
+++ lib/lp/translations/tests/test_potmsgset.py	2011-01-26 22:24:37 +0000
@@ -337,11 +337,11 @@
         product = external_template.productseries.product
         product.translations_usage = ServiceUsage.LAUNCHPAD
         external_potmsgset = self.factory.makePOTMsgSet(
-            external_template,
-            singular=self.potmsgset.singular_text)
-        external_potmsgset.setSequence(external_template, 1)
-        external_pofile = self.factory.makePOFile('sr', external_template)
-        serbian = external_pofile.language
+            external_template, singular=self.potmsgset.singular_text,
+            sequence=1)
+        external_pofile = self.factory.makePOFile(
+            potemplate=external_template)
+        language = external_pofile.language
         self._refreshSuggestiveTemplatesCache()
 
         transaction.commit()
@@ -349,7 +349,7 @@
         # When there is no translation for the external POTMsgSet,
         # no externally used suggestions are returned.
         self.assertEquals(
-            self.potmsgset.getExternallyUsedTranslationMessages(serbian),
+            self.potmsgset.getExternallyUsedTranslationMessages(language),
             [])
 
         # If there are only suggestions on the external POTMsgSet,
@@ -360,32 +360,31 @@
         transaction.commit()
 
         self.assertEquals(
-            self.potmsgset.getExternallyUsedTranslationMessages(serbian),
+            self.potmsgset.getExternallyUsedTranslationMessages(language),
             [])
 
-        # If there is an imported translation on the external POTMsgSet,
-        # it is returned as the externally used suggestion.
-        imported_translation = self.factory.makeCurrentTranslationMessage(
+        # If there is a translation for the other side on the external
+        # POTMsgSet, it is returned as an externally used suggestion.
+        other_translation = self.factory.makeSuggestion(
             pofile=external_pofile, potmsgset=external_potmsgset)
-        imported_translation.makeCurrentUbuntu(False)
+        removeSecurityProxy(other_translation).is_current_ubuntu = True
 
         transaction.commit()
 
         self.assertEquals(
-            self.potmsgset.getExternallyUsedTranslationMessages(serbian),
-            [imported_translation])
+            self.potmsgset.getExternallyUsedTranslationMessages(language),
+            [other_translation])
 
         # If there is a current translation on the external POTMsgSet,
         # it is returned as the externally used suggestion as well.
-        current_translation = self.factory.makeSharedTranslationMessage(
-            pofile=external_pofile, potmsgset=external_potmsgset,
-            is_current_upstream=False)
+        current_translation = self.factory.makeCurrentTranslationMessage(
+            pofile=external_pofile, potmsgset=external_potmsgset)
 
         transaction.commit()
 
-        self.assertEquals(
-            self.potmsgset.getExternallyUsedTranslationMessages(serbian),
-            [imported_translation, current_translation])
+        self.assertContentEqual(
+            self.potmsgset.getExternallyUsedTranslationMessages(language),
+            [other_translation, current_translation])
 
     def test_getExternallySuggestedTranslationMessages(self):
         """Test retrieval of externally suggested translations."""
@@ -396,11 +395,11 @@
         product = external_template.productseries.product
         product.translations_usage = ServiceUsage.LAUNCHPAD
         external_potmsgset = self.factory.makePOTMsgSet(
-            external_template,
-            singular=self.potmsgset.singular_text)
-        external_potmsgset.setSequence(external_template, 1)
-        external_pofile = self.factory.makePOFile('sr', external_template)
-        serbian = external_pofile.language
+            external_template, singular=self.potmsgset.singular_text,
+            sequence=1)
+        external_pofile = self.factory.makePOFile(
+            potemplate=external_template)
+        language = external_pofile.language
         self._refreshSuggestiveTemplatesCache()
 
         transaction.commit()
@@ -408,7 +407,8 @@
         # When there is no translation for the external POTMsgSet,
         # no externally used suggestions are returned.
         self.assertEquals(
-            self.potmsgset.getExternallySuggestedTranslationMessages(serbian),
+            self.potmsgset.getExternallySuggestedTranslationMessages(
+                language),
             [])
 
         # If there is a suggestion on the external POTMsgSet,
@@ -419,29 +419,32 @@
         transaction.commit()
 
         self.assertEquals(
-            self.potmsgset.getExternallySuggestedTranslationMessages(serbian),
+            self.potmsgset.getExternallySuggestedTranslationMessages(
+                language),
             [external_suggestion])
 
-        # If there is an imported, non-current translation on the external
+        # If there is a translation for the other side on the external
         # POTMsgSet, it is not returned as the external suggestion.
-        imported_translation = self.factory.makeCurrentTranslationMessage(
+        other_translation = self.factory.makeSuggestion(
             pofile=external_pofile, potmsgset=external_potmsgset)
+        removeSecurityProxy(other_translation).is_current_ubuntu = True
         transaction.commit()
 
         self.assertEquals(
-            self.potmsgset.getExternallySuggestedTranslationMessages(serbian),
+            self.potmsgset.getExternallySuggestedTranslationMessages(
+                language),
             [external_suggestion])
 
         # A current translation on the external POTMsgSet is not
         # considered an external suggestion.
-        current_translation = self.factory.makeSharedTranslationMessage(
-            pofile=external_pofile, potmsgset=external_potmsgset,
-            is_current_upstream=False)
+        current_translation = self.factory.makeCurrentTranslationMessage(
+            pofile=external_pofile, potmsgset=external_potmsgset)
 
         transaction.commit()
 
         self.assertEquals(
-            self.potmsgset.getExternallySuggestedTranslationMessages(serbian),
+            self.potmsgset.getExternallySuggestedTranslationMessages(
+                language),
             [external_suggestion])
 
     def test_hasTranslationChangedInLaunchpad(self):
@@ -711,8 +714,8 @@
         transaction.commit()
         # Make the translation a suggestion, too.
         suggestion3 = self.translation
-        suggestion3.makeCurrentUbuntu(False)
-        suggestion3.makeCurrentUpstream(False)
+        removeSecurityProxy(suggestion3).is_current_ubuntu = False
+        removeSecurityProxy(suggestion3).is_current_upstream = False
         self._setDateCreated(suggestion3)
         transaction.commit()
         # All suggestions are visible.

=== removed file 'lib/lp/translations/utilities/tests/import-flags.txt'
--- lib/lp/translations/utilities/tests/import-flags.txt	2010-12-14 16:57:36 +0000
+++ lib/lp/translations/utilities/tests/import-flags.txt	1970-01-01 00:00:00 +0000
@@ -1,544 +0,0 @@
-= Importing translation files =
-
-We are using gettext PO file to document how our translation files
-are being imported into our database, showing how translations are
-overridden or not, depending on the type of the import.
-
-We'll be going through usual steps of the PO file lifetime:
- * importing a template
- * importing a translation from package
- * importing updated translation from a translator
- * importing an updated translation from a package
- * importing update from a translator again
-
-== Helper imports ==
-
-    >>> from canonical.database.sqlbase import flush_database_caches
-    >>> from lp.registry.interfaces.person import IPersonSet
-    >>> from lp.registry.interfaces.product import IProductSet
-    >>> from lp.translations.model.potemplate import POTemplateSubset
-    >>> import datetime
-    >>> import pytz
-    >>> UTC = pytz.timezone('UTC')
-    >>> def ISO_FORMATTED_DATE(): return datetime.datetime.now(UTC).isoformat()
-
-To ease the pain of importing many files during testing, we use this
-helper function to import either a PO file or a PO template from a
-string with the contents of the file.
-
-    >>> from lp.translations.utilities.tests.helpers import (
-    ...     import_pofile_or_potemplate)
-
-And lets define a nice printout function for PO files.
-
-    >>> def print_pofile(pofile):
-    ...     # We are using length=18 for msgid, translation and
-    ...     # imported translation to be able to fit them with two
-    ...     # fuzzy flags into a single line for nicer and more
-    ...     # readable diffs in the test.
-    ...     def strip_to_length(string, length=18):
-    ...         if string is None: return None
-    ...         if len(string)>length:
-    ...             return string[:length-3]+'...'
-    ...         else:
-    ...             return string
-    ...
-    ...     print "%2s. %-18s %-18s %-18s" % (
-    ...         "no", "msgid", "translation", "imported")
-    ...     for potmsgset in pofile.potemplate.getPOTMsgSets():
-    ...         msgid = potmsgset.singular_text
-    ...         current = potmsgset.getCurrentTranslationMessage(
-    ...             pofile.potemplate, pofile.language)
-    ...         imported = potmsgset.getOtherTranslation(
-    ...             pofile.language, pofile.potemplate.translation_side)
-    ...         imported_translation = translation = None
-    ...         if imported is not None:
-    ...             imported_translation = imported.msgstr0.translation
-    ...         if current is not None:
-    ...             translation = current.msgstr0.translation
-    ...         print "% 2d. %-18s %-18s %-18s *" % (
-    ...             potmsgset.sequence,
-    ...             strip_to_length(msgid),
-    ...             strip_to_length(translation),
-    ...             strip_to_length(imported_translation))
-
-We need to print out stats for the pofile as well.
-
-    >>> # We are indenting those counts which are contained in the parent
-    >>> # one.  Thus, 'translated' count is the sum of 'imported' and 'new'.
-    >>> # 'imported' also includes the 'changed' entries.
-    >>> def print_pofile_stats(pofile):
-    ...     pofile.updateStatistics()
-    ...     print "total:", pofile.messageCount()
-    ...     print "translated:", pofile.translatedCount()
-    ...     print "  imported:", pofile.currentCount()
-    ...     print "    changed:", pofile.updatesCount()
-    ...     print "  new:", pofile.rosettaCount()
-
-We'll be doing all our imports into Firefox trunk as
-carlos@xxxxxxxxxxxxx.
-
-    >>> carlos = getUtility(IPersonSet).getByEmail('carlos@xxxxxxxxxxxxx')
-    >>> login('carlos@xxxxxxxxxxxxx')
-
-    >>> firefox = getUtility(IProductSet).getByName('firefox')
-    >>> firefox_trunk = firefox.getSeries('trunk')
-    >>> firefox_potsubset = POTemplateSubset(productseries=firefox_trunk)
-
-    >>> firefox_potemplate = firefox_potsubset.new(
-    ...     name='firefox',
-    ...     translation_domain='firefox',
-    ...     path='po/firefox.pot',
-    ...     owner=carlos)
-
-== Importing a template ==
-
-To avoid using sample data, we import a template into Firefox here, to
-be able to import translations later on.
-
-    >>> test_template = r'''
-    ... msgid ""
-    ... msgstr ""
-    ... "POT-Creation-Date: 2004-07-11 16:16+0900\n"
-    ... "Content-Type: text/plain; charset=CHARSET\n"
-    ... "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
-    ...
-    ... msgid "first"
-    ... msgstr ""
-    ...
-    ... msgid "second"
-    ... msgstr ""
-    ...
-    ... msgid "third"
-    ... msgstr ""
-    ...
-    ... msgid "fourth"
-    ... msgstr ""
-    ...
-    ... msgid "fifth"
-    ... msgstr ""
-    ...
-    ... msgid "sixth"
-    ... msgstr ""
-    ... '''
-    >>> entry = import_pofile_or_potemplate(test_template, carlos,
-    ...                                     potemplate=firefox_potemplate)
-    >>> print entry.status.name
-    IMPORTED
-    >>> flush_database_caches()
-
-Usually, the first import we get is imported (i.e. coming from a
-package upload in Ubuntu).
-
-    # fifth and sixth are untranslated
-    >>> test_translation_imported = r'''
-    ... msgid ""
-    ... msgstr ""
-    ... "PO-Revision-Date: %s\n"
-    ... "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-    ... "Content-Type: text/plain; charset=UTF-8\n"
-    ... "X-Launchpad-Export-Date: 2005-05-03 20:40+0100\n"
-    ...
-    ... msgid "first"
-    ... msgstr "a"
-    ...
-    ... msgid "second"
-    ... msgstr "b"
-    ...
-    ... #, fuzzy
-    ... msgid "third"
-    ... msgstr "c"
-    ...
-    ... #, fuzzy
-    ... msgid "fourth"
-    ... msgstr "d"
-    ... ''' % ISO_FORMATTED_DATE()
-
-    >>> firefox_serbian = firefox_potemplate.newPOFile('sr')
-    >>> firefox_serbian.path='sr.po'
-    >>> entry = import_pofile_or_potemplate(test_translation_imported,
-    ...                                     carlos, pofile=firefox_serbian)
-    >>> print entry.status.name
-    IMPORTED
-    >>> flush_database_caches()
-
-When this file is imported, we notice that all the messages are
-imported as expected: current translation is set to the same imported
-one, and fuzzy messages are ignored (treated as empty messages).
-
-    >>> print_pofile(firefox_serbian)
-    no. msgid              translation        imported
-     1. first              a                  a                  *
-     2. second             b                  b                  *
-     3. third              None               None               *
-     4. fourth             None               None               *
-     5. fifth              None               None               *
-     6. sixth              None               None               *
-
-If we look at the statistics, only non-fuzzy imported messages are counted
-as valid translations.
-
-    >>> print_pofile_stats(firefox_serbian)
-    total: 6
-    translated: 2
-      imported: 2
-        changed: 0
-      new: 0
-
-After initial translation import from the package, it's common for
-translators to work either directly in Launchpad or to upload PO files
-with their updates.  This is a file where the "second" and "fourth"
-message are updated with new translations, the fuzzy flag is removed
-from the "fourth" message, and the "fifth" message is newly translated.
-
-    >>> test_translation_update1 = r'''
-    ... msgid ""
-    ... msgstr ""
-    ... "PO-Revision-Date: %s\n"
-    ... "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-    ... "Content-Type: text/plain; charset=UTF-8\n"
-    ... "X-Launchpad-Export-Date: %s\n"
-    ...
-    ... # stays as imported
-    ... msgid "first"
-    ... msgstr "a"
-    ...
-    ... # changes imported translation
-    ... msgid "second"
-    ... msgstr "b-from-LP"
-    ...
-    ... # same as already imported one
-    ... #, fuzzy
-    ... msgid "third"
-    ... msgstr "c"
-    ...
-    ... # takes the fuzzy flag off and updates the translation
-    ... msgid "fourth"
-    ... msgstr "d-from-LP"
-    ...
-    ... # translates untranslated message
-    ... msgid "fifth"
-    ... msgstr "e-from-LP"
-    ... ''' % (ISO_FORMATTED_DATE(), ISO_FORMATTED_DATE())
-
-    >>> entry = import_pofile_or_potemplate(test_translation_update1,
-    ...                                     carlos, pofile=firefox_serbian,
-    ...                                     by_maintainer=False)
-    >>> print entry.status.name
-    IMPORTED
-    >>> flush_database_caches()
-
-Again, PO file in the database reflects the changes: translations for
-"second", "fourth" and "fifth" are updated (and now different from
-imported translations). Fuzzy flag is ignored on "fourth" as well.
-
-    >>> print_pofile(firefox_serbian)
-    no. msgid              translation        imported
-     1. first              a                  a                  *
-     2. second             b-from-LP          b                  *
-     3. third              None               None               *
-     4. fourth             d-from-LP          None               *
-     5. fifth              e-from-LP          None               *
-     6. sixth              None               None               *
-
-We can notice that we have 4 translations (fuzzy messages are not considered
-translated), with "second" imported one now considered 'changed in Ubuntu', and
-two new translations through Launchpad ("d-from-LP" and "e-from-LP"):
-
-    >>> print_pofile_stats(firefox_serbian)
-    total: 6
-    translated: 4
-      imported: 1
-        changed: 1
-      new: 3
-
-Common next step is having a new package upload which provides us with
-updated translations upstream.  The "second" message translation is changed,
-a fuzzy flag is removed from the "fourth" message, and both "fifth" and
-"sixth" are translated.
-
-    >>> test_translation_imported_update = r'''
-    ... msgid ""
-    ... msgstr ""
-    ... "PO-Revision-Date: %s\n"
-    ... "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-    ... "Content-Type: text/plain; charset=UTF-8\n"
-    ... "X-Launchpad-Export-Date: %s\n"
-    ...
-    ... msgid "first"
-    ... msgstr "a"
-    ...
-    ... msgid "second"
-    ... msgstr "b-updated"
-    ...
-    ... #, fuzzy
-    ... msgid "third"
-    ... msgstr "c"
-    ...
-    ... # removes the fuzzy flag on the imported translation
-    ... msgid "fourth"
-    ... msgstr "d"
-    ...
-    ... # translate remaining messages
-    ... msgid "fifth"
-    ... msgstr "e"
-    ...
-    ... msgid "sixth"
-    ... msgstr "f"
-    ... ''' % (ISO_FORMATTED_DATE(), ISO_FORMATTED_DATE())
-
-    >>> entry = import_pofile_or_potemplate(test_translation_imported_update,
-    ...                                     carlos, pofile=firefox_serbian,
-    ...                                     by_maintainer=True)
-    >>> print entry.status.name
-    IMPORTED
-    >>> flush_database_caches()
-
-We can see that the imported fuzzy flag has been removed from the
-"fourth" message in the database, and that imported translations for
-"fifth" and "sixth" have been updated.  Also note how the current
-translations for "fourth" and "fifth" messages have been reverted
-to imported ones.
-
-    >>> print_pofile(firefox_serbian)
-    no. msgid              translation        imported
-     1. first              a                  a                  *
-     2. second             b-from-LP          b-updated          *
-     3. third              None               None               *
-     4. fourth             d                  d                  *
-     5. fifth              e                  e                  *
-     6. sixth              f                  f                  *
-
-With this latest import, we've got five non-fuzzy messages, which are all
-considered 'translated'. Since we are reverting to imported translations
-when there's only a Launchpad-done translation, only a single message is
-marked as 'changed in Ubuntu':
-
-    >>> print_pofile_stats(firefox_serbian)
-    total: 6
-    translated: 5
-      imported: 4
-        changed: 1
-      new: 1
-
-A new translation for "second" message through Launchpad is added.  We also
-do another translator (i.e. not from a package) update, where we remove the
-fuzzy flag from the imported translation for "third", and revert "fourth"
-to the imported translation.  Finally, "fifth" translation is updated with
-a new translation.
-
-    >>> test_translation_update2 = r'''
-    ... msgid ""
-    ... msgstr ""
-    ... "PO-Revision-Date: %s\n"
-    ... "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-    ... "Content-Type: text/plain; charset=UTF-8\n"
-    ... "X-Launchpad-Export-Date: %s\n"
-    ...
-    ... # stays as imported
-    ... msgid "first"
-    ... msgstr "a"
-    ...
-    ... msgid "second"
-    ... msgstr "b-from-LP-two"
-    ...
-    ... # same as already imported one, removes the fuzzy flag
-    ... msgid "third"
-    ... msgstr "c"
-    ...
-    ... # revert to imported translation
-    ... msgid "fourth"
-    ... msgstr "d"
-    ...
-    ... # updates current translation
-    ... msgid "fifth"
-    ... msgstr "e-from-LP-two"
-    ...
-    ... # sixth message is not being updated at all
-    ... msgid "sixth"
-    ... msgstr "f"
-    ... ''' % (ISO_FORMATTED_DATE(), ISO_FORMATTED_DATE())
-
-    >>> entry = import_pofile_or_potemplate(test_translation_update2,
-    ...                                     carlos, pofile=firefox_serbian,
-    ...                                     by_maintainer=False)
-    >>> print entry.status.name
-    IMPORTED
-    >>> flush_database_caches()
-
-We can see that "third" message has fuzzy flag removed from the current
-translation (but not from the imported one), "fourth" is reverted to
-the same translation as imported, and "fifth" has an updated
-translation.
-
-    >>> print_pofile(firefox_serbian)
-    no. msgid              translation        imported
-     1. first              a                  a                  *
-     2. second             b-from-LP-two      b-updated          *
-     3. third              c                  None               *
-     4. fourth             d                  d                  *
-     5. fifth              e-from-LP-two      e                  *
-     6. sixth              f                  f                  *
-
-Removing a fuzzy flag from imported translation for "third" actually makes
-a 'new' translation, which is reflected in the statistics below, and
-reverting a "fourth" translation to the imported one is shown by the decreased
-'changed' count:
-
-    >>> print_pofile_stats(firefox_serbian)
-    total: 6
-    translated: 6
-      imported: 3
-        changed: 2
-      new: 3
-
-Finally, we make sure that adding another suggestion to the "second" message
-works properly, even if it makes us have two non-current and non-imported
-suggestions.
-
-    >>> test_translation_update3 = r'''
-    ... msgid ""
-    ... msgstr ""
-    ... "PO-Revision-Date: %s\n"
-    ... "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-    ... "Content-Type: text/plain; charset=UTF-8\n"
-    ... "X-Launchpad-Export-Date: %s\n"
-    ...
-    ... # stays as imported
-    ... msgid "first"
-    ... msgstr "a"
-    ...
-    ... msgid "second"
-    ... msgstr "b-from-LP-three"
-    ...
-    ... # same as already imported one, removes the fuzzy flag
-    ... msgid "third"
-    ... msgstr "c"
-    ...
-    ... # revert to imported translation
-    ... msgid "fourth"
-    ... msgstr "d"
-    ...
-    ... # updates current translation
-    ... msgid "fifth"
-    ... msgstr "e-from-LP-two"
-    ...
-    ... # sixth message is not being updated at all
-    ... msgid "sixth"
-    ... msgstr "f"
-    ... ''' % (ISO_FORMATTED_DATE(), ISO_FORMATTED_DATE())
-
-    >>> entry = import_pofile_or_potemplate(test_translation_update3,
-    ...                                     carlos, pofile=firefox_serbian,
-    ...                                     by_maintainer=False)
-    >>> print entry.status.name
-    IMPORTED
-
-Notice that "second" message is indeed updated properly.  We are making sure
-we don't get any problems with too many non-current suggestions for that
-one ("b-from-LP", "b-from-LP-two").
-
-    >>> print_pofile(firefox_serbian)
-    no. msgid              translation        imported
-     1. first              a                  a                  *
-     2. second             b-from-LP-three    b-updated          *
-     3. third              c                  None               *
-     4. fourth             d                  d                  *
-     5. fifth              e-from-LP-two      e                  *
-     6. sixth              f                  f                  *
-
-Statistics have not changed from the previous, since translation for "second"
-was already 'changed':
-
-    >>> print_pofile_stats(firefox_serbian)
-    total: 6
-    translated: 6
-      imported: 3
-        changed: 2
-      new: 3
-
-If a translation actually uses a different plural expression from the
-one we default to in Launchpad, non-plural messages are not reordered
-(this is mostly a regression test).  The specific problematic case
-occured when formula required reordering messages (i.e. a first form
-was moved to another place), thus ending up with None for non-plural
-messages.  The PO file contents below are no different from the above
-one except for the plural expression definition.
-
-    >>> test_translation_update3 = r'''
-    ... msgid ""
-    ... msgstr ""
-    ... "PO-Revision-Date: %s\n"
-    ... "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-    ... "Content-Type: text/plain; charset=UTF-8\n"
-    ... "Plural-Forms: nplurals=3; plural=n%%10==1 && n%%100!=11 ? 1 : "
-    ... "n%%10>=2 && n%%10<=4 && (n%%100<10 || n%%100>=20) ? 2 : 0\n"
-    ... "X-Launchpad-Export-Date: %s\n"
-    ...
-    ... # stays as imported
-    ... msgid "first"
-    ... msgstr "a"
-    ...
-    ... msgid "second"
-    ... msgstr "b-from-LP-three"
-    ...
-    ... # same as already imported one, removes the fuzzy flag
-    ... msgid "third"
-    ... msgstr "c"
-    ...
-    ... # revert to imported translation
-    ... msgid "fourth"
-    ... msgstr "d"
-    ...
-    ... # updates current translation
-    ... msgid "fifth"
-    ... msgstr "e-from-LP-two"
-    ...
-    ... # sixth message is not being updated at all
-    ... msgid "sixth"
-    ... msgstr "f"
-    ... ''' % (ISO_FORMATTED_DATE(), ISO_FORMATTED_DATE())
-
-    >>> entry = import_pofile_or_potemplate(test_translation_update3,
-    ...                                     carlos, pofile=firefox_serbian,
-    ...                                     by_maintainer=False)
-    >>> print entry.status.name
-    IMPORTED
-
-Neither contents nor statistics have changed, so we've got the same output.
-
-    >>> print_pofile(firefox_serbian)
-    no. msgid              translation        imported
-     1. first              a                  a                  *
-     2. second             b-from-LP-three    b-updated          *
-     3. third              c                  None               *
-     4. fourth             d                  d                  *
-     5. fifth              e-from-LP-two      e                  *
-     6. sixth              f                  f                  *
-
-    >>> print_pofile_stats(firefox_serbian)
-    total: 6
-    translated: 6
-      imported: 3
-        changed: 2
-      new: 3
-
-Sometimes, people will send back their translations to upstream, which will
-be back with next automatic sync from upstream:
-
-    >>> entry = import_pofile_or_potemplate(test_translation_update3,
-    ...                                     carlos, pofile=firefox_serbian,
-    ...                                     by_maintainer=True)
-    >>> print entry.status.name
-    IMPORTED
-
-Imported strings match the ones translated in Launchpad.
-
-    >>> print_pofile(firefox_serbian)
-    no. msgid              translation        imported
-     1. first              a                  a                  *
-     2. second             b-from-LP-three    b-from-LP-three    *
-     3. third              c                  c                  *
-     4. fourth             d                  d                  *
-     5. fifth              e-from-LP-two      e-from-LP-two      *
-     6. sixth              f                  f                  *


Follow ups