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)
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
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)