From d3fade95650ba10db2f905e55562bdfc99d3999c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Fri, 27 Mar 2015 13:31:36 +0100 Subject: [PATCH] Add gettext to translatable strings --- locale/en/LC_MESSAGES/django.po | 2 +- taiga/auth/api.py | 2 +- taiga/auth/serializers.py | 7 +- taiga/auth/services.py | 6 +- taiga/auth/tokens.py | 5 +- taiga/base/api/generics.py | 60 ++-- taiga/base/api/mixins.py | 11 +- taiga/base/api/permissions.py | 3 +- taiga/base/api/views.py | 15 +- taiga/base/api/viewsets.py | 11 +- taiga/base/filters.py | 21 +- taiga/base/utils/signals.py | 4 +- taiga/export_import/api.py | 2 +- taiga/export_import/dump_service.py | 26 +- taiga/export_import/serializers.py | 7 +- taiga/export_import/tasks.py | 9 +- taiga/hooks/api.py | 2 +- taiga/hooks/bitbucket/event_hooks.py | 7 +- taiga/hooks/github/event_hooks.py | 10 +- taiga/hooks/gitlab/event_hooks.py | 6 +- taiga/locale/en/LC_MESSAGES/django.po | 372 +++++++++++++++++++-- taiga/projects/api.py | 6 +- taiga/projects/attachments/api.py | 12 +- taiga/projects/choices.py | 7 +- taiga/projects/history/api.py | 5 +- taiga/projects/history/mixins.py | 2 +- taiga/projects/issues/api.py | 2 +- taiga/projects/milestones/models.py | 2 +- taiga/projects/milestones/serializers.py | 7 +- taiga/projects/milestones/validators.py | 2 +- taiga/projects/mixins/ordering.py | 2 +- taiga/projects/notifications/models.py | 12 +- taiga/projects/notifications/services.py | 9 +- taiga/projects/notifications/validators.py | 4 +- taiga/projects/occ/mixins.py | 6 +- taiga/projects/permissions.py | 2 +- taiga/projects/serializers.py | 12 +- taiga/projects/services/stats.py | 10 +- taiga/projects/tasks/api.py | 2 +- taiga/projects/tasks/validators.py | 2 +- taiga/projects/userstories/validators.py | 4 +- taiga/projects/validators.py | 2 +- taiga/projects/wiki/api.py | 2 +- taiga/users/api.py | 2 +- taiga/users/services.py | 15 +- taiga/users/validators.py | 2 +- taiga/userstorage/api.py | 2 +- taiga/webhooks/models.py | 12 +- 48 files changed, 524 insertions(+), 211 deletions(-) diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 8b986771..6a22a978 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: taiga-back\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-03-25 20:09+0100\n" +"POT-Creation-Date: 2015-04-06 17:04+0200\n" "PO-Revision-Date: 2015-03-25 20:09+0100\n" "Last-Translator: Taiga Dev Team \n" "Language-Team: Taiga Dev Team \n" diff --git a/taiga/auth/api.py b/taiga/auth/api.py index 48c1041d..717269ae 100644 --- a/taiga/auth/api.py +++ b/taiga/auth/api.py @@ -17,7 +17,7 @@ from functools import partial from enum import Enum -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from django.conf import settings from rest_framework import serializers diff --git a/taiga/auth/serializers.py b/taiga/auth/serializers.py index 8fbba177..23789656 100644 --- a/taiga/auth/serializers.py +++ b/taiga/auth/serializers.py @@ -18,6 +18,7 @@ from rest_framework import serializers from django.core import validators from django.core.exceptions import ValidationError +from django.utils.translation import ugettext as _ import re @@ -29,13 +30,13 @@ class BaseRegisterSerializer(serializers.Serializer): def validate_username(self, attrs, source): value = attrs[source] - validator = validators.RegexValidator(re.compile('^[\w.-]+$'), "invalid username", "invalid") + validator = validators.RegexValidator(re.compile('^[\w.-]+$'), _("invalid username"), "invalid") try: validator(value) except ValidationError: - raise serializers.ValidationError("Required. 255 characters or fewer. Letters, numbers " - "and /./-/_ characters'") + raise serializers.ValidationError(_("Required. 255 characters or fewer. Letters, numbers " + "and /./-/_ characters'")) return attrs diff --git a/taiga/auth/services.py b/taiga/auth/services.py index 33a82baa..0498bddd 100644 --- a/taiga/auth/services.py +++ b/taiga/auth/services.py @@ -91,7 +91,7 @@ def get_membership_by_token(token:str): membership_model = apps.get_model("projects", "Membership") qs = membership_model.objects.filter(token=token) if len(qs) == 0: - raise exc.NotFound("Token not matches any valid invitation.") + raise exc.NotFound(_("Token not matches any valid invitation.")) return qs[0] @@ -119,7 +119,7 @@ def public_register(username:str, password:str, email:str, full_name:str): try: user.save() except IntegrityError: - raise exc.WrongArguments("User is already register.") + raise exc.WrongArguments(_("User is already register.")) send_register_email(user) user_registered_signal.send(sender=user.__class__, user=user) @@ -143,7 +143,7 @@ def private_register_for_existing_user(token:str, username:str, password:str): membership.user = user membership.save(update_fields=["user"]) except IntegrityError: - raise exc.IntegrityError("Membership with user is already exists.") + raise exc.IntegrityError(_("Membership with user is already exists.")) send_register_email(user) return user diff --git a/taiga/auth/tokens.py b/taiga/auth/tokens.py index 75d36e21..f113ba8a 100644 --- a/taiga/auth/tokens.py +++ b/taiga/auth/tokens.py @@ -18,6 +18,7 @@ from taiga.base import exceptions as exc from django.apps import apps from django.core import signing +from django.utils.translation import ugettext as _ def get_token_for_user(user, scope): @@ -43,13 +44,13 @@ def get_user_for_token(token, scope, max_age=None): try: data = signing.loads(token, max_age=max_age) except signing.BadSignature: - raise exc.NotAuthenticated("Invalid token") + raise exc.NotAuthenticated(_("Invalid token")) model_cls = apps.get_model("users", "User") try: user = model_cls.objects.get(pk=data["user_%s_id" % (scope)]) except (model_cls.DoesNotExist, KeyError): - raise exc.NotAuthenticated("Invalid token") + raise exc.NotAuthenticated(_("Invalid token")) else: return user diff --git a/taiga/base/api/generics.py b/taiga/base/api/generics.py index a5b40c18..9536cb04 100644 --- a/taiga/base/api/generics.py +++ b/taiga/base/api/generics.py @@ -126,11 +126,11 @@ class GenericAPIView(views.APIView): """ deprecated_style = False if page_size is not None: - warnings.warn('The `page_size` parameter to `paginate_queryset()` ' - 'is due to be deprecated. ' - 'Note that the return style of this method is also ' - 'changed, and will simply return a page object ' - 'when called without a `page_size` argument.', + warnings.warn(_('The `page_size` parameter to `paginate_queryset()` ' + 'is due to be deprecated. ' + 'Note that the return style of this method is also ' + 'changed, and will simply return a page object ' + 'when called without a `page_size` argument.'), PendingDeprecationWarning, stacklevel=2) deprecated_style = True else: @@ -141,12 +141,10 @@ class GenericAPIView(views.APIView): return None if not self.allow_empty: - warnings.warn( - 'The `allow_empty` parameter is due to be deprecated. ' - 'To use `allow_empty=False` style behavior, You should override ' - '`get_queryset()` and explicitly raise a 404 on empty querysets.', - PendingDeprecationWarning, stacklevel=2 - ) + warnings.warn(_('The `allow_empty` parameter is due to be deprecated. ' + 'To use `allow_empty=False` style behavior, You should override ' + '`get_queryset()` and explicitly raise a 404 on empty querysets.'), + PendingDeprecationWarning, stacklevel=2) paginator = self.paginator_class(queryset, page_size, allow_empty_first_page=self.allow_empty) @@ -191,10 +189,10 @@ class GenericAPIView(views.APIView): """ filter_backends = self.filter_backends or [] if not filter_backends and hasattr(self, 'filter_backend'): - raise RuntimeError('The `filter_backend` attribute and `FILTER_BACKEND` setting ' - 'are due to be deprecated in favor of a `filter_backends` ' - 'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take ' - 'a *list* of filter backend classes.') + raise RuntimeError(_('The `filter_backend` attribute and `FILTER_BACKEND` setting ' + 'are due to be deprecated in favor of a `filter_backends` ' + 'attribute and `DEFAULT_FILTER_BACKENDS` setting, that take ' + 'a *list* of filter backend classes.')) return filter_backends ########################################################### @@ -212,8 +210,8 @@ class GenericAPIView(views.APIView): Otherwise defaults to using `self.paginate_by`. """ if queryset is not None: - raise RuntimeError('The `queryset` parameter to `get_paginate_by()` ' - 'is due to be deprecated.') + raise RuntimeError(_('The `queryset` parameter to `get_paginate_by()` ' + 'is due to be deprecated.')) if self.paginate_by_param: try: return strict_positive_int( @@ -233,11 +231,9 @@ class GenericAPIView(views.APIView): if serializer_class is not None: return serializer_class - assert self.model is not None, \ - "'%s' should either include a 'serializer_class' attribute, " \ - "or use the 'model' attribute as a shortcut for " \ - "automatically generating a serializer class." \ - % self.__class__.__name__ + assert self.model is not None, _("'%s' should either include a 'serializer_class' attribute, " + "or use the 'model' attribute as a shortcut for " + "automatically generating a serializer class." % self.__class__.__name__) class DefaultSerializer(self.model_serializer_class): class Meta: @@ -261,7 +257,7 @@ class GenericAPIView(views.APIView): if self.model is not None: return self.model._default_manager.all() - raise ImproperlyConfigured("'%s' must define 'queryset' or 'model'" % self.__class__.__name__) + raise ImproperlyConfigured(_("'%s' must define 'queryset' or 'model'" % self.__class__.__name__)) def get_object(self, queryset=None): """ @@ -289,18 +285,16 @@ class GenericAPIView(views.APIView): if lookup is not None: filter_kwargs = {self.lookup_field: lookup} elif pk is not None and self.lookup_field == 'pk': - raise RuntimeError('The `pk_url_kwarg` attribute is due to be deprecated. ' - 'Use the `lookup_field` attribute instead') + raise RuntimeError(_('The `pk_url_kwarg` attribute is due to be deprecated. ' + 'Use the `lookup_field` attribute instead')) elif slug is not None and self.lookup_field == 'pk': - raise RuntimeError('The `slug_url_kwarg` attribute is due to be deprecated. ' - 'Use the `lookup_field` attribute instead') + raise RuntimeError(_('The `slug_url_kwarg` attribute is due to be deprecated. ' + 'Use the `lookup_field` attribute instead')) else: - raise ImproperlyConfigured( - 'Expected view %s to be called with a URL keyword argument ' - 'named "%s". Fix your URL conf, or set the `.lookup_field` ' - 'attribute on the view correctly.' % - (self.__class__.__name__, self.lookup_field) - ) + raise ImproperlyConfigured(_('Expected view %s to be called with a URL keyword argument ' + 'named "%s". Fix your URL conf, or set the `.lookup_field` ' + 'attribute on the view correctly.' % + (self.__class__.__name__, self.lookup_field))) obj = get_object_or_404(queryset, **filter_kwargs) return obj diff --git a/taiga/base/api/mixins.py b/taiga/base/api/mixins.py index ed2b2f24..d28c8d06 100644 --- a/taiga/base/api/mixins.py +++ b/taiga/base/api/mixins.py @@ -22,6 +22,7 @@ import warnings from django.core.exceptions import ValidationError from django.http import Http404 from django.db import transaction as tx +from django.utils.translation import ugettext as _ from taiga.base import response from rest_framework.settings import api_settings @@ -94,12 +95,10 @@ class ListModelMixin(object): # Default is to allow empty querysets. This can be altered by setting # `.allow_empty = False`, to raise 404 errors on empty querysets. if not self.allow_empty and not self.object_list: - warnings.warn( - 'The `allow_empty` parameter is due to be deprecated. ' - 'To use `allow_empty=False` style behavior, You should override ' - '`get_queryset()` and explicitly raise a 404 on empty querysets.', - PendingDeprecationWarning - ) + warnings.warn(_('The `allow_empty` parameter is due to be deprecated. ' + 'To use `allow_empty=False` style behavior, You should override ' + '`get_queryset()` and explicitly raise a 404 on empty querysets.'), + PendingDeprecationWarning) class_name = self.__class__.__name__ error_msg = self.empty_error % {'class_name': class_name} raise Http404(error_msg) diff --git a/taiga/base/api/permissions.py b/taiga/base/api/permissions.py index ff1f8bef..c4e6917d 100644 --- a/taiga/base/api/permissions.py +++ b/taiga/base/api/permissions.py @@ -20,6 +20,7 @@ from taiga.base.utils import sequence as sq from taiga.permissions.service import user_has_perm, is_project_owner from django.apps import apps +from django.utils.translation import ugettext as _ ###################################################################### # Base permissiones definition @@ -57,7 +58,7 @@ class ResourcePermission(object): elif inspect.isclass(permset) and issubclass(permset, PermissionComponent): permset = permset() else: - raise RuntimeError("Invalid permission definition.") + raise RuntimeError(_("Invalid permission definition.")) if self.global_perms: permset = (self.global_perms & permset) diff --git a/taiga/base/api/views.py b/taiga/base/api/views.py index 26cc5970..3656024e 100644 --- a/taiga/base/api/views.py +++ b/taiga/base/api/views.py @@ -23,6 +23,7 @@ from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponse from django.utils.datastructures import SortedDict from django.views.decorators.csrf import csrf_exempt +from django.utils.translation import ugettext as _ from rest_framework import status, exceptions from rest_framework.compat import smart_text, HttpResponseBase, View @@ -93,10 +94,10 @@ def exception_handler(exc): headers=headers) elif isinstance(exc, Http404): - return NotFound({'detail': 'Not found'}) + return NotFound({'detail': _('Not found')}) elif isinstance(exc, PermissionDenied): - return Forbidden({'detail': 'Permission denied'}) + return Forbidden({'detail': _('Permission denied')}) # Note: Unhandled exceptions will raise a 500 error. return None @@ -345,11 +346,9 @@ class APIView(View): Returns the final response object. """ # Make the error obvious if a proper response is not returned - assert isinstance(response, HttpResponseBase), ( - 'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` ' - 'to be returned from the view, but received a `%s`' - % type(response) - ) + assert isinstance(response, HttpResponseBase), _('Expected a `Response`, `HttpResponse` or ' + '`HttpStreamingResponse` to be returned from the view, ' + 'but received a `%s`' % type(response)) if isinstance(response, Response): if not getattr(request, 'accepted_renderer', None): @@ -446,6 +445,6 @@ class APIView(View): def api_server_error(request, *args, **kwargs): if settings.DEBUG is False and request.META['CONTENT_TYPE'] == "application/json": - return HttpResponse(json.dumps({"error": "Server application error"}), + return HttpResponse(json.dumps({"error": _("Server application error")}), status=status.HTTP_500_INTERNAL_SERVER_ERROR) return server_error(request, *args, **kwargs) diff --git a/taiga/base/api/viewsets.py b/taiga/base/api/viewsets.py index cad36dcd..82d29ef1 100644 --- a/taiga/base/api/viewsets.py +++ b/taiga/base/api/viewsets.py @@ -19,6 +19,7 @@ from functools import update_wrapper from django.utils.decorators import classonlymethod +from django.utils.translation import ugettext as _ from . import views from . import mixins @@ -53,12 +54,12 @@ class ViewSetMixin(object): # sanitize keyword arguments for key in initkwargs: if key in cls.http_method_names: - raise TypeError("You tried to pass in the %s method name as a " - "keyword argument to %s(). Don't do that." - % (key, cls.__name__)) + raise TypeError(_("You tried to pass in the %s method name as a " + "keyword argument to %s(). Don't do that." + % (key, cls.__name__))) if not hasattr(cls, key): - raise TypeError("%s() received an invalid keyword %r" % ( - cls.__name__, key)) + raise TypeError(_("%s() received an invalid keyword %r" + % (cls.__name__, key))) def view(request, *args, **kwargs): self = cls(**initkwargs) diff --git a/taiga/base/filters.py b/taiga/base/filters.py index 5f7c50e8..5ae4434b 100644 --- a/taiga/base/filters.py +++ b/taiga/base/filters.py @@ -19,7 +19,7 @@ import logging from django.apps import apps from django.db.models import Q -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from rest_framework import filters @@ -60,7 +60,7 @@ class QueryParamsFilterMixin(filters.BaseFilterBackend): try: queryset = queryset.filter(**query_params) except ValueError: - raise exc.BadRequest("Error in filter params types.") + raise exc.BadRequest(_("Error in filter params types.")) return queryset @@ -104,10 +104,10 @@ class PermissionBasedFilterBackend(FilterBackend): try: project_id = int(request.QUERY_PARAMS["project"]) except: - logger.error("Filtering project diferent value than an integer: {}".format( + logger.error(_("Filtering project diferent value than an integer: {}".format( request.QUERY_PARAMS["project"] - )) - raise exc.BadRequest("'project' must be an integer value.") + ))) + raise exc.BadRequest(_("'project' must be an integer value.")) qs = queryset @@ -193,10 +193,10 @@ class CanViewProjectObjFilterBackend(FilterBackend): try: project_id = int(request.QUERY_PARAMS["project"]) except: - logger.error("Filtering project diferent value than an integer: {}".format( + logger.error(_("Filtering project diferent value than an integer: {}".format( request.QUERY_PARAMS["project"] - )) - raise exc.BadRequest("'project' must be an integer value.") + ))) + raise exc.BadRequest(_("'project' must be an integer value.")) qs = queryset @@ -250,8 +250,9 @@ class MembersFilterBackend(PermissionBasedFilterBackend): try: project_id = int(request.QUERY_PARAMS["project"]) except: - logger.error("Filtering project diferent value than an integer: {}".format(request.QUERY_PARAMS["project"])) - raise exc.BadRequest("'project' must be an integer value.") + logger.error(_("Filtering project diferent value than an integer: {}".format( + request.QUERY_PARAMS["project"]))) + raise exc.BadRequest(_("'project' must be an integer value.")) if project_id: Project = apps.get_model('projects', 'Project') diff --git a/taiga/base/utils/signals.py b/taiga/base/utils/signals.py index 64cc580a..0c326c95 100644 --- a/taiga/base/utils/signals.py +++ b/taiga/base/utils/signals.py @@ -15,6 +15,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from django.utils.translation import ugettext as _ + from contextlib import contextmanager @@ -22,7 +24,7 @@ from contextlib import contextmanager def without_signals(*disablers): for disabler in disablers: if not (isinstance(disabler, list) or isinstance(disabler, tuple)) or len(disabler) == 0: - raise ValueError("The parameters must be lists of at least one parameter (the signal)") + raise ValueError(_("The parameters must be lists of at least one parameter (the signal).")) signal, *ids = disabler signal.backup_receivers = signal.receivers diff --git a/taiga/export_import/api.py b/taiga/export_import/api.py index 8ddb4c15..01947685 100644 --- a/taiga/export_import/api.py +++ b/taiga/export_import/api.py @@ -19,7 +19,7 @@ import codecs import uuid from django.utils.decorators import method_decorator -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from django.db.transaction import atomic from django.db.models import signals from django.conf import settings diff --git a/taiga/export_import/dump_service.py b/taiga/export_import/dump_service.py index 2ef615a1..13b09a4c 100644 --- a/taiga/export_import/dump_service.py +++ b/taiga/export_import/dump_service.py @@ -14,6 +14,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from django.utils.translation import ugettext as _ + from taiga.projects.models import Membership from . import serializers @@ -83,7 +85,7 @@ def dict_to_project(data, owner=None): project_serialized = service.store_project(data) if not project_serialized: - raise TaigaImportError('error importing project') + raise TaigaImportError(_('error importing project')) proj = project_serialized.object @@ -96,12 +98,12 @@ def dict_to_project(data, owner=None): service.store_choices(proj, data, "severities", serializers.SeverityExportSerializer) if service.get_errors(clear=False): - raise TaigaImportError('error importing choices') + raise TaigaImportError(_('error importing choices')) service.store_default_choices(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing default choices') + raise TaigaImportError(_('error importing default choices')) service.store_custom_attributes(proj, data, "userstorycustomattributes", serializers.UserStoryCustomAttributeExportSerializer) @@ -111,12 +113,12 @@ def dict_to_project(data, owner=None): serializers.IssueCustomAttributeExportSerializer) if service.get_errors(clear=False): - raise TaigaImportError('error importing custom attributes') + raise TaigaImportError(_('error importing custom attributes')) service.store_roles(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing roles') + raise TaigaImportError(_('error importing roles')) service.store_memberships(proj, data) @@ -131,37 +133,37 @@ def dict_to_project(data, owner=None): ) if service.get_errors(clear=False): - raise TaigaImportError('error importing memberships') + raise TaigaImportError(_('error importing memberships')) store_milestones(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing milestones') + raise TaigaImportError(_('error importing milestones')) store_wiki_pages(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing wiki pages') + raise TaigaImportError(_('error importing wiki pages')) store_wiki_links(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing wiki links') + raise TaigaImportError(_('error importing wiki links')) store_issues(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing issues') + raise TaigaImportError(_('error importing issues')) store_user_stories(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing user stories') + raise TaigaImportError(_('error importing user stories')) store_tasks(proj, data) if service.get_errors(clear=False): - raise TaigaImportError('error importing issues') + raise TaigaImportError(_('error importing issues')) store_tags_colors(proj, data) diff --git a/taiga/export_import/serializers.py b/taiga/export_import/serializers.py index 6287e78d..1805c465 100644 --- a/taiga/export_import/serializers.py +++ b/taiga/export_import/serializers.py @@ -18,11 +18,12 @@ import base64 import os from collections import OrderedDict -from django.contrib.contenttypes.models import ContentType from django.core.files.base import ContentFile from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ValidationError from django.core.exceptions import ObjectDoesNotExist +from django.utils.translation import ugettext as _ +from django.contrib.contenttypes.models import ContentType from rest_framework import serializers @@ -153,7 +154,7 @@ class ProjectRelatedField(serializers.RelatedField): kwargs = {self.slug_field: data, "project": self.context['project']} return self.queryset.get(**kwargs) except ObjectDoesNotExist: - raise ValidationError("{}=\"{}\" not found in this project".format(self.slug_field, data)) + raise ValidationError(_("{}=\"{}\" not found in this project".format(self.slug_field, data))) class HistoryUserField(JsonField): @@ -458,7 +459,7 @@ class MilestoneExportSerializer(serializers.ModelSerializer): name = attrs[source] qs = self.project.milestones.filter(name=name) if qs.exists(): - raise serializers.ValidationError("Name duplicated for the project") + raise serializers.ValidationError(_("Name duplicated for the project")) return attrs diff --git a/taiga/export_import/tasks.py b/taiga/export_import/tasks.py index 29032861..9ac5b42f 100644 --- a/taiga/export_import/tasks.py +++ b/taiga/export_import/tasks.py @@ -20,6 +20,7 @@ from django.core.files.storage import default_storage from django.core.files.base import ContentFile from django.utils import timezone from django.conf import settings +from django.utils.translation import ugettext as _ from djmail.template_mail import MagicMailBuilder, InlineCSSTemplateMail @@ -45,8 +46,8 @@ def dump_project(self, user, project): except Exception: ctx = { "user": user, - "error_subject": "Error generating project dump", - "error_message": "Error generating project dump", + "error_subject": _("Error generating project dump"), + "error_message": _("Error generating project dump"), "project": project } email = mbuilder.export_error(user, ctx) @@ -78,8 +79,8 @@ def load_project_dump(user, dump): except Exception: ctx = { "user": user, - "error_subject": "Error loading project dump", - "error_message": "Error loading project dump", + "error_subject": _("Error loading project dump"), + "error_message": _("Error loading project dump"), } email = mbuilder.import_error(user, ctx) email.send() diff --git a/taiga/hooks/api.py b/taiga/hooks/api.py index a95d6fbe..d4345cbc 100644 --- a/taiga/hooks/api.py +++ b/taiga/hooks/api.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.base import exceptions as exc from taiga.base import response diff --git a/taiga/hooks/bitbucket/event_hooks.py b/taiga/hooks/bitbucket/event_hooks.py index d82d3d4e..7461eabb 100644 --- a/taiga/hooks/bitbucket/event_hooks.py +++ b/taiga/hooks/bitbucket/event_hooks.py @@ -16,7 +16,7 @@ import re -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.base import exceptions as exc from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus @@ -27,11 +27,10 @@ from taiga.projects.history.services import take_snapshot from taiga.projects.notifications.services import send_notifications from taiga.hooks.event_hooks import BaseEventHook from taiga.hooks.exceptions import ActionSyntaxException +from taiga.base.utils import json from .services import get_bitbucket_user -import json - class PushEventHook(BaseEventHook): def process_event(self): @@ -92,7 +91,7 @@ class PushEventHook(BaseEventHook): element.save() snapshot = take_snapshot(element, - comment="Status changed from BitBucket commit", + comment=_("Status changed from BitBucket commit"), user=get_bitbucket_user(bitbucket_user)) send_notifications(element, history=snapshot) diff --git a/taiga/hooks/github/event_hooks.py b/taiga/hooks/github/event_hooks.py index 50c465c5..6ccac3da 100644 --- a/taiga/hooks/github/event_hooks.py +++ b/taiga/hooks/github/event_hooks.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus @@ -85,7 +85,7 @@ class PushEventHook(BaseEventHook): element.save() snapshot = take_snapshot(element, - comment="Status changed from GitHub commit", + comment=_("Status changed from GitHub commit"), user=get_github_user(github_user)) send_notifications(element, history=snapshot) @@ -93,7 +93,7 @@ class PushEventHook(BaseEventHook): def replace_github_references(project_url, wiki_text): if wiki_text == None: wiki_text = "" - + template = "\g<1>[GitHub#\g<2>]({}/issues/\g<2>)\g<3>".format(project_url) return re.sub(r"(\s|^)#(\d+)(\s|$)", template, wiki_text, 0, re.M) @@ -125,7 +125,7 @@ class IssuesEventHook(BaseEventHook): ) take_snapshot(issue, user=get_github_user(github_user)) - snapshot = take_snapshot(issue, comment="Created from GitHub", user=get_github_user(github_user)) + snapshot = take_snapshot(issue, comment=_("Created from GitHub"), user=get_github_user(github_user)) send_notifications(issue, history=snapshot) @@ -149,6 +149,6 @@ class IssueCommentEventHook(BaseEventHook): for item in list(issues) + list(tasks) + list(uss): snapshot = take_snapshot(item, - comment="From GitHub:\n\n{}".format(comment_message), + comment=_("From GitHub:\n\n{}".format(comment_message)), user=get_github_user(github_user)) send_notifications(item, history=snapshot) diff --git a/taiga/hooks/gitlab/event_hooks.py b/taiga/hooks/gitlab/event_hooks.py index faa81df1..8776d8c7 100644 --- a/taiga/hooks/gitlab/event_hooks.py +++ b/taiga/hooks/gitlab/event_hooks.py @@ -17,7 +17,7 @@ import re import os -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.projects.models import IssueStatus, TaskStatus, UserStoryStatus @@ -84,7 +84,7 @@ class PushEventHook(BaseEventHook): element.save() snapshot = take_snapshot(element, - comment="Status changed from GitLab commit", + comment=_("Status changed from GitLab commit"), user=get_gitlab_user(gitlab_user)) send_notifications(element, history=snapshot) @@ -126,5 +126,5 @@ class IssuesEventHook(BaseEventHook): ) take_snapshot(issue, user=get_gitlab_user(None)) - snapshot = take_snapshot(issue, comment="Created from GitLab", user=get_gitlab_user(None)) + snapshot = take_snapshot(issue, comment=_("Created from GitLab"), user=get_gitlab_user(None)) send_notifications(issue, history=snapshot) diff --git a/taiga/locale/en/LC_MESSAGES/django.po b/taiga/locale/en/LC_MESSAGES/django.po index 742c8bcd..0f1631d5 100644 --- a/taiga/locale/en/LC_MESSAGES/django.po +++ b/taiga/locale/en/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: taiga-back\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-03-25 20:09+0100\n" +"POT-Creation-Date: 2015-04-06 17:04+0200\n" "PO-Revision-Date: 2015-03-25 20:09+0100\n" "Last-Translator: Taiga Dev Team \n" "Language-Team: Taiga Dev Team \n" @@ -28,6 +28,15 @@ msgstr "" msgid "invalid login type" msgstr "" +#: taiga/auth/serializers.py:33 taiga/users/serializers.py:52 +msgid "invalid username" +msgstr "" + +#: taiga/auth/serializers.py:38 taiga/users/serializers.py:58 +msgid "" +"Required. 255 characters or fewer. Letters, numbers and /./-/_ characters'" +msgstr "" + #: taiga/auth/services.py:75 msgid "Username is already in use." msgstr "" @@ -36,19 +45,129 @@ msgstr "" msgid "Email is already in use." msgstr "" +#: taiga/auth/services.py:94 +msgid "Token not matches any valid invitation." +msgstr "" + +#: taiga/auth/services.py:122 +msgid "User is already register." +msgstr "" + +#: taiga/auth/services.py:146 +msgid "Membership with user is already exists." +msgstr "" + #: taiga/auth/services.py:172 msgid "Error on creating new user." msgstr "" -#: taiga/base/api/generics.py:162 +#: taiga/auth/tokens.py:47 taiga/auth/tokens.py:54 +msgid "Invalid token" +msgstr "" + +#: taiga/base/api/generics.py:129 +msgid "" +"The `page_size` parameter to `paginate_queryset()` is due to be deprecated. " +"Note that the return style of this method is also changed, and will simply " +"return a page object when called without a `page_size` argument." +msgstr "" + +#: taiga/base/api/generics.py:144 taiga/base/api/mixins.py:98 +msgid "" +"The `allow_empty` parameter is due to be deprecated. To use " +"`allow_empty=False` style behavior, You should override `get_queryset()` and " +"explicitly raise a 404 on empty querysets." +msgstr "" + +#: taiga/base/api/generics.py:160 msgid "Page is not 'last', nor can it be converted to an int." msgstr "" -#: taiga/base/api/generics.py:166 +#: taiga/base/api/generics.py:164 #, python-format msgid "Invalid page (%(page_number)s): %(message)s" msgstr "" +#: taiga/base/api/generics.py:192 +msgid "" +"The `filter_backend` attribute and `FILTER_BACKEND` setting are due to be " +"deprecated in favor of a `filter_backends` attribute and " +"`DEFAULT_FILTER_BACKENDS` setting, that take a *list* of filter backend " +"classes." +msgstr "" + +#: taiga/base/api/generics.py:213 +msgid "" +"The `queryset` parameter to `get_paginate_by()` is due to be deprecated." +msgstr "" + +#: taiga/base/api/generics.py:234 +#, python-format +msgid "" +"'%s' should either include a 'serializer_class' attribute, or use the " +"'model' attribute as a shortcut for automatically generating a serializer " +"class." +msgstr "" + +#: taiga/base/api/generics.py:260 +#, python-format +msgid "'%s' must define 'queryset' or 'model'" +msgstr "" + +#: taiga/base/api/generics.py:288 +msgid "" +"The `pk_url_kwarg` attribute is due to be deprecated. Use the `lookup_field` " +"attribute instead" +msgstr "" + +#: taiga/base/api/generics.py:291 +msgid "" +"The `slug_url_kwarg` attribute is due to be deprecated. Use the " +"`lookup_field` attribute instead" +msgstr "" + +#: taiga/base/api/generics.py:294 +#, python-format +msgid "" +"Expected view %s to be called with a URL keyword argument named \"%s\". Fix " +"your URL conf, or set the `.lookup_field` attribute on the view correctly." +msgstr "" + +#: taiga/base/api/permissions.py:61 +msgid "Invalid permission definition." +msgstr "" + +#: taiga/base/api/views.py:97 +msgid "Not found" +msgstr "" + +#: taiga/base/api/views.py:100 +msgid "Permission denied" +msgstr "" + +#: taiga/base/api/views.py:349 +#, python-format +msgid "" +"Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be " +"returned from the view, but received a `%s`" +msgstr "" + +#: taiga/base/api/views.py:448 +msgid "Server application error" +msgstr "" + +#: taiga/base/api/viewsets.py:57 +#, python-format +msgid "" +"You tried to pass in the %s method name as a keyword argument to %s(). Don't " +"do that." +msgstr "" + +#: taiga/base/api/viewsets.py:61 +#, python-format +msgid "%s() received an invalid keyword %r" +msgstr "" + #: taiga/base/connectors/exceptions.py:24 msgid "Connection error." msgstr "" @@ -81,6 +200,20 @@ msgstr "" msgid "Precondition error" msgstr "" +#: taiga/base/filters.py:63 +msgid "Error in filter params types." +msgstr "" + +#: taiga/base/filters.py:107 taiga/base/filters.py:196 +#: taiga/base/filters.py:253 +msgid "Filtering project diferent value than an integer: {}" +msgstr "" + +#: taiga/base/filters.py:110 taiga/base/filters.py:199 +#: taiga/base/filters.py:255 +msgid "'project' must be an integer value." +msgstr "" + #: taiga/base/tags.py:25 msgid "tags" msgstr "" @@ -166,6 +299,10 @@ msgid "" " " msgstr "" +#: taiga/base/utils/signals.py:27 +msgid "The parameters must be lists of at least one parameter (the signal)." +msgstr "" + #: taiga/export_import/api.py:183 msgid "Needed dump file" msgstr "" @@ -174,16 +311,80 @@ msgstr "" msgid "Invalid dump format" msgstr "" -#: taiga/export_import/serializers.py:377 +#: taiga/export_import/dump_service.py:88 +msgid "error importing project" +msgstr "" + +#: taiga/export_import/dump_service.py:101 +msgid "error importing choices" +msgstr "" + +#: taiga/export_import/dump_service.py:106 +msgid "error importing default choices" +msgstr "" + +#: taiga/export_import/dump_service.py:116 +msgid "error importing custom attributes" +msgstr "" + +#: taiga/export_import/dump_service.py:121 +msgid "error importing roles" +msgstr "" + +#: taiga/export_import/dump_service.py:136 +msgid "error importing memberships" +msgstr "" + +#: taiga/export_import/dump_service.py:141 +msgid "error importing milestones" +msgstr "" + +#: taiga/export_import/dump_service.py:146 +msgid "error importing wiki pages" +msgstr "" + +#: taiga/export_import/dump_service.py:151 +msgid "error importing wiki links" +msgstr "" + +#: taiga/export_import/dump_service.py:156 +#: taiga/export_import/dump_service.py:166 +msgid "error importing issues" +msgstr "" + +#: taiga/export_import/dump_service.py:161 +msgid "error importing user stories" +msgstr "" + +#: taiga/export_import/serializers.py:157 +msgid "{}=\"{}\" not found in this project" +msgstr "" + +#: taiga/export_import/serializers.py:378 #: taiga/projects/custom_attributes/serializers.py:104 msgid "Invalid content. It must be {\"key\": \"value\",...}" msgstr "" -#: taiga/export_import/serializers.py:392 +#: taiga/export_import/serializers.py:393 #: taiga/projects/custom_attributes/serializers.py:119 msgid "It contain invalid custom fields." msgstr "" +#: taiga/export_import/serializers.py:462 +#: taiga/projects/milestones/serializers.py:63 +#: taiga/projects/serializers.py:64 taiga/projects/serializers.py:88 +#: taiga/projects/serializers.py:110 taiga/projects/serializers.py:142 +msgid "Name duplicated for the project" +msgstr "" + +#: taiga/export_import/tasks.py:49 taiga/export_import/tasks.py:50 +msgid "Error generating project dump" +msgstr "" + +#: taiga/export_import/tasks.py:82 taiga/export_import/tasks.py:83 +msgid "Error loading project dump" +msgstr "" + #: taiga/export_import/templates/emails/dump_project-subject.jinja:1 #, python-format msgid "[%(project)s] Your project dump has been generated" @@ -286,28 +487,55 @@ msgstr "" msgid "The payload is not a valid application/x-www-form-urlencoded" msgstr "" -#: taiga/hooks/bitbucket/event_hooks.py:46 +#: taiga/hooks/bitbucket/event_hooks.py:45 msgid "The payload is not valid" msgstr "" -#: taiga/hooks/bitbucket/event_hooks.py:82 +#: taiga/hooks/bitbucket/event_hooks.py:81 #: taiga/hooks/github/event_hooks.py:75 taiga/hooks/gitlab/event_hooks.py:74 msgid "The referenced element doesn't exist" msgstr "" -#: taiga/hooks/bitbucket/event_hooks.py:89 +#: taiga/hooks/bitbucket/event_hooks.py:88 #: taiga/hooks/github/event_hooks.py:82 taiga/hooks/gitlab/event_hooks.py:81 msgid "The status doesn't exist" msgstr "" +#: taiga/hooks/bitbucket/event_hooks.py:94 +msgid "Status changed from BitBucket commit" +msgstr "" + +#: taiga/hooks/github/event_hooks.py:88 +msgid "Status changed from GitHub commit" +msgstr "" + #: taiga/hooks/github/event_hooks.py:113 taiga/hooks/gitlab/event_hooks.py:114 msgid "Invalid issue information" msgstr "" +#: taiga/hooks/github/event_hooks.py:128 +msgid "Created from GitHub" +msgstr "" + #: taiga/hooks/github/event_hooks.py:135 taiga/hooks/github/event_hooks.py:144 msgid "Invalid issue comment information" msgstr "" +#: taiga/hooks/github/event_hooks.py:152 +msgid "" +"From GitHub:\n" +"\n" +"{}" +msgstr "" + +#: taiga/hooks/gitlab/event_hooks.py:87 +msgid "Status changed from GitLab commit" +msgstr "" + +#: taiga/hooks/gitlab/event_hooks.py:129 +msgid "Created from GitLab" +msgstr "" + #: taiga/permissions/permissions.py:21 taiga/permissions/permissions.py:31 #: taiga/permissions/permissions.py:52 msgid "View project" @@ -470,6 +698,14 @@ msgstr "" msgid "Admin roles" msgstr "" +#: taiga/projects/api.py:189 +msgid "Not valid template name" +msgstr "" + +#: taiga/projects/api.py:192 +msgid "Not valid template description" +msgstr "" + #: taiga/projects/api.py:454 taiga/projects/serializers.py:227 msgid "At least one of the user must be an active admin" msgstr "" @@ -478,10 +714,19 @@ msgstr "" msgid "You don't have permisions to see that." msgstr "" +#: taiga/projects/attachments/api.py:47 +msgid "Non partial updates not supported" +msgstr "" + +#: taiga/projects/attachments/api.py:62 +msgid "Project ID not matches between object and project" +msgstr "" + #: taiga/projects/attachments/models.py:54 taiga/projects/issues/models.py:38 #: taiga/projects/milestones/models.py:39 taiga/projects/models.py:131 -#: taiga/projects/tasks/models.py:37 taiga/projects/userstories/models.py:64 -#: taiga/projects/wiki/models.py:34 taiga/userstorage/models.py:25 +#: taiga/projects/notifications/models.py:57 taiga/projects/tasks/models.py:37 +#: taiga/projects/userstories/models.py:64 taiga/projects/wiki/models.py:34 +#: taiga/userstorage/models.py:25 msgid "owner" msgstr "" @@ -492,9 +737,9 @@ msgstr "" #: taiga/projects/models.py:383 taiga/projects/models.py:412 #: taiga/projects/models.py:445 taiga/projects/models.py:468 #: taiga/projects/models.py:495 taiga/projects/models.py:526 -#: taiga/projects/tasks/models.py:41 taiga/projects/userstories/models.py:62 -#: taiga/projects/wiki/models.py:28 taiga/projects/wiki/models.py:66 -#: taiga/users/models.py:193 +#: taiga/projects/notifications/models.py:69 taiga/projects/tasks/models.py:41 +#: taiga/projects/userstories/models.py:62 taiga/projects/wiki/models.py:28 +#: taiga/projects/wiki/models.py:66 taiga/users/models.py:193 msgid "project" msgstr "" @@ -542,6 +787,14 @@ msgstr "" msgid "order" msgstr "" +#: taiga/projects/choices.py:21 +msgid "AppearIn" +msgstr "" + +#: taiga/projects/choices.py:22 +msgid "Talky" +msgstr "" + #: taiga/projects/custom_attributes/models.py:31 #: taiga/projects/milestones/models.py:34 taiga/projects/models.py:120 #: taiga/projects/models.py:338 taiga/projects/models.py:377 @@ -573,6 +826,14 @@ msgstr "" msgid "Already exists one with the same name." msgstr "" +#: taiga/projects/history/api.py:70 +msgid "Comment already deleted" +msgstr "" + +#: taiga/projects/history/api.py:89 +msgid "Comment not deleted" +msgstr "" + #: taiga/projects/history/choices.py:27 msgid "Change" msgstr "" @@ -637,6 +898,7 @@ msgstr "" #: taiga/projects/history/templates/emails/includes/fields_diff-html.jinja:134 #: taiga/projects/history/templates/emails/includes/fields_diff-html.jinja:145 +#: taiga/projects/services/stats.py:124 taiga/projects/services/stats.py:125 msgid "Unassigned" msgstr "" @@ -783,6 +1045,10 @@ msgstr "" msgid "disponibility" msgstr "" +#: taiga/projects/milestones/models.py:75 +msgid "The estimated start must be previous to the estimated finish." +msgstr "" + #: taiga/projects/milestones/validators.py:12 msgid "There's no sprint with that id" msgstr "" @@ -984,14 +1250,27 @@ msgstr "" msgid "watchers" msgstr "" -#: taiga/projects/notifications/models.py:57 +#: taiga/projects/notifications/models.py:59 msgid "created date time" msgstr "" -#: taiga/projects/notifications/models.py:59 +#: taiga/projects/notifications/models.py:61 msgid "updated date time" msgstr "" +#: taiga/projects/notifications/models.py:63 +msgid "history entries" +msgstr "" + +#: taiga/projects/notifications/models.py:66 +msgid "notify users" +msgstr "" + +#: taiga/projects/notifications/services.py:63 +#: taiga/projects/notifications/services.py:77 +msgid "Notify exists for specified user and project" +msgstr "" + #: taiga/projects/notifications/templates/emails/wiki/wikipage-change-subject.jinja:1 #, python-format msgid "" @@ -1013,6 +1292,22 @@ msgid "" "[%(project)s] Deleted the Wiki Page \"%(page)s\"\n" msgstr "" +#: taiga/projects/notifications/validators.py:43 +msgid "Watchers contains invalid users" +msgstr "" + +#: taiga/projects/occ/mixins.py:34 +msgid "The version must be an integer" +msgstr "" + +#: taiga/projects/occ/mixins.py:55 +msgid "The version is not valid" +msgstr "" + +#: taiga/projects/occ/mixins.py:71 +msgid "The version doesn't match with the current one" +msgstr "" + #: taiga/projects/occ/mixins.py:91 msgid "version" msgstr "" @@ -1029,6 +1324,10 @@ msgstr "" msgid "Invalid role for the project" msgstr "" +#: taiga/projects/serializers.py:313 +msgid "Total milestones must be major or equal to zero" +msgstr "" + #: taiga/projects/serializers.py:370 msgid "Default options" msgstr "" @@ -1065,6 +1364,14 @@ msgstr "" msgid "Roles" msgstr "" +#: taiga/projects/services/stats.py:72 +msgid "Future sprint" +msgstr "" + +#: taiga/projects/services/stats.py:89 +msgid "Project End" +msgstr "" + #: taiga/projects/tasks/api.py:57 taiga/projects/tasks/api.py:60 #: taiga/projects/tasks/api.py:63 taiga/projects/tasks/api.py:66 msgid "You don't have permissions for add/modify this task." @@ -1189,15 +1496,15 @@ msgstr "" msgid "There's no user story with that id" msgstr "" -#: taiga/projects/validators.py:12 +#: taiga/projects/validators.py:28 msgid "There's no project with that id" msgstr "" -#: taiga/projects/validators.py:21 +#: taiga/projects/validators.py:37 msgid "There's no user story status with that id" msgstr "" -#: taiga/projects/validators.py:30 +#: taiga/projects/validators.py:46 msgid "There's no task status with that id" msgstr "" @@ -1286,12 +1593,12 @@ msgstr "" msgid "Not valid email" msgstr "" -#: taiga/users/api.py:246 taiga/users/api.py:252 +#: taiga/users/api.py:247 taiga/users/api.py:253 msgid "" "Invalid, are you sure the token is correct and you didn't use it before?" msgstr "" -#: taiga/users/api.py:279 taiga/users/api.py:287 taiga/users/api.py:290 +#: taiga/users/api.py:280 taiga/users/api.py:288 taiga/users/api.py:291 msgid "Invalid, are you sure the token is correct?" msgstr "" @@ -1364,23 +1671,18 @@ msgstr "" msgid "permissions" msgstr "" -#: taiga/users/serializers.py:52 -msgid "invalid username" -msgstr "" - #: taiga/users/serializers.py:53 msgid "invalid" msgstr "" -#: taiga/users/serializers.py:58 -msgid "" -"Required. 255 characters or fewer. Letters, numbers and /./-/_ characters'" -msgstr "" - #: taiga/users/serializers.py:64 msgid "Invalid username. Try with a different one." msgstr "" +#: taiga/users/services.py:48 taiga/users/services.py:52 +msgid "Username or password does not matches user." +msgstr "" + #: taiga/users/templates/emails/change_email-body-html.jinja:4 #, python-format msgid "" @@ -1507,25 +1809,25 @@ msgid "secret key" msgstr "" #: taiga/webhooks/models.py:39 -msgid "Status code" +msgid "status code" msgstr "" #: taiga/webhooks/models.py:40 -msgid "Request data" +msgid "request data" msgstr "" #: taiga/webhooks/models.py:41 -msgid "Request headers" +msgid "request headers" msgstr "" #: taiga/webhooks/models.py:42 -msgid "Response data" +msgid "response data" msgstr "" #: taiga/webhooks/models.py:43 -msgid "Response headers" +msgid "response headers" msgstr "" #: taiga/webhooks/models.py:44 -msgid "Duration" +msgid "duration" msgstr "" diff --git a/taiga/projects/api.py b/taiga/projects/api.py index f7317873..f0695984 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -18,7 +18,7 @@ import uuid from django.db.models import signals from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.base import filters from taiga.base import response @@ -186,10 +186,10 @@ class ProjectViewSet(ModelCrudViewSet): template_description = request.DATA.get('template_description', None) if not template_name: - raise response.BadRequest("Not valid template name") + raise response.BadRequest(_("Not valid template name")) if not template_description: - raise response.BadRequest("Not valid template description") + raise response.BadRequest(_("Not valid template description")) template_slug = slugify_uniquely(template_name, models.ProjectTemplate) diff --git a/taiga/projects/attachments/api.py b/taiga/projects/attachments/api.py index 383dcbba..0d26a0a8 100644 --- a/taiga/projects/attachments/api.py +++ b/taiga/projects/attachments/api.py @@ -14,24 +14,18 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import os import os.path as path -import hashlib import mimetypes mimetypes.init() +from django.utils.translation import ugettext as _ from django.contrib.contenttypes.models import ContentType -from django.conf import settings -from django import http from taiga.base import filters from taiga.base import exceptions as exc -from taiga.base.api import generics from taiga.base.api import ModelCrudViewSet from taiga.base.api.utils import get_object_or_404 -from taiga.users.models import User - from taiga.projects.notifications.mixins import WatchedResourceMixin from taiga.projects.history.mixins import HistoryResourceMixin @@ -50,7 +44,7 @@ class BaseAttachmentViewSet(HistoryResourceMixin, WatchedResourceMixin, ModelCru def update(self, *args, **kwargs): partial = kwargs.get("partial", False) if not partial: - raise exc.NotSupported("Non partial updates not supported") + raise exc.NotSupported(_("Non partial updates not supported")) return super().update(*args, **kwargs) def get_content_type(self): @@ -65,7 +59,7 @@ class BaseAttachmentViewSet(HistoryResourceMixin, WatchedResourceMixin, ModelCru obj.name = path.basename(obj.attached_file.name).lower() if obj.project_id != obj.content_object.project_id: - raise exc.WrongArguments("Project ID not matches between object and project") + raise exc.WrongArguments(_("Project ID not matches between object and project")) super().pre_save(obj) diff --git a/taiga/projects/choices.py b/taiga/projects/choices.py index d1c9171b..4ab6f2e0 100644 --- a/taiga/projects/choices.py +++ b/taiga/projects/choices.py @@ -14,7 +14,10 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from django.utils.translation import ugettext_lazy as _ + + VIDEOCONFERENCES_CHOICES = ( - ("appear-in", "AppearIn"), - ("talky", "Talky"), + ("appear-in", _("AppearIn")), + ("talky", _("Talky")), ) diff --git a/taiga/projects/history/api.py b/taiga/projects/history/api.py index 49023f94..2d6c365b 100644 --- a/taiga/projects/history/api.py +++ b/taiga/projects/history/api.py @@ -15,6 +15,7 @@ # along with this program. If not, see . from django.contrib.contenttypes.models import ContentType +from django.utils.translation import ugettext as _ from django.utils import timezone from taiga.base import response @@ -66,7 +67,7 @@ class HistoryViewSet(ReadOnlyListViewSet): return response.NotFound() if comment.delete_comment_date or comment.delete_comment_user: - return response.BadRequest({"error": "Comment already deleted"}) + return response.BadRequest({"error": _("Comment already deleted")}) comment.delete_comment_date = timezone.now() comment.delete_comment_user = {"pk": request.user.pk, "name": request.user.get_full_name()} @@ -85,7 +86,7 @@ class HistoryViewSet(ReadOnlyListViewSet): return response.NotFound() if not comment.delete_comment_date and not comment.delete_comment_user: - return response.BadRequest({"error": "Comment not deleted"}) + return response.BadRequest({"error": _("Comment not deleted")}) comment.delete_comment_date = None comment.delete_comment_user = None diff --git a/taiga/projects/history/mixins.py b/taiga/projects/history/mixins.py index 573f778f..9e379f77 100644 --- a/taiga/projects/history/mixins.py +++ b/taiga/projects/history/mixins.py @@ -33,7 +33,7 @@ class HistoryResourceMixin(object): def get_last_history(self): if not self.__object_saved: - message = ("get_last_history() function called before any object are saved. " + message = ("get_last_history() function called before any object are saved. " "Seems you have a wrong mixing order on your resource.") warnings.warn(message, RuntimeWarning) return self.__last_history diff --git a/taiga/projects/issues/api.py b/taiga/projects/issues/api.py index d51f6686..3a6133d6 100644 --- a/taiga/projects/issues/api.py +++ b/taiga/projects/issues/api.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from django.db.models import Q from django.http import Http404, HttpResponse diff --git a/taiga/projects/milestones/models.py b/taiga/projects/milestones/models.py index 22a9b179..7e18048e 100644 --- a/taiga/projects/milestones/models.py +++ b/taiga/projects/milestones/models.py @@ -72,7 +72,7 @@ class Milestone(WatchedModelMixin, models.Model): def clean(self): # Don't allow draft entries to have a pub_date. if self.estimated_start and self.estimated_finish and self.estimated_start > self.estimated_finish: - raise ValidationError('The estimated start must be previous to the estimated finish.') + raise ValidationError(_('The estimated start must be previous to the estimated finish.')) def save(self, *args, **kwargs): if not self._importing or not self.modified_date: diff --git a/taiga/projects/milestones/serializers.py b/taiga/projects/milestones/serializers.py index e333c71f..aa46539d 100644 --- a/taiga/projects/milestones/serializers.py +++ b/taiga/projects/milestones/serializers.py @@ -14,15 +14,16 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -import json +from django.utils.translation import ugettext as _ from rest_framework import serializers +from taiga.base.utils import json + from ..userstories.serializers import UserStorySerializer from . import models - class MilestoneSerializer(serializers.ModelSerializer): user_stories = UserStorySerializer(many=True, required=False, read_only=True) total_points = serializers.SerializerMethodField("get_total_points") @@ -59,6 +60,6 @@ class MilestoneSerializer(serializers.ModelSerializer): qs = models.Milestone.objects.filter(project=attrs["project"], name=attrs[source]) if qs and qs.exists(): - raise serializers.ValidationError("Name duplicated for the project") + raise serializers.ValidationError(_("Name duplicated for the project")) return attrs diff --git a/taiga/projects/milestones/validators.py b/taiga/projects/milestones/validators.py index 7add2199..2e767b3e 100644 --- a/taiga/projects/milestones/validators.py +++ b/taiga/projects/milestones/validators.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from rest_framework import serializers diff --git a/taiga/projects/mixins/ordering.py b/taiga/projects/mixins/ordering.py index e9438d27..b818a25e 100644 --- a/taiga/projects/mixins/ordering.py +++ b/taiga/projects/mixins/ordering.py @@ -15,7 +15,7 @@ # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.base import response from taiga.base import exceptions as exc diff --git a/taiga/projects/notifications/models.py b/taiga/projects/notifications/models.py index 6b631abc..29983f90 100644 --- a/taiga/projects/notifications/models.py +++ b/taiga/projects/notifications/models.py @@ -18,9 +18,11 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils import timezone -from .choices import NOTIFY_LEVEL_CHOICES from taiga.projects.history.choices import HISTORY_TYPE_CHOICES +from .choices import NOTIFY_LEVEL_CHOICES + + class NotifyPolicy(models.Model): """ This class represents a persistence for @@ -52,19 +54,19 @@ class HistoryChangeNotification(models.Model): """ key = models.CharField(max_length=255, unique=False, editable=False) owner = models.ForeignKey("users.User", null=False, blank=False, - verbose_name="owner",related_name="+") + verbose_name=_("owner"), related_name="+") created_datetime = models.DateTimeField(null=False, blank=False, auto_now_add=True, verbose_name=_("created date time")) updated_datetime = models.DateTimeField(null=False, blank=False, auto_now_add=True, verbose_name=_("updated date time")) history_entries = models.ManyToManyField("history.HistoryEntry", null=True, blank=True, - verbose_name="history entries", + verbose_name=_("history entries"), related_name="+") notify_users = models.ManyToManyField("users.User", null=True, blank=True, - verbose_name="notify users", + verbose_name=_("notify users"), related_name="+") project = models.ForeignKey("projects.Project", null=False, blank=False, - verbose_name="project",related_name="+") + verbose_name=_("project"),related_name="+") history_type = models.SmallIntegerField(choices=HISTORY_TYPE_CHOICES) diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index b066da34..d8bfaa24 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -22,6 +22,7 @@ from django.contrib.contenttypes.models import ContentType from django.utils import timezone from django.db import transaction from django.conf import settings +from django.utils.translation import ugettext as _ from djmail import template_mail @@ -37,6 +38,7 @@ from taiga.users.models import User from .models import HistoryChangeNotification + def notify_policy_exists(project, user) -> bool: """ Check if policy exists for specified project @@ -58,7 +60,7 @@ def create_notify_policy(project, user, level=NotifyLevel.notwatch): user=user, notify_level=level) except IntegrityError as e: - raise exc.IntegrityError("Notify exists for specified user and project") from e + raise exc.IntegrityError(_("Notify exists for specified user and project")) from e def create_notify_policy_if_not_exists(project, user, level=NotifyLevel.notwatch): @@ -72,7 +74,7 @@ def create_notify_policy_if_not_exists(project, user, level=NotifyLevel.notwatch defaults={"notify_level": level}) return result[0] except IntegrityError as e: - raise exc.IntegrityError("Notify exists for specified user and project") from e + raise exc.IntegrityError(_("Notify exists for specified user and project")) from e def get_notify_policy(project, user): @@ -256,8 +258,7 @@ def send_sync_notifications(notification_id): obj, _ = get_last_snapshot_for_key(notification.key) obj_class = get_model_from_key(obj.key) - context = { - "obj_class": obj_class, + context = {"obj_class": obj_class, "snapshot": obj.snapshot, "project": notification.project, "changer": notification.owner, diff --git a/taiga/projects/notifications/validators.py b/taiga/projects/notifications/validators.py index 5088d446..66a07d98 100644 --- a/taiga/projects/notifications/validators.py +++ b/taiga/projects/notifications/validators.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from rest_framework import serializers @@ -40,6 +40,6 @@ class WatchersValidator: # in project members list result = set(users).difference(set(project.members.all())) if result: - raise serializers.ValidationError("Watchers contains invalid users") + raise serializers.ValidationError(_("Watchers contains invalid users")) return attrs diff --git a/taiga/projects/occ/mixins.py b/taiga/projects/occ/mixins.py index c9bdeeac..0e37685b 100644 --- a/taiga/projects/occ/mixins.py +++ b/taiga/projects/occ/mixins.py @@ -31,7 +31,7 @@ class OCCResourceMixin(object): try: param_version = param_version and int(param_version) except (ValueError, TypeError): - raise exc.WrongArguments({"version": "The version must be an integer"}) + raise exc.WrongArguments({"version": _("The version must be an integer")}) return param_version @@ -52,7 +52,7 @@ class OCCResourceMixin(object): # Extract param version param_version = self._extract_param_version() if not self._validate_param_version(param_version, current_version): - raise exc.WrongArguments({"version": "The version is not valid"}) + raise exc.WrongArguments({"version": _("The version is not valid")}) if current_version != param_version: diff_versions = current_version - param_version @@ -68,7 +68,7 @@ class OCCResourceMixin(object): both_modified = modifying_fields & modified_fields if both_modified: - raise exc.WrongArguments({"version": "The version doesn't match with the current one"}) + raise exc.WrongArguments({"version": _("The version doesn't match with the current one")}) if obj.id: obj.version = models.F('version') + 1 diff --git a/taiga/projects/permissions.py b/taiga/projects/permissions.py index 08b900a7..5483e3d6 100644 --- a/taiga/projects/permissions.py +++ b/taiga/projects/permissions.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.base.api.permissions import TaigaResourcePermission from taiga.base.api.permissions import HasProjectPerm diff --git a/taiga/projects/serializers.py b/taiga/projects/serializers.py index 5d9d3a4d..2dfb27aa 100644 --- a/taiga/projects/serializers.py +++ b/taiga/projects/serializers.py @@ -15,7 +15,7 @@ # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from django.db.models import Q from rest_framework import serializers @@ -61,7 +61,7 @@ class PointsSerializer(ModelSerializer): qs = models.Points.objects.filter(project=attrs["project"], name=attrs[source]) if qs and qs.exists(): - raise serializers.ValidationError("Name duplicated for the project") + raise serializers.ValidationError(_("Name duplicated for the project")) return attrs @@ -85,7 +85,7 @@ class UserStoryStatusSerializer(ModelSerializer): name=attrs[source]) if qs and qs.exists(): - raise serializers.ValidationError("Name duplicated for the project") + raise serializers.ValidationError(_("Name duplicated for the project")) return attrs @@ -107,7 +107,7 @@ class TaskStatusSerializer(ModelSerializer): qs = models.TaskStatus.objects.filter(project=attrs["project"], name=attrs[source]) if qs and qs.exists(): - raise serializers.ValidationError("Name duplicated for the project") + raise serializers.ValidationError(_("Name duplicated for the project")) return attrs @@ -139,7 +139,7 @@ class IssueStatusSerializer(ModelSerializer): qs = models.IssueStatus.objects.filter(project=attrs["project"], name=attrs[source]) if qs and qs.exists(): - raise serializers.ValidationError("Name duplicated for the project") + raise serializers.ValidationError(_("Name duplicated for the project")) return attrs @@ -310,7 +310,7 @@ class ProjectSerializer(ModelSerializer): """ value = attrs[source] if value is None: - raise serializers.ValidationError("Total milestones must be major or equal to zero") + raise serializers.ValidationError(_("Total milestones must be major or equal to zero")) return attrs diff --git a/taiga/projects/services/stats.py b/taiga/projects/services/stats.py index c852459f..b7586cb5 100644 --- a/taiga/projects/services/stats.py +++ b/taiga/projects/services/stats.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from django.utils.translation import ugettext as _ from django.db.models import Q, Count from django.apps import apps import datetime @@ -21,6 +22,7 @@ import copy from taiga.projects.history.models import HistoryEntry + def _get_milestones_stats_for_backlog(project): """ Get collection of stats for each millestone of project. @@ -67,7 +69,7 @@ def _get_milestones_stats_for_backlog(project): current_client_increment += sum(ml.client_increment_points.values()) else: - milestone_name = "Future sprint" + milestone_name = _("Future sprint") team_increment = current_team_increment + future_team_increment, client_increment = current_client_increment + future_client_increment, current_evolution = None @@ -84,7 +86,7 @@ def _get_milestones_stats_for_backlog(project): evolution = (project.total_story_points - current_evolution if current_evolution is not None and project.total_story_points else None) yield { - 'name': 'Project End', + 'name': _('Project End'), 'optimal': optimal_points, 'evolution': evolution, 'team-increment': team_increment, @@ -119,8 +121,8 @@ def _count_owned_object(user_obj, counting_storage): else: counting_storage[0] = {} counting_storage[0]['count'] = 1 - counting_storage[0]['username'] = 'Unassigned' - counting_storage[0]['name'] = 'Unassigned' + counting_storage[0]['username'] = _('Unassigned') + counting_storage[0]['name'] = _('Unassigned') counting_storage[0]['id'] = 0 counting_storage[0]['color'] = 'black' diff --git a/taiga/projects/tasks/api.py b/taiga/projects/tasks/api.py index 92d94908..64b05d9d 100644 --- a/taiga/projects/tasks/api.py +++ b/taiga/projects/tasks/api.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from taiga.base.api.utils import get_object_or_404 from taiga.base import filters, response diff --git a/taiga/projects/tasks/validators.py b/taiga/projects/tasks/validators.py index c7f1293b..38089fe7 100644 --- a/taiga/projects/tasks/validators.py +++ b/taiga/projects/tasks/validators.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from rest_framework import serializers diff --git a/taiga/projects/userstories/validators.py b/taiga/projects/userstories/validators.py index 7c31670b..3efd7b8f 100644 --- a/taiga/projects/userstories/validators.py +++ b/taiga/projects/userstories/validators.py @@ -14,9 +14,9 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ -from rest_framework import serializers +from taiga.base.api import serializers from . import models diff --git a/taiga/projects/validators.py b/taiga/projects/validators.py index 700fa3ab..9659261e 100644 --- a/taiga/projects/validators.py +++ b/taiga/projects/validators.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from rest_framework import serializers diff --git a/taiga/projects/wiki/api.py b/taiga/projects/wiki/api.py index f67150bf..d21269df 100644 --- a/taiga/projects/wiki/api.py +++ b/taiga/projects/wiki/api.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from rest_framework.permissions import IsAuthenticated diff --git a/taiga/users/api.py b/taiga/users/api.py index 36dff9b1..9265865d 100644 --- a/taiga/users/api.py +++ b/taiga/users/api.py @@ -18,7 +18,7 @@ import uuid from django.apps import apps from django.db.models import Q -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from django.core.validators import validate_email from django.core.exceptions import ValidationError from django.conf import settings diff --git a/taiga/users/services.py b/taiga/users/services.py index 9366cee8..99b8975d 100644 --- a/taiga/users/services.py +++ b/taiga/users/services.py @@ -21,6 +21,7 @@ This model contains a domain logic for users application. from django.apps import apps from django.db.models import Q from django.conf import settings +from django.utils.translation import ugettext as _ from easy_thumbnails.files import get_thumbnailer from easy_thumbnails.exceptions import InvalidImageFormatError @@ -44,11 +45,11 @@ def get_and_validate_user(*, username:str, password:str) -> bool: qs = user_model.objects.filter(Q(username=username) | Q(email=username)) if len(qs) == 0: - raise exc.WrongArguments("Username or password does not matches user.") + raise exc.WrongArguments(_("Username or password does not matches user.")) user = qs[0] if not user.check_password(password): - raise exc.WrongArguments("Username or password does not matches user.") + raise exc.WrongArguments(_("Username or password does not matches user.")) return user @@ -80,6 +81,10 @@ def get_big_photo_url(photo): def get_big_photo_or_gravatar_url(user): """Get the user's big photo/gravatar url.""" - if user: - return get_big_photo_url(user.photo) if user.photo else get_gravatar_url(user.email, size=settings.DEFAULT_BIG_AVATAR_SIZE) - return "" + if not user: + return "" + + if user.photo: + return get_big_photo_url(user.photo) + else: + return get_gravatar_url(user.email, size=settings.DEFAULT_BIG_AVATAR_SIZE) diff --git a/taiga/users/validators.py b/taiga/users/validators.py index 1f26ffa5..7a83ed3c 100644 --- a/taiga/users/validators.py +++ b/taiga/users/validators.py @@ -15,7 +15,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from rest_framework import serializers diff --git a/taiga/userstorage/api.py b/taiga/userstorage/api.py index 31324c17..6755f3ac 100644 --- a/taiga/userstorage/api.py +++ b/taiga/userstorage/api.py @@ -14,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext as _ from django.db import IntegrityError from taiga.base.api import ModelCrudViewSet diff --git a/taiga/webhooks/models.py b/taiga/webhooks/models.py index 41f6fc84..0704b77b 100644 --- a/taiga/webhooks/models.py +++ b/taiga/webhooks/models.py @@ -36,12 +36,12 @@ class WebhookLog(models.Model): webhook = models.ForeignKey(Webhook, null=False, blank=False, related_name="logs") url = models.URLField(null=False, blank=False, verbose_name=_("URL")) - status = models.IntegerField(null=False, blank=False, verbose_name=_("Status code")) - request_data = JsonField(null=False, blank=False, verbose_name=_("Request data")) - request_headers = JsonField(null=False, blank=False, verbose_name=_("Request headers"), default={}) - response_data = models.TextField(null=False, blank=False, verbose_name=_("Response data")) - response_headers = JsonField(null=False, blank=False, verbose_name=_("Response headers"), default={}) - duration = models.FloatField(null=False, blank=False, verbose_name=_("Duration"), default=0) + status = models.IntegerField(null=False, blank=False, verbose_name=_("status code")) + request_data = JsonField(null=False, blank=False, verbose_name=_("request data")) + request_headers = JsonField(null=False, blank=False, verbose_name=_("request headers"), default={}) + response_data = models.TextField(null=False, blank=False, verbose_name=_("response data")) + response_headers = JsonField(null=False, blank=False, verbose_name=_("response headers"), default={}) + duration = models.FloatField(null=False, blank=False, verbose_name=_("duration"), default=0) created = models.DateTimeField(auto_now_add=True) class Meta: