예제 #1
0
    def upload_messages_to_transifex(self,
                                     legalcode,
                                     pofile: polib.POFile = None):
        """
        We get the metadata from the legalcode object.
        You can omit the pofile and we'll get it using legalcode.get_pofile().
        We allow passing it in separately because it makes writing tests so much easier.
        """
        language_code = legalcode.language_code
        resource_slug = legalcode.license.resource_slug
        resource_name = legalcode.license.resource_name
        pofilename = legalcode.translation_filename()

        resources = self.get_transifex_resources()
        resource_slugs = [item["slug"] for item in resources]

        if pofile is None:
            pofile = legalcode.get_pofile()

        pofile_content = get_pofile_content(pofile)

        if resource_slug not in resource_slugs:
            if language_code != DEFAULT_LANGUAGE_CODE:
                raise ValueError(
                    f"The resource {resource_slug} does not yet exist in Transifex. Must upload English first to create it."
                )
            self.create_resource(resource_slug, resource_name, pofilename,
                                 pofile_content)
        elif language_code == DEFAULT_LANGUAGE_CODE:
            # We're doing English, which is the source language.
            self.update_source_messages(resource_slug, pofilename,
                                        pofile_content)
        else:
            self.update_translations(resource_slug, language_code, pofilename,
                                     pofile_content)
예제 #2
0
    def help_test_check_for_translation_updates(
        self, first_time, changed, resource_exists=True, language_exists=True
    ):
        """
        Helper to test several conditions, since all the setup is so
        convoluted.
        """
        language_code = "zh-Hans"
        license = LicenseFactory(version="4.0", license_code="by-nd")

        first_translation_update_datetime = datetime.datetime(
            2007, 1, 25, 12, 0, 0, tzinfo=utc
        )
        changed_translation_update_datetime = datetime.datetime(
            2020, 9, 30, 13, 11, 52, tzinfo=utc
        )

        if first_time:
            # We don't yet know when the last update was.
            legalcode_last_update = None
        else:
            # The last update we know of was at this time.
            legalcode_last_update = first_translation_update_datetime

        legalcode = LegalCodeFactory(
            license=license,
            language_code=language_code,
            translation_last_update=legalcode_last_update,
        )
        resource_slug = license.resource_slug

        # Will need an English legalcode if we need to create the resource
        if not resource_exists and language_code != DEFAULT_LANGUAGE_CODE:
            LegalCodeFactory(
                license=license,
                language_code=DEFAULT_LANGUAGE_CODE,
            )

        # 'timestamp' returns on translation stats from transifex
        if changed:
            # now it's the newer time
            timestamp = changed_translation_update_datetime.isoformat()
        else:
            # it's still the first time
            timestamp = first_translation_update_datetime.isoformat()

        mock_repo = MagicMock()
        mock_repo.is_dirty.return_value = False

        legalcodes = [legalcode]
        dummy_repo = DummyRepo("/trans/repo")

        # A couple of places use git.Repo(path) to get a git repo object. Have
        # them all get back our same dummy repo.
        def dummy_repo_factory(path):
            return dummy_repo

        helper = TransifexHelper()

        with mpo(
            helper, "handle_legalcodes_with_updated_translations"
        ) as mock_handle_legalcodes, mpo(
            helper, "get_transifex_resource_stats"
        ) as mock_get_transifex_resource_stats, mpo(
            helper, "create_resource"
        ) as mock_create_resource, mpo(
            LegalCode, "get_pofile"
        ) as mock_get_pofile, mpo(
            helper, "upload_messages_to_transifex"
        ) as mock_upload:
            if resource_exists:
                if language_exists:
                    mock_get_transifex_resource_stats.return_value = {
                        resource_slug: {
                            language_code: {
                                "translated": {
                                    "last_activity": timestamp,
                                }
                            }
                        }
                    }
                else:
                    # language does not exist first time, does the second time
                    mock_get_transifex_resource_stats.side_effect = [
                        {resource_slug: {}},
                        {
                            resource_slug: {
                                language_code: {
                                    "translated": {
                                        "last_activity": timestamp,
                                    }
                                }
                            }
                        },
                    ]
            else:
                # First time does not exist, second time does
                mock_get_transifex_resource_stats.side_effect = [
                    {},
                    {
                        resource_slug: {
                            language_code: {
                                "translated": {
                                    "last_activity": timestamp,
                                }
                            }
                        }
                    },
                ]
                # Will need pofile
                mock_get_pofile.return_value = polib.POFile()
            helper.check_for_translation_updates_with_repo_and_legalcodes(
                dummy_repo, legalcodes
            )

        if not resource_exists:
            # Should have tried to create resource
            mock_create_resource.assert_called_with(
                resource_slug=resource_slug,
                resource_name=legalcode.license.fat_code(),
                pofilename=os.path.basename(legalcode.translation_filename()),
                pofile_content=get_pofile_content(
                    mock_get_pofile.return_value
                ),
            )
        else:
            # Not
            mock_create_resource.assert_not_called()

        if language_exists:
            mock_upload.assert_not_called()
        else:
            mock_upload.assert_called()

        mock_get_transifex_resource_stats.assert_called_with()
        legalcode.refresh_from_db()
        if changed:
            # we mocked the actual processing, so...
            self.assertEqual(
                first_translation_update_datetime,
                legalcode.translation_last_update,
            )
            mock_handle_legalcodes.assert_called_with(dummy_repo, [legalcode])
        else:
            self.assertEqual(
                first_translation_update_datetime,
                legalcode.translation_last_update,
            )
            mock_handle_legalcodes.assert_called_with(dummy_repo, [])
        return
