Skip to content

Commit aa14123

Browse files
committed
fix(component): properly log translation removals from the repo
The repository-originated translation removals were invisible in the history. See #20088
1 parent 67473c4 commit aa14123

2 files changed

Lines changed: 85 additions & 3 deletions

File tree

weblate/trans/models/component.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3996,15 +3996,32 @@ def _create_translations( # ruff: ignore[complex-structure, too-many-statements
39963996

39973997
# Delete possibly no longer existing translations
39983998
if langs is None:
3999-
todelete = self.translation_set.exclude(id__in=translations.keys())
4000-
if todelete.exists():
3999+
todelete = list(
4000+
self.translation_set.exclude(id__in=translations.keys()).select_related(
4001+
"language"
4002+
)
4003+
)
4004+
if todelete:
40014005
self.needs_cleanup = True
40024006
with transaction.atomic():
40034007
self.log_info(
40044008
"removing stale translations: %s",
40054009
",".join(trans.language.code for trans in todelete),
40064010
)
4007-
todelete.delete()
4011+
user = self.acting_user or (request.user if request else None)
4012+
Change.objects.bulk_create(
4013+
Change(
4014+
component=self,
4015+
action=ActionEvents.REMOVE_TRANSLATION,
4016+
target=translation.filename,
4017+
user=user,
4018+
author=user,
4019+
)
4020+
for translation in todelete
4021+
)
4022+
Translation.objects.filter(
4023+
id__in=[translation.id for translation in todelete]
4024+
).delete()
40084025
# Indicate a change to invalidate stats
40094026
was_change = True
40104027

weblate/trans/tests/test_component.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from weblate.trans.actions import ActionEvents
2626
from weblate.trans.exceptions import FileParseError
2727
from weblate.trans.models import (
28+
Change,
2829
CommitPolicyChoices,
2930
Component,
3031
PendingUnitChange,
@@ -2300,6 +2301,17 @@ def test_handle_restore_pending_translation_failure_without_translation(
23002301

23012302

23022303
class ResetDiscardRevisionTest(ComponentTestCase):
2304+
def assert_removed_translation_change(self, filename: str) -> None:
2305+
change = Change.objects.get(
2306+
component=self.component,
2307+
action=ActionEvents.REMOVE_TRANSLATION,
2308+
target=filename,
2309+
)
2310+
self.assertEqual(change.user, self.user)
2311+
self.assertEqual(change.author, self.user)
2312+
self.assertEqual(change.project, self.project)
2313+
self.assertIsNone(change.translation_id)
2314+
23032315
def test_reset_updates_stored_local_revision(self) -> None:
23042316
start_rev = self.component.repository.last_revision
23052317

@@ -2317,6 +2329,43 @@ def test_reset_updates_stored_local_revision(self) -> None:
23172329
self.assertEqual(start_rev, self.component.repository.last_revision)
23182330
self.assertEqual(start_rev, self.component.local_revision)
23192331

2332+
def test_file_scan_removes_stale_translation_with_change(self) -> None:
2333+
translation = self.component.translation_set.get(language_code="cs")
2334+
filename = translation.filename
2335+
pathlib.Path(cast("str", translation.get_filename())).unlink()
2336+
2337+
self.assertTrue(
2338+
self.component.create_translations_immediate(
2339+
force=True, request=self.get_request()
2340+
)
2341+
)
2342+
2343+
self.assertFalse(
2344+
self.component.translation_set.filter(language_code="cs").exists()
2345+
)
2346+
self.assert_removed_translation_change(filename)
2347+
self.assertFalse(self.project.has_language(Language.objects.get(code="cs")))
2348+
2349+
def test_reset_removes_upstream_deleted_translation_with_change(self) -> None:
2350+
translation = self.component.translation_set.get(language_code="cs")
2351+
filename = translation.filename
2352+
2353+
with self.component.repository.lock:
2354+
self.component.repository.remove([filename], "Remove Czech translation")
2355+
self.component.repository.push(self.component.push_branch)
2356+
2357+
self.assertTrue(
2358+
self.component.translation_set.filter(language_code="cs").exists()
2359+
)
2360+
2361+
self.assertTrue(self.component.do_reset(self.get_request()))
2362+
2363+
self.assertFalse(
2364+
self.component.translation_set.filter(language_code="cs").exists()
2365+
)
2366+
self.assert_removed_translation_change(filename)
2367+
self.assertFalse(self.project.has_language(Language.objects.get(code="cs")))
2368+
23202369

23212370
class TranslationRemoveRevisionTest(ComponentTestCase):
23222371
def test_remove_updates_stored_local_revision(self) -> None:
@@ -2333,6 +2382,22 @@ def test_remove_updates_stored_local_revision(self) -> None:
23332382
self.component.local_revision, self.component.repository.last_revision
23342383
)
23352384

2385+
def test_remove_creates_change(self) -> None:
2386+
translation = self.component.translation_set.get(language_code="de")
2387+
filename = translation.filename
2388+
2389+
translation.remove(self.user)
2390+
2391+
change = Change.objects.get(
2392+
component=self.component,
2393+
action=ActionEvents.REMOVE_TRANSLATION,
2394+
target=filename,
2395+
)
2396+
self.assertEqual(change.user, self.user)
2397+
self.assertEqual(change.author, self.user)
2398+
self.assertEqual(change.project, self.project)
2399+
self.assertIsNone(change.translation_id)
2400+
23362401

23372402
class LastCommitLookupTest(ComponentTestCase):
23382403
def test_get_last_commit_keeps_stale_local_revision_unchanged(self) -> None:

0 commit comments

Comments
 (0)