-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add bulk accept suggestions feature #17712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add bulk accept suggestions feature #17712
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a bulk accept suggestions feature that allows users with appropriate permissions to accept all suggestions from a specific user with a single button click. The feature provides visual feedback showing progress, acceptance count, and percentage, then auto-reloads the page upon completion.
Changes:
- New backend view for bulk accepting suggestions with permission checking and transaction support
- Frontend button appearing next to each suggestion author with JavaScript handling for async operations
- Custom CSS styling for the button and status indicators
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 18 comments.
Show a summary per file
| File | Description |
|---|---|
| weblate/trans/views/bulk_suggestions.py | New view handling bulk suggestion acceptance with permission checks and error handling |
| weblate/urls.py | Added URL routing for the bulk accept endpoint |
| weblate/templates/snippets/suggestions.html | Added bulk accept button to suggestion display and loaded CSS/JS assets |
| weblate/static/js/bulk-accept-suggestions.js | Client-side logic for AJAX request, progress display, and page reload |
| weblate/static/styles/bulk-accept.css | Styling for the bulk accept button and status indicators |
| # Copyright © 2026 Hendrik Leethaus <hendrik@leethaus.de> | ||
| # | ||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||
| from __future__ import annotations | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| from django.contrib.auth.decorators import login_required | ||
| from django.db import transaction | ||
| from django.http import JsonResponse | ||
| from django.shortcuts import get_object_or_404 | ||
| from django.utils.translation import gettext | ||
| from django.views.decorators.http import require_POST | ||
|
|
||
| from weblate.auth.models import User | ||
| from weblate.trans.models import Suggestion, Translation | ||
| from weblate.utils.state import STATE_TRANSLATED | ||
|
|
||
| if TYPE_CHECKING: | ||
| from weblate.auth.models import AuthenticatedHttpRequest | ||
|
|
||
|
|
||
| @require_POST | ||
| @login_required | ||
| @transaction.atomic | ||
| def bulk_accept_user_suggestions( | ||
| request: AuthenticatedHttpRequest, project: str, component: str, lang: str | ||
| ): | ||
| """Accept all suggestions from a specific user for a translation.""" | ||
| # Get the translation object | ||
| translation = get_object_or_404( | ||
| Translation.objects.prefetch(), | ||
| component__project__slug=project, | ||
| component__slug=component, | ||
| language__code=lang, | ||
| ) | ||
|
|
||
| # Check permission | ||
| if not request.user.has_perm("suggestion.accept", translation): | ||
| return JsonResponse( | ||
| {"error": gettext("You do not have privilege to accept suggestions!")}, | ||
| status=403, | ||
| ) | ||
|
|
||
| # Get target username from POST | ||
| target_username = request.POST.get("username") | ||
| if not target_username: | ||
| return JsonResponse({"error": "No username provided"}, status=400) | ||
|
|
||
| # Get the target user | ||
| try: | ||
| target_user = User.objects.get(username=target_username) | ||
| except User.DoesNotExist: | ||
| return JsonResponse({"error": "User not found"}, status=404) | ||
|
|
||
| # Get all suggestions from this user for this translation | ||
| suggestions = Suggestion.objects.filter( | ||
| unit__translation=translation, user=target_user | ||
| ).select_related("unit") | ||
|
|
||
| total = suggestions.count() | ||
| accepted_count = 0 | ||
| failed_count = 0 | ||
|
|
||
| # Accept each suggestion | ||
| for suggestion in suggestions: | ||
| try: | ||
| # Check permission for each unit | ||
| if not request.user.has_perm("suggestion.accept", suggestion.unit): | ||
| failed_count += 1 | ||
| continue | ||
|
|
||
| # Accept the suggestion (uses existing method) | ||
| suggestion.accept(request, state=STATE_TRANSLATED) | ||
| accepted_count += 1 | ||
| except Exception: | ||
| failed_count += 1 | ||
| continue | ||
|
|
||
| return JsonResponse( | ||
| { | ||
| "success": True, | ||
| "accepted": accepted_count, | ||
| "failed": failed_count, | ||
| "total": total, | ||
| "message": gettext( | ||
| "Accepted %(count)d of %(total)d suggestions from %(user)s" | ||
| ) | ||
| % { | ||
| "count": accepted_count, | ||
| "total": total, | ||
| "user": target_username, | ||
| }, | ||
| } | ||
| ) |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR adds a new user-facing feature (bulk accept suggestions) but does not include any documentation updates. According to the coding guidelines, user-visible changes should be documented with an entry in the changelog (docs/changes.rst) and potentially in the user documentation (e.g., docs/user/translating.rst which already documents suggestions). Users and administrators should be informed about this new capability.
nijel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't look at the frontend code, @KarenKonou please comment on that.
|
I just noticed that an error message is now appearing after my fix. I'm working on getting it working again and meeting your requirements. (This is my first PR) |
- Use object_path URL pattern for categorized components - Add BulkAcceptForm with UserField validation - Remove exception swallowing in suggestion loop - Use ngettext for proper pluralization - Wrap all error messages with gettext - Use CSS theme variables instead of hardcoded colors - Add ARIA attributes for accessibility - Update comment style to lowercase
- Remove German comment - Add 'from None' to ValidationError
7393aae to
2d6ffaa
Compare
|
Hi @nijel, I've spent the last few hours trying to fix all the mistakes to meet your requirements. Please let me know if I've forgotten anything or done anything wrong. (P.S. This is my first PR) |
|
Hi @devimarj, Interesting that we both worked on this! Your addon approach with conditions looks useful for automated workflows. My implementation is simpler, just a UI button for manual bulk accept. I oriented it on the bookmarklet/extension concept that was created for Anna's Archive. Maybe both approaches could complement each other? Let's see what @nijel thinks about which direction fits better! |
|
@nijel Thanks for the feedback! I'll work on moving the button to the action bar as you suggested. |
|
Hi @nijel
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
- Remove nested @transaction.atomic decorator to avoid rollback issues - Fix path type annotation: list[str] | tuple[str, ...] instead of str - Add comprehensive unit tests covering all endpoints and edge cases - Internationalize all JavaScript strings with gettext/ngettext - Add null check for suggestion.user in template (anonymous users) - Fix button rendering: use ifchanged instead of forloop.first - Add type='button' attribute and translate button title - Add try-except around suggestion.accept() for better error handling
for more information, see https://pre-commit.ci
|
Addressed all Copilot feedback. Added tests, fixed type annotations, i18n, and template logic. All checks passing. |
|
Hello! I'm looking at the frontend code and will also do some local testing, will have a response soon |
|
Hi, I had Copilot review the code in my repository again and it suggested a few things. Should I post the changes here or are you already satisfied? |
- Replace deprecated sr-only class with visually-hidden (Bootstrap 5) - Add account-check icon to improve UX distinction from accept-and-approve action
|
@KarenKonou @nijel Fixed |


This PR adds a "bulk accept suggestions" feature that allows users to accept all suggestions from a specific user with a single button click.
Features
bulk_accept_user_suggestions) handling suggestion acceptanceImplementation
weblate/trans/views/bulk_suggestions.py(91 lines)weblate/static/js/bulk-accept-suggestions.js(74 lines)weblate/static/styles/bulk-accept.css(56 lines)weblate/urls.py(added route)weblate/templates/snippets/suggestions.html(added button)Related
Testing
suggestion.accept)