예제 #3
0
    def check_for_translation_updates_with_repo_and_legalcodes(
            self, repo: git.Repo,
            legalcodes: Iterable["licenses.models.LegalCode"]):
        """
        Use the Transifex API to find the last update timestamp for all our translations.
        If translations are updated, we'll create a branch if there isn't already one
        for that translation, then update it with the updated translations, rebuild the
        HTML, commit all the changes, and push it upstream.

        Return a list of the names of all local branches that have been updated, that
        can be used e.g. to run publish on those branches.
        """
        self.say(3, "check if repo is dirty")
        if repo.is_dirty():
            raise Exception(
                f"Git repo at {settings.TRANSLATION_REPOSITORY_DIRECTORY} is dirty. "
                f"We cannot continue.")
        self.say(2, "Fetch to update repo")
        repo.remotes.origin.fetch()
        resource_slugs_on_transifex = self.stats.keys()

        # We only have the BY* 4.0 licenses in our database so far.
        # We'd like to process one potential translation branch at a time.
        # For the BY* 4.0 licenses, there's a single translation branch for
        # each language. So identify all the languages and iterate over those.
        # (Except English)

        # Gather the files we need to update in git.
        # This is a dict with keys = branch names, and values dictionaries mapping
        # relative paths of files to update, to their contents (bytes).
        self.branches_to_update = defaultdict(_empty_branch_object)
        self.legalcodes_to_update = []
        self.branch_objects_to_update = []

        legalcodes_with_updated_translations = []

        for legalcode in legalcodes:
            language_code = legalcode.language_code
            resource_slug = legalcode.license.resource_slug
            if resource_slug not in resource_slugs_on_transifex:
                self.say(
                    2, f"Transifex has no resource {resource_slug}. Creating.")

                # Create the resource
                english_pofile = legalcode.get_english_pofile()
                pofile_content = get_pofile_content(english_pofile)
                self.create_resource(
                    resource_slug=resource_slug,
                    resource_name=legalcode.license.fat_code(),
                    pofilename=os.path.basename(
                        legalcode.translation_filename()),
                    pofile_content=pofile_content,
                )
                self.clear_transifex_stats()

            if language_code not in self.stats[resource_slug]:
                self.say(
                    2,
                    f"Transifex has no {language_code} translation for {resource_slug}",
                )  # pragma: no cover

                # Upload the language
                self.upload_messages_to_transifex(legalcode)
                self.clear_transifex_stats()

            # We have a translation in this language for this license on Transifex.
            # When was it last updated?
            last_activity = self.stats[resource_slug][language_code][
                "translated"]["last_activity"]
            last_tx_update = (iso8601.parse_date(last_activity)
                              if last_activity else None)

            if legalcode.translation_last_update is None:
                # First time: initialize, don't create branch
                legalcode.translation_last_update = last_tx_update
                legalcode.save()
                self.say(2, f"Initialized last update time for {legalcode}")
                continue

            if last_tx_update <= legalcode.translation_last_update:
                # No change
                self.say(3, f"No changes for {legalcode}")
                continue

            # Translation has changed!
            self.say(2, f"Translation has changed for {legalcode}")
            legalcodes_with_updated_translations.append(legalcode)

        return self.handle_legalcodes_with_updated_translations(
            repo, legalcodes_with_updated_translations)