15049 add missing gettext to error strings

This commit is contained in:
Arthur 2024-02-14 08:54:49 -08:00
parent 7cc215437f
commit 4416657681
22 changed files with 82 additions and 62 deletions

View File

@ -234,9 +234,9 @@ class CircuitTermination(
# Must define either site *or* provider network
if self.site is None and self.provider_network is None:
raise ValidationError("A circuit termination must attach to either a site or a provider network.")
raise ValidationError(_("A circuit termination must attach to either a site or a provider network."))
if self.site and self.provider_network:
raise ValidationError("A circuit termination cannot attach to both a site and a provider network.")
raise ValidationError(_("A circuit termination cannot attach to both a site and a provider network."))
def to_objectchange(self, action):
objectchange = super().to_objectchange(action)

View File

@ -103,9 +103,9 @@ class ManagedFileForm(SyncedDataMixin, NetBoxModelForm):
super().clean()
if self.cleaned_data.get('upload_file') and self.cleaned_data.get('data_file'):
raise forms.ValidationError("Cannot upload a file and sync from an existing file")
raise forms.ValidationError(_("Cannot upload a file and sync from an existing file"))
if not self.cleaned_data.get('upload_file') and not self.cleaned_data.get('data_file'):
raise forms.ValidationError("Must upload a file or select a data file to sync")
raise forms.ValidationError(_("Must upload a file or select a data file to sync"))
return self.cleaned_data

View File

@ -177,7 +177,7 @@ class DataSource(JobsMixin, PrimaryModel):
Create/update/delete child DataFiles as necessary to synchronize with the remote source.
"""
if self.status == DataSourceStatusChoices.SYNCING:
raise SyncError("Cannot initiate sync; syncing already in progress.")
raise SyncError(_("Cannot initiate sync; syncing already in progress."))
# Emit the pre_sync signal
pre_sync.send(sender=self.__class__, instance=self)
@ -190,7 +190,7 @@ class DataSource(JobsMixin, PrimaryModel):
backend = self.get_backend()
except ModuleNotFoundError as e:
raise SyncError(
f"There was an error initializing the backend. A dependency needs to be installed: {e}"
_("There was an error initializing the backend. A dependency needs to be installed: ") + str(e)
)
with backend.fetch() as local_path:

View File

@ -160,24 +160,24 @@ class Cable(PrimaryModel):
# Validate length and length_unit
if self.length is not None and not self.length_unit:
raise ValidationError("Must specify a unit when setting a cable length")
raise ValidationError(_("Must specify a unit when setting a cable length"))
if self.pk is None and (not self.a_terminations or not self.b_terminations):
raise ValidationError("Must define A and B terminations when creating a new cable.")
raise ValidationError(_("Must define A and B terminations when creating a new cable."))
if self._terminations_modified:
# Check that all termination objects for either end are of the same type
for terms in (self.a_terminations, self.b_terminations):
if len(terms) > 1 and not all(isinstance(t, type(terms[0])) for t in terms[1:]):
raise ValidationError("Cannot connect different termination types to same end of cable.")
raise ValidationError(_("Cannot connect different termination types to same end of cable."))
# Check that termination types are compatible
if self.a_terminations and self.b_terminations:
a_type = self.a_terminations[0]._meta.model_name
b_type = self.b_terminations[0]._meta.model_name
if b_type not in COMPATIBLE_TERMINATION_TYPES.get(a_type):
raise ValidationError(f"Incompatible termination types: {a_type} and {b_type}")
raise ValidationError(_("Incompatible termination types: ") + str(a_type) + _(" and ") + str(b_type))
if a_type == b_type:
# can't directly use self.a_terminations here as possible they
@ -323,17 +323,21 @@ class CableTermination(ChangeLoggedModel):
).first()
if existing_termination is not None:
raise ValidationError(
f"Duplicate termination found for {self.termination_type.app_label}.{self.termination_type.model} "
f"{self.termination_id}: cable {existing_termination.cable.pk}"
_("Duplicate termination found for {app_label}.{model} {termination_id}: cable {cable_pk}".format(
app_label=self.termination_type.app_label,
model=self.termination_type.model,
termination_id=self.termination_id,
cable_pk=existing_termination.cable.pk))
)
# Validate interface type (if applicable)
if self.termination_type.model == 'interface' and self.termination.type in NONCONNECTABLE_IFACE_TYPES:
raise ValidationError(f"Cables cannot be terminated to {self.termination.get_type_display()} interfaces")
raise ValidationError(_("Cables cannot be terminated to {type_display} interfaces").format(
type_display=self.termination.get_type_display()))
# A CircuitTermination attached to a ProviderNetwork cannot have a Cable
if self.termination_type.model == 'circuittermination' and self.termination.provider_network is not None:
raise ValidationError("Circuit terminations attached to a provider network may not be cabled.")
raise ValidationError(_("Circuit terminations attached to a provider network may not be cabled."))
def save(self, *args, **kwargs):

View File

@ -1,6 +1,7 @@
from django.contrib.auth import get_user_model
from django.test import override_settings
from django.urls import reverse
from django.utils.translation import gettext as _
from rest_framework import status
from dcim.choices import *
@ -45,7 +46,7 @@ class Mixins:
name='Peer Device'
)
if self.peer_termination_type is None:
raise NotImplementedError("Test case must set peer_termination_type")
raise NotImplementedError(_("Test case must set peer_termination_type"))
peer_obj = self.peer_termination_type.objects.create(
device=peer_device,
name='Peer Termination'

View File

@ -1,5 +1,6 @@
from django.contrib.auth import get_user_model
from django.core.exceptions import ObjectDoesNotExist
from django.utils.translation import gettext as _
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
@ -150,7 +151,7 @@ class CustomFieldSerializer(ValidatedModelSerializer):
def validate_type(self, value):
if self.instance and self.instance.type != value:
raise serializers.ValidationError('Changing the type of custom fields is not supported.')
raise serializers.ValidationError(_('Changing the type of custom fields is not supported.'))
return value
@ -545,12 +546,12 @@ class ReportInputSerializer(serializers.Serializer):
def validate_schedule_at(self, value):
if value and not self.context['report'].scheduling_enabled:
raise serializers.ValidationError("Scheduling is not enabled for this report.")
raise serializers.ValidationError(_("Scheduling is not enabled for this report."))
return value
def validate_interval(self, value):
if value and not self.context['report'].scheduling_enabled:
raise serializers.ValidationError("Scheduling is not enabled for this report.")
raise serializers.ValidationError(_("Scheduling is not enabled for this report."))
return value
@ -595,12 +596,12 @@ class ScriptInputSerializer(serializers.Serializer):
def validate_schedule_at(self, value):
if value and not self.context['script'].scheduling_enabled:
raise serializers.ValidationError("Scheduling is not enabled for this script.")
raise serializers.ValidationError(_("Scheduling is not enabled for this script."))
return value
def validate_interval(self, value):
if value and not self.context['script'].scheduling_enabled:
raise serializers.ValidationError("Scheduling is not enabled for this script.")
raise serializers.ValidationError(_("Scheduling is not enabled for this script."))
return value

View File

@ -178,7 +178,7 @@ class ObjectCountsWidget(DashboardWidget):
try:
dict(data)
except TypeError:
raise forms.ValidationError("Invalid format. Object filters must be passed as a dictionary.")
raise forms.ValidationError(_("Invalid format. Object filters must be passed as a dictionary."))
return data
def render(self, request):
@ -232,7 +232,7 @@ class ObjectListWidget(DashboardWidget):
try:
urlencode(data)
except (TypeError, ValueError):
raise forms.ValidationError("Invalid format. URL parameters must be passed as a dictionary.")
raise forms.ValidationError(_("Invalid format. URL parameters must be passed as a dictionary."))
return data
def render(self, request):

View File

@ -1,5 +1,6 @@
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand, CommandError
from django.utils.translation import gettext as _
from netbox.registry import registry
from netbox.search.backends import search_backend
@ -62,7 +63,7 @@ class Command(BaseCommand):
# Determine which models to reindex
indexers = self._get_indexers(*model_labels)
if not indexers:
raise CommandError("No indexers found!")
raise CommandError(_("No indexers found!"))
self.stdout.write(f'Reindexing {len(indexers)} models.')
# Clear all cached values for the specified models (if not being lazy)

View File

@ -11,6 +11,7 @@ from django.conf import settings
from django.core.validators import RegexValidator
from django.db import transaction
from django.utils.functional import classproperty
from django.utils.translation import gettext as _
from core.choices import JobStatusChoices
from core.models import Job
@ -356,7 +357,7 @@ class BaseScript:
return ordered_vars
def run(self, data, commit):
raise NotImplementedError("The script must define a run() method.")
raise NotImplementedError(_("The script must define a run() method."))
# Form rendering
@ -367,11 +368,11 @@ class BaseScript:
fieldsets.extend(self.fieldsets)
else:
fields = list(name for name, _ in self._get_vars().items())
fieldsets.append(('Script Data', fields))
fieldsets.append((_('Script Data'), fields))
# Append the default fieldset if defined in the Meta class
exec_parameters = ('_schedule_at', '_interval', '_commit') if self.scheduling_enabled else ('_commit',)
fieldsets.append(('Script Execution Parameters', exec_parameters))
fieldsets.append((_('Script Execution Parameters'), exec_parameters))
return fieldsets

View File

@ -3,6 +3,7 @@ from copy import deepcopy
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db import transaction
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from django_pglocks import advisory_lock
from drf_spectacular.utils import extend_schema
from netaddr import IPSet
@ -379,7 +380,7 @@ class AvailablePrefixesView(AvailableObjectsView):
'vrf': parent.vrf.pk if parent.vrf else None,
})
else:
raise ValidationError("Insufficient space is available to accommodate the requested prefix size(s)")
raise ValidationError(_("Insufficient space is available to accommodate the requested prefix size(s)"))
return requested_objects

View File

@ -1,6 +1,7 @@
from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from django.utils.translation import gettext as _
from netaddr import AddrFormatError, IPNetwork
from . import lookups, validators
@ -32,7 +33,7 @@ class BaseIPField(models.Field):
# Always return a netaddr.IPNetwork object. (netaddr.IPAddress does not provide a mask.)
return IPNetwork(value)
except AddrFormatError:
raise ValidationError("Invalid IP address format: {}".format(value))
raise ValidationError(_("Invalid IP address format: {}").format(value))
except (TypeError, ValueError) as e:
raise ValidationError(e)

View File

@ -1,6 +1,7 @@
from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import validate_ipv4_address, validate_ipv6_address
from django.utils.translation import gettext_lazy as _
from netaddr import IPAddress, IPNetwork, AddrFormatError
@ -10,7 +11,7 @@ from netaddr import IPAddress, IPNetwork, AddrFormatError
class IPAddressFormField(forms.Field):
default_error_messages = {
'invalid': "Enter a valid IPv4 or IPv6 address (without a mask).",
'invalid': _("Enter a valid IPv4 or IPv6 address (without a mask)."),
}
def to_python(self, value):
@ -28,19 +29,19 @@ class IPAddressFormField(forms.Field):
try:
validate_ipv6_address(value)
except ValidationError:
raise ValidationError("Invalid IPv4/IPv6 address format: {}".format(value))
raise ValidationError(_("Invalid IPv4/IPv6 address format: {}").format(value))
try:
return IPAddress(value)
except ValueError:
raise ValidationError('This field requires an IP address without a mask.')
raise ValidationError(_('This field requires an IP address without a mask.'))
except AddrFormatError:
raise ValidationError("Please specify a valid IPv4 or IPv6 address.")
raise ValidationError(_("Please specify a valid IPv4 or IPv6 address."))
class IPNetworkFormField(forms.Field):
default_error_messages = {
'invalid': "Enter a valid IPv4 or IPv6 address (with CIDR mask).",
'invalid': _("Enter a valid IPv4 or IPv6 address (with CIDR mask)."),
}
def to_python(self, value):
@ -52,9 +53,9 @@ class IPNetworkFormField(forms.Field):
# Ensure that a subnet mask has been specified. This prevents IPs from defaulting to a /32 or /128.
if len(value.split('/')) != 2:
raise ValidationError('CIDR mask (e.g. /24) is required.')
raise ValidationError(_('CIDR mask (e.g. /24) is required.'))
try:
return IPNetwork(value)
except AddrFormatError:
raise ValidationError("Please specify a valid IPv4 or IPv6 address.")
raise ValidationError(_("Please specify a valid IPv4 or IPv6 address."))

View File

@ -751,4 +751,4 @@ class ServiceCreateForm(ServiceForm):
if not self.cleaned_data['description']:
self.cleaned_data['description'] = service_template.description
elif not all(self.cleaned_data[f] for f in ('name', 'protocol', 'ports')):
raise forms.ValidationError("Must specify name, protocol, and port(s) if not using a service template.")
raise forms.ValidationError(_("Must specify name, protocol, and port(s) if not using a service template."))

View File

@ -1,14 +1,15 @@
from django.core.exceptions import ValidationError
from django.core.validators import BaseValidator, RegexValidator
from django.utils.translation import gettext_lazy as _
def prefix_validator(prefix):
if prefix.ip != prefix.cidr.ip:
raise ValidationError("{} is not a valid prefix. Did you mean {}?".format(prefix, prefix.cidr))
raise ValidationError(_("{} is not a valid prefix. Did you mean {}?").format(prefix, prefix.cidr))
class MaxPrefixLengthValidator(BaseValidator):
message = 'The prefix length must be less than or equal to %(limit_value)s.'
message = _('The prefix length must be less than or equal to %(limit_value)s.')
code = 'max_prefix_length'
def compare(self, a, b):
@ -16,7 +17,7 @@ class MaxPrefixLengthValidator(BaseValidator):
class MinPrefixLengthValidator(BaseValidator):
message = 'The prefix length must be greater than or equal to %(limit_value)s.'
message = _('The prefix length must be greater than or equal to %(limit_value)s.')
code = 'min_prefix_length'
def compare(self, a, b):
@ -25,6 +26,6 @@ class MinPrefixLengthValidator(BaseValidator):
DNSValidator = RegexValidator(
regex=r'^([0-9A-Za-z_-]+|\*)(\.[0-9A-Za-z_-]+)*\.?$',
message='Only alphanumeric characters, asterisks, hyphens, periods, and underscores are allowed in DNS names',
message=_('Only alphanumeric characters, asterisks, hyphens, periods, and underscores are allowed in DNS names'),
code='invalid'
)

View File

@ -1,4 +1,5 @@
from django.core.exceptions import ObjectDoesNotExist
from django.utils.translation import gettext as _
from drf_spectacular.utils import extend_schema_field
from drf_spectacular.types import OpenApiTypes
from netaddr import IPNetwork
@ -58,11 +59,11 @@ class ChoiceField(serializers.Field):
if data == '':
if self.allow_blank:
return data
raise ValidationError("This field may not be blank.")
raise ValidationError(_("This field may not be blank."))
# Provide an explicit error message if the request is trying to write a dict or list
if isinstance(data, (dict, list)):
raise ValidationError('Value must be passed directly (e.g. "foo": 123); do not use a dictionary or list.')
raise ValidationError(_('Value must be passed directly (e.g. "foo": 123); do not use a dictionary or list.'))
# Check for string representations of boolean/integer values
if hasattr(data, 'lower'):
@ -95,8 +96,8 @@ class ContentTypeField(RelatedField):
Represent a ContentType as '<app_label>.<model>'
"""
default_error_messages = {
"does_not_exist": "Invalid content type: {content_type}",
"invalid": "Invalid value. Specify a content type as '<app_label>.<model_name>'.",
"does_not_exist": _("Invalid content type: {content_type}"),
"invalid": _("Invalid value. Specify a content type as '<app_label>.<model_name>'."),
}
def to_internal_value(self, data):

View File

@ -1,6 +1,7 @@
from netbox.navigation import MenuGroup
from utilities.choices import ButtonColorChoices
from django.utils.text import slugify
from django.utils.translation import gettext as _
__all__ = (
'PluginMenu',
@ -42,11 +43,11 @@ class PluginMenuItem:
self.staff_only = staff_only
if permissions is not None:
if type(permissions) not in (list, tuple):
raise TypeError("Permissions must be passed as a tuple or list.")
raise TypeError(_("Permissions must be passed as a tuple or list."))
self.permissions = permissions
if buttons is not None:
if type(buttons) not in (list, tuple):
raise TypeError("Buttons must be passed as a tuple or list.")
raise TypeError(_("Buttons must be passed as a tuple or list."))
self.buttons = buttons
@ -64,9 +65,9 @@ class PluginMenuButton:
self.icon_class = icon_class
if permissions is not None:
if type(permissions) not in (list, tuple):
raise TypeError("Permissions must be passed as a tuple or list.")
raise TypeError(_("Permissions must be passed as a tuple or list."))
self.permissions = permissions
if color is not None:
if color not in ButtonColorChoices.values():
raise ValueError("Button color must be a choice within ButtonColorChoices.")
raise ValueError(_("Button color must be a choice within ButtonColorChoices."))
self.color = color

View File

@ -1,4 +1,5 @@
from django.template.loader import get_template
from django.utils.translation import gettext as _
__all__ = (
'PluginTemplateExtension',
@ -31,7 +32,7 @@ class PluginTemplateExtension:
if extra_context is None:
extra_context = {}
elif not isinstance(extra_context, dict):
raise TypeError("extra_context must be a dictionary")
raise TypeError(_("extra_context must be a dictionary"))
return get_template(template_name).render({**self.context, **extra_context})

View File

@ -1,4 +1,5 @@
import collections
from django.utils.translation import gettext as _
class Registry(dict):
@ -13,10 +14,10 @@ class Registry(dict):
raise KeyError(f"Invalid store: {key}")
def __setitem__(self, key, value):
raise TypeError("Cannot add stores to registry after initialization")
raise TypeError(_("Cannot add stores to registry after initialization"))
def __delitem__(self, key):
raise TypeError("Cannot delete stores from registry")
raise TypeError(_("Cannot delete stores from registry"))
# Initialize the global registry

View File

@ -93,7 +93,7 @@ class RestrictedGenericForeignKey(GenericForeignKey):
if type(queryset) is dict:
restrict_params = queryset
elif queryset is not None:
raise ValueError("Custom queryset can't be used for this lookup.")
raise ValueError(_("Custom queryset can't be used for this lookup."))
# For efficiency, group the instances by content type and then do one
# query per model

View File

@ -49,7 +49,7 @@ class BulkImportForm(BootstrapMixin, SyncedDataMixin, forms.Form):
# Determine whether we're reading from form data or an uploaded file
if self.cleaned_data['data'] and import_method != ImportMethodChoices.DIRECT:
raise forms.ValidationError("Form data must be empty when uploading/selecting a file.")
raise forms.ValidationError(_("Form data must be empty when uploading/selecting a file."))
if import_method == ImportMethodChoices.UPLOAD:
self.upload_file = 'upload_file'
file = self.files.get('upload_file')

View File

@ -6,6 +6,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db.models import ForeignKey
from django.test import override_settings
from django.urls import reverse
from django.utils.translation import gettext as _
from extras.choices import ObjectChangeActionChoices
from extras.models import ObjectChange
@ -621,7 +622,7 @@ class ViewTestCases:
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
def test_bulk_update_objects_with_permission(self):
if not hasattr(self, 'csv_update_data'):
raise NotImplementedError("The test must define csv_update_data.")
raise NotImplementedError(_("The test must define csv_update_data."))
initial_count = self._get_queryset().count()
array, csv_data = self._get_update_csv_data()

View File

@ -15,6 +15,7 @@ from django.utils import timezone
from django.utils.datastructures import MultiValueDict
from django.utils.html import escape
from django.utils.timezone import localtime
from django.utils.translation import gettext as _
from jinja2.sandbox import SandboxedEnvironment
from mptt.models import MPTTModel
@ -306,13 +307,14 @@ def to_meters(length, unit):
"""
try:
if length < 0:
raise ValueError("Length must be a positive number")
raise ValueError(_("Length must be a positive number"))
except TypeError:
raise TypeError(f"Invalid value '{length}' for length (must be a number)")
raise TypeError(_("Invalid value '{length}' for length (must be a number)").format(length=length))
valid_units = CableLengthUnitChoices.values()
if unit not in valid_units:
raise ValueError(f"Unknown unit {unit}. Must be one of the following: {', '.join(valid_units)}")
raise ValueError(_("Unknown unit {unit}. Must be one of the following: {valid_units}".format(
unit=unit, valid_units=', '.join(valid_units))))
if unit == CableLengthUnitChoices.UNIT_KILOMETER:
return length * 1000
@ -326,7 +328,7 @@ def to_meters(length, unit):
return length * Decimal(0.3048)
if unit == CableLengthUnitChoices.UNIT_INCH:
return length * Decimal(0.0254)
raise ValueError(f"Unknown unit {unit}. Must be 'km', 'm', 'cm', 'mi', 'ft', or 'in'.")
raise ValueError(_("Unknown unit {unit}. Must be 'km', 'm', 'cm', 'mi', 'ft', or 'in'.").format(unit=unit))
def to_grams(weight, unit):
@ -335,13 +337,14 @@ def to_grams(weight, unit):
"""
try:
if weight < 0:
raise ValueError("Weight must be a positive number")
raise ValueError(_("Weight must be a positive number"))
except TypeError:
raise TypeError(f"Invalid value '{weight}' for weight (must be a number)")
raise TypeError(_("Invalid value '{weight}' for weight (must be a number)").format(weight=weight))
valid_units = WeightUnitChoices.values()
if unit not in valid_units:
raise ValueError(f"Unknown unit {unit}. Must be one of the following: {', '.join(valid_units)}")
raise ValueError(_("Unknown unit {unit}. Must be one of the following: {valid_units}".format(
unit=unit, valid_units=', '.join(valid_units))))
if unit == WeightUnitChoices.UNIT_KILOGRAM:
return weight * 1000
@ -351,7 +354,7 @@ def to_grams(weight, unit):
return weight * Decimal(453.592)
if unit == WeightUnitChoices.UNIT_OUNCE:
return weight * Decimal(28.3495)
raise ValueError(f"Unknown unit {unit}. Must be 'kg', 'g', 'lb', 'oz'.")
raise ValueError(_("Unknown unit {unit}. Must be 'kg', 'g', 'lb', 'oz'.").format(unit=unit))
def render_jinja2(template_code, context):