From 8a9a6671d54b6c73f04df81f49a1acfa20cecf65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Thu, 12 Oct 2023 10:35:45 +0200 Subject: [PATCH 1/2] changes: drop ACTION_NEW_STRING It was really doing just aggregation which can now be handled in the notification subsystem. Notification now triggers on ACTION_NEW_UNIT and is doing digests for users who had instant notification up to now. Fixes #10153 --- docs/changes.rst | 1 + .../0002_new_string_notification.py | 28 ++++++ weblate/accounts/notifications.py | 7 +- weblate/accounts/tests/test_notifications.py | 16 +-- weblate/api/tests.py | 10 +- weblate/templates/mail/new_string.html | 6 +- weblate/templates/mail/new_string_subject.txt | 2 +- .../mail/snippets/unit-screenshots.html | 2 +- weblate/templates/translate.html | 2 +- weblate/templates/zen-units.html | 2 +- .../migrations/0006_alter_change_action.py | 98 +++++++++++++++++++ weblate/trans/models/change.py | 38 +------ weblate/trans/models/component.py | 4 - weblate/trans/models/translation.py | 37 ------- weblate/trans/templatetags/translations.py | 4 +- weblate/trans/tests/test_templatetags.py | 30 +++--- 16 files changed, 168 insertions(+), 119 deletions(-) create mode 100644 weblate/accounts/migrations/0002_new_string_notification.py create mode 100644 weblate/trans/migrations/0006_alter_change_action.py diff --git a/docs/changes.rst b/docs/changes.rst index 99c3d44cfccd..ed808a0aa99d 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -23,6 +23,7 @@ Not yet released. * Highlight whitespace in :ref:`machine-translation`. * Faster comment and component removal. * Show disabled save button reason more prominently. +* New string notification can now be triggered for each string. **Bug fixes** diff --git a/weblate/accounts/migrations/0002_new_string_notification.py b/weblate/accounts/migrations/0002_new_string_notification.py new file mode 100644 index 000000000000..20b186cc07ba --- /dev/null +++ b/weblate/accounts/migrations/0002_new_string_notification.py @@ -0,0 +1,28 @@ +# Copyright © Michal Čihař +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# Generated by Django 4.2.5 on 2023-10-12 08:25 + +from django.db import migrations + + +def migrate_subscription(apps, schema_editor): + Subscription = apps.get_model("accounts", "Subscription") + # Change instant to daily, because this now has string granularity + Subscription.objects.filter( + notification="NewStringNotificaton", frequency=1 + ).update(frequency=2) + + +class Migration(migrations.Migration): + dependencies = [ + ("accounts", "0001_squashed_weblate_5"), + ("trans", "0006_alter_change_action"), + ] + + operations = [ + migrations.RunPython( + migrate_subscription, migrations.RunPython.noop, elidable=True + ), + ] diff --git a/weblate/accounts/notifications.py b/weblate/accounts/notifications.py index 5eb0331ba9f3..6a0ea9369834 100644 --- a/weblate/accounts/notifications.py +++ b/weblate/accounts/notifications.py @@ -265,7 +265,9 @@ def get_context( result["changes"] = changes if subscription is not None: result["unsubscribe_nonce"] = TimestampSigner().sign(subscription.pk) - result["user"] = subscription.user + result["subscription_user"] = subscription.user + else: + result["subscription_user"] = None if extracontext: result.update(extracontext) if change: @@ -489,12 +491,13 @@ def get_context( @register_notification class NewStringNotificaton(Notification): - actions = (Change.ACTION_NEW_STRING,) + actions = (Change.ACTION_NEW_UNIT,) verbose = pgettext_lazy( "Notification name", "New string is available for translation" ) template_name = "new_string" filter_languages = True + required_attr = "unit" @register_notification diff --git a/weblate/accounts/tests/test_notifications.py b/weblate/accounts/tests/test_notifications.py index 746efc1faccd..4d8843fe8fda 100644 --- a/weblate/accounts/tests/test_notifications.py +++ b/weblate/accounts/tests/test_notifications.py @@ -195,27 +195,13 @@ def test_notify_parse_error(self): self.validate_notifications(3, "[Weblate] Parse error in Test/Test") def test_notify_new_string(self): - Change.objects.create( - translation=self.get_translation(), action=Change.ACTION_NEW_STRING - ) + Change.objects.create(unit=self.get_unit(), action=Change.ACTION_NEW_UNIT) # Check mail self.validate_notifications( 1, "[Weblate] New string to translate in Test/Test — Czech" ) - def test_notify_new_strings(self): - Change.objects.create( - translation=self.get_translation(), - action=Change.ACTION_NEW_STRING, - details={"count": 10}, - ) - - # Check mail - self.validate_notifications( - 1, "[Weblate] New strings to translate in Test/Test — Czech" - ) - def test_notify_new_translation(self): Change.objects.create( unit=self.get_unit(), diff --git a/weblate/api/tests.py b/weblate/api/tests.py index 0b3ebead713c..34631242f099 100644 --- a/weblate/api/tests.py +++ b/weblate/api/tests.py @@ -968,7 +968,7 @@ def test_components(self): def test_changes(self): request = self.do_request("api:project-changes", self.project_kwargs) - self.assertEqual(request.data["count"], 33) + self.assertEqual(request.data["count"], 30) def test_statistics(self): request = self.do_request("api:project-statistics", self.project_kwargs) @@ -1904,7 +1904,7 @@ def test_translations(self): def test_changes(self): request = self.do_request("api:component-changes", self.component_kwargs) - self.assertEqual(request.data["count"], 25) + self.assertEqual(request.data["count"], 22) def test_screenshots(self): request = self.do_request("api:component-screenshots", self.component_kwargs) @@ -2648,7 +2648,7 @@ def test_statistics(self): def test_changes(self): request = self.do_request("api:translation-changes", self.translation_kwargs) - self.assertEqual(request.data["count"], 6) + self.assertEqual(request.data["count"], 5) def test_units(self): request = self.do_request("api:translation-units", self.translation_kwargs) @@ -3576,7 +3576,7 @@ def test_units_delete(self): class ChangeAPITest(APIBaseTest): def test_list_changes(self): response = self.client.get(reverse("api:change-list")) - self.assertEqual(response.data["count"], 33) + self.assertEqual(response.data["count"], 30) def test_filter_changes_after(self): """Filter changes since timestamp.""" @@ -3584,7 +3584,7 @@ def test_filter_changes_after(self): response = self.client.get( reverse("api:change-list"), {"timestamp_after": start.isoformat()} ) - self.assertEqual(response.data["count"], 33) + self.assertEqual(response.data["count"], 30) def test_filter_changes_before(self): """Filter changes prior to timestamp.""" diff --git a/weblate/templates/mail/new_string.html b/weblate/templates/mail/new_string.html index 4addb239ea25..932ccb40bd56 100644 --- a/weblate/templates/mail/new_string.html +++ b/weblate/templates/mail/new_string.html @@ -3,7 +3,11 @@ {% load i18n %}{% load translations %} {% block content %} +{% include "mail/snippets/source-string.html" %} + + +{% include "mail/snippets/unit-screenshots.html" %} {% endblock %} diff --git a/weblate/templates/mail/new_string_subject.txt b/weblate/templates/mail/new_string_subject.txt index aa0035902c5d..632138007abf 100644 --- a/weblate/templates/mail/new_string_subject.txt +++ b/weblate/templates/mail/new_string_subject.txt @@ -1,4 +1,4 @@ {% load i18n %} {% autoescape off %} -{% blocktrans count count=change.plural_count %}New string to translate in {{ translation }}{% plural %}New strings to translate in {{ translation }}{% endblocktrans %} +{% blocktrans %}New string to translate in {{ translation }}{% endblocktrans %} {% endautoescape %} diff --git a/weblate/templates/mail/snippets/unit-screenshots.html b/weblate/templates/mail/snippets/unit-screenshots.html index 8a36e4d2a92f..dc5a1be1b7f5 100644 --- a/weblate/templates/mail/snippets/unit-screenshots.html +++ b/weblate/templates/mail/snippets/unit-screenshots.html @@ -5,7 +5,7 @@

{% trans "Source string location" %}

- {% get_location_links user.profile unit %} + {% get_location_links subscription_user unit %}

{% endif %} diff --git a/weblate/templates/translate.html b/weblate/templates/translate.html index 54decf477cc4..4de994edbd68 100644 --- a/weblate/templates/translate.html +++ b/weblate/templates/translate.html @@ -679,7 +679,7 @@
{% trans "Source string location" %}
- {% get_location_links user.profile unit %} + {% get_location_links user unit %} {% endif %}
diff --git a/weblate/templates/zen-units.html b/weblate/templates/zen-units.html index f3fe2dd51680..880230d144eb 100644 --- a/weblate/templates/zen-units.html +++ b/weblate/templates/zen-units.html @@ -19,7 +19,7 @@ {% icon "link.svg" %} {% icon "pencil-mini.svg" %}
-{% get_location_links user.profile item.unit %} +{% get_location_links user item.unit %} diff --git a/weblate/trans/migrations/0006_alter_change_action.py b/weblate/trans/migrations/0006_alter_change_action.py new file mode 100644 index 000000000000..62305d03f1ba --- /dev/null +++ b/weblate/trans/migrations/0006_alter_change_action.py @@ -0,0 +1,98 @@ +# Copyright © Michal Čihař +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# Generated by Django 4.2.5 on 2023-10-12 08:25 + +from django.db import migrations, models + +ACTION_NEW_STRING = 44 + + +def migrate_changes(apps, schema_editor): + Change = apps.get_model("trans", "Change") + Change.objects.filter(action=ACTION_NEW_STRING).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ("trans", "0005_alter_change_alert_alter_change_announcement_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="change", + name="action", + field=models.IntegerField( + choices=[ + (0, "Resource update"), + (1, "Translation completed"), + (2, "Translation changed"), + (5, "New translation"), + (3, "Comment added"), + (4, "Suggestion added"), + (6, "Automatic translation"), + (7, "Suggestion accepted"), + (8, "Translation reverted"), + (9, "Translation uploaded"), + (13, "New source string"), + (14, "Component locked"), + (15, "Component unlocked"), + (17, "Committed changes"), + (18, "Pushed changes"), + (19, "Reset repository"), + (20, "Merged repository"), + (21, "Rebased repository"), + (22, "Failed merge on repository"), + (23, "Failed rebase on repository"), + (28, "Failed push on repository"), + (24, "Parse error"), + (25, "Removed translation"), + (26, "Suggestion removed"), + (27, "Search and replace"), + (29, "Suggestion removed during cleanup"), + (30, "Source string changed"), + (31, "New string added"), + (32, "Bulk status change"), + (33, "Changed visibility"), + (34, "Added user"), + (35, "Removed user"), + (36, "Translation approved"), + (37, "Marked for edit"), + (38, "Removed component"), + (39, "Removed project"), + (41, "Renamed project"), + (42, "Renamed component"), + (43, "Moved component"), + (45, "New contributor"), + (46, "New announcement"), + (47, "New alert"), + (48, "Added new language"), + (49, "Requested new language"), + (50, "Created project"), + (51, "Created component"), + (52, "Invited user"), + (53, "Received repository notification"), + (54, "Replaced file by upload"), + (55, "License changed"), + (56, "Contributor agreement changed"), + (57, "Screnshot added"), + (58, "Screnshot uploaded"), + (59, "String updated in the repository"), + (60, "Add-on installed"), + (61, "Add-on configuration changed"), + (62, "Add-on uninstalled"), + (63, "Removed string"), + (64, "Removed comment"), + (65, "Resolved comment"), + (66, "Explanation updated"), + (67, "Removed category"), + (68, "Renamed category"), + (69, "Moved category"), + (70, "Could not save string"), + ], + default=2, + ), + ), + migrations.RunPython(migrate_changes, migrations.RunPython.noop, elidable=True), + ] diff --git a/weblate/trans/models/change.py b/weblate/trans/models/change.py index 5f33e3e95a4e..877c022288f4 100644 --- a/weblate/trans/models/change.py +++ b/weblate/trans/models/change.py @@ -11,14 +11,7 @@ from django.db.models.base import post_save from django.utils import timezone from django.utils.html import escape, format_html -from django.utils.translation import ( - gettext, - gettext_lazy, - ngettext, - ngettext_lazy, - pgettext, - pgettext_lazy, -) +from django.utils.translation import gettext, gettext_lazy, pgettext, pgettext_lazy from rapidfuzz.distance import DamerauLevenshtein from weblate.lang.models import Language @@ -266,7 +259,7 @@ class Change(models.Model, UserDisplayMixin): ACTION_RENAME_PROJECT = 41 ACTION_RENAME_COMPONENT = 42 ACTION_MOVE_COMPONENT = 43 - ACTION_NEW_STRING = 44 + # Used to be ACTION_NEW_STRING = 44 ACTION_NEW_CONTRIBUTOR = 45 ACTION_ANNOUNCEMENT = 46 ACTION_ALERT = 47 @@ -373,12 +366,6 @@ class Change(models.Model, UserDisplayMixin): (ACTION_RENAME_COMPONENT, gettext_lazy("Renamed component")), # Translators: Name of event in the history (ACTION_MOVE_COMPONENT, gettext_lazy("Moved component")), - # Using pgettext to differentiate from the plural - # Translators: Name of event in the history - ( - ACTION_NEW_STRING, - pgettext_lazy("Name of event in the history", "New string to translate"), - ), # Translators: Name of event in the history (ACTION_NEW_CONTRIBUTOR, gettext_lazy("New contributor")), # Translators: Name of event in the history @@ -502,11 +489,6 @@ class Change(models.Model, UserDisplayMixin): ACTION_FAILED_PUSH, } - PLURAL_ACTIONS = { - ACTION_NEW_STRING: ngettext_lazy( - "New string to translate", "New strings to translate" - ), - } AUTO_ACTIONS = { # Translators: Name of event in the history ACTION_LOCK: gettext_lazy( @@ -606,8 +588,6 @@ def get_absolute_url(self): if self.screenshot is not None: return self.screenshot.get_absolute_url() if self.translation is not None: - if self.action == self.ACTION_NEW_STRING: - return self.translation.get_translate_url() + "?q=is:untranslated" return self.translation.get_absolute_url() if self.component is not None: return self.component.get_absolute_url() @@ -673,8 +653,6 @@ def auto_status(self): return self.details.get("auto", False) def get_action_display(self): - if self.action in self.PLURAL_ACTIONS: - return self.PLURAL_ACTIONS[self.action] % self.plural_count return str(self.ACTIONS_DICT.get(self.action, self.action)) def get_state_display(self): @@ -714,18 +692,6 @@ def get_details_display(self): # noqa: C901 details = self.details - if self.action == self.ACTION_NEW_STRING: - result = ngettext( - "%d new string to translate appeared in the translation.", - "%d new strings to translate appeared to the translation.", - self.plural_count, - ) - try: - return result % self.plural_count - except TypeError: - # The string does not contain %d - return result - if self.action in (self.ACTION_ANNOUNCEMENT, self.ACTION_AGREEMENT_CHANGE): return render_markdown(self.target) diff --git a/weblate/trans/models/component.py b/weblate/trans/models/component.py index b48b152f0614..5977528ba36f 100644 --- a/weblate/trans/models/component.py +++ b/weblate/trans/models/component.py @@ -2484,10 +2484,6 @@ def _create_translations( # noqa: C901 transaction.on_commit(lambda: cleanup_component.delay(self.id)) - # Send notifications on new string - for translation in translations.values(): - translation.notify_new(request) - if was_change: if self.needs_variants_update: self.update_variants() diff --git a/weblate/trans/models/translation.py b/weblate/trans/models/translation.py index 41a41219e242..196a89a1fa91 100644 --- a/weblate/trans/models/translation.py +++ b/weblate/trans/models/translation.py @@ -164,7 +164,6 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.stats = TranslationStats(self) self.addon_commit_files = [] - self.was_new = 0 self.reason = "" self._invalidate_scheduled = False self.update_changes = [] @@ -221,19 +220,6 @@ def clean(self): % {"file": self.filename, "error": str(error)} ) - def notify_new(self, request): - if self.was_new: - # Create change after flags has been updated and cache - # invalidated, otherwise we might be sending notification - # with outdated values - self.change_set.create( - action=Change.ACTION_NEW_STRING, - user=request.user if request else None, - author=request.user if request else None, - details={"count": self.was_new}, - ) - self.was_new = 0 - def get_url_path(self): return (*self.component.get_url_path(), self.language.code) @@ -328,18 +314,6 @@ def sync_unit( ): newunit.update_from_unit(unit, pos, is_new) - # Check if unit is worth notification: - # - new and untranslated - # - newly untranslated - # - newly fuzzy - # - source string changed - if newunit.state < STATE_TRANSLATED and ( - newunit.state != newunit.old_unit["state"] - or is_new - or newunit.source != newunit.old_unit["source"] - ): - self.was_new += 1 - # Store current unit ID updated[id_hash] = newunit @@ -414,9 +388,6 @@ def check_sync(self, force=False, request=None, change=None): # noqa: C901 self.plural = plural self.save(update_fields=["plural"]) - # Was there change? - self.was_new = 0 - # Select all current units for update dbunits = { unit.id_hash: unit @@ -1171,8 +1142,6 @@ def handle_add_upload(self, request, store, fuzzy: str = ""): ) existing.add(idkey) accepted += 1 - self.was_new = accepted - self.notify_new(request) component.invalidate_cache() if component.needs_variants_update: component.update_variants() @@ -1351,7 +1320,6 @@ def handle_store_change(self, request, user, previous_revision: str, change=None self.component.invalidate_cache() else: self.check_sync(request=request, change=change) - self.notify_new(request) self.invalidate_cache() # Trigger post-update signal self.component.trigger_post_update(previous_revision, False) @@ -1521,8 +1489,6 @@ def add_unit( # noqa: C901 ) component.invalidate_cache() component_post_update.send(sender=self.__class__, component=component) - self.was_new = 1 - self.notify_new(request) return result def notify_deletion(self, unit, user): @@ -1599,7 +1565,6 @@ def sync_terminology(self): if not self.is_source or not self.component.manage_units: return expected_count = self.component.translation_set.count() - self.was_new = 0 for source in self.component.get_all_sources(): # Is the string a terminology if "terminology" not in source.all_flags: @@ -1615,8 +1580,6 @@ def sync_terminology(self): is_batch_update=True, skip_existing=True, ) - self.was_new += 1 - self.notify_new(None) def validate_new_unit_data( self, diff --git a/weblate/trans/templatetags/translations.py b/weblate/trans/templatetags/translations.py index c41e060b1acf..8c0db885295e 100644 --- a/weblate/trans/templatetags/translations.py +++ b/weblate/trans/templatetags/translations.py @@ -808,7 +808,7 @@ def try_linkify_filename( @register.simple_tag -def get_location_links(profile, unit): +def get_location_links(user: User | None, unit): """Generate links to source files where translation was used.""" # Fallback to source unit if it has more information if not unit.location and unit.source_unit.location: @@ -822,6 +822,8 @@ def get_location_links(profile, unit): if unit.location.isdigit(): return gettext("string ID %s") % unit.location + profile = user.profile if user else None + # Go through all locations separated by comma return format_html_join( format_html('\n\n'), diff --git a/weblate/trans/tests/test_templatetags.py b/weblate/trans/tests/test_templatetags.py index 7a64c83da525..117c240fbc5a 100644 --- a/weblate/trans/tests/test_templatetags.py +++ b/weblate/trans/tests/test_templatetags.py @@ -12,7 +12,7 @@ from django.utils import timezone from django.utils.html import format_html -from weblate.accounts.models import Profile +from weblate.auth.models import User from weblate.checks.tests.test_checks import MockLanguage, MockUnit from weblate.lang.models import Language from weblate.trans.models import Component, Project, Translation, Unit @@ -92,25 +92,27 @@ def setUp(self): pk=-1, ) self.unit.source_unit = self.unit - self.profile = Profile() + self.user = User.objects.create(username="location-test") def test_empty(self): - self.assertEqual(get_location_links(self.profile, self.unit), "") + self.assertEqual(get_location_links(self.user, self.unit), "") def test_numeric(self): self.unit.location = "123" - self.assertEqual(get_location_links(self.profile, self.unit), "string ID 123") + self.assertEqual(get_location_links(self.user, self.unit), "string ID 123") def test_filename(self): self.unit.location = "f&oo.bar:123" - self.assertEqual( - get_location_links(self.profile, self.unit), "f&oo.bar:123" - ) + self.assertEqual(get_location_links(self.user, self.unit), "f&oo.bar:123") def test_filenames(self): self.unit.location = "foo.bar:123,bar.foo:321" self.assertEqual( - get_location_links(self.profile, self.unit), + get_location_links(self.user, self.unit), + 'foo.bar:123\n\nbar.foo:321', + ) + self.assertEqual( + get_location_links(None, self.unit), 'foo.bar:123\n\nbar.foo:321', ) @@ -120,7 +122,7 @@ def test_repowebs(self): ) self.unit.location = "foo.bar:123,bar.foo:321" self.assertHTMLEqual( - get_location_links(self.profile, self.unit), + get_location_links(self.user, self.unit), """ Date: Tue, 10 Oct 2023 12:53:57 +0200 Subject: [PATCH 2/2] changes: consolidate action names Consistently use noun + verb past. Fixes #9824 --- .../migrations/0007_alter_change_action.py | 90 +++++++++++++++++++ weblate/trans/models/change.py | 82 ++++++++--------- weblate/trans/tests/test_changes.py | 4 +- 3 files changed, 133 insertions(+), 43 deletions(-) create mode 100644 weblate/trans/migrations/0007_alter_change_action.py diff --git a/weblate/trans/migrations/0007_alter_change_action.py b/weblate/trans/migrations/0007_alter_change_action.py new file mode 100644 index 000000000000..3b8ac5c4862c --- /dev/null +++ b/weblate/trans/migrations/0007_alter_change_action.py @@ -0,0 +1,90 @@ +# Copyright © Michal Čihař +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# Generated by Django 4.2.6 on 2023-10-12 12:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("trans", "0006_alter_change_action"), + ] + + operations = [ + migrations.AlterField( + model_name="change", + name="action", + field=models.IntegerField( + choices=[ + (0, "Resource updated"), + (1, "Translation completed"), + (2, "Translation changed"), + (5, "Translation added"), + (3, "Comment added"), + (4, "Suggestion added"), + (6, "Automatically translated"), + (7, "Suggestion accepted"), + (8, "Translation reverted"), + (9, "Translation uploaded"), + (13, "Source string added"), + (14, "Component locked"), + (15, "Component unlocked"), + (17, "Changes committed"), + (18, "Changes pushed"), + (19, "Repository reset"), + (20, "Repository merged"), + (21, "Repository rebased"), + (22, "Repository merge failed"), + (23, "Repository rebase failed"), + (28, "Repository push failed"), + (24, "Parsing failed"), + (25, "Translation removed"), + (26, "Suggestion removed"), + (27, "Translation replaced"), + (29, "Suggestion removed during cleanup"), + (30, "Source string changed"), + (31, "String added"), + (32, "Bulk status changed"), + (33, "Visibility changed"), + (34, "User added"), + (35, "User removed"), + (36, "Translation approved"), + (37, "Marked for edit"), + (38, "Component removed"), + (39, "Project removed"), + (41, "Project renamed"), + (42, "Component renamed"), + (43, "Moved component"), + (45, "Contributor joined"), + (46, "Announcement posted"), + (47, "Alert triggered"), + (48, "Language added"), + (49, "Language requested"), + (50, "Project created"), + (51, "Component created"), + (52, "User invited"), + (53, "Repository notification received"), + (54, "Translation replaced file by upload"), + (55, "License changed"), + (56, "Contributor agreement changed"), + (57, "Screnshot added"), + (58, "Screnshot uploaded"), + (59, "String updated in the repository"), + (60, "Add-on installed"), + (61, "Add-on configuration changed"), + (62, "Add-on uninstalled"), + (63, "String removed"), + (64, "Comment removed"), + (65, "Comment resolved"), + (66, "Explanation updated"), + (67, "Category removed"), + (68, "Category renamed"), + (69, "Category moved"), + (70, "Saving string failed"), + ], + default=2, + ), + ), + ] diff --git a/weblate/trans/models/change.py b/weblate/trans/models/change.py index 877c022288f4..5edf5301a5a2 100644 --- a/weblate/trans/models/change.py +++ b/weblate/trans/models/change.py @@ -289,19 +289,19 @@ class Change(models.Model, UserDisplayMixin): ACTION_CHOICES = ( # Translators: Name of event in the history - (ACTION_UPDATE, gettext_lazy("Resource update")), + (ACTION_UPDATE, gettext_lazy("Resource updated")), # Translators: Name of event in the history (ACTION_COMPLETE, gettext_lazy("Translation completed")), # Translators: Name of event in the history (ACTION_CHANGE, gettext_lazy("Translation changed")), # Translators: Name of event in the history - (ACTION_NEW, gettext_lazy("New translation")), + (ACTION_NEW, gettext_lazy("Translation added")), # Translators: Name of event in the history (ACTION_COMMENT, gettext_lazy("Comment added")), # Translators: Name of event in the history (ACTION_SUGGESTION, gettext_lazy("Suggestion added")), # Translators: Name of event in the history - (ACTION_AUTO, gettext_lazy("Automatic translation")), + (ACTION_AUTO, gettext_lazy("Automatically translated")), # Translators: Name of event in the history (ACTION_ACCEPT, gettext_lazy("Suggestion accepted")), # Translators: Name of event in the history @@ -309,83 +309,83 @@ class Change(models.Model, UserDisplayMixin): # Translators: Name of event in the history (ACTION_UPLOAD, gettext_lazy("Translation uploaded")), # Translators: Name of event in the history - (ACTION_NEW_SOURCE, gettext_lazy("New source string")), + (ACTION_NEW_SOURCE, gettext_lazy("Source string added")), # Translators: Name of event in the history (ACTION_LOCK, gettext_lazy("Component locked")), # Translators: Name of event in the history (ACTION_UNLOCK, gettext_lazy("Component unlocked")), # Translators: Name of event in the history - (ACTION_COMMIT, gettext_lazy("Committed changes")), + (ACTION_COMMIT, gettext_lazy("Changes committed")), # Translators: Name of event in the history - (ACTION_PUSH, gettext_lazy("Pushed changes")), + (ACTION_PUSH, gettext_lazy("Changes pushed")), # Translators: Name of event in the history - (ACTION_RESET, gettext_lazy("Reset repository")), + (ACTION_RESET, gettext_lazy("Repository reset")), # Translators: Name of event in the history - (ACTION_MERGE, gettext_lazy("Merged repository")), + (ACTION_MERGE, gettext_lazy("Repository merged")), # Translators: Name of event in the history - (ACTION_REBASE, gettext_lazy("Rebased repository")), + (ACTION_REBASE, gettext_lazy("Repository rebased")), # Translators: Name of event in the history - (ACTION_FAILED_MERGE, gettext_lazy("Failed merge on repository")), + (ACTION_FAILED_MERGE, gettext_lazy("Repository merge failed")), # Translators: Name of event in the history - (ACTION_FAILED_REBASE, gettext_lazy("Failed rebase on repository")), + (ACTION_FAILED_REBASE, gettext_lazy("Repository rebase failed")), # Translators: Name of event in the history - (ACTION_FAILED_PUSH, gettext_lazy("Failed push on repository")), + (ACTION_FAILED_PUSH, gettext_lazy("Repository push failed")), # Translators: Name of event in the history - (ACTION_PARSE_ERROR, gettext_lazy("Parse error")), + (ACTION_PARSE_ERROR, gettext_lazy("Parsing failed")), # Translators: Name of event in the history - (ACTION_REMOVE_TRANSLATION, gettext_lazy("Removed translation")), + (ACTION_REMOVE_TRANSLATION, gettext_lazy("Translation removed")), # Translators: Name of event in the history (ACTION_SUGGESTION_DELETE, gettext_lazy("Suggestion removed")), # Translators: Name of event in the history - (ACTION_REPLACE, gettext_lazy("Search and replace")), + (ACTION_REPLACE, gettext_lazy("Translation replaced")), # Translators: Name of event in the history (ACTION_SUGGESTION_CLEANUP, gettext_lazy("Suggestion removed during cleanup")), # Translators: Name of event in the history (ACTION_SOURCE_CHANGE, gettext_lazy("Source string changed")), # Translators: Name of event in the history - (ACTION_NEW_UNIT, gettext_lazy("New string added")), + (ACTION_NEW_UNIT, gettext_lazy("String added")), # Translators: Name of event in the history - (ACTION_BULK_EDIT, gettext_lazy("Bulk status change")), + (ACTION_BULK_EDIT, gettext_lazy("Bulk status changed")), # Translators: Name of event in the history - (ACTION_ACCESS_EDIT, gettext_lazy("Changed visibility")), + (ACTION_ACCESS_EDIT, gettext_lazy("Visibility changed")), # Translators: Name of event in the history - (ACTION_ADD_USER, gettext_lazy("Added user")), + (ACTION_ADD_USER, gettext_lazy("User added")), # Translators: Name of event in the history - (ACTION_REMOVE_USER, gettext_lazy("Removed user")), + (ACTION_REMOVE_USER, gettext_lazy("User removed")), # Translators: Name of event in the history (ACTION_APPROVE, gettext_lazy("Translation approved")), # Translators: Name of event in the history (ACTION_MARKED_EDIT, gettext_lazy("Marked for edit")), # Translators: Name of event in the history - (ACTION_REMOVE_COMPONENT, gettext_lazy("Removed component")), + (ACTION_REMOVE_COMPONENT, gettext_lazy("Component removed")), # Translators: Name of event in the history - (ACTION_REMOVE_PROJECT, gettext_lazy("Removed project")), + (ACTION_REMOVE_PROJECT, gettext_lazy("Project removed")), # Translators: Name of event in the history - (ACTION_RENAME_PROJECT, gettext_lazy("Renamed project")), + (ACTION_RENAME_PROJECT, gettext_lazy("Project renamed")), # Translators: Name of event in the history - (ACTION_RENAME_COMPONENT, gettext_lazy("Renamed component")), + (ACTION_RENAME_COMPONENT, gettext_lazy("Component renamed")), # Translators: Name of event in the history (ACTION_MOVE_COMPONENT, gettext_lazy("Moved component")), # Translators: Name of event in the history - (ACTION_NEW_CONTRIBUTOR, gettext_lazy("New contributor")), + (ACTION_NEW_CONTRIBUTOR, gettext_lazy("Contributor joined")), # Translators: Name of event in the history - (ACTION_ANNOUNCEMENT, gettext_lazy("New announcement")), + (ACTION_ANNOUNCEMENT, gettext_lazy("Announcement posted")), # Translators: Name of event in the history - (ACTION_ALERT, gettext_lazy("New alert")), + (ACTION_ALERT, gettext_lazy("Alert triggered")), # Translators: Name of event in the history - (ACTION_ADDED_LANGUAGE, gettext_lazy("Added new language")), + (ACTION_ADDED_LANGUAGE, gettext_lazy("Language added")), # Translators: Name of event in the history - (ACTION_REQUESTED_LANGUAGE, gettext_lazy("Requested new language")), + (ACTION_REQUESTED_LANGUAGE, gettext_lazy("Language requested")), # Translators: Name of event in the history - (ACTION_CREATE_PROJECT, gettext_lazy("Created project")), + (ACTION_CREATE_PROJECT, gettext_lazy("Project created")), # Translators: Name of event in the history - (ACTION_CREATE_COMPONENT, gettext_lazy("Created component")), + (ACTION_CREATE_COMPONENT, gettext_lazy("Component created")), # Translators: Name of event in the history - (ACTION_INVITE_USER, gettext_lazy("Invited user")), + (ACTION_INVITE_USER, gettext_lazy("User invited")), # Translators: Name of event in the history - (ACTION_HOOK, gettext_lazy("Received repository notification")), + (ACTION_HOOK, gettext_lazy("Repository notification received")), # Translators: Name of event in the history - (ACTION_REPLACE_UPLOAD, gettext_lazy("Replaced file by upload")), + (ACTION_REPLACE_UPLOAD, gettext_lazy("Translation replaced file by upload")), # Translators: Name of event in the history (ACTION_LICENSE_CHANGE, gettext_lazy("License changed")), # Translators: Name of event in the history @@ -403,24 +403,24 @@ class Change(models.Model, UserDisplayMixin): # Translators: Name of event in the history (ACTION_ADDON_REMOVE, gettext_lazy("Add-on uninstalled")), # Translators: Name of event in the history - (ACTION_STRING_REMOVE, gettext_lazy("Removed string")), + (ACTION_STRING_REMOVE, gettext_lazy("String removed")), # Translators: Name of event in the history - (ACTION_COMMENT_DELETE, gettext_lazy("Removed comment")), + (ACTION_COMMENT_DELETE, gettext_lazy("Comment removed")), # Translators: Name of event in the history ( ACTION_COMMENT_RESOLVE, - pgettext_lazy("Name of event in the history", "Resolved comment"), + pgettext_lazy("Name of event in the history", "Comment resolved"), ), # Translators: Name of event in the history (ACTION_EXPLANATION, gettext_lazy("Explanation updated")), # Translators: Name of event in the history - (ACTION_REMOVE_CATEGORY, gettext_lazy("Removed category")), + (ACTION_REMOVE_CATEGORY, gettext_lazy("Category removed")), # Translators: Name of event in the history - (ACTION_RENAME_CATEGORY, gettext_lazy("Renamed category")), + (ACTION_RENAME_CATEGORY, gettext_lazy("Category renamed")), # Translators: Name of event in the history - (ACTION_MOVE_CATEGORY, gettext_lazy("Moved category")), + (ACTION_MOVE_CATEGORY, gettext_lazy("Category moved")), # Translators: Name of event in the history - (ACTION_SAVE_FAILED, gettext_lazy("Could not save string")), + (ACTION_SAVE_FAILED, gettext_lazy("Saving string failed")), ) ACTIONS_DICT = dict(ACTION_CHOICES) ACTION_STRINGS = { diff --git a/weblate/trans/tests/test_changes.py b/weblate/trans/tests/test_changes.py index e8373612fe6f..57f2d1d4a502 100644 --- a/weblate/trans/tests/test_changes.py +++ b/weblate/trans/tests/test_changes.py @@ -49,11 +49,11 @@ def test_string(self): response = self.client.get( reverse("changes", kwargs={"path": Unit.objects.first().get_url_path()}) ) - self.assertContains(response, "New source string") + self.assertContains(response, "Source string added") self.assertContains(response, "Changes of string in") def test_user(self): self.edit_unit("Hello, world!\n", "Nazdar svete!\n") response = self.client.get(reverse("changes"), {"user": self.user.username}) - self.assertContains(response, "New translation") + self.assertContains(response, "Translation added") self.assertNotContains(response, "Invalid search string!")