diff --git a/netbox/circuits/forms/bulk_edit.py b/netbox/circuits/forms/bulk_edit.py index 9dba87e47..1a9366583 100644 --- a/netbox/circuits/forms/bulk_edit.py +++ b/netbox/circuits/forms/bulk_edit.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from circuits.choices import CircuitCommitRateChoices, CircuitStatusChoices from circuits.models import * @@ -26,12 +26,11 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() model = Provider fieldsets = ( @@ -44,16 +43,16 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm): class ProviderAccountBulkEditForm(NetBoxModelBulkEditForm): provider = DynamicModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() model = ProviderAccount fieldsets = ( @@ -66,6 +65,7 @@ class ProviderAccountBulkEditForm(NetBoxModelBulkEditForm): class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm): provider = DynamicModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all(), required=False ) @@ -75,12 +75,11 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm): label=_('Service ID') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() model = ProviderNetwork fieldsets = ( @@ -93,6 +92,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm): class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm): description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -106,14 +106,17 @@ class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm): class CircuitBulkEditForm(NetBoxModelBulkEditForm): type = DynamicModelChoiceField( + label=_('Type'), queryset=CircuitType.objects.all(), required=False ) provider = DynamicModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all(), required=False ) provider_account = DynamicModelChoiceField( + label=_('Provider account'), queryset=ProviderAccount.objects.all(), required=False, query_params={ @@ -121,19 +124,23 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm): } ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(CircuitStatusChoices), required=False, initial='' ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) install_date = forms.DateField( + label=_('Install date'), required=False, widget=DatePicker() ) termination_date = forms.DateField( + label=_('Termination date'), required=False, widget=DatePicker() ) @@ -145,18 +152,17 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm): ) ) description = forms.CharField( + label=_('Description'), max_length=100, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() model = Circuit fieldsets = ( - ('Circuit', ('provider', 'type', 'status', 'description')), - ('Service Parameters', ('provider_account', 'install_date', 'termination_date', 'commit_rate')), - ('Tenancy', ('tenant',)), + (_('Circuit'), ('provider', 'type', 'status', 'description')), + (_('Service Parameters'), ('provider_account', 'install_date', 'termination_date', 'commit_rate')), + (_('Tenancy'), ('tenant',)), ) nullable_fields = ( 'tenant', 'commit_rate', 'description', 'comments', diff --git a/netbox/circuits/forms/bulk_import.py b/netbox/circuits/forms/bulk_import.py index 3941ef574..d2217b45b 100644 --- a/netbox/circuits/forms/bulk_import.py +++ b/netbox/circuits/forms/bulk_import.py @@ -3,7 +3,7 @@ from django import forms from circuits.choices import CircuitStatusChoices from circuits.models import * from dcim.models import Site -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from netbox.forms import NetBoxModelImportForm from tenancy.models import Tenant from utilities.forms import BootstrapMixin @@ -31,6 +31,7 @@ class ProviderImportForm(NetBoxModelImportForm): class ProviderAccountImportForm(NetBoxModelImportForm): provider = CSVModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all(), to_field_name='name', help_text=_('Assigned provider') @@ -45,6 +46,7 @@ class ProviderAccountImportForm(NetBoxModelImportForm): class ProviderNetworkImportForm(NetBoxModelImportForm): provider = CSVModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all(), to_field_name='name', help_text=_('Assigned provider') @@ -67,26 +69,31 @@ class CircuitTypeImportForm(NetBoxModelImportForm): class CircuitImportForm(NetBoxModelImportForm): provider = CSVModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all(), to_field_name='name', help_text=_('Assigned provider') ) provider_account = CSVModelChoiceField( + label=_('Provider account'), queryset=ProviderAccount.objects.all(), to_field_name='name', help_text=_('Assigned provider account'), required=False ) type = CSVModelChoiceField( + label=_('Type'), queryset=CircuitType.objects.all(), to_field_name='name', help_text=_('Type of circuit') ) status = CSVChoiceField( + label=_('Status'), choices=CircuitStatusChoices, help_text=_('Operational status') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -103,11 +110,13 @@ class CircuitImportForm(NetBoxModelImportForm): class CircuitTerminationImportForm(BootstrapMixin, forms.ModelForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', required=False ) provider_network = CSVModelChoiceField( + label=_('Provider network'), queryset=ProviderNetwork.objects.all(), to_field_name='name', required=False diff --git a/netbox/circuits/forms/filtersets.py b/netbox/circuits/forms/filtersets.py index 83da0d50a..1fb239023 100644 --- a/netbox/circuits/forms/filtersets.py +++ b/netbox/circuits/forms/filtersets.py @@ -23,9 +23,9 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): model = Provider fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id')), - ('ASN', ('asn',)), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Location'), ('region_id', 'site_group_id', 'site_id')), + (_('ASN'), ('asn',)), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -62,7 +62,7 @@ class ProviderAccountFilterForm(NetBoxModelFilterSetForm): model = ProviderAccount fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('provider_id', 'account')), + (_('Attributes'), ('provider_id', 'account')), ) provider_id = DynamicModelMultipleChoiceField( queryset=Provider.objects.all(), @@ -70,6 +70,7 @@ class ProviderAccountFilterForm(NetBoxModelFilterSetForm): label=_('Provider') ) account = forms.CharField( + label=_('Account'), required=False ) tag = TagFilterField(model) @@ -79,7 +80,7 @@ class ProviderNetworkFilterForm(NetBoxModelFilterSetForm): model = ProviderNetwork fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('provider_id', 'service_id')), + (_('Attributes'), ('provider_id', 'service_id')), ) provider_id = DynamicModelMultipleChoiceField( queryset=Provider.objects.all(), @@ -87,6 +88,7 @@ class ProviderNetworkFilterForm(NetBoxModelFilterSetForm): label=_('Provider') ) service_id = forms.CharField( + label=_('Service id'), max_length=100, required=False ) @@ -102,11 +104,11 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi model = Circuit fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Provider', ('provider_id', 'provider_account_id', 'provider_network_id')), - ('Attributes', ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')), - ('Location', ('region_id', 'site_group_id', 'site_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Provider'), ('provider_id', 'provider_account_id', 'provider_network_id')), + (_('Attributes'), ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')), + (_('Location'), ('region_id', 'site_group_id', 'site_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) type_id = DynamicModelMultipleChoiceField( queryset=CircuitType.objects.all(), @@ -135,6 +137,7 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi label=_('Provider network') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=CircuitStatusChoices, required=False ) @@ -158,10 +161,12 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi label=_('Site') ) install_date = forms.DateField( + label=_('Install date'), required=False, widget=DatePicker ) termination_date = forms.DateField( + label=_('Termination date'), required=False, widget=DatePicker ) diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py index d3929c08a..8a540032e 100644 --- a/netbox/circuits/forms/model_forms.py +++ b/netbox/circuits/forms/model_forms.py @@ -1,4 +1,4 @@ -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from circuits.choices import CircuitCommitRateChoices, CircuitTerminationPortSpeedChoices from circuits.models import * @@ -29,7 +29,7 @@ class ProviderForm(NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Provider', ('name', 'slug', 'asns', 'description', 'tags')), + (_('Provider'), ('name', 'slug', 'asns', 'description', 'tags')), ) class Meta: @@ -41,6 +41,7 @@ class ProviderForm(NetBoxModelForm): class ProviderAccountForm(NetBoxModelForm): provider = DynamicModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all() ) comments = CommentField() @@ -54,12 +55,13 @@ class ProviderAccountForm(NetBoxModelForm): class ProviderNetworkForm(NetBoxModelForm): provider = DynamicModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all() ) comments = CommentField() fieldsets = ( - ('Provider Network', ('provider', 'name', 'service_id', 'description', 'tags')), + (_('Provider Network'), ('provider', 'name', 'service_id', 'description', 'tags')), ) class Meta: @@ -73,7 +75,7 @@ class CircuitTypeForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Circuit Type', ( + (_('Circuit Type'), ( 'name', 'slug', 'description', 'tags', )), ) @@ -87,10 +89,12 @@ class CircuitTypeForm(NetBoxModelForm): class CircuitForm(TenancyForm, NetBoxModelForm): provider = DynamicModelChoiceField( + label=_('Provider'), queryset=Provider.objects.all(), selector=True ) provider_account = DynamicModelChoiceField( + label=_('Provider account'), queryset=ProviderAccount.objects.all(), required=False, query_params={ @@ -103,9 +107,9 @@ class CircuitForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Circuit', ('provider', 'provider_account', 'cid', 'type', 'status', 'description', 'tags')), - ('Service Parameters', ('install_date', 'termination_date', 'commit_rate')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('Circuit'), ('provider', 'provider_account', 'cid', 'type', 'status', 'description', 'tags')), + (_('Service Parameters'), ('install_date', 'termination_date', 'commit_rate')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -125,15 +129,18 @@ class CircuitForm(TenancyForm, NetBoxModelForm): class CircuitTerminationForm(NetBoxModelForm): circuit = DynamicModelChoiceField( + label=_('Circuit'), queryset=Circuit.objects.all(), selector=True ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, selector=True ) provider_network = DynamicModelChoiceField( + label=_('Provider network'), queryset=ProviderNetwork.objects.all(), required=False, selector=True diff --git a/netbox/core/forms/bulk_edit.py b/netbox/core/forms/bulk_edit.py index de8727643..a4ecd646f 100644 --- a/netbox/core/forms/bulk_edit.py +++ b/netbox/core/forms/bulk_edit.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from core.choices import DataSourceTypeChoices from core.models import * @@ -15,6 +15,7 @@ __all__ = ( class DataSourceBulkEditForm(NetBoxModelBulkEditForm): type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(DataSourceTypeChoices), required=False, initial='' @@ -25,16 +26,17 @@ class DataSourceBulkEditForm(NetBoxModelBulkEditForm): label=_('Enforce unique space') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() parameters = forms.JSONField( + label=_('Parameters'), required=False ) ignore_rules = forms.CharField( + label=_('Ignore rules'), required=False, widget=forms.Textarea() ) diff --git a/netbox/core/forms/filtersets.py b/netbox/core/forms/filtersets.py index d8624f6b6..f7a6f3595 100644 --- a/netbox/core/forms/filtersets.py +++ b/netbox/core/forms/filtersets.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from core.choices import * from core.models import * @@ -23,17 +23,20 @@ class DataSourceFilterForm(NetBoxModelFilterSetForm): model = DataSource fieldsets = ( (None, ('q', 'filter_id')), - ('Data Source', ('type', 'status')), + (_('Data Source'), ('type', 'status')), ) type = forms.MultipleChoiceField( + label=_('Type'), choices=DataSourceTypeChoices, required=False ) status = forms.MultipleChoiceField( + label=_('Status'), choices=DataSourceStatusChoices, required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -45,7 +48,7 @@ class DataFileFilterForm(NetBoxModelFilterSetForm): model = DataFile fieldsets = ( (None, ('q', 'filter_id')), - ('File', ('source_id',)), + (_('File'), ('source_id',)), ) source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -57,8 +60,8 @@ class DataFileFilterForm(NetBoxModelFilterSetForm): class JobFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ('object_type', 'status')), - ('Creation', ( + (_('Attributes'), ('object_type', 'status')), + (_('Creation'), ( 'created__before', 'created__after', 'scheduled__before', 'scheduled__after', 'started__before', 'started__after', 'completed__before', 'completed__after', 'user', )), @@ -69,38 +72,47 @@ class JobFilterForm(SavedFiltersMixin, FilterForm): required=False, ) status = forms.MultipleChoiceField( + label=_('Status'), choices=JobStatusChoices, required=False ) created__after = forms.DateTimeField( + label=_('Created after'), required=False, widget=DateTimePicker() ) created__before = forms.DateTimeField( + label=_('Created before'), required=False, widget=DateTimePicker() ) scheduled__after = forms.DateTimeField( + label=_('Scheduled after'), required=False, widget=DateTimePicker() ) scheduled__before = forms.DateTimeField( + label=_('Scheduled before'), required=False, widget=DateTimePicker() ) started__after = forms.DateTimeField( + label=_('Started after'), required=False, widget=DateTimePicker() ) started__before = forms.DateTimeField( + label=_('Started before'), required=False, widget=DateTimePicker() ) completed__after = forms.DateTimeField( + label=_('Completed after'), required=False, widget=DateTimePicker() ) completed__before = forms.DateTimeField( + label=_('Completed before'), required=False, widget=DateTimePicker() ) diff --git a/netbox/core/forms/mixins.py b/netbox/core/forms/mixins.py index 3e76f67a2..0b559fa57 100644 --- a/netbox/core/forms/mixins.py +++ b/netbox/core/forms/mixins.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from core.models import DataFile, DataSource from utilities.forms.fields import DynamicModelChoiceField diff --git a/netbox/core/forms/model_forms.py b/netbox/core/forms/model_forms.py index 666a19e85..01d5474c6 100644 --- a/netbox/core/forms/model_forms.py +++ b/netbox/core/forms/model_forms.py @@ -1,6 +1,7 @@ import copy from django import forms +from django.utils.translation import gettext_lazy as _ from core.forms.mixins import SyncedDataMixin from core.models import * @@ -38,11 +39,11 @@ class DataSourceForm(NetBoxModelForm): @property def fieldsets(self): fieldsets = [ - ('Source', ('name', 'type', 'source_url', 'enabled', 'description', 'tags', 'ignore_rules')), + (_('Source'), ('name', 'type', 'source_url', 'enabled', 'description', 'tags', 'ignore_rules')), ] if self.backend_fields: fieldsets.append( - ('Backend Parameters', self.backend_fields) + (_('Backend Parameters'), self.backend_fields) ) return fieldsets @@ -79,8 +80,8 @@ class ManagedFileForm(SyncedDataMixin, NetBoxModelForm): ) fieldsets = ( - ('File Upload', ('upload_file',)), - ('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), + (_('File Upload'), ('upload_file',)), + (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), ) class Meta: diff --git a/netbox/dcim/forms/bulk_create.py b/netbox/dcim/forms/bulk_create.py index 2d86a1718..02aa5a3e4 100644 --- a/netbox/dcim/forms/bulk_create.py +++ b/netbox/dcim/forms/bulk_create.py @@ -1,7 +1,7 @@ from django import forms from dcim.models import * -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.forms import CustomFieldsMixin from extras.models import Tag from utilities.forms import BootstrapMixin, form_from_model @@ -32,10 +32,12 @@ class DeviceBulkAddComponentForm(BootstrapMixin, CustomFieldsMixin, ComponentCre widget=forms.MultipleHiddenInput() ) description = forms.CharField( + label=_('Description'), max_length=100, required=False ) tags = DynamicModelMultipleChoiceField( + label=_('Tags'), queryset=Tag.objects.all(), required=False ) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index 9ee938859..33e60322d 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -1,7 +1,7 @@ from django import forms from django.conf import settings from django.contrib.auth import get_user_model -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from timezone_field import TimeZoneFormField from dcim.choices import * @@ -63,10 +63,12 @@ __all__ = ( class RegionBulkEditForm(NetBoxModelBulkEditForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=Region.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -80,10 +82,12 @@ class RegionBulkEditForm(NetBoxModelBulkEditForm): class SiteGroupBulkEditForm(NetBoxModelBulkEditForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=SiteGroup.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -97,19 +101,23 @@ class SiteGroupBulkEditForm(NetBoxModelBulkEditForm): class SiteBulkEditForm(NetBoxModelBulkEditForm): status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(SiteStatusChoices), required=False, initial='' ) region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False ) group = DynamicModelChoiceField( + label=_('Group'), queryset=SiteGroup.objects.all(), required=False ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) @@ -119,10 +127,12 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm): required=False ) contact_name = forms.CharField( + label=_('Contact name'), max_length=50, required=False ) contact_phone = forms.CharField( + label=_('Contact phone'), max_length=20, required=False ) @@ -131,16 +141,16 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm): label=_('Contact E-mail') ) time_zone = TimeZoneFormField( + label=_('Time zone'), choices=add_blank_choice(TimeZoneFormField().choices), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Site fieldsets = ( @@ -153,10 +163,12 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm): class LocationBulkEditForm(NetBoxModelBulkEditForm): site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False ) parent = DynamicModelChoiceField( + label=_('Parent'), queryset=Location.objects.all(), required=False, query_params={ @@ -164,15 +176,18 @@ class LocationBulkEditForm(NetBoxModelBulkEditForm): } ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(LocationStatusChoices), required=False, initial='' ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -186,9 +201,11 @@ class LocationBulkEditForm(NetBoxModelBulkEditForm): class RackRoleBulkEditForm(NetBoxModelBulkEditForm): color = ColorField( + label=_('Color'), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -202,6 +219,7 @@ class RackRoleBulkEditForm(NetBoxModelBulkEditForm): class RackBulkEditForm(NetBoxModelBulkEditForm): region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False, initial_params={ @@ -209,6 +227,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): } ) site_group = DynamicModelChoiceField( + label=_('Site group'), queryset=SiteGroup.objects.all(), required=False, initial_params={ @@ -216,6 +235,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): } ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, query_params={ @@ -224,6 +244,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): } ) location = DynamicModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, query_params={ @@ -231,15 +252,18 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): } ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(RackStatusChoices), required=False, initial='' ) role = DynamicModelChoiceField( + label=_('Role'), queryset=RackRole.objects.all(), required=False ) @@ -249,14 +273,17 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): label=_('Serial Number') ) asset_tag = forms.CharField( + label=_('Asset tag'), max_length=50, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(RackTypeChoices), required=False ) width = forms.ChoiceField( + label=_('Width'), choices=add_blank_choice(RackWidthChoices), required=False ) @@ -270,50 +297,56 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): label=_('Descending units') ) outer_width = forms.IntegerField( + label=_('Outer width'), required=False, min_value=1 ) outer_depth = forms.IntegerField( + label=_('Outer depth'), required=False, min_value=1 ) outer_unit = forms.ChoiceField( + label=_('Outer unit'), choices=add_blank_choice(RackDimensionUnitChoices), required=False ) mounting_depth = forms.IntegerField( + label=_('Mounting depth'), required=False, min_value=1 ) weight = forms.DecimalField( + label=_('Weight'), min_value=0, required=False ) max_weight = forms.IntegerField( + label=_('Max weight'), min_value=0, required=False ) weight_unit = forms.ChoiceField( + label=_('Weight unit'), choices=add_blank_choice(WeightUnitChoices), required=False, initial='' ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Rack fieldsets = ( - ('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag', 'description')), - ('Location', ('region', 'site_group', 'site', 'location')), - ('Hardware', ( + (_('Rack'), ('status', 'role', 'tenant', 'serial', 'asset_tag', 'description')), + (_('Location'), ('region', 'site_group', 'site', 'location')), + (_('Hardware'), ( 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', )), - ('Weight', ('weight', 'max_weight', 'weight_unit')), + (_('Weight'), ('weight', 'max_weight', 'weight_unit')), ) nullable_fields = ( 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'weight', @@ -323,22 +356,23 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): class RackReservationBulkEditForm(NetBoxModelBulkEditForm): user = forms.ModelChoiceField( + label=_('User'), queryset=get_user_model().objects.order_by( 'username' ), required=False ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = RackReservation fieldsets = ( @@ -349,6 +383,7 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm): class ManufacturerBulkEditForm(NetBoxModelBulkEditForm): description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -362,17 +397,21 @@ class ManufacturerBulkEditForm(NetBoxModelBulkEditForm): class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) default_platform = DynamicModelChoiceField( + label=_('Default platform'), queryset=Platform.objects.all(), required=False ) part_number = forms.CharField( + label=_('Part number'), required=False ) u_height = forms.IntegerField( + label=_('U height'), min_value=1, required=False ) @@ -382,69 +421,75 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm): label=_('Is full depth') ) airflow = forms.ChoiceField( + label=_('Airflow'), choices=add_blank_choice(DeviceAirflowChoices), required=False ) weight = forms.DecimalField( + label=_('Weight'), min_value=0, required=False ) weight_unit = forms.ChoiceField( + label=_('Weight unit'), choices=add_blank_choice(WeightUnitChoices), required=False, initial='' ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = DeviceType fieldsets = ( - ('Device Type', ('manufacturer', 'default_platform', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')), - ('Weight', ('weight', 'weight_unit')), + (_('Device Type'), ('manufacturer', 'default_platform', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')), + (_('Weight'), ('weight', 'weight_unit')), ) nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments') class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) part_number = forms.CharField( + label=_('Part number'), required=False ) weight = forms.DecimalField( + label=_('Weight'), min_value=0, required=False ) weight_unit = forms.ChoiceField( + label=_('Weight unit'), choices=add_blank_choice(WeightUnitChoices), required=False, initial='' ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = ModuleType fieldsets = ( - ('Module Type', ('manufacturer', 'part_number', 'description')), - ('Weight', ('weight', 'weight_unit')), + (_('Module Type'), ('manufacturer', 'part_number', 'description')), + (_('Weight'), ('weight', 'weight_unit')), ) nullable_fields = ('part_number', 'weight', 'weight_unit', 'description', 'comments') class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): color = ColorField( + label=_('Color'), required=False ) vm_role = forms.NullBooleanField( @@ -453,10 +498,12 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): label=_('VM role') ) config_template = DynamicModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -470,14 +517,17 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): class PlatformBulkEditForm(NetBoxModelBulkEditForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) config_template = DynamicModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -491,10 +541,12 @@ class PlatformBulkEditForm(NetBoxModelBulkEditForm): class DeviceBulkEditForm(NetBoxModelBulkEditForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) device_type = DynamicModelChoiceField( + label=_('Device type'), queryset=DeviceType.objects.all(), required=False, query_params={ @@ -502,14 +554,17 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm): } ) device_role = DynamicModelChoiceField( + label=_('Device role'), queryset=DeviceRole.objects.all(), required=False ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False ) location = DynamicModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, query_params={ @@ -517,18 +572,22 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm): } ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) platform = DynamicModelChoiceField( + label=_('Platform'), queryset=Platform.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(DeviceStatusChoices), required=False ) airflow = forms.ChoiceField( + label=_('Airflow'), choices=add_blank_choice(DeviceAirflowChoices), required=False ) @@ -538,23 +597,23 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm): label=_('Serial Number') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) config_template = DynamicModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Device fieldsets = ( - ('Device', ('device_role', 'status', 'tenant', 'platform', 'description')), - ('Location', ('site', 'location')), - ('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')), - ('Configuration', ('config_template',)), + (_('Device'), ('device_role', 'status', 'tenant', 'platform', 'description')), + (_('Location'), ('site', 'location')), + (_('Hardware'), ('manufacturer', 'device_type', 'airflow', 'serial')), + (_('Configuration'), ('config_template',)), ) nullable_fields = ( 'location', 'tenant', 'platform', 'serial', 'airflow', 'description', 'comments', @@ -563,10 +622,12 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm): class ModuleBulkEditForm(NetBoxModelBulkEditForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) module_type = DynamicModelChoiceField( + label=_('Module type'), queryset=ModuleType.objects.all(), required=False, query_params={ @@ -574,6 +635,7 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm): } ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(ModuleStatusChoices), required=False, initial='' @@ -584,12 +646,11 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm): label=_('Serial Number') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Module fieldsets = ( @@ -600,47 +661,53 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm): class CableBulkEditForm(NetBoxModelBulkEditForm): type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(CableTypeChoices), required=False, initial='' ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(LinkStatusChoices), required=False, initial='' ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) label = forms.CharField( + label=_('Label'), max_length=100, required=False ) color = ColorField( + label=_('Color'), required=False ) length = forms.DecimalField( + label=_('Length'), min_value=0, required=False ) length_unit = forms.ChoiceField( + label=_('Length unit'), choices=add_blank_choice(CableLengthUnitChoices), required=False, initial='' ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Cable fieldsets = ( (None, ('type', 'status', 'tenant', 'label', 'description')), - ('Attributes', ('color', 'length', 'length_unit')), + (_('Attributes'), ('color', 'length', 'length_unit')), ) nullable_fields = ( 'type', 'status', 'tenant', 'label', 'color', 'length', 'description', 'comments', @@ -649,16 +716,16 @@ class CableBulkEditForm(NetBoxModelBulkEditForm): class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm): domain = forms.CharField( + label=_('Domain'), max_length=30, required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = VirtualChassis fieldsets = ( @@ -669,6 +736,7 @@ class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm): class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False, initial_params={ @@ -676,6 +744,7 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): } ) site_group = DynamicModelChoiceField( + label=_('Site group'), queryset=SiteGroup.objects.all(), required=False, initial_params={ @@ -683,6 +752,7 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): } ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, query_params={ @@ -691,6 +761,7 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): } ) location = DynamicModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, query_params={ @@ -698,12 +769,11 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): } ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = PowerPanel fieldsets = ( @@ -714,43 +784,53 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): power_panel = DynamicModelChoiceField( + label=_('Power panel'), queryset=PowerPanel.objects.all(), required=False ) rack = DynamicModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), required=False, ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(PowerFeedStatusChoices), required=False, initial='' ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(PowerFeedTypeChoices), required=False, initial='' ) supply = forms.ChoiceField( + label=_('Supply'), choices=add_blank_choice(PowerFeedSupplyChoices), required=False, initial='' ) phase = forms.ChoiceField( + label=_('Phase'), choices=add_blank_choice(PowerFeedPhaseChoices), required=False, initial='' ) voltage = forms.IntegerField( + label=_('Voltage'), required=False ) amperage = forms.IntegerField( + label=_('Amperage'), required=False ) max_utilization = forms.IntegerField( + label=_('Max utilization'), required=False ) mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) @@ -759,17 +839,16 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() model = PowerFeed fieldsets = ( (None, ('power_panel', 'rack', 'status', 'type', 'mark_connected', 'description', 'tenant')), - ('Power', ('supply', 'phase', 'voltage', 'amperage', 'max_utilization')) + (_('Power'), ('supply', 'phase', 'voltage', 'amperage', 'max_utilization')) ) nullable_fields = ('location', 'tenant', 'description', 'comments') @@ -784,10 +863,12 @@ class ConsolePortTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(ConsolePortTypeChoices), required=False ) @@ -801,14 +882,17 @@ class ConsoleServerPortTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(ConsolePortTypeChoices), required=False ) description = forms.CharField( + label=_('Description'), required=False ) @@ -821,24 +905,29 @@ class PowerPortTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(PowerPortTypeChoices), required=False ) maximum_draw = forms.IntegerField( + label=_('Maximum draw'), min_value=1, required=False, help_text=_("Maximum power draw (watts)") ) allocated_draw = forms.IntegerField( + label=_('Allocated draw'), min_value=1, required=False, help_text=_("Allocated power draw (watts)") ) description = forms.CharField( + label=_('Description'), required=False ) @@ -851,28 +940,34 @@ class PowerOutletTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) device_type = forms.ModelChoiceField( + label=_('Device type'), queryset=DeviceType.objects.all(), required=False, disabled=True, widget=forms.HiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(PowerOutletTypeChoices), required=False ) power_port = forms.ModelChoiceField( + label=_('Power port'), queryset=PowerPortTemplate.objects.all(), required=False ) feed_leg = forms.ChoiceField( + label=_('Feed leg'), choices=add_blank_choice(PowerOutletFeedLegChoices), required=False ) description = forms.CharField( + label=_('Description'), required=False ) @@ -896,14 +991,17 @@ class InterfaceTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(InterfaceTypeChoices), required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=BulkEditNullBooleanSelect ) @@ -913,6 +1011,7 @@ class InterfaceTemplateBulkEditForm(BulkEditForm): label=_('Management only') ) description = forms.CharField( + label=_('Description'), required=False ) poe_mode = forms.ChoiceField( @@ -943,17 +1042,21 @@ class FrontPortTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(PortTypeChoices), required=False ) color = ColorField( + label=_('Color'), required=False ) description = forms.CharField( + label=_('Description'), required=False ) @@ -966,17 +1069,21 @@ class RearPortTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(PortTypeChoices), required=False ) color = ColorField( + label=_('Color'), required=False ) description = forms.CharField( + label=_('Description'), required=False ) @@ -989,10 +1096,12 @@ class ModuleBayTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) description = forms.CharField( + label=_('Description'), required=False ) @@ -1005,10 +1114,12 @@ class DeviceBayTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) description = forms.CharField( + label=_('Description'), required=False ) @@ -1021,17 +1132,21 @@ class InventoryItemTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput() ) label = forms.CharField( + label=_('Label'), max_length=64, required=False ) description = forms.CharField( + label=_('Description'), required=False ) role = DynamicModelChoiceField( + label=_('Role'), queryset=InventoryItemRole.objects.all(), required=False ) manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) @@ -1045,12 +1160,14 @@ class InventoryItemTemplateBulkEditForm(BulkEditForm): class ComponentBulkEditForm(NetBoxModelBulkEditForm): device = forms.ModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False, disabled=True, widget=forms.HiddenInput() ) module = forms.ModelChoiceField( + label=_('Module'), queryset=Module.objects.all(), required=False ) @@ -1072,6 +1189,7 @@ class ConsolePortBulkEditForm( ComponentBulkEditForm ): mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) @@ -1088,6 +1206,7 @@ class ConsoleServerPortBulkEditForm( ComponentBulkEditForm ): mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) @@ -1104,6 +1223,7 @@ class PowerPortBulkEditForm( ComponentBulkEditForm ): mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) @@ -1111,7 +1231,7 @@ class PowerPortBulkEditForm( model = PowerPort fieldsets = ( (None, ('module', 'type', 'label', 'description', 'mark_connected')), - ('Power', ('maximum_draw', 'allocated_draw')), + (_('Power'), ('maximum_draw', 'allocated_draw')), ) nullable_fields = ('module', 'label', 'description', 'maximum_draw', 'allocated_draw') @@ -1121,6 +1241,7 @@ class PowerOutletBulkEditForm( ComponentBulkEditForm ): mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) @@ -1128,7 +1249,7 @@ class PowerOutletBulkEditForm( model = PowerOutlet fieldsets = ( (None, ('module', 'type', 'label', 'description', 'mark_connected')), - ('Power', ('feed_leg', 'power_port')), + (_('Power'), ('feed_leg', 'power_port')), ) nullable_fields = ('module', 'label', 'type', 'feed_leg', 'power_port', 'description') @@ -1153,14 +1274,17 @@ class InterfaceBulkEditForm( ComponentBulkEditForm ): enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=BulkEditNullBooleanSelect ) parent = DynamicModelChoiceField( + label=_('Parent'), queryset=Interface.objects.all(), required=False ) bridge = DynamicModelChoiceField( + label=_('Bridge'), queryset=Interface.objects.all(), required=False ) @@ -1175,12 +1299,13 @@ class InterfaceBulkEditForm( vdcs = DynamicModelMultipleChoiceField( queryset=VirtualDeviceContext.objects.all(), required=False, - label='Virtual Device Contexts', + label=_('Virtual device contexts'), query_params={ 'device_id': '$device', } ) speed = forms.IntegerField( + label=_('Speed'), required=False, widget=NumberWithOptions( options=InterfaceSpeedChoices @@ -1204,10 +1329,12 @@ class InterfaceBulkEditForm( label=_('PoE type') ) mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) mode = forms.ChoiceField( + label=_('Mode'), choices=add_blank_choice(InterfaceModeChoices), required=False, initial='' @@ -1255,12 +1382,12 @@ class InterfaceBulkEditForm( model = Interface fieldsets = ( (None, ('module', 'type', 'label', 'speed', 'duplex', 'description')), - ('Addressing', ('vrf', 'mac_address', 'wwn')), - ('Operation', ('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), - ('PoE', ('poe_mode', 'poe_type')), - ('Related Interfaces', ('parent', 'bridge', 'lag')), - ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), - ('Wireless', ( + (_('Addressing'), ('vrf', 'mac_address', 'wwn')), + (_('Operation'), ('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), + (_('PoE'), ('poe_mode', 'poe_type')), + (_('Related Interfaces'), ('parent', 'bridge', 'lag')), + (_('802.1Q Switching'), ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), + (_('Wireless'), ( 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'wireless_lan_group', 'wireless_lans', )), ) @@ -1320,14 +1447,14 @@ class InterfaceBulkEditForm( if not self.cleaned_data['mode']: if self.cleaned_data['untagged_vlan']: - raise forms.ValidationError({'untagged_vlan': "Interface mode must be specified to assign VLANs"}) + raise forms.ValidationError({'untagged_vlan': _("Interface mode must be specified to assign VLANs")}) elif self.cleaned_data['tagged_vlans']: - raise forms.ValidationError({'tagged_vlans': "Interface mode must be specified to assign VLANs"}) + raise forms.ValidationError({'tagged_vlans': _("Interface mode must be specified to assign VLANs")}) # Untagged interfaces cannot be assigned tagged VLANs elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and self.cleaned_data['tagged_vlans']: raise forms.ValidationError({ - 'mode': "An access interface cannot have tagged VLANs assigned." + 'mode': _("An access interface cannot have tagged VLANs assigned.") }) # Remove all tagged VLAN assignments from "tagged all" interfaces @@ -1340,6 +1467,7 @@ class FrontPortBulkEditForm( ComponentBulkEditForm ): mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) @@ -1356,6 +1484,7 @@ class RearPortBulkEditForm( ComponentBulkEditForm ): mark_connected = forms.NullBooleanField( + label=_('Mark connected'), required=False, widget=BulkEditNullBooleanSelect ) @@ -1394,14 +1523,17 @@ class InventoryItemBulkEditForm( NetBoxModelBulkEditForm ): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False ) role = DynamicModelChoiceField( + label=_('Role'), queryset=InventoryItemRole.objects.all(), required=False ) manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) @@ -1419,9 +1551,11 @@ class InventoryItemBulkEditForm( class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm): color = ColorField( + label=_('Color'), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -1435,14 +1569,17 @@ class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm): class VirtualDeviceContextBulkEditForm(NetBoxModelBulkEditForm): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), required=False, choices=add_blank_choice(VirtualDeviceContextStatusChoices) ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index d3acbc716..85d2b88bd 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -3,7 +3,7 @@ from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.forms.array import SimpleArrayField from django.core.exceptions import ObjectDoesNotExist from django.utils.safestring import mark_safe -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import * from dcim.constants import * @@ -56,6 +56,7 @@ __all__ = ( class RegionImportForm(NetBoxModelImportForm): parent = CSVModelChoiceField( + label=_('Parent'), queryset=Region.objects.all(), required=False, to_field_name='name', @@ -69,6 +70,7 @@ class RegionImportForm(NetBoxModelImportForm): class SiteGroupImportForm(NetBoxModelImportForm): parent = CSVModelChoiceField( + label=_('Parent'), queryset=SiteGroup.objects.all(), required=False, to_field_name='name', @@ -82,22 +84,26 @@ class SiteGroupImportForm(NetBoxModelImportForm): class SiteImportForm(NetBoxModelImportForm): status = CSVChoiceField( + label=_('Status'), choices=SiteStatusChoices, help_text=_('Operational status') ) region = CSVModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False, to_field_name='name', help_text=_('Assigned region') ) group = CSVModelChoiceField( + label=_('Group'), queryset=SiteGroup.objects.all(), required=False, to_field_name='name', help_text=_('Assigned group') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -119,11 +125,13 @@ class SiteImportForm(NetBoxModelImportForm): class LocationImportForm(NetBoxModelImportForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', help_text=_('Assigned site') ) parent = CSVModelChoiceField( + label=_('Parent'), queryset=Location.objects.all(), required=False, to_field_name='name', @@ -133,10 +141,12 @@ class LocationImportForm(NetBoxModelImportForm): } ) status = CSVChoiceField( + label=_('Status'), choices=LocationStatusChoices, help_text=_('Operational status') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -161,45 +171,54 @@ class RackRoleImportForm(NetBoxModelImportForm): class RackImportForm(NetBoxModelImportForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name' ) location = CSVModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, to_field_name='name' ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Name of assigned tenant') ) status = CSVChoiceField( + label=_('Status'), choices=RackStatusChoices, help_text=_('Operational status') ) role = CSVModelChoiceField( + label=_('Role'), queryset=RackRole.objects.all(), required=False, to_field_name='name', help_text=_('Name of assigned role') ) type = CSVChoiceField( + label=_('Type'), choices=RackTypeChoices, required=False, help_text=_('Rack type') ) width = forms.ChoiceField( + label=_('Width'), choices=RackWidthChoices, help_text=_('Rail-to-rail width (in inches)') ) outer_unit = CSVChoiceField( + label=_('Outer unit'), choices=RackDimensionUnitChoices, required=False, help_text=_('Unit for outer dimensions') ) weight_unit = CSVChoiceField( + label=_('Weight unit'), choices=WeightUnitChoices, required=False, help_text=_('Unit for rack weights') @@ -225,27 +244,32 @@ class RackImportForm(NetBoxModelImportForm): class RackReservationImportForm(NetBoxModelImportForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', help_text=_('Parent site') ) location = CSVModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), to_field_name='name', required=False, help_text=_("Rack's location (if any)") ) rack = CSVModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), to_field_name='name', help_text=_('Rack') ) units = SimpleArrayField( + label=_('Units'), base_field=forms.IntegerField(), required=True, help_text=_('Comma-separated list of individual unit numbers') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -282,21 +306,25 @@ class ManufacturerImportForm(NetBoxModelImportForm): class DeviceTypeImportForm(NetBoxModelImportForm): manufacturer = forms.ModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), to_field_name='name', help_text=_('The manufacturer which produces this device type') ) default_platform = forms.ModelChoiceField( + label=_('Default platform'), queryset=Platform.objects.all(), to_field_name='name', required=False, help_text=_('The default platform for devices of this type (optional)') ) weight = forms.DecimalField( + label=_('Weight'), required=False, help_text=_('Device weight'), ) weight_unit = CSVChoiceField( + label=_('Weight unit'), choices=WeightUnitChoices, required=False, help_text=_('Unit for device weight') @@ -312,14 +340,17 @@ class DeviceTypeImportForm(NetBoxModelImportForm): class ModuleTypeImportForm(NetBoxModelImportForm): manufacturer = forms.ModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), to_field_name='name' ) weight = forms.DecimalField( + label=_('Weight'), required=False, help_text=_('Module weight'), ) weight_unit = CSVChoiceField( + label=_('Weight unit'), choices=WeightUnitChoices, required=False, help_text=_('Unit for module weight') @@ -332,6 +363,7 @@ class ModuleTypeImportForm(NetBoxModelImportForm): class DeviceRoleImportForm(NetBoxModelImportForm): config_template = CSVModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), to_field_name='name', required=False, @@ -350,12 +382,14 @@ class DeviceRoleImportForm(NetBoxModelImportForm): class PlatformImportForm(NetBoxModelImportForm): slug = SlugField() manufacturer = CSVModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False, to_field_name='name', help_text=_('Limit platform assignments to this manufacturer') ) config_template = CSVModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), to_field_name='name', required=False, @@ -371,43 +405,51 @@ class PlatformImportForm(NetBoxModelImportForm): class BaseDeviceImportForm(NetBoxModelImportForm): device_role = CSVModelChoiceField( + label=_('Device role'), queryset=DeviceRole.objects.all(), to_field_name='name', help_text=_('Assigned role') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Assigned tenant') ) manufacturer = CSVModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), to_field_name='name', help_text=_('Device type manufacturer') ) device_type = CSVModelChoiceField( + label=_('Device type'), queryset=DeviceType.objects.all(), to_field_name='model', help_text=_('Device type model') ) platform = CSVModelChoiceField( + label=_('Platform'), queryset=Platform.objects.all(), required=False, to_field_name='name', help_text=_('Assigned platform') ) status = CSVChoiceField( + label=_('Status'), choices=DeviceStatusChoices, help_text=_('Operational status') ) virtual_chassis = CSVModelChoiceField( + label=_('Virtual chassis'), queryset=VirtualChassis.objects.all(), to_field_name='name', required=False, help_text=_('Virtual chassis') ) cluster = CSVModelChoiceField( + label=_('Cluster'), queryset=Cluster.objects.all(), to_field_name='name', required=False, @@ -430,45 +472,53 @@ class BaseDeviceImportForm(NetBoxModelImportForm): class DeviceImportForm(BaseDeviceImportForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', help_text=_('Assigned site') ) location = CSVModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), to_field_name='name', required=False, help_text=_("Assigned location (if any)") ) rack = CSVModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), to_field_name='name', required=False, help_text=_("Assigned rack (if any)") ) face = CSVChoiceField( + label=_('Face'), choices=DeviceFaceChoices, required=False, help_text=_('Mounted rack face') ) parent = CSVModelChoiceField( + label=_('Parent'), queryset=Device.objects.all(), to_field_name='name', required=False, help_text=_('Parent device (for child devices)') ) device_bay = CSVModelChoiceField( + label=_('Device bay'), queryset=DeviceBay.objects.all(), to_field_name='name', required=False, help_text=_('Device bay in which this device is installed (for child devices)') ) airflow = CSVChoiceField( + label=_('Airflow'), choices=DeviceAirflowChoices, required=False, help_text=_('Airflow direction') ) config_template = CSVModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), to_field_name='name', required=False, @@ -523,29 +573,35 @@ class DeviceImportForm(BaseDeviceImportForm): class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name', help_text=_('The device in which this module is installed') ) module_bay = CSVModelChoiceField( + label=_('Module bay'), queryset=ModuleBay.objects.all(), to_field_name='name', help_text=_('The module bay in which this module is installed') ) module_type = CSVModelChoiceField( + label=_('Module type'), queryset=ModuleType.objects.all(), to_field_name='model', help_text=_('The type of module') ) status = CSVChoiceField( + label=_('Status'), choices=ModuleStatusChoices, help_text=_('Operational status') ) replicate_components = forms.BooleanField( + label=_('Replicate components'), required=False, help_text=_('Automatically populate components associated with this module type (enabled by default)') ) adopt_components = forms.BooleanField( + label=_('Adopt components'), required=False, help_text=_('Adopt already existing components') ) @@ -579,15 +635,18 @@ class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm): class ConsolePortImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) type = CSVChoiceField( + label=_('Type'), choices=ConsolePortTypeChoices, required=False, help_text=_('Port type') ) speed = CSVTypedChoiceField( + label=_('Speed'), choices=ConsolePortSpeedChoices, coerce=int, empty_value=None, @@ -602,15 +661,18 @@ class ConsolePortImportForm(NetBoxModelImportForm): class ConsoleServerPortImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) type = CSVChoiceField( + label=_('Type'), choices=ConsolePortTypeChoices, required=False, help_text=_('Port type') ) speed = CSVTypedChoiceField( + label=_('Speed'), choices=ConsolePortSpeedChoices, coerce=int, empty_value=None, @@ -625,10 +687,12 @@ class ConsoleServerPortImportForm(NetBoxModelImportForm): class PowerPortImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) type = CSVChoiceField( + label=_('Type'), choices=PowerPortTypeChoices, required=False, help_text=_('Port type') @@ -643,21 +707,25 @@ class PowerPortImportForm(NetBoxModelImportForm): class PowerOutletImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) type = CSVChoiceField( + label=_('Type'), choices=PowerOutletTypeChoices, required=False, help_text=_('Outlet type') ) power_port = CSVModelChoiceField( + label=_('Power port'), queryset=PowerPort.objects.all(), required=False, to_field_name='name', help_text=_('Local power port which feeds this outlet') ) feed_leg = CSVChoiceField( + label=_('Feed lag'), choices=PowerOutletFeedLegChoices, required=False, help_text=_('Electrical phase (for three-phase circuits)') @@ -692,63 +760,75 @@ class PowerOutletImportForm(NetBoxModelImportForm): class InterfaceImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) parent = CSVModelChoiceField( + label=_('Parent'), queryset=Interface.objects.all(), required=False, to_field_name='name', help_text=_('Parent interface') ) bridge = CSVModelChoiceField( + label=_('Bridge'), queryset=Interface.objects.all(), required=False, to_field_name='name', help_text=_('Bridged interface') ) lag = CSVModelChoiceField( + label=_('Lag'), queryset=Interface.objects.all(), required=False, to_field_name='name', help_text=_('Parent LAG interface') ) vdcs = CSVModelMultipleChoiceField( + label=_('Vdcs'), queryset=VirtualDeviceContext.objects.all(), required=False, to_field_name='name', - help_text='VDC names separated by commas, encased with double quotes (e.g. "vdc1, vdc2, vdc3")' + help_text=_('VDC names separated by commas, encased with double quotes (e.g. "vdc1, vdc2, vdc3")') ) type = CSVChoiceField( + label=_('Type'), choices=InterfaceTypeChoices, help_text=_('Physical medium') ) duplex = CSVChoiceField( + label=_('Duplex'), choices=InterfaceDuplexChoices, required=False ) poe_mode = CSVChoiceField( + label=_('Poe mode'), choices=InterfacePoEModeChoices, required=False, help_text=_('PoE mode') ) poe_type = CSVChoiceField( + label=_('Poe type'), choices=InterfacePoETypeChoices, required=False, help_text=_('PoE type') ) mode = CSVChoiceField( + label=_('Mode'), choices=InterfaceModeChoices, required=False, help_text=_('IEEE 802.1Q operational mode (for L2 interfaces)') ) vrf = CSVModelChoiceField( + label=_('VRF'), queryset=VRF.objects.all(), required=False, to_field_name='rd', help_text=_('Assigned VRF') ) rf_role = CSVChoiceField( + label=_('Rf role'), choices=WirelessRoleChoices, required=False, help_text=_('Wireless role (AP/station)') @@ -792,15 +872,18 @@ class InterfaceImportForm(NetBoxModelImportForm): class FrontPortImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) rear_port = CSVModelChoiceField( + label=_('Rear port'), queryset=RearPort.objects.all(), to_field_name='name', help_text=_('Corresponding rear port') ) type = CSVChoiceField( + label=_('Type'), choices=PortTypeChoices, help_text=_('Physical medium classification') ) @@ -837,10 +920,12 @@ class FrontPortImportForm(NetBoxModelImportForm): class RearPortImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) type = CSVChoiceField( + label=_('Type'), help_text=_('Physical medium classification'), choices=PortTypeChoices, ) @@ -852,6 +937,7 @@ class RearPortImportForm(NetBoxModelImportForm): class ModuleBayImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) @@ -863,10 +949,12 @@ class ModuleBayImportForm(NetBoxModelImportForm): class DeviceBayImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) installed_device = CSVModelChoiceField( + label=_('Installed device'), queryset=Device.objects.all(), required=False, to_field_name='name', @@ -909,32 +997,38 @@ class DeviceBayImportForm(NetBoxModelImportForm): class InventoryItemImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name' ) role = CSVModelChoiceField( + label=_('Role'), queryset=InventoryItemRole.objects.all(), to_field_name='name', required=False ) manufacturer = CSVModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), to_field_name='name', required=False ) parent = CSVModelChoiceField( + label=_('Parent'), queryset=Device.objects.all(), to_field_name='name', required=False, help_text=_('Parent inventory item') ) component_type = CSVContentTypeField( + label=_('Component type'), queryset=ContentType.objects.all(), limit_choices_to=MODULAR_COMPONENT_MODELS, required=False, help_text=_('Component Type') ) component_name = forms.CharField( + label=_('Compnent name'), required=False, help_text=_('Component Name') ) @@ -1002,52 +1096,62 @@ class InventoryItemRoleImportForm(NetBoxModelImportForm): class CableImportForm(NetBoxModelImportForm): # Termination A side_a_device = CSVModelChoiceField( + label=_('Side a device'), queryset=Device.objects.all(), to_field_name='name', help_text=_('Side A device') ) side_a_type = CSVContentTypeField( + label=_('Side a type'), queryset=ContentType.objects.all(), limit_choices_to=CABLE_TERMINATION_MODELS, help_text=_('Side A type') ) side_a_name = forms.CharField( + label=_('Side a name'), help_text=_('Side A component name') ) # Termination B side_b_device = CSVModelChoiceField( + label=_('Side b device'), queryset=Device.objects.all(), to_field_name='name', help_text=_('Side B device') ) side_b_type = CSVContentTypeField( + label=_('Side b type'), queryset=ContentType.objects.all(), limit_choices_to=CABLE_TERMINATION_MODELS, help_text=_('Side B type') ) side_b_name = forms.CharField( + label=_('Side b name'), help_text=_('Side B component name') ) # Cable attributes status = CSVChoiceField( + label=_('Status'), choices=LinkStatusChoices, required=False, help_text=_('Connection status') ) type = CSVChoiceField( + label=_('Type'), choices=CableTypeChoices, required=False, help_text=_('Physical medium classification') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Assigned tenant') ) length_unit = CSVChoiceField( + label=_('Length unit'), choices=CableLengthUnitChoices, required=False, help_text=_('Length unit') @@ -1110,6 +1214,7 @@ class CableImportForm(NetBoxModelImportForm): class VirtualChassisImportForm(NetBoxModelImportForm): master = CSVModelChoiceField( + label=_('Master'), queryset=Device.objects.all(), to_field_name='name', required=False, @@ -1127,11 +1232,13 @@ class VirtualChassisImportForm(NetBoxModelImportForm): class PowerPanelImportForm(NetBoxModelImportForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', help_text=_('Name of parent site') ) location = CSVModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, to_field_name='name' @@ -1153,22 +1260,26 @@ class PowerPanelImportForm(NetBoxModelImportForm): class PowerFeedImportForm(NetBoxModelImportForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', help_text=_('Assigned site') ) power_panel = CSVModelChoiceField( + label=_('Power panel'), queryset=PowerPanel.objects.all(), to_field_name='name', help_text=_('Upstream power panel') ) location = CSVModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), to_field_name='name', required=False, help_text=_("Rack's location (if any)") ) rack = CSVModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), to_field_name='name', required=False, @@ -1181,18 +1292,22 @@ class PowerFeedImportForm(NetBoxModelImportForm): help_text=_('Assigned tenant') ) status = CSVChoiceField( + label=_('Status'), choices=PowerFeedStatusChoices, help_text=_('Operational status') ) type = CSVChoiceField( + label=_('Type'), choices=PowerFeedTypeChoices, help_text=_('Primary or redundant') ) supply = CSVChoiceField( + label=_('Supply'), choices=PowerFeedSupplyChoices, help_text=_('Supply type (AC/DC)') ) phase = CSVChoiceField( + label=_('Phase'), choices=PowerFeedPhaseChoices, help_text=_('Single or three-phase') ) @@ -1228,11 +1343,13 @@ class PowerFeedImportForm(NetBoxModelImportForm): class VirtualDeviceContextImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name', help_text='Assigned role' ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', diff --git a/netbox/dcim/forms/common.py b/netbox/dcim/forms/common.py index 064a9a80b..77543af12 100644 --- a/netbox/dcim/forms/common.py +++ b/netbox/dcim/forms/common.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import * from dcim.constants import * @@ -47,7 +47,7 @@ class InterfaceCommonForm(forms.Form): # Untagged interfaces cannot be assigned tagged VLANs if self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and tagged_vlans: raise forms.ValidationError({ - 'mode': "An access interface cannot have tagged VLANs assigned." + 'mode': _("An access interface cannot have tagged VLANs assigned.") }) # Remove all tagged VLAN assignments from "tagged all" interfaces @@ -61,8 +61,10 @@ class InterfaceCommonForm(forms.Form): if invalid_vlans: raise forms.ValidationError({ - 'tagged_vlans': f"The tagged VLANs ({', '.join(invalid_vlans)}) must belong to the same site as " - f"the interface's parent device/VM, or they must be global" + 'tagged_vlans': _( + "The tagged VLANs ({vlans}) must belong to the same site as the interface's parent device/VM, " + "or they must be global" + ).format(vlans=', '.join(invalid_vlans)) }) @@ -105,7 +107,7 @@ class ModuleCommonForm(forms.Form): # Installing modules with placeholders require that the bay has a position value if MODULE_TOKEN in template.name and not module_bay.position: raise forms.ValidationError( - "Cannot install module with placeholder values in a module bay with no position defined" + _("Cannot install module with placeholder values in a module bay with no position defined.") ) resolved_name = template.name.replace(MODULE_TOKEN, module_bay.position) @@ -114,12 +116,17 @@ class ModuleCommonForm(forms.Form): # It is not possible to adopt components already belonging to a module if adopt_components and existing_item and existing_item.module: raise forms.ValidationError( - f"Cannot adopt {template.component_model.__name__} '{resolved_name}' as it already belongs " - f"to a module" + _("Cannot adopt {name} '{resolved_name}' as it already belongs to a module").format( + name=template.component_model.__name__, + resolved_name=resolved_name + ) ) # If we are not adopting components we error if the component exists if not adopt_components and resolved_name in installed_components: raise forms.ValidationError( - f"{template.component_model.__name__} - {resolved_name} already exists" + _("{name} - {resolved_name} already exists").format( + name=template.component_model.__name__, + resolved_name=resolved_name + ) ) diff --git a/netbox/dcim/forms/connections.py b/netbox/dcim/forms/connections.py index 8e3dcdc68..854c5ebed 100644 --- a/netbox/dcim/forms/connections.py +++ b/netbox/dcim/forms/connections.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from circuits.models import Circuit, CircuitTermination from dcim.models import * diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index f0ac017fa..3efbfb974 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.auth import get_user_model -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import * from dcim.constants import * @@ -56,9 +56,11 @@ __all__ = ( class DeviceComponentFilterForm(NetBoxModelFilterSetForm): name = forms.CharField( + label=_('Name'), required=False ) label = forms.CharField( + label=_('Label'), required=False ) region_id = DynamicModelMultipleChoiceField( @@ -130,7 +132,7 @@ class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): model = Region fieldsets = ( (None, ('q', 'filter_id', 'tag', 'parent_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')) + (_('Contacts'), ('contact', 'contact_role', 'contact_group')) ) parent_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -144,7 +146,7 @@ class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): model = SiteGroup fieldsets = ( (None, ('q', 'filter_id', 'tag', 'parent_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')) + (_('Contacts'), ('contact', 'contact_role', 'contact_group')) ) parent_id = DynamicModelMultipleChoiceField( queryset=SiteGroup.objects.all(), @@ -158,11 +160,12 @@ class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte model = Site fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('status', 'region_id', 'group_id', 'asn_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Attributes'), ('status', 'region_id', 'group_id', 'asn_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) status = forms.MultipleChoiceField( + label=_('Status'), choices=SiteStatusChoices, required=False ) @@ -188,9 +191,9 @@ class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelF model = Location fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('region_id', 'site_group_id', 'site_id', 'parent_id', 'status')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Attributes'), ('region_id', 'site_group_id', 'site_id', 'parent_id', 'status')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -221,6 +224,7 @@ class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelF label=_('Parent') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=LocationStatusChoices, required=False ) @@ -236,12 +240,12 @@ class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte model = Rack fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')), - ('Function', ('status', 'role_id')), - ('Hardware', ('type', 'width', 'serial', 'asset_tag')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), - ('Weight', ('weight', 'max_weight', 'weight_unit')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id')), + (_('Function'), ('status', 'role_id')), + (_('Hardware'), ('type', 'width', 'serial', 'asset_tag')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), + (_('Weight'), ('weight', 'max_weight', 'weight_unit')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -271,14 +275,17 @@ class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte label=_('Location') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=RackStatusChoices, required=False ) type = forms.MultipleChoiceField( + label=_('Type'), choices=RackTypeChoices, required=False ) width = forms.MultipleChoiceField( + label=_('Width'), choices=RackWidthChoices, required=False ) @@ -289,21 +296,26 @@ class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte label=_('Role') ) serial = forms.CharField( + label=_('Serial'), required=False ) asset_tag = forms.CharField( + label=_('Asset tag'), required=False ) tag = TagFilterField(model) weight = forms.DecimalField( + label=_('Weight'), required=False, min_value=1 ) max_weight = forms.IntegerField( + label=_('Max weight'), required=False, min_value=1 ) weight_unit = forms.ChoiceField( + label=_('Weight unit'), choices=add_blank_choice(WeightUnitChoices), required=False ) @@ -312,12 +324,12 @@ class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte class RackElevationFilterForm(RackFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'id')), - ('Function', ('status', 'role_id')), - ('Hardware', ('type', 'width', 'serial', 'asset_tag')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), - ('Weight', ('weight', 'max_weight', 'weight_unit')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'id')), + (_('Function'), ('status', 'role_id')), + (_('Hardware'), ('type', 'width', 'serial', 'asset_tag')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), + (_('Weight'), ('weight', 'max_weight', 'weight_unit')), ) id = DynamicModelMultipleChoiceField( queryset=Rack.objects.all(), @@ -334,9 +346,9 @@ class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = RackReservation fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('User', ('user_id',)), - ('Rack', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('User'), ('user_id',)), + (_('Rack'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -390,7 +402,7 @@ class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): model = Manufacturer fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Contacts', ('contact', 'contact_role', 'contact_group')) + (_('Contacts'), ('contact', 'contact_role', 'contact_group')) ) tag = TagFilterField(model) @@ -399,13 +411,13 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm): model = DeviceType fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Hardware', ('manufacturer_id', 'default_platform_id', 'part_number', 'subdevice_role', 'airflow')), - ('Images', ('has_front_image', 'has_rear_image')), - ('Components', ( + (_('Hardware'), ('manufacturer_id', 'default_platform_id', 'part_number', 'subdevice_role', 'airflow')), + (_('Images'), ('has_front_image', 'has_rear_image')), + (_('Components'), ( 'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items', )), - ('Weight', ('weight', 'weight_unit')), + (_('Weight'), ('weight', 'weight_unit')), ) manufacturer_id = DynamicModelMultipleChoiceField( queryset=Manufacturer.objects.all(), @@ -418,98 +430,103 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm): label=_('Default platform') ) part_number = forms.CharField( + label=_('Part number'), required=False ) subdevice_role = forms.MultipleChoiceField( + label=_('Subdevice role'), choices=add_blank_choice(SubdeviceRoleChoices), required=False ) airflow = forms.MultipleChoiceField( + label=_('Airflow'), choices=add_blank_choice(DeviceAirflowChoices), required=False ) has_front_image = forms.NullBooleanField( required=False, - label='Has a front image', + label=_('Has a front image'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) has_rear_image = forms.NullBooleanField( required=False, - label='Has a rear image', + label=_('Has a rear image'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) console_ports = forms.NullBooleanField( required=False, - label='Has console ports', + label=_('Has console ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) console_server_ports = forms.NullBooleanField( required=False, - label='Has console server ports', + label=_('Has console server ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) power_ports = forms.NullBooleanField( required=False, - label='Has power ports', + label=_('Has power ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) power_outlets = forms.NullBooleanField( required=False, - label='Has power outlets', + label=_('Has power outlets'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) interfaces = forms.NullBooleanField( required=False, - label='Has interfaces', + label=_('Has interfaces'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) pass_through_ports = forms.NullBooleanField( required=False, - label='Has pass-through ports', + label=_('Has pass-through ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) device_bays = forms.NullBooleanField( required=False, - label='Has device bays', + label=_('Has device bays'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) module_bays = forms.NullBooleanField( required=False, - label='Has module bays', + label=_('Has module bays'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) inventory_items = forms.NullBooleanField( required=False, - label='Has inventory items', + label=_('Has inventory items'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) tag = TagFilterField(model) weight = forms.DecimalField( + label=_('Weight'), required=False ) weight_unit = forms.ChoiceField( + label=_('Weight unit'), choices=add_blank_choice(WeightUnitChoices), required=False ) @@ -519,12 +536,12 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm): model = ModuleType fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Hardware', ('manufacturer_id', 'part_number')), - ('Components', ( + (_('Hardware'), ('manufacturer_id', 'part_number')), + (_('Components'), ( 'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports', )), - ('Weight', ('weight', 'weight_unit')), + (_('Weight'), ('weight', 'weight_unit')), ) manufacturer_id = DynamicModelMultipleChoiceField( queryset=Manufacturer.objects.all(), @@ -533,55 +550,58 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm): fetch_trigger='open' ) part_number = forms.CharField( + label=_('Part number'), required=False ) console_ports = forms.NullBooleanField( required=False, - label='Has console ports', + label=_('Has console ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) console_server_ports = forms.NullBooleanField( required=False, - label='Has console server ports', + label=_('Has console server ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) power_ports = forms.NullBooleanField( required=False, - label='Has power ports', + label=_('Has power ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) power_outlets = forms.NullBooleanField( required=False, - label='Has power outlets', + label=_('Has power outlets'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) interfaces = forms.NullBooleanField( required=False, - label='Has interfaces', + label=_('Has interfaces'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) pass_through_ports = forms.NullBooleanField( required=False, - label='Has pass-through ports', + label=_('Has pass-through ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) tag = TagFilterField(model) weight = forms.DecimalField( + label=_('Weight'), required=False ) weight_unit = forms.ChoiceField( + label=_('Weight unit'), choices=add_blank_choice(WeightUnitChoices), required=False ) @@ -621,15 +641,17 @@ class DeviceFilterForm( model = Device fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Operation', ('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address')), - ('Hardware', ('manufacturer_id', 'device_type_id', 'platform_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), - ('Components', ( + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Operation'), ('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address')), + (_('Hardware'), ('manufacturer_id', 'device_type_id', 'platform_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), + (_('Components'), ( 'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports', )), - ('Miscellaneous', ('has_primary_ip', 'has_oob_ip', 'virtual_chassis_member', 'config_template_id', 'local_context_data')) + (_('Miscellaneous'), ( + 'has_primary_ip', 'has_oob_ip', 'virtual_chassis_member', 'config_template_id', 'local_context_data', + )) ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -694,22 +716,26 @@ class DeviceFilterForm( label=_('Platform') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=DeviceStatusChoices, required=False ) airflow = forms.MultipleChoiceField( + label=_('Airflow'), choices=add_blank_choice(DeviceAirflowChoices), required=False ) serial = forms.CharField( + label=_('Serial'), required=False ) asset_tag = forms.CharField( + label=_('Asset tag'), required=False ) mac_address = forms.CharField( required=False, - label='MAC address' + label=_('MAC address') ) config_template_id = DynamicModelMultipleChoiceField( queryset=ConfigTemplate.objects.all(), @@ -718,7 +744,7 @@ class DeviceFilterForm( ) has_primary_ip = forms.NullBooleanField( required=False, - label='Has a primary IP', + label=_('Has a primary IP'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) @@ -732,49 +758,49 @@ class DeviceFilterForm( ) virtual_chassis_member = forms.NullBooleanField( required=False, - label='Virtual chassis member', + label=_('Virtual chassis member'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) console_ports = forms.NullBooleanField( required=False, - label='Has console ports', + label=_('Has console ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) console_server_ports = forms.NullBooleanField( required=False, - label='Has console server ports', + label=_('Has console server ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) power_ports = forms.NullBooleanField( required=False, - label='Has power ports', + label=_('Has power ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) power_outlets = forms.NullBooleanField( required=False, - label='Has power outlets', + label=_('Has power outlets'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) interfaces = forms.NullBooleanField( required=False, - label='Has interfaces', + label=_('Has interfaces'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) pass_through_ports = forms.NullBooleanField( required=False, - label='Has pass-through ports', + label=_('Has pass-through ports'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) @@ -789,8 +815,8 @@ class VirtualDeviceContextFilterForm( model = VirtualDeviceContext fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('device', 'status', 'has_primary_ip')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Attributes'), ('device', 'status', 'has_primary_ip')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) device = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), @@ -799,12 +825,13 @@ class VirtualDeviceContextFilterForm( fetch_trigger='open' ) status = forms.MultipleChoiceField( + label=_('Status'), required=False, choices=add_blank_choice(VirtualDeviceContextStatusChoices) ) has_primary_ip = forms.NullBooleanField( required=False, - label='Has a primary IP', + label=_('Has a primary IP'), widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) @@ -816,7 +843,7 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo model = Module fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Hardware', ('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag')), + (_('Hardware'), ('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag')), ) manufacturer_id = DynamicModelMultipleChoiceField( queryset=Manufacturer.objects.all(), @@ -834,13 +861,16 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo fetch_trigger='open' ) status = forms.MultipleChoiceField( + label=_('Status'), choices=ModuleStatusChoices, required=False ) serial = forms.CharField( + label=_('Serial'), required=False ) asset_tag = forms.CharField( + label=_('Asset tag'), required=False ) tag = TagFilterField(model) @@ -850,8 +880,8 @@ class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = VirtualChassis fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Location'), ('region_id', 'site_group_id', 'site_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -879,9 +909,9 @@ class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = Cable fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('site_id', 'location_id', 'rack_id', 'device_id')), - ('Attributes', ('type', 'status', 'color', 'length', 'length_unit')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Location'), ('site_id', 'location_id', 'rack_id', 'device_id')), + (_('Attributes'), ('type', 'status', 'color', 'length', 'length_unit')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -927,20 +957,25 @@ class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('Device') ) type = forms.MultipleChoiceField( + label=_('Type'), choices=add_blank_choice(CableTypeChoices), required=False ) status = forms.MultipleChoiceField( + label=_('Status'), required=False, choices=add_blank_choice(LinkStatusChoices) ) color = ColorField( + label=_('Color'), required=False ) length = forms.IntegerField( + label=_('Length'), required=False ) length_unit = forms.ChoiceField( + label=_('Length unit'), choices=add_blank_choice(CableLengthUnitChoices), required=False ) @@ -951,8 +986,8 @@ class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): model = PowerPanel fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -989,9 +1024,9 @@ class PowerFeedFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = PowerFeed fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Attributes', ('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Attributes'), ('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -1030,28 +1065,35 @@ class PowerFeedFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('Rack') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=PowerFeedStatusChoices, required=False ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(PowerFeedTypeChoices), required=False ) supply = forms.ChoiceField( + label=_('Supply'), choices=add_blank_choice(PowerFeedSupplyChoices), required=False ) phase = forms.ChoiceField( + label=_('Phase'), choices=add_blank_choice(PowerFeedPhaseChoices), required=False ) voltage = forms.IntegerField( + label=_('Voltage'), required=False ) amperage = forms.IntegerField( + label=_('Amperage'), required=False ) max_utilization = forms.IntegerField( + label=_('Max utilization'), required=False ) tag = TagFilterField(model) @@ -1063,12 +1105,14 @@ class PowerFeedFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class CabledFilterForm(forms.Form): cabled = forms.NullBooleanField( + label=_('Cabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) occupied = forms.NullBooleanField( + label=_('Occupied'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -1078,6 +1122,7 @@ class CabledFilterForm(forms.Form): class PathEndpointFilterForm(CabledFilterForm): connected = forms.NullBooleanField( + label=_('Connected'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -1089,16 +1134,18 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = ConsolePort fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'type', 'speed')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), - ('Connection', ('cabled', 'connected', 'occupied')), + (_('Attributes'), ('name', 'label', 'type', 'speed')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Connection'), ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( + label=_('Type'), choices=ConsolePortTypeChoices, required=False ) speed = forms.MultipleChoiceField( + label=_('Speed'), choices=ConsolePortSpeedChoices, required=False ) @@ -1109,16 +1156,18 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF model = ConsoleServerPort fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'type', 'speed')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), - ('Connection', ('cabled', 'connected', 'occupied')), + (_('Attributes'), ('name', 'label', 'type', 'speed')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Connection'), ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( + label=_('Type'), choices=ConsolePortTypeChoices, required=False ) speed = forms.MultipleChoiceField( + label=_('Speed'), choices=ConsolePortSpeedChoices, required=False ) @@ -1129,12 +1178,13 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = PowerPort fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'type')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), - ('Connection', ('cabled', 'connected', 'occupied')), + (_('Attributes'), ('name', 'label', 'type')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Connection'), ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( + label=_('Type'), choices=PowerPortTypeChoices, required=False ) @@ -1145,12 +1195,13 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = PowerOutlet fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'type')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), - ('Connection', ('cabled', 'connected', 'occupied')), + (_('Attributes'), ('name', 'label', 'type')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Connection'), ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( + label=_('Type'), choices=PowerOutletTypeChoices, required=False ) @@ -1161,13 +1212,13 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = Interface fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only')), - ('Addressing', ('vrf_id', 'l2vpn_id', 'mac_address', 'wwn')), - ('PoE', ('poe_mode', 'poe_type')), - ('Wireless', ('rf_role', 'rf_channel', 'rf_channel_width', 'tx_power')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id', 'vdc_id')), - ('Connection', ('cabled', 'connected', 'occupied')), + (_('Attributes'), ('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only')), + (_('Addressing'), ('vrf_id', 'l2vpn_id', 'mac_address', 'wwn')), + (_('PoE'), ('poe_mode', 'poe_type')), + (_('Wireless'), ('rf_role', 'rf_channel', 'rf_channel_width', 'tx_power')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id', 'vdc_id')), + (_('Connection'), ('cabled', 'connected', 'occupied')), ) vdc_id = DynamicModelMultipleChoiceField( queryset=VirtualDeviceContext.objects.all(), @@ -1178,30 +1229,36 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): label=_('Virtual Device Context') ) kind = forms.MultipleChoiceField( + label=_('Kind'), choices=InterfaceKindChoices, required=False ) type = forms.MultipleChoiceField( + label=_('Type'), choices=InterfaceTypeChoices, required=False ) speed = forms.IntegerField( + label=_('Speed'), required=False, widget=NumberWithOptions( options=InterfaceSpeedChoices ) ) duplex = forms.MultipleChoiceField( + label=_('Duplex'), choices=InterfaceDuplexChoices, required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) mgmt_only = forms.NullBooleanField( + label=_('Mgmt only'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -1209,50 +1266,50 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): ) mac_address = forms.CharField( required=False, - label='MAC address' + label=_('MAC address') ) wwn = forms.CharField( required=False, - label='WWN' + label=_('WWN') ) poe_mode = forms.MultipleChoiceField( choices=InterfacePoEModeChoices, required=False, - label='PoE mode' + label=_('PoE mode') ) poe_type = forms.MultipleChoiceField( choices=InterfacePoETypeChoices, required=False, - label='PoE type' + label=_('PoE type') ) rf_role = forms.MultipleChoiceField( choices=WirelessRoleChoices, required=False, - label='Wireless role' + label=_('Wireless role') ) rf_channel = forms.MultipleChoiceField( choices=WirelessChannelChoices, required=False, - label='Wireless channel' + label=_('Wireless channel') ) rf_channel_frequency = forms.IntegerField( required=False, - label='Channel frequency (MHz)' + label=_('Channel frequency (MHz)') ) rf_channel_width = forms.IntegerField( required=False, - label='Channel width (MHz)' + label=_('Channel width (MHz)') ) tx_power = forms.IntegerField( required=False, - label='Transmit power (dBm)', + label=_('Transmit power (dBm)'), min_value=0, max_value=127 ) vrf_id = DynamicModelMultipleChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) l2vpn_id = DynamicModelMultipleChoiceField( queryset=L2VPN.objects.all(), @@ -1265,17 +1322,19 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'type', 'color')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), - ('Cable', ('cabled', 'occupied')), + (_('Attributes'), ('name', 'label', 'type', 'color')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Cable'), ('cabled', 'occupied')), ) model = FrontPort type = forms.MultipleChoiceField( + label=_('Type'), choices=PortTypeChoices, required=False ) color = ColorField( + label=_('Color'), required=False ) tag = TagFilterField(model) @@ -1285,16 +1344,18 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): model = RearPort fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'type', 'color')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), - ('Cable', ('cabled', 'occupied')), + (_('Attributes'), ('name', 'label', 'type', 'color')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Cable'), ('cabled', 'occupied')), ) type = forms.MultipleChoiceField( + label=_('Type'), choices=PortTypeChoices, required=False ) color = ColorField( + label=_('Color'), required=False ) tag = TagFilterField(model) @@ -1304,12 +1365,13 @@ class ModuleBayFilterForm(DeviceComponentFilterForm): model = ModuleBay fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'position')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Attributes'), ('name', 'label', 'position')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ) tag = TagFilterField(model) position = forms.CharField( + label=_('Position'), required=False ) @@ -1318,9 +1380,9 @@ class DeviceBayFilterForm(DeviceComponentFilterForm): model = DeviceBay fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Attributes'), ('name', 'label')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ) tag = TagFilterField(model) @@ -1329,9 +1391,9 @@ class InventoryItemFilterForm(DeviceComponentFilterForm): model = InventoryItem fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), + (_('Attributes'), ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + (_('Device'), ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ) role_id = DynamicModelMultipleChoiceField( queryset=InventoryItemRole.objects.all(), @@ -1345,12 +1407,15 @@ class InventoryItemFilterForm(DeviceComponentFilterForm): label=_('Manufacturer') ) serial = forms.CharField( + label=_('Serial'), required=False ) asset_tag = forms.CharField( + label=_('Asset tag'), required=False ) discovered = forms.NullBooleanField( + label=_('Discovered'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES diff --git a/netbox/dcim/forms/formsets.py b/netbox/dcim/forms/formsets.py index 6109a1575..0b9d89a5d 100644 --- a/netbox/dcim/forms/formsets.py +++ b/netbox/dcim/forms/formsets.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext_lazy as _ __all__ = ( 'BaseVCMemberFormSet', @@ -16,6 +17,8 @@ class BaseVCMemberFormSet(forms.BaseModelFormSet): vc_position = form.cleaned_data.get('vc_position') if vc_position: if vc_position in vc_position_list: - error_msg = f"A virtual chassis member already exists in position {vc_position}." + error_msg = _("A virtual chassis member already exists in position {vc_position}.").format( + vc_position=vc_position + ) form.add_error('vc_position', error_msg) vc_position_list.append(vc_position) diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 4c382babc..4bdb19120 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from timezone_field import TimeZoneFormField from dcim.choices import * @@ -70,13 +70,14 @@ __all__ = ( class RegionForm(NetBoxModelForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=Region.objects.all(), required=False ) slug = SlugField() fieldsets = ( - ('Region', ( + (_('Region'), ( 'parent', 'name', 'slug', 'description', 'tags', )), ) @@ -90,13 +91,14 @@ class RegionForm(NetBoxModelForm): class SiteGroupForm(NetBoxModelForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=SiteGroup.objects.all(), required=False ) slug = SlugField() fieldsets = ( - ('Site Group', ( + (_('Site Group'), ( 'parent', 'name', 'slug', 'description', 'tags', )), ) @@ -110,10 +112,12 @@ class SiteGroupForm(NetBoxModelForm): class SiteForm(TenancyForm, NetBoxModelForm): region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False ) group = DynamicModelChoiceField( + label=_('Group'), queryset=SiteGroup.objects.all(), required=False ) @@ -124,17 +128,18 @@ class SiteForm(TenancyForm, NetBoxModelForm): ) slug = SlugField() time_zone = TimeZoneFormField( + label=_('Time zone'), choices=add_blank_choice(TimeZoneFormField().choices), required=False ) comments = CommentField() fieldsets = ( - ('Site', ( + (_('Site'), ( 'name', 'slug', 'status', 'region', 'group', 'facility', 'asns', 'time_zone', 'description', 'tags', )), - ('Tenancy', ('tenant_group', 'tenant')), - ('Contact Info', ('physical_address', 'shipping_address', 'latitude', 'longitude')), + (_('Tenancy'), ('tenant_group', 'tenant')), + (_('Contact Info'), ('physical_address', 'shipping_address', 'latitude', 'longitude')), ) class Meta: @@ -159,10 +164,12 @@ class SiteForm(TenancyForm, NetBoxModelForm): class LocationForm(TenancyForm, NetBoxModelForm): site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), selector=True ) parent = DynamicModelChoiceField( + label=_('Parent'), queryset=Location.objects.all(), required=False, query_params={ @@ -172,8 +179,8 @@ class LocationForm(TenancyForm, NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Location', ('site', 'parent', 'name', 'slug', 'status', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('Location'), ('site', 'parent', 'name', 'slug', 'status', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -187,7 +194,7 @@ class RackRoleForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Rack Role', ( + (_('Rack Role'), ( 'name', 'slug', 'color', 'description', 'tags', )), ) @@ -201,10 +208,12 @@ class RackRoleForm(NetBoxModelForm): class RackForm(TenancyForm, NetBoxModelForm): site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), selector=True ) location = DynamicModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, query_params={ @@ -212,6 +221,7 @@ class RackForm(TenancyForm, NetBoxModelForm): } ) role = DynamicModelChoiceField( + label=_('Role'), queryset=RackRole.objects.all(), required=False ) @@ -228,14 +238,17 @@ class RackForm(TenancyForm, NetBoxModelForm): class RackReservationForm(TenancyForm, NetBoxModelForm): rack = DynamicModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), selector=True ) units = NumericArrayField( + label=_('Units'), base_field=forms.IntegerField(), help_text=_("Comma-separated list of numeric unit IDs. A range may be specified using a hyphen.") ) user = forms.ModelChoiceField( + label=_('User'), queryset=get_user_model().objects.order_by( 'username' ) @@ -243,8 +256,8 @@ class RackReservationForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Reservation', ('rack', 'units', 'user', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('Reservation'), ('rack', 'units', 'user', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -258,7 +271,7 @@ class ManufacturerForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Manufacturer', ( + (_('Manufacturer'), ( 'name', 'slug', 'description', 'tags', )), ) @@ -272,23 +285,26 @@ class ManufacturerForm(NetBoxModelForm): class DeviceTypeForm(NetBoxModelForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all() ) default_platform = DynamicModelChoiceField( + label=_('Default platform'), queryset=Platform.objects.all(), required=False ) slug = SlugField( + label=_('Slug'), slug_source='model' ) comments = CommentField() fieldsets = ( - ('Device Type', ('manufacturer', 'model', 'slug', 'default_platform', 'description', 'tags')), - ('Chassis', ( + (_('Device Type'), ('manufacturer', 'model', 'slug', 'default_platform', 'description', 'tags')), + (_('Chassis'), ( 'u_height', 'is_full_depth', 'part_number', 'subdevice_role', 'airflow', 'weight', 'weight_unit', )), - ('Images', ('front_image', 'rear_image')), + (_('Images'), ('front_image', 'rear_image')), ) class Meta: @@ -310,13 +326,14 @@ class DeviceTypeForm(NetBoxModelForm): class ModuleTypeForm(NetBoxModelForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all() ) comments = CommentField() fieldsets = ( - ('Module Type', ('manufacturer', 'model', 'part_number', 'description', 'tags')), - ('Weight', ('weight', 'weight_unit')) + (_('Module Type'), ('manufacturer', 'model', 'part_number', 'description', 'tags')), + (_('Weight'), ('weight', 'weight_unit')) ) class Meta: @@ -328,13 +345,14 @@ class ModuleTypeForm(NetBoxModelForm): class DeviceRoleForm(NetBoxModelForm): config_template = DynamicModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), required=False ) slug = SlugField() fieldsets = ( - ('Device Role', ( + (_('Device Role'), ( 'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags', )), ) @@ -348,19 +366,22 @@ class DeviceRoleForm(NetBoxModelForm): class PlatformForm(NetBoxModelForm): manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) config_template = DynamicModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), required=False ) slug = SlugField( + label=_('Slug'), max_length=64 ) fieldsets = ( - ('Platform', ('name', 'slug', 'manufacturer', 'config_template', 'description', 'tags')), + (_('Platform'), ('name', 'slug', 'manufacturer', 'config_template', 'description', 'tags')), ) class Meta: @@ -372,10 +393,12 @@ class PlatformForm(NetBoxModelForm): class DeviceForm(TenancyForm, NetBoxModelForm): site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), selector=True ) location = DynamicModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, query_params={ @@ -386,6 +409,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm): } ) rack = DynamicModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), required=False, query_params={ @@ -394,6 +418,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm): } ) position = forms.DecimalField( + label=_('Position'), required=False, help_text=_("The lowest-numbered unit occupied by the device"), widget=APISelect( @@ -405,17 +430,21 @@ class DeviceForm(TenancyForm, NetBoxModelForm): ) ) device_type = DynamicModelChoiceField( + label=_('Device type'), queryset=DeviceType.objects.all(), selector=True ) device_role = DynamicModelChoiceField( + label=_('Device role'), queryset=DeviceRole.objects.all() ) platform = DynamicModelChoiceField( + label=_('Platform'), queryset=Platform.objects.all(), required=False ) cluster = DynamicModelChoiceField( + label=_('Cluster'), queryset=Cluster.objects.all(), required=False, selector=True @@ -426,6 +455,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm): label='' ) virtual_chassis = DynamicModelChoiceField( + label=_('Virtual chassis'), queryset=VirtualChassis.objects.all(), required=False, selector=True @@ -441,6 +471,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm): help_text=_("The priority of the device in the virtual chassis") ) config_template = DynamicModelChoiceField( + label=_('Config template'), queryset=ConfigTemplate.objects.all(), required=False ) @@ -518,36 +549,41 @@ class DeviceForm(TenancyForm, NetBoxModelForm): class ModuleForm(ModuleCommonForm, NetBoxModelForm): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), initial_params={ 'modulebays': '$module_bay' } ) module_bay = DynamicModelChoiceField( + label=_('Module bay'), queryset=ModuleBay.objects.all(), query_params={ 'device_id': '$device' } ) module_type = DynamicModelChoiceField( + label=_('Module type'), queryset=ModuleType.objects.all(), selector=True ) comments = CommentField() replicate_components = forms.BooleanField( + label=_('Replicate components'), required=False, initial=True, help_text=_("Automatically populate components associated with this module type") ) adopt_components = forms.BooleanField( + label=_('Adopt components'), required=False, initial=False, help_text=_("Adopt already existing components") ) fieldsets = ( - ('Module', ('device', 'module_bay', 'module_type', 'status', 'description', 'tags')), - ('Hardware', ( + (_('Module'), ('device', 'module_bay', 'module_type', 'status', 'description', 'tags')), + (_('Hardware'), ( 'serial', 'asset_tag', 'replicate_components', 'adopt_components', )), ) @@ -581,17 +617,19 @@ class CableForm(TenancyForm, NetBoxModelForm): ] error_messages = { 'length': { - 'max_value': 'Maximum length is 32767 (any unit)' + 'max_value': _('Maximum length is 32767 (any unit)') } } class PowerPanelForm(NetBoxModelForm): site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), selector=True ) location = DynamicModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, query_params={ @@ -613,10 +651,12 @@ class PowerPanelForm(NetBoxModelForm): class PowerFeedForm(TenancyForm, NetBoxModelForm): power_panel = DynamicModelChoiceField( + label=_('Power panel'), queryset=PowerPanel.objects.all(), selector=True ) rack = DynamicModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), required=False, selector=True @@ -624,9 +664,9 @@ class PowerFeedForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Power Feed', ('power_panel', 'rack', 'name', 'status', 'type', 'description', 'mark_connected', 'tags')), - ('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('Power Feed'), ('power_panel', 'rack', 'name', 'status', 'type', 'description', 'mark_connected', 'tags')), + (_('Characteristics'), ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -643,6 +683,7 @@ class PowerFeedForm(TenancyForm, NetBoxModelForm): class VirtualChassisForm(NetBoxModelForm): master = forms.ModelChoiceField( + label=_('Master'), queryset=Device.objects.all(), required=False, ) @@ -706,6 +747,7 @@ class DeviceVCMembershipForm(forms.ModelForm): class VCMemberSelectForm(BootstrapMixin, forms.Form): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), query_params={ 'virtual_chassis_id': 'null', @@ -728,6 +770,7 @@ class VCMemberSelectForm(BootstrapMixin, forms.Form): class ComponentTemplateForm(BootstrapMixin, forms.ModelForm): device_type = DynamicModelChoiceField( + label=_('Device type'), queryset=DeviceType.objects.all() ) @@ -741,10 +784,12 @@ class ComponentTemplateForm(BootstrapMixin, forms.ModelForm): class ModularComponentTemplateForm(ComponentTemplateForm): device_type = DynamicModelChoiceField( + label=_('Device type'), queryset=DeviceType.objects.all().all(), required=False ) module_type = DynamicModelChoiceField( + label=_('Module type'), queryset=ModuleType.objects.all(), required=False ) @@ -797,6 +842,7 @@ class PowerPortTemplateForm(ModularComponentTemplateForm): class PowerOutletTemplateForm(ModularComponentTemplateForm): power_port = DynamicModelChoiceField( + label=_('Power port'), queryset=PowerPortTemplate.objects.all(), required=False, query_params={ @@ -817,6 +863,7 @@ class PowerOutletTemplateForm(ModularComponentTemplateForm): class InterfaceTemplateForm(ModularComponentTemplateForm): bridge = DynamicModelChoiceField( + label=_('Bridge'), queryset=InterfaceTemplate.objects.all(), required=False, query_params={ @@ -827,8 +874,8 @@ class InterfaceTemplateForm(ModularComponentTemplateForm): fieldsets = ( (None, ('device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'bridge')), - ('PoE', ('poe_mode', 'poe_type')), - ('Wireless', ('rf_role',)) + (_('PoE'), ('poe_mode', 'poe_type')), + (_('Wireless'), ('rf_role',)), ) class Meta: @@ -840,6 +887,7 @@ class InterfaceTemplateForm(ModularComponentTemplateForm): class FrontPortTemplateForm(ModularComponentTemplateForm): rear_port = DynamicModelChoiceField( + label=_('Rear port'), queryset=RearPortTemplate.objects.all(), required=False, query_params={ @@ -901,6 +949,7 @@ class DeviceBayTemplateForm(ComponentTemplateForm): class InventoryItemTemplateForm(ComponentTemplateForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=InventoryItemTemplate.objects.all(), required=False, query_params={ @@ -908,10 +957,12 @@ class InventoryItemTemplateForm(ComponentTemplateForm): } ) role = DynamicModelChoiceField( + label=_('Role'), queryset=InventoryItemRole.objects.all(), required=False ) manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) @@ -947,6 +998,7 @@ class InventoryItemTemplateForm(ComponentTemplateForm): class DeviceComponentForm(NetBoxModelForm): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), selector=True ) @@ -961,6 +1013,7 @@ class DeviceComponentForm(NetBoxModelForm): class ModularDeviceComponentForm(DeviceComponentForm): module = DynamicModelChoiceField( + label=_('Module'), queryset=Module.objects.all(), required=False, query_params={ @@ -1017,6 +1070,7 @@ class PowerPortForm(ModularDeviceComponentForm): class PowerOutletForm(ModularDeviceComponentForm): power_port = DynamicModelChoiceField( + label=_('Power port'), queryset=PowerPort.objects.all(), required=False, query_params={ @@ -1043,7 +1097,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): vdcs = DynamicModelMultipleChoiceField( queryset=VirtualDeviceContext.objects.all(), required=False, - label='Virtual Device Contexts', + label=_('Virtual device contexts'), query_params={ 'device_id': '$device', } @@ -1121,13 +1175,13 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): ) fieldsets = ( - ('Interface', ('device', 'module', 'name', 'label', 'type', 'speed', 'duplex', 'description', 'tags')), - ('Addressing', ('vrf', 'mac_address', 'wwn')), - ('Operation', ('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), - ('Related Interfaces', ('parent', 'bridge', 'lag')), - ('PoE', ('poe_mode', 'poe_type')), - ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), - ('Wireless', ( + (_('Interface'), ('device', 'module', 'name', 'label', 'type', 'speed', 'duplex', 'description', 'tags')), + (_('Addressing'), ('vrf', 'mac_address', 'wwn')), + (_('Operation'), ('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')), + (_('Related Interfaces'), ('parent', 'bridge', 'lag')), + (_('PoE'), ('poe_mode', 'poe_type')), + (_('802.1Q Switching'), ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), + (_('Wireless'), ( 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'wireless_lan_group', 'wireless_lans', )), ) @@ -1233,6 +1287,7 @@ class PopulateDeviceBayForm(BootstrapMixin, forms.Form): class InventoryItemForm(DeviceComponentForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=InventoryItem.objects.all(), required=False, query_params={ @@ -1240,10 +1295,12 @@ class InventoryItemForm(DeviceComponentForm): } ) role = DynamicModelChoiceField( + label=_('Role'), queryset=InventoryItemRole.objects.all(), required=False ) manufacturer = DynamicModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), required=False ) @@ -1307,8 +1364,8 @@ class InventoryItemForm(DeviceComponentForm): ) fieldsets = ( - ('Inventory Item', ('device', 'parent', 'name', 'label', 'role', 'description', 'tags')), - ('Hardware', ('manufacturer', 'part_id', 'serial', 'asset_tag')), + (_('Inventory Item'), ('device', 'parent', 'name', 'label', 'role', 'description', 'tags')), + (_('Hardware'), ('manufacturer', 'part_id', 'serial', 'asset_tag')), ) class Meta: @@ -1359,7 +1416,7 @@ class InventoryItemForm(DeviceComponentForm): ) if self.cleaned_data[field] ] if len(selected_objects) > 1: - raise forms.ValidationError("An InventoryItem can only be assigned to a single component.") + raise forms.ValidationError(_("An InventoryItem can only be assigned to a single component.")) elif selected_objects: self.instance.component = self.cleaned_data[selected_objects[0]] else: @@ -1373,7 +1430,7 @@ class InventoryItemRoleForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Inventory Item Role', ( + (_('Inventory Item Role'), ( 'name', 'slug', 'color', 'description', 'tags', )), ) @@ -1387,12 +1444,13 @@ class InventoryItemRoleForm(NetBoxModelForm): class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), selector=True ) primary_ip4 = DynamicModelChoiceField( queryset=IPAddress.objects.all(), - label='Primary IPv4', + label=_('Primary IPv4'), required=False, query_params={ 'device_id': '$device', @@ -1401,7 +1459,7 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm): ) primary_ip6 = DynamicModelChoiceField( queryset=IPAddress.objects.all(), - label='Primary IPv6', + label=_('Primary IPv6'), required=False, query_params={ 'device_id': '$device', @@ -1410,8 +1468,8 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm): ) fieldsets = ( - ('Virtual Device Context', ('device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')) + (_('Virtual Device Context'), ('device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')) ) class Meta: diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index 9589ab533..b41e63b58 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.models import * from netbox.forms import NetBoxModelForm @@ -38,8 +38,11 @@ class ComponentCreateForm(forms.Form): Subclass this form when facilitating the creation of one or more component or component template objects based on a name pattern. """ - name = ExpandableNameField() + name = ExpandableNameField( + label=_('Name'), + ) label = ExpandableNameField( + label=_('Label'), required=False, help_text=_('Alphanumeric ranges are supported. (Must match the number of objects being created.)') ) @@ -57,8 +60,9 @@ class ComponentCreateForm(forms.Form): value_count = len(self.cleaned_data[field_name]) if self.cleaned_data[field_name] and value_count != pattern_count: raise forms.ValidationError({ - field_name: f'The provided pattern specifies {value_count} values, but {pattern_count} are ' - f'expected.' + field_name: _( + "The provided pattern specifies {value_count} values, but {pattern_count} are expected." + ).format(value_count=value_count, pattern_count=pattern_count) }, code='label_pattern_mismatch') @@ -222,12 +226,14 @@ class InterfaceCreateForm(ComponentCreateForm, model_forms.InterfaceForm): super().__init__(*args, **kwargs) if 'module' in self.fields: - self.fields['name'].help_text += ' The string {module} will be replaced with the position ' \ - 'of the assigned module, if any' + self.fields['name'].help_text += _( + "The string {module} will be replaced with the position of the assigned module, if any." + ) class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), selector=True, widget=APISelect( @@ -329,6 +335,7 @@ class InventoryItemCreateForm(ComponentCreateForm, model_forms.InventoryItemForm class VirtualChassisCreateForm(NetBoxModelForm): region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False, initial_params={ @@ -336,6 +343,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): } ) site_group = DynamicModelChoiceField( + label=_('Site group'), queryset=SiteGroup.objects.all(), required=False, initial_params={ @@ -343,6 +351,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): } ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, query_params={ @@ -351,6 +360,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): } ) rack = DynamicModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), required=False, null_option='None', @@ -359,6 +369,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): } ) members = DynamicModelMultipleChoiceField( + label=_('Members'), queryset=Device.objects.all(), required=False, query_params={ @@ -367,6 +378,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): } ) initial_position = forms.IntegerField( + label=_('Initial position'), initial=1, required=False, help_text=_('Position of the first member device. Increases by one for each additional member.') @@ -383,7 +395,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): if self.cleaned_data['members'] and self.cleaned_data['initial_position'] is None: raise forms.ValidationError({ - 'initial_position': "A position must be specified for the first VC member." + 'initial_position': _("A position must be specified for the first VC member.") }) def save(self, *args, **kwargs): diff --git a/netbox/dcim/forms/object_import.py b/netbox/dcim/forms/object_import.py index 01efbe123..bab8876da 100644 --- a/netbox/dcim/forms/object_import.py +++ b/netbox/dcim/forms/object_import.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices from dcim.models import * @@ -57,6 +57,7 @@ class PowerPortTemplateImportForm(ComponentTemplateImportForm): class PowerOutletTemplateImportForm(ComponentTemplateImportForm): power_port = forms.ModelChoiceField( + label=_('Power port'), queryset=PowerPortTemplate.objects.all(), to_field_name='name', required=False @@ -85,6 +86,7 @@ class PowerOutletTemplateImportForm(ComponentTemplateImportForm): class InterfaceTemplateImportForm(ComponentTemplateImportForm): type = forms.ChoiceField( + label=_('Type'), choices=InterfaceTypeChoices.CHOICES ) poe_mode = forms.ChoiceField( @@ -113,9 +115,11 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm): class FrontPortTemplateImportForm(ComponentTemplateImportForm): type = forms.ChoiceField( + label=_('Type'), choices=PortTypeChoices.CHOICES ) rear_port = forms.ModelChoiceField( + label=_('Rear port'), queryset=RearPortTemplate.objects.all(), to_field_name='name' ) @@ -143,6 +147,7 @@ class FrontPortTemplateImportForm(ComponentTemplateImportForm): class RearPortTemplateImportForm(ComponentTemplateImportForm): type = forms.ChoiceField( + label=_('Type'), choices=PortTypeChoices.CHOICES ) @@ -173,15 +178,18 @@ class DeviceBayTemplateImportForm(ComponentTemplateImportForm): class InventoryItemTemplateImportForm(ComponentTemplateImportForm): parent = forms.ModelChoiceField( + label=_('Parent'), queryset=InventoryItemTemplate.objects.all(), required=False ) role = forms.ModelChoiceField( + label=_('Role'), queryset=InventoryItemRole.objects.all(), to_field_name='name', required=False ) manufacturer = forms.ModelChoiceField( + label=_('Manufacturer'), queryset=Manufacturer.objects.all(), to_field_name='name', required=False diff --git a/netbox/extras/forms/bulk_edit.py b/netbox/extras/forms/bulk_edit.py index 2a55d87da..46bd4d64c 100644 --- a/netbox/extras/forms/bulk_edit.py +++ b/netbox/extras/forms/bulk_edit.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import * from extras.models import * @@ -27,16 +27,20 @@ class CustomFieldBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) group_name = forms.CharField( + label=_('Group name'), required=False ) description = forms.CharField( + label=_('Description'), required=False ) required = forms.NullBooleanField( + label=_('Required'), required=False, widget=BulkEditNullBooleanSelect() ) weight = forms.IntegerField( + label=_('Weight'), required=False ) choice_set = DynamicModelChoiceField( @@ -50,6 +54,7 @@ class CustomFieldBulkEditForm(BulkEditForm): initial='' ) is_cloneable = forms.NullBooleanField( + label=_('Is cloneable'), required=False, widget=BulkEditNullBooleanSelect() ) @@ -83,17 +88,21 @@ class CustomLinkBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=BulkEditNullBooleanSelect() ) new_window = forms.NullBooleanField( + label=_('New window'), required=False, widget=BulkEditNullBooleanSelect() ) weight = forms.IntegerField( + label=_('Weight'), required=False ) button_class = forms.ChoiceField( + label=_('Button class'), choices=add_blank_choice(CustomLinkButtonClassChoices), required=False ) @@ -105,18 +114,22 @@ class ExportTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) mime_type = forms.CharField( + label=_('MIME type'), max_length=50, required=False ) file_extension = forms.CharField( + label=_('File extension'), max_length=15, required=False ) as_attachment = forms.NullBooleanField( + label=_('As attachment'), required=False, widget=BulkEditNullBooleanSelect() ) @@ -130,17 +143,21 @@ class SavedFilterBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) weight = forms.IntegerField( + label=_('Weight'), required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=BulkEditNullBooleanSelect() ) shared = forms.NullBooleanField( + label=_('Shared'), required=False, widget=BulkEditNullBooleanSelect() ) @@ -154,26 +171,32 @@ class WebhookBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=BulkEditNullBooleanSelect() ) type_create = forms.NullBooleanField( + label=_('On create'), required=False, widget=BulkEditNullBooleanSelect() ) type_update = forms.NullBooleanField( + label=_('On update'), required=False, widget=BulkEditNullBooleanSelect() ) type_delete = forms.NullBooleanField( + label=_('On delete'), required=False, widget=BulkEditNullBooleanSelect() ) type_job_start = forms.NullBooleanField( + label=_('On job start'), required=False, widget=BulkEditNullBooleanSelect() ) type_job_end = forms.NullBooleanField( + label=_('On job end'), required=False, widget=BulkEditNullBooleanSelect() ) @@ -192,6 +215,7 @@ class WebhookBulkEditForm(BulkEditForm): label=_('SSL verification') ) secret = forms.CharField( + label=_('Secret'), required=False ) ca_file_path = forms.CharField( @@ -208,9 +232,11 @@ class TagBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) color = ColorField( + label=_('Color'), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -224,14 +250,17 @@ class ConfigContextBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) weight = forms.IntegerField( + label=_('Weight'), required=False, min_value=0 ) is_active = forms.NullBooleanField( + label=_('Is active'), required=False, widget=BulkEditNullBooleanSelect() ) description = forms.CharField( + label=_('Description'), required=False, max_length=100 ) @@ -245,6 +274,7 @@ class ConfigTemplateBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -258,10 +288,12 @@ class JournalEntryBulkEditForm(BulkEditForm): widget=forms.MultipleHiddenInput ) kind = forms.ChoiceField( + label=_('Kind'), choices=add_blank_choice(JournalEntryKindChoices), required=False ) comments = forms.CharField( + label=_('Comments'), required=False, widget=forms.Textarea() ) diff --git a/netbox/extras/forms/bulk_import.py b/netbox/extras/forms/bulk_import.py index e91ce7e93..31afbd39d 100644 --- a/netbox/extras/forms/bulk_import.py +++ b/netbox/extras/forms/bulk_import.py @@ -2,7 +2,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.forms import SimpleArrayField from django.utils.safestring import mark_safe -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import * from extras.models import * @@ -28,27 +28,32 @@ __all__ = ( class CustomFieldImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), help_text=_("One or more assigned object types") ) type = CSVChoiceField( + label=_('Type'), choices=CustomFieldTypeChoices, help_text=_('Field data type (e.g. text, integer, etc.)') ) object_type = CSVContentTypeField( + label=_('Object type'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False, help_text=_("Object type (for object or multi-object fields)") ) choice_set = CSVModelChoiceField( + label=_('Choice set'), queryset=CustomFieldChoiceSet.objects.all(), to_field_name='name', required=False, help_text=_('Choice set (for selection fields)') ) ui_visibility = CSVChoiceField( + label=_('UI visibility'), choices=CustomFieldVisibilityChoices, help_text=_('How the custom field is displayed in the user interface') ) @@ -83,6 +88,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm): class CustomLinkImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links'), help_text=_("One or more assigned object types") @@ -98,6 +104,7 @@ class CustomLinkImportForm(CSVModelForm): class ExportTemplateImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates'), help_text=_("One or more assigned object types") @@ -121,6 +128,7 @@ class ConfigTemplateImportForm(CSVModelForm): class SavedFilterImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), help_text=_("One or more assigned object types") ) @@ -134,6 +142,7 @@ class SavedFilterImportForm(CSVModelForm): class WebhookImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks'), help_text=_("One or more assigned object types") @@ -165,6 +174,7 @@ class JournalEntryImportForm(NetBoxModelImportForm): label=_('Assigned object type'), ) kind = CSVChoiceField( + label=_('Kind'), choices=JournalEntryKindChoices, help_text=_('The classification of entry') ) diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index a181e9a18..5d1d2015e 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from core.models import DataFile, DataSource from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup @@ -39,7 +39,7 @@ __all__ = ( class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ( + (_('Attributes'), ( 'type', 'content_type_id', 'group_name', 'weight', 'required', 'choice_set_id', 'ui_visibility', 'is_cloneable', )), @@ -55,12 +55,15 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): label=_('Field type') ) group_name = forms.CharField( + label=_('Group name'), required=False ) weight = forms.IntegerField( + label=_('Weight'), required=False ) required = forms.NullBooleanField( + label=_('Required'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -77,6 +80,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): label=_('UI visibility') ) is_cloneable = forms.NullBooleanField( + label=_('Is cloneable'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -104,22 +108,26 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): (_('Attributes'), ('content_types', 'enabled', 'new_window', 'weight')), ) content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.filter(FeatureQuery('custom_links').get_query()), required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) new_window = forms.NullBooleanField( + label=_('New window'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) weight = forms.IntegerField( + label=_('Weight'), required=False ) @@ -127,8 +135,8 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Data', ('data_source_id', 'data_file_id')), - ('Attributes', ('content_types', 'mime_type', 'file_extension', 'as_attachment')), + (_('Data'), ('data_source_id', 'data_file_id')), + (_('Attributes'), ('content_types', 'mime_type', 'file_extension', 'as_attachment')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -144,6 +152,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): } ) content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()), required=False ) @@ -152,9 +161,11 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): label=_('MIME type') ) file_extension = forms.CharField( + label=_('File extension'), required=False ) as_attachment = forms.NullBooleanField( + label=_('As attachment'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -165,13 +176,15 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ('content_type_id', 'name',)), + (_('Attributes'), ('content_type_id', 'name',)), ) content_type_id = ContentTypeChoiceField( + label=_('Content type'), queryset=ContentType.objects.filter(FeatureQuery('custom_fields').get_query()), required=False ) name = forms.CharField( + label=_('Name'), required=False ) @@ -179,25 +192,29 @@ class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm): class SavedFilterFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ('content_types', 'enabled', 'shared', 'weight')), + (_('Attributes'), ('content_types', 'enabled', 'shared', 'weight')), ) content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()), required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) shared = forms.NullBooleanField( + label=_('Shared'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) weight = forms.IntegerField( + label=_('Weight'), required=False ) @@ -205,8 +222,8 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm): class WebhookFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ('content_type_id', 'http_method', 'enabled')), - ('Events', ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), + (_('Attributes'), ('content_type_id', 'http_method', 'enabled')), + (_('Events'), ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), ) content_type_id = ContentTypeMultipleChoiceField( queryset=ContentType.objects.filter(FeatureQuery('webhooks').get_query()), @@ -219,6 +236,7 @@ class WebhookFilterForm(SavedFiltersMixin, FilterForm): label=_('HTTP method') ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -278,11 +296,11 @@ class TagFilterForm(SavedFiltersMixin, FilterForm): class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag_id')), - ('Data', ('data_source_id', 'data_file_id')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')), - ('Device', ('device_type_id', 'platform_id', 'role_id')), - ('Cluster', ('cluster_type_id', 'cluster_group_id', 'cluster_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')) + (_('Data'), ('data_source_id', 'data_file_id')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id')), + (_('Device'), ('device_type_id', 'platform_id', 'role_id')), + (_('Cluster'), ('cluster_type_id', 'cluster_group_id', 'cluster_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')) ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -368,7 +386,7 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Data', ('data_source_id', 'data_file_id')), + (_('Data'), ('data_source_id', 'data_file_id')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -400,8 +418,8 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm): model = JournalEntry fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Creation', ('created_before', 'created_after', 'created_by_id')), - ('Attributes', ('assigned_object_type_id', 'kind')) + (_('Creation'), ('created_before', 'created_after', 'created_by_id')), + (_('Attributes'), ('assigned_object_type_id', 'kind')) ) created_after = forms.DateTimeField( required=False, @@ -430,6 +448,7 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm): ) ) kind = forms.ChoiceField( + label=_('Kind'), choices=add_blank_choice(JournalEntryKindChoices), required=False ) @@ -440,8 +459,8 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm): model = ObjectChange fieldsets = ( (None, ('q', 'filter_id')), - ('Time', ('time_before', 'time_after')), - ('Attributes', ('action', 'user_id', 'changed_object_type_id')), + (_('Time'), ('time_before', 'time_after')), + (_('Attributes'), ('action', 'user_id', 'changed_object_type_id')), ) time_after = forms.DateTimeField( required=False, @@ -454,6 +473,7 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm): widget=DateTimePicker() ) action = forms.ChoiceField( + label=_('Action'), choices=add_blank_choice(ObjectChangeActionChoices), required=False ) diff --git a/netbox/extras/forms/misc.py b/netbox/extras/forms/misc.py index b52338e76..0fd1a889d 100644 --- a/netbox/extras/forms/misc.py +++ b/netbox/extras/forms/misc.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext_lazy as _ __all__ = ( 'RenderMarkdownForm', @@ -10,5 +11,6 @@ class RenderMarkdownForm(forms.Form): Provides basic validation for markup to be rendered. """ text = forms.CharField( + label=_('Text'), required=False ) diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 35700967c..414563f59 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -4,7 +4,7 @@ from django import forms from django.conf import settings from django.db.models import Q from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from core.forms.mixins import SyncedDataMixin from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup @@ -42,10 +42,12 @@ __all__ = ( class CustomFieldForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), ) object_type = ContentTypeChoiceField( + label=_('Object type'), queryset=ContentType.objects.all(), # TODO: Come up with a canonical way to register suitable models limit_choices_to=FeatureQuery('webhooks').get_query() | Q(app_label='auth', model__in=['user', 'group']), @@ -58,12 +60,12 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm): ) fieldsets = ( - ('Custom Field', ( + (_('Custom Field'), ( 'content_types', 'name', 'label', 'group_name', 'type', 'object_type', 'required', 'description', )), - ('Behavior', ('search_weight', 'filter_logic', 'ui_visibility', 'weight', 'is_cloneable')), - ('Values', ('default', 'choice_set')), - ('Validation', ('validation_minimum', 'validation_maximum', 'validation_regex')), + (_('Behavior'), ('search_weight', 'filter_logic', 'ui_visibility', 'weight', 'is_cloneable')), + (_('Values'), ('default', 'choice_set')), + (_('Validation'), ('validation_minimum', 'validation_maximum', 'validation_regex')), ) class Meta: @@ -106,13 +108,14 @@ class CustomFieldChoiceSetForm(BootstrapMixin, forms.ModelForm): class CustomLinkForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links') ) fieldsets = ( - ('Custom Link', ('name', 'content_types', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')), - ('Templates', ('link_text', 'link_url')), + (_('Custom Link'), ('name', 'content_types', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')), + (_('Templates'), ('link_text', 'link_url')), ) class Meta: @@ -133,18 +136,20 @@ class CustomLinkForm(BootstrapMixin, forms.ModelForm): class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates') ) template_code = forms.CharField( + label=_('Template code'), required=False, widget=forms.Textarea(attrs={'class': 'font-monospace'}) ) fieldsets = ( - ('Export Template', ('name', 'content_types', 'description', 'template_code')), - ('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), - ('Rendering', ('mime_type', 'file_extension', 'as_attachment')), + (_('Export Template'), ('name', 'content_types', 'description', 'template_code')), + (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), + (_('Rendering'), ('mime_type', 'file_extension', 'as_attachment')), ) class Meta: @@ -165,7 +170,7 @@ class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): super().clean() if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'): - raise forms.ValidationError("Must specify either local content or a data file") + raise forms.ValidationError(_("Must specify either local content or a data file")) return self.cleaned_data @@ -173,13 +178,14 @@ class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): class SavedFilterForm(BootstrapMixin, forms.ModelForm): slug = SlugField() content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all() ) parameters = JSONField() fieldsets = ( - ('Saved Filter', ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')), - ('Parameters', ('parameters',)), + (_('Saved Filter'), ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')), + (_('Parameters'), ('parameters',)), ) class Meta: @@ -198,6 +204,7 @@ class SavedFilterForm(BootstrapMixin, forms.ModelForm): class BookmarkForm(BootstrapMixin, forms.ModelForm): object_type = ContentTypeChoiceField( + label=_('Object type'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('bookmarks').get_query() ) @@ -209,29 +216,30 @@ class BookmarkForm(BootstrapMixin, forms.ModelForm): class WebhookForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks') ) fieldsets = ( - ('Webhook', ('name', 'content_types', 'enabled')), - ('Events', ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), - ('HTTP Request', ( + (_('Webhook'), ('name', 'content_types', 'enabled')), + (_('Events'), ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), + (_('HTTP Request'), ( 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', )), - ('Conditions', ('conditions',)), - ('SSL', ('ssl_verification', 'ca_file_path')), + (_('Conditions'), ('conditions',)), + (_('SSL'), ('ssl_verification', 'ca_file_path')), ) class Meta: model = Webhook fields = '__all__' labels = { - 'type_create': 'Creations', - 'type_update': 'Updates', - 'type_delete': 'Deletions', - 'type_job_start': 'Job executions', - 'type_job_end': 'Job terminations', + 'type_create': _('Creations'), + 'type_update': _('Updates'), + 'type_delete': _('Deletions'), + 'type_job_start': _('Job executions'), + 'type_job_end': _('Job terminations'), } widgets = { 'additional_headers': forms.Textarea(attrs={'class': 'font-monospace'}), @@ -243,6 +251,7 @@ class WebhookForm(BootstrapMixin, forms.ModelForm): class TagForm(BootstrapMixin, forms.ModelForm): slug = SlugField() object_types = ContentTypeMultipleChoiceField( + label=_('Object types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('tags'), required=False @@ -261,65 +270,79 @@ class TagForm(BootstrapMixin, forms.ModelForm): class ConfigContextForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): regions = DynamicModelMultipleChoiceField( + label=_('Regions'), queryset=Region.objects.all(), required=False ) site_groups = DynamicModelMultipleChoiceField( + label=_('Site groups'), queryset=SiteGroup.objects.all(), required=False ) sites = DynamicModelMultipleChoiceField( + label=_('Sites'), queryset=Site.objects.all(), required=False ) locations = DynamicModelMultipleChoiceField( + label=_('Locations'), queryset=Location.objects.all(), required=False ) device_types = DynamicModelMultipleChoiceField( + label=_('Device types'), queryset=DeviceType.objects.all(), required=False ) roles = DynamicModelMultipleChoiceField( + label=_('Roles'), queryset=DeviceRole.objects.all(), required=False ) platforms = DynamicModelMultipleChoiceField( + label=_('Platforms'), queryset=Platform.objects.all(), required=False ) cluster_types = DynamicModelMultipleChoiceField( + label=_('Cluster types'), queryset=ClusterType.objects.all(), required=False ) cluster_groups = DynamicModelMultipleChoiceField( + label=_('Cluster groups'), queryset=ClusterGroup.objects.all(), required=False ) clusters = DynamicModelMultipleChoiceField( + label=_('Clusters'), queryset=Cluster.objects.all(), required=False ) tenant_groups = DynamicModelMultipleChoiceField( + label=_('Tenat groups'), queryset=TenantGroup.objects.all(), required=False ) tenants = DynamicModelMultipleChoiceField( + label=_('Tenants'), queryset=Tenant.objects.all(), required=False ) tags = DynamicModelMultipleChoiceField( + label=_('Tags'), queryset=Tag.objects.all(), required=False ) data = JSONField( + label=_('Data'), required=False ) fieldsets = ( - ('Config Context', ('name', 'weight', 'description', 'data', 'is_active')), - ('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), - ('Assignment', ( + (_('Config Context'), ('name', 'weight', 'description', 'data', 'is_active')), + (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), + (_('Assignment'), ( 'regions', 'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types', 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', )), @@ -351,25 +374,27 @@ class ConfigContextForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): super().clean() if not self.cleaned_data.get('data') and not self.cleaned_data.get('data_file'): - raise forms.ValidationError("Must specify either local data or a data file") + raise forms.ValidationError(_("Must specify either local data or a data file")) return self.cleaned_data class ConfigTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): tags = DynamicModelMultipleChoiceField( + label=_('Tags'), queryset=Tag.objects.all(), required=False ) template_code = forms.CharField( + label=_('Template code'), required=False, widget=forms.Textarea(attrs={'class': 'font-monospace'}) ) fieldsets = ( - ('Config Template', ('name', 'description', 'environment_params', 'tags')), - ('Content', ('template_code',)), - ('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), + (_('Config Template'), ('name', 'description', 'environment_params', 'tags')), + (_('Content'), ('template_code',)), + (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), ) class Meta: @@ -393,7 +418,7 @@ class ConfigTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): super().clean() if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'): - raise forms.ValidationError("Must specify either local content or a data file") + raise forms.ValidationError(_("Must specify either local content or a data file")) return self.cleaned_data @@ -409,6 +434,7 @@ class ImageAttachmentForm(BootstrapMixin, forms.ModelForm): class JournalEntryForm(NetBoxModelForm): kind = forms.ChoiceField( + label=_('Kind'), choices=add_blank_choice(JournalEntryKindChoices), required=False ) @@ -451,16 +477,16 @@ class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMe """ fieldsets = ( - ('Rack Elevations', ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH')), - ('Power', ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')), - ('IPAM', ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4')), - ('Security', ('ALLOWED_URL_SCHEMES',)), - ('Banners', ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM')), - ('Pagination', ('PAGINATE_COUNT', 'MAX_PAGE_SIZE')), - ('Validation', ('CUSTOM_VALIDATORS',)), - ('User Preferences', ('DEFAULT_USER_PREFERENCES',)), - ('Miscellaneous', ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL')), - ('Config Revision', ('comment',)) + (_('Rack Elevations'), ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH')), + (_('Power'), ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')), + (_('IPAM'), ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4')), + (_('Security'), ('ALLOWED_URL_SCHEMES',)), + (_('Banners'), ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM')), + (_('Pagination'), ('PAGINATE_COUNT', 'MAX_PAGE_SIZE')), + (_('Validation'), ('CUSTOM_VALIDATORS',)), + (_('User Preferences'), ('DEFAULT_USER_PREFERENCES',)), + (_('Miscellaneous'), ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL')), + (_('Config Revision'), ('comment',)) ) class Meta: @@ -487,11 +513,11 @@ class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMe help_text = self.fields[param.name].help_text if help_text: help_text += '
' # Line break - help_text += f'Current value: {value}' + help_text += _('Current value: {value}').format(value=value) if is_static: - help_text += ' (defined statically)' + help_text += _(' (defined statically)') elif value == param.default: - help_text += ' (default)' + help_text += _(' (default)') self.fields[param.name].help_text = help_text self.fields[param.name].initial = value if is_static: diff --git a/netbox/extras/forms/reports.py b/netbox/extras/forms/reports.py index 4000c01e6..0ff7d1509 100644 --- a/netbox/extras/forms/reports.py +++ b/netbox/extras/forms/reports.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import DurationChoices from utilities.forms import BootstrapMixin @@ -33,7 +33,7 @@ class ReportForm(BootstrapMixin, forms.Form): # Annotate the current system time for reference now = local_now().strftime('%Y-%m-%d %H:%M:%S') - self.fields['schedule_at'].help_text += f' (current time: {now})' + self.fields['schedule_at'].help_text += _(' (current time: {now})').format(now=now) # Remove scheduling fields if scheduling is disabled if not scheduling_enabled: diff --git a/netbox/extras/forms/scripts.py b/netbox/extras/forms/scripts.py index 19a7878e1..c555747ae 100644 --- a/netbox/extras/forms/scripts.py +++ b/netbox/extras/forms/scripts.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import DurationChoices from utilities.forms import BootstrapMixin @@ -39,7 +39,7 @@ class ScriptForm(BootstrapMixin, forms.Form): # Annotate the current system time for reference now = local_now().strftime('%Y-%m-%d %H:%M:%S') - self.fields['_schedule_at'].help_text += f' (current time: {now})' + self.fields['_schedule_at'].help_text += _(' (current time: {now})').format(now=now) # Remove scheduling fields if scheduling is disabled if not scheduling_enabled: diff --git a/netbox/ipam/forms/bulk_create.py b/netbox/ipam/forms/bulk_create.py index 1ba786aae..ea553c655 100644 --- a/netbox/ipam/forms/bulk_create.py +++ b/netbox/ipam/forms/bulk_create.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from utilities.forms import BootstrapMixin from utilities.forms.fields import ExpandableIPAddressField diff --git a/netbox/ipam/forms/bulk_edit.py b/netbox/ipam/forms/bulk_edit.py index 71ce14040..548d01afa 100644 --- a/netbox/ipam/forms/bulk_edit.py +++ b/netbox/ipam/forms/bulk_edit.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.models import Region, Site, SiteGroup from ipam.choices import * @@ -37,6 +37,7 @@ __all__ = ( class VRFBulkEditForm(NetBoxModelBulkEditForm): tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) @@ -46,12 +47,11 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm): label=_('Enforce unique space') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = VRF fieldsets = ( @@ -62,16 +62,16 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm): class RouteTargetBulkEditForm(NetBoxModelBulkEditForm): tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = RouteTarget fieldsets = ( @@ -82,10 +82,12 @@ class RouteTargetBulkEditForm(NetBoxModelBulkEditForm): class RIRBulkEditForm(NetBoxModelBulkEditForm): is_private = forms.NullBooleanField( + label=_('Is private'), required=False, widget=BulkEditNullBooleanSelect ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -104,10 +106,12 @@ class ASNRangeBulkEditForm(NetBoxModelBulkEditForm): label=_('RIR') ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -121,6 +125,7 @@ class ASNRangeBulkEditForm(NetBoxModelBulkEditForm): class ASNBulkEditForm(NetBoxModelBulkEditForm): sites = DynamicModelMultipleChoiceField( + label=_('Sites'), queryset=Site.objects.all(), required=False ) @@ -130,16 +135,16 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm): label=_('RIR') ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = ASN fieldsets = ( @@ -155,19 +160,20 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm): label=_('RIR') ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) date_added = forms.DateField( + label=_('Date added'), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Aggregate fieldsets = ( @@ -178,9 +184,11 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm): class RoleBulkEditForm(NetBoxModelBulkEditForm): weight = forms.IntegerField( + label=_('Weight'), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -194,14 +202,17 @@ class RoleBulkEditForm(NetBoxModelBulkEditForm): class PrefixBulkEditForm(NetBoxModelBulkEditForm): region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False ) site_group = DynamicModelChoiceField( + label=_('Site group'), queryset=SiteGroup.objects.all(), required=False ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, query_params={ @@ -215,19 +226,23 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm): label=_('VRF') ) prefix_length = forms.IntegerField( + label=_('Prefix length'), min_value=PREFIX_LENGTH_MIN, max_value=PREFIX_LENGTH_MAX, required=False ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(PrefixStatusChoices), required=False ) role = DynamicModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False ) @@ -242,18 +257,17 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm): label=_('Treat as 100% utilized') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Prefix fieldsets = ( (None, ('tenant', 'status', 'role', 'description')), - ('Site', ('region', 'site_group', 'site')), - ('Addressing', ('vrf', 'prefix_length', 'is_pool', 'mark_utilized')), + (_('Site'), ('region', 'site_group', 'site')), + (_('Addressing'), ('vrf', 'prefix_length', 'is_pool', 'mark_utilized')), ) nullable_fields = ( 'site', 'vrf', 'tenant', 'role', 'description', 'comments', @@ -267,14 +281,17 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm): label=_('VRF') ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(IPRangeStatusChoices), required=False ) role = DynamicModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False ) @@ -284,12 +301,11 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm): label=_('Treat as 100% utilized') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = IPRange fieldsets = ( @@ -307,19 +323,23 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): label=_('VRF') ) mask_length = forms.IntegerField( + label=_('Mask length'), min_value=IPADDRESS_MASK_LENGTH_MIN, max_value=IPADDRESS_MASK_LENGTH_MAX, required=False ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(IPAddressStatusChoices), required=False ) role = forms.ChoiceField( + label=_('Role'), choices=add_blank_choice(IPAddressRoleChoices), required=False ) @@ -329,17 +349,16 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): label=_('DNS name') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = IPAddress fieldsets = ( (None, ('status', 'role', 'tenant', 'description')), - ('Addressing', ('vrf', 'mask_length', 'dns_name')), + (_('Addressing'), ('vrf', 'mask_length', 'dns_name')), ) nullable_fields = ( 'vrf', 'role', 'tenant', 'dns_name', 'description', 'comments', @@ -348,6 +367,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm): protocol = forms.ChoiceField( + label=_('Protocol'), choices=add_blank_choice(FHRPGroupProtocolChoices), required=False ) @@ -367,27 +387,28 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm): label=_('Authentication key') ) name = forms.CharField( + label=_('Name'), max_length=100, required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = FHRPGroup fieldsets = ( (None, ('protocol', 'group_id', 'name', 'description')), - ('Authentication', ('auth_type', 'auth_key')), + (_('Authentication'), ('auth_type', 'auth_key')), ) nullable_fields = ('auth_type', 'auth_key', 'name', 'description', 'comments') class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False ) @@ -404,6 +425,7 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): label=_('Maximum child VLAN VID') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -417,14 +439,17 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): class VLANBulkEditForm(NetBoxModelBulkEditForm): region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False ) site_group = DynamicModelChoiceField( + label=_('Site group'), queryset=SiteGroup.objects.all(), required=False ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, query_params={ @@ -433,6 +458,7 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm): } ) group = DynamicModelChoiceField( + label=_('Group'), queryset=VLANGroup.objects.all(), required=False, query_params={ @@ -440,29 +466,31 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm): } ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(VLANStatusChoices), required=False ) role = DynamicModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = VLAN fieldsets = ( (None, ('status', 'role', 'tenant', 'description')), - ('Site & Group', ('region', 'site_group', 'site', 'group')), + (_('Site & Group'), ('region', 'site_group', 'site', 'group')), ) nullable_fields = ( 'site', 'group', 'tenant', 'role', 'description', 'comments', @@ -471,10 +499,12 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm): class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm): protocol = forms.ChoiceField( + label=_('Protocol'), choices=add_blank_choice(ServiceProtocolChoices), required=False ) ports = NumericArrayField( + label=_('Ports'), base_field=forms.IntegerField( min_value=SERVICE_PORT_MIN, max_value=SERVICE_PORT_MAX @@ -482,12 +512,11 @@ class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = ServiceTemplate fieldsets = ( @@ -502,20 +531,21 @@ class ServiceBulkEditForm(ServiceTemplateBulkEditForm): class L2VPNBulkEditForm(NetBoxModelBulkEditForm): type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(L2VPNTypeChoices), required=False ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = L2VPN fieldsets = ( diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py index 683d40f49..9b7c624d2 100644 --- a/netbox/ipam/forms/bulk_import.py +++ b/netbox/ipam/forms/bulk_import.py @@ -2,7 +2,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db.models import Q -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.models import Device, Interface, Site from ipam.choices import * @@ -36,6 +36,7 @@ __all__ = ( class VRFImportForm(NetBoxModelImportForm): tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -49,6 +50,7 @@ class VRFImportForm(NetBoxModelImportForm): class RouteTargetImportForm(NetBoxModelImportForm): tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -70,11 +72,13 @@ class RIRImportForm(NetBoxModelImportForm): class AggregateImportForm(NetBoxModelImportForm): rir = CSVModelChoiceField( + label=_('RIR'), queryset=RIR.objects.all(), to_field_name='name', help_text=_('Assigned RIR') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -88,11 +92,13 @@ class AggregateImportForm(NetBoxModelImportForm): class ASNRangeImportForm(NetBoxModelImportForm): rir = CSVModelChoiceField( + label=_('RIR'), queryset=RIR.objects.all(), to_field_name='name', help_text=_('Assigned RIR') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -106,11 +112,13 @@ class ASNRangeImportForm(NetBoxModelImportForm): class ASNImportForm(NetBoxModelImportForm): rir = CSVModelChoiceField( + label=_('RIR'), queryset=RIR.objects.all(), to_field_name='name', help_text=_('Assigned RIR') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', @@ -132,40 +140,47 @@ class RoleImportForm(NetBoxModelImportForm): class PrefixImportForm(NetBoxModelImportForm): vrf = CSVModelChoiceField( + label=_('VRF'), queryset=VRF.objects.all(), to_field_name='name', required=False, help_text=_('Assigned VRF') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Assigned tenant') ) site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, to_field_name='name', help_text=_('Assigned site') ) vlan_group = CSVModelChoiceField( + label=_('VLAN group'), queryset=VLANGroup.objects.all(), required=False, to_field_name='name', help_text=_("VLAN's group (if any)") ) vlan = CSVModelChoiceField( + label=_('VLAN'), queryset=VLAN.objects.all(), required=False, to_field_name='vid', help_text=_("Assigned VLAN") ) status = CSVChoiceField( + label=_('Status'), choices=PrefixStatusChoices, help_text=_('Operational status') ) role = CSVModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False, to_field_name='name', @@ -211,22 +226,26 @@ class PrefixImportForm(NetBoxModelImportForm): class IPRangeImportForm(NetBoxModelImportForm): vrf = CSVModelChoiceField( + label=_('VRF'), queryset=VRF.objects.all(), to_field_name='name', required=False, help_text=_('Assigned VRF') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Assigned tenant') ) status = CSVChoiceField( + label=_('Status'), choices=IPRangeStatusChoices, help_text=_('Operational status') ) role = CSVModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False, to_field_name='name', @@ -243,45 +262,53 @@ class IPRangeImportForm(NetBoxModelImportForm): class IPAddressImportForm(NetBoxModelImportForm): vrf = CSVModelChoiceField( + label=_('VRF'), queryset=VRF.objects.all(), to_field_name='name', required=False, help_text=_('Assigned VRF') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), to_field_name='name', required=False, help_text=_('Assigned tenant') ) status = CSVChoiceField( + label=_('Status'), choices=IPAddressStatusChoices, help_text=_('Operational status') ) role = CSVChoiceField( + label=_('Role'), choices=IPAddressRoleChoices, required=False, help_text=_('Functional role') ) device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False, to_field_name='name', help_text=_('Parent device of assigned interface (if any)') ) virtual_machine = CSVModelChoiceField( + label=_('Virtual machine'), queryset=VirtualMachine.objects.all(), required=False, to_field_name='name', help_text=_('Parent VM of assigned interface (if any)') ) interface = CSVModelChoiceField( + label=_('Interface'), queryset=Interface.objects.none(), # Can also refer to VMInterface required=False, to_field_name='name', help_text=_('Assigned interface') ) is_primary = forms.BooleanField( + label=_('Is primary'), help_text=_('Make this the primary IP for the assigned device'), required=False ) @@ -321,11 +348,11 @@ class IPAddressImportForm(NetBoxModelImportForm): # Validate is_primary if is_primary and not device and not virtual_machine: raise forms.ValidationError({ - "is_primary": "No device or virtual machine specified; cannot set as primary IP" + "is_primary": _("No device or virtual machine specified; cannot set as primary IP") }) if is_primary and not interface: raise forms.ValidationError({ - "is_primary": "No interface specified; cannot set as primary IP" + "is_primary": _("No interface specified; cannot set as primary IP") }) def save(self, *args, **kwargs): @@ -350,9 +377,11 @@ class IPAddressImportForm(NetBoxModelImportForm): class FHRPGroupImportForm(NetBoxModelImportForm): protocol = CSVChoiceField( + label=_('Protocol'), choices=FHRPGroupProtocolChoices ) auth_type = CSVChoiceField( + label=_('Auth type'), choices=FHRPGroupAuthTypeChoices, required=False ) @@ -373,13 +402,13 @@ class VLANGroupImportForm(NetBoxModelImportForm): min_value=VLAN_VID_MIN, max_value=VLAN_VID_MAX, required=False, - label=f'Minimum child VLAN VID (default: {VLAN_VID_MIN})' + label=_('Minimum child VLAN VID (default: {minimum})').format(minimum=VLAN_VID_MIN) ) max_vid = forms.IntegerField( min_value=VLAN_VID_MIN, max_value=VLAN_VID_MAX, required=False, - label=f'Maximum child VLAN VID (default: {VLAN_VID_MIN})' + label=_('Maximum child VLAN VID (default: {maximum})').format(maximum=VLAN_VID_MIN) ) class Meta: @@ -392,28 +421,33 @@ class VLANGroupImportForm(NetBoxModelImportForm): class VLANImportForm(NetBoxModelImportForm): site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, to_field_name='name', help_text=_('Assigned site') ) group = CSVModelChoiceField( + label=_('Group'), queryset=VLANGroup.objects.all(), required=False, to_field_name='name', help_text=_('Assigned VLAN group') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), to_field_name='name', required=False, help_text=_('Assigned tenant') ) status = CSVChoiceField( + label=_('Status'), choices=VLANStatusChoices, help_text=_('Operational status') ) role = CSVModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False, to_field_name='name', @@ -427,6 +461,7 @@ class VLANImportForm(NetBoxModelImportForm): class ServiceTemplateImportForm(NetBoxModelImportForm): protocol = CSVChoiceField( + label=_('Protocol'), choices=ServiceProtocolChoices, help_text=_('IP protocol') ) @@ -438,18 +473,21 @@ class ServiceTemplateImportForm(NetBoxModelImportForm): class ServiceImportForm(NetBoxModelImportForm): device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False, to_field_name='name', help_text=_('Required if not assigned to a VM') ) virtual_machine = CSVModelChoiceField( + label=_('Virtual machine'), queryset=VirtualMachine.objects.all(), required=False, to_field_name='name', help_text=_('Required if not assigned to a device') ) protocol = CSVChoiceField( + label=_('Protocol'), choices=ServiceProtocolChoices, help_text=_('IP protocol') ) @@ -461,11 +499,13 @@ class ServiceImportForm(NetBoxModelImportForm): class L2VPNImportForm(NetBoxModelImportForm): tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', ) type = CSVChoiceField( + label=_('Type'), choices=L2VPNTypeChoices, help_text=_('L2VPN type') ) @@ -484,24 +524,28 @@ class L2VPNTerminationImportForm(NetBoxModelImportForm): label=_('L2VPN'), ) device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False, to_field_name='name', help_text=_('Parent device (for interface)') ) virtual_machine = CSVModelChoiceField( + label=_('Virtual machine'), queryset=VirtualMachine.objects.all(), required=False, to_field_name='name', help_text=_('Parent virtual machine (for interface)') ) interface = CSVModelChoiceField( + label=_('Interface'), queryset=Interface.objects.none(), # Can also refer to VMInterface required=False, to_field_name='name', help_text=_('Assigned interface (device or VM)') ) vlan = CSVModelChoiceField( + label=_('VLAN'), queryset=VLAN.objects.all(), required=False, to_field_name='name', @@ -531,10 +575,10 @@ class L2VPNTerminationImportForm(NetBoxModelImportForm): super().clean() if self.cleaned_data.get('device') and self.cleaned_data.get('virtual_machine'): - raise ValidationError('Cannot import device and VM interface terminations simultaneously.') + raise ValidationError(_('Cannot import device and VM interface terminations simultaneously.')) if not (self.cleaned_data.get('interface') or self.cleaned_data.get('vlan')): - raise ValidationError('Each termination must specify either an interface or a VLAN.') + raise ValidationError(_('Each termination must specify either an interface or a VLAN.')) if self.cleaned_data.get('interface') and self.cleaned_data.get('vlan'): - raise ValidationError('Cannot assign both an interface and a VLAN.') + raise ValidationError(_('Cannot assign both an interface and a VLAN.')) self.instance.assigned_object = self.cleaned_data.get('interface') or self.cleaned_data.get('vlan') diff --git a/netbox/ipam/forms/filtersets.py b/netbox/ipam/forms/filtersets.py index 53fecfe2f..299d70565 100644 --- a/netbox/ipam/forms/filtersets.py +++ b/netbox/ipam/forms/filtersets.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.models import Location, Rack, Region, Site, SiteGroup, Device from ipam.choices import * @@ -47,8 +47,8 @@ class VRFFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = VRF fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Route Targets', ('import_target_id', 'export_target_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Route Targets'), ('import_target_id', 'export_target_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) import_target_id = DynamicModelMultipleChoiceField( queryset=RouteTarget.objects.all(), @@ -67,8 +67,8 @@ class RouteTargetFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = RouteTarget fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('VRF', ('importing_vrf_id', 'exporting_vrf_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('VRF'), ('importing_vrf_id', 'exporting_vrf_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) importing_vrf_id = DynamicModelMultipleChoiceField( queryset=VRF.objects.all(), @@ -99,8 +99,8 @@ class AggregateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = Aggregate fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('family', 'rir_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Attributes'), ('family', 'rir_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) family = forms.ChoiceField( required=False, @@ -119,8 +119,8 @@ class ASNRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = ASNRange fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Range', ('rir_id', 'start', 'end')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Range'), ('rir_id', 'start', 'end')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) rir_id = DynamicModelMultipleChoiceField( queryset=RIR.objects.all(), @@ -128,9 +128,11 @@ class ASNRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('RIR') ) start = forms.IntegerField( + label=_('Start'), required=False ) end = forms.IntegerField( + label=_('End'), required=False ) tag = TagFilterField(model) @@ -140,8 +142,8 @@ class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = ASN fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Assignment', ('rir_id', 'site_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Assignment'), ('rir_id', 'site_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) rir_id = DynamicModelMultipleChoiceField( queryset=RIR.objects.all(), @@ -165,10 +167,10 @@ class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = Prefix fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Addressing', ('within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized')), - ('VRF', ('vrf_id', 'present_in_vrf_id')), - ('Location', ('region_id', 'site_group_id', 'site_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Addressing'), ('within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized')), + (_('VRF'), ('vrf_id', 'present_in_vrf_id')), + (_('Location'), ('region_id', 'site_group_id', 'site_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) mask_length__lte = forms.IntegerField( widget=forms.HiddenInput() @@ -204,6 +206,7 @@ class PrefixFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('Present in VRF') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=PrefixStatusChoices, required=False ) @@ -253,8 +256,8 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = IPRange fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attriubtes', ('family', 'vrf_id', 'status', 'role_id', 'mark_utilized')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Attriubtes'), ('family', 'vrf_id', 'status', 'role_id', 'mark_utilized')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) family = forms.ChoiceField( required=False, @@ -268,6 +271,7 @@ class IPRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): null_option='Global' ) status = forms.MultipleChoiceField( + label=_('Status'), choices=IPRangeStatusChoices, required=False ) @@ -291,10 +295,10 @@ class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = IPAddress fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface')), - ('VRF', ('vrf_id', 'present_in_vrf_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Device/VM', ('device_id', 'virtual_machine_id')), + (_('Attributes'), ('parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface')), + (_('VRF'), ('vrf_id', 'present_in_vrf_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Device/VM'), ('device_id', 'virtual_machine_id')), ) parent = forms.CharField( required=False, @@ -337,10 +341,12 @@ class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('Assigned VM'), ) status = forms.MultipleChoiceField( + label=_('Status'), choices=IPAddressStatusChoices, required=False ) role = forms.MultipleChoiceField( + label=_('Role'), choices=IPAddressRoleChoices, required=False ) @@ -358,29 +364,31 @@ class FHRPGroupFilterForm(NetBoxModelFilterSetForm): model = FHRPGroup fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('name', 'protocol', 'group_id')), - ('Authentication', ('auth_type', 'auth_key')), + (_('Attributes'), ('name', 'protocol', 'group_id')), + (_('Authentication'), ('auth_type', 'auth_key')), ) name = forms.CharField( + label=_('Name'), required=False ) protocol = forms.MultipleChoiceField( + label=_('Protocol'), choices=FHRPGroupProtocolChoices, required=False ) group_id = forms.IntegerField( min_value=0, required=False, - label='Group ID' + label=_('Group ID') ) auth_type = forms.MultipleChoiceField( choices=FHRPGroupAuthTypeChoices, required=False, - label='Authentication type' + label=_('Authentication type') ) auth_key = forms.CharField( required=False, - label='Authentication key' + label=_('Authentication key') ) tag = TagFilterField(model) @@ -388,8 +396,8 @@ class FHRPGroupFilterForm(NetBoxModelFilterSetForm): class VLANGroupFilterForm(NetBoxModelFilterSetForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region', 'sitegroup', 'site', 'location', 'rack')), - ('VLAN ID', ('min_vid', 'max_vid')), + (_('Location'), ('region', 'sitegroup', 'site', 'location', 'rack')), + (_('VLAN ID'), ('min_vid', 'max_vid')), ) model = VLANGroup region = DynamicModelMultipleChoiceField( @@ -436,9 +444,9 @@ class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = VLAN fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Location', ('region_id', 'site_group_id', 'site_id')), - ('Attributes', ('group_id', 'status', 'role_id', 'vid', 'l2vpn_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Location'), ('region_id', 'site_group_id', 'site_id')), + (_('Attributes'), ('group_id', 'status', 'role_id', 'vid', 'l2vpn_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -469,6 +477,7 @@ class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('VLAN group') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=VLANStatusChoices, required=False ) @@ -480,7 +489,7 @@ class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): ) vid = forms.IntegerField( required=False, - label='VLAN ID' + label=_('VLAN ID') ) l2vpn_id = DynamicModelMultipleChoiceField( queryset=L2VPN.objects.all(), @@ -494,13 +503,15 @@ class ServiceTemplateFilterForm(NetBoxModelFilterSetForm): model = ServiceTemplate fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('protocol', 'port')), + (_('Attributes'), ('protocol', 'port')), ) protocol = forms.ChoiceField( + label=_('Protocol'), choices=add_blank_choice(ServiceProtocolChoices), required=False ) port = forms.IntegerField( + label=_('Port'), required=False, ) tag = TagFilterField(model) @@ -515,10 +526,11 @@ class L2VPNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = L2VPN fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('type', 'import_target_id', 'export_target_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), + (_('Attributes'), ('type', 'import_target_id', 'export_target_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), ) type = forms.ChoiceField( + label=_('Type'), choices=add_blank_choice(L2VPNTypeChoices), required=False ) @@ -539,14 +551,14 @@ class L2VPNTerminationFilterForm(NetBoxModelFilterSetForm): model = L2VPNTermination fieldsets = ( (None, ('filter_id', 'l2vpn_id',)), - ('Assigned Object', ( + (_('Assigned Object'), ( 'assigned_object_type_id', 'region_id', 'site_id', 'device_id', 'virtual_machine_id', 'vlan_id', )), ) l2vpn_id = DynamicModelChoiceField( queryset=L2VPN.objects.all(), required=False, - label='L2VPN' + label=_('L2VPN') ) assigned_object_type_id = ContentTypeMultipleChoiceField( queryset=ContentType.objects.filter(L2VPN_ASSIGNMENT_MODELS), diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index a3c218fc9..c466e279f 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup from ipam.choices import * @@ -46,19 +46,21 @@ __all__ = ( class VRFForm(TenancyForm, NetBoxModelForm): import_targets = DynamicModelMultipleChoiceField( + label=_('Import targets'), queryset=RouteTarget.objects.all(), required=False ) export_targets = DynamicModelMultipleChoiceField( + label=_('Export targets'), queryset=RouteTarget.objects.all(), required=False ) comments = CommentField() fieldsets = ( - ('VRF', ('name', 'rd', 'enforce_unique', 'description', 'tags')), - ('Route Targets', ('import_targets', 'export_targets')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('VRF'), ('name', 'rd', 'enforce_unique', 'description', 'tags')), + (_('Route Targets'), ('import_targets', 'export_targets')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -90,7 +92,7 @@ class RIRForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('RIR', ( + (_('RIR'), ( 'name', 'slug', 'is_private', 'description', 'tags', )), ) @@ -110,8 +112,8 @@ class AggregateForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Aggregate', ('prefix', 'rir', 'date_added', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('Aggregate'), ('prefix', 'rir', 'date_added', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -131,8 +133,8 @@ class ASNRangeForm(TenancyForm, NetBoxModelForm): ) slug = SlugField() fieldsets = ( - ('ASN Range', ('name', 'slug', 'rir', 'start', 'end', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('ASN Range'), ('name', 'slug', 'rir', 'start', 'end', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -155,8 +157,8 @@ class ASNForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('ASN', ('asn', 'rir', 'sites', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('ASN'), ('asn', 'rir', 'sites', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -184,7 +186,7 @@ class RoleForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Role', ( + (_('Role'), ( 'name', 'slug', 'weight', 'description', 'tags', )), ) @@ -203,6 +205,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm): label=_('VRF') ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, selector=True, @@ -215,15 +218,16 @@ class PrefixForm(TenancyForm, NetBoxModelForm): label=_('VLAN'), ) role = DynamicModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False ) comments = CommentField() fieldsets = ( - ('Prefix', ('prefix', 'status', 'vrf', 'role', 'is_pool', 'mark_utilized', 'description', 'tags')), - ('Site/VLAN Assignment', ('site', 'vlan')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('Prefix'), ('prefix', 'status', 'vrf', 'role', 'is_pool', 'mark_utilized', 'description', 'tags')), + (_('Site/VLAN Assignment'), ('site', 'vlan')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -241,14 +245,15 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): label=_('VRF') ) role = DynamicModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False ) comments = CommentField() fieldsets = ( - ('IP Range', ('vrf', 'start_address', 'end_address', 'role', 'status', 'mark_utilized', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('IP Range'), ('vrf', 'start_address', 'end_address', 'role', 'status', 'mark_utilized', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -261,6 +266,7 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): class IPAddressForm(TenancyForm, NetBoxModelForm): interface = DynamicModelChoiceField( + label=_('Interface'), queryset=Interface.objects.all(), required=False, selector=True, @@ -341,13 +347,13 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): ] if len(selected_objects) > 1: raise forms.ValidationError({ - selected_objects[1]: "An IP address can only be assigned to a single object." + selected_objects[1]: _("An IP address can only be assigned to a single object.") }) elif selected_objects: assigned_object = self.cleaned_data[selected_objects[0]] if self.instance.pk and self.cleaned_data['primary_for_parent'] and assigned_object != self.instance.assigned_object: raise ValidationError( - "Cannot reassign IP address while it is designated as the primary IP for the parent object" + _("Cannot reassign IP address while it is designated as the primary IP for the parent object") ) self.instance.assigned_object = assigned_object else: @@ -357,19 +363,21 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): interface = self.cleaned_data.get('interface') or self.cleaned_data.get('vminterface') if self.cleaned_data.get('primary_for_parent') and not interface: self.add_error( - 'primary_for_parent', "Only IP addresses assigned to an interface can be designated as primary IPs." + 'primary_for_parent', _("Only IP addresses assigned to an interface can be designated as primary IPs.") ) # Do not allow assigning a network ID or broadcast address to an interface. if interface and (address := self.cleaned_data.get('address')): if address.ip == address.network: - msg = f"{address} is a network ID, which may not be assigned to an interface." + msg = _("{address} is a network ID, which may not be assigned to an interface.").format(address=address) if address.version == 4 and address.prefixlen not in (31, 32): raise ValidationError(msg) if address.version == 6 and address.prefixlen not in (127, 128): raise ValidationError(msg) if address.version == 4 and address.ip == address.broadcast and address.prefixlen not in (31, 32): - msg = f"{address} is a broadcast address, which may not be assigned to an interface." + msg = _("{address} is a broadcast address, which may not be assigned to an interface.").format( + address=address + ) raise ValidationError(msg) def save(self, *args, **kwargs): @@ -442,9 +450,9 @@ class FHRPGroupForm(NetBoxModelForm): comments = CommentField() fieldsets = ( - ('FHRP Group', ('protocol', 'group_id', 'name', 'description', 'tags')), - ('Authentication', ('auth_type', 'auth_key')), - ('Virtual IP Address', ('ip_vrf', 'ip_address', 'ip_status')) + (_('FHRP Group'), ('protocol', 'group_id', 'name', 'description', 'tags')), + (_('Authentication'), ('auth_type', 'auth_key')), + (_('Virtual IP Address'), ('ip_vrf', 'ip_address', 'ip_status')) ) class Meta: @@ -497,6 +505,7 @@ class FHRPGroupForm(NetBoxModelForm): class FHRPGroupAssignmentForm(BootstrapMixin, forms.ModelForm): group = DynamicModelChoiceField( + label=_('Group'), queryset=FHRPGroup.objects.all() ) @@ -514,10 +523,12 @@ class FHRPGroupAssignmentForm(BootstrapMixin, forms.ModelForm): class VLANGroupForm(NetBoxModelForm): scope_type = ContentTypeChoiceField( + label=_('Scope type'), queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES), required=False ) region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False, initial_params={ @@ -533,6 +544,7 @@ class VLANGroupForm(NetBoxModelForm): label=_('Site group') ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, initial_params={ @@ -544,6 +556,7 @@ class VLANGroupForm(NetBoxModelForm): } ) location = DynamicModelChoiceField( + label=_('Location'), queryset=Location.objects.all(), required=False, initial_params={ @@ -554,6 +567,7 @@ class VLANGroupForm(NetBoxModelForm): } ) rack = DynamicModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), required=False, query_params={ @@ -570,6 +584,7 @@ class VLANGroupForm(NetBoxModelForm): label=_('Cluster group') ) cluster = DynamicModelChoiceField( + label=_('Cluster'), queryset=Cluster.objects.all(), required=False, query_params={ @@ -579,9 +594,9 @@ class VLANGroupForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('VLAN Group', ('name', 'slug', 'description', 'tags')), - ('Child VLANs', ('min_vid', 'max_vid')), - ('Scope', ('scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster')), + (_('VLAN Group'), ('name', 'slug', 'description', 'tags')), + (_('Child VLANs'), ('min_vid', 'max_vid')), + (_('Scope'), ('scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster')), ) class Meta: @@ -621,12 +636,14 @@ class VLANForm(TenancyForm, NetBoxModelForm): label=_('VLAN Group') ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, null_option='None', selector=True ) role = DynamicModelChoiceField( + label=_('Role'), queryset=Role.objects.all(), required=False ) @@ -642,6 +659,7 @@ class VLANForm(TenancyForm, NetBoxModelForm): class ServiceTemplateForm(NetBoxModelForm): ports = NumericArrayField( + label=_('Ports'), base_field=forms.IntegerField( min_value=SERVICE_PORT_MIN, max_value=SERVICE_PORT_MAX @@ -651,7 +669,7 @@ class ServiceTemplateForm(NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Service Template', ( + (_('Service Template'), ( 'name', 'protocol', 'ports', 'description', 'tags', )), ) @@ -663,16 +681,19 @@ class ServiceTemplateForm(NetBoxModelForm): class ServiceForm(NetBoxModelForm): device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False, selector=True ) virtual_machine = DynamicModelChoiceField( + label=_('Virtual machine'), queryset=VirtualMachine.objects.all(), required=False, selector=True ) ports = NumericArrayField( + label=_('Ports'), base_field=forms.IntegerField( min_value=SERVICE_PORT_MIN, max_value=SERVICE_PORT_MAX @@ -699,6 +720,7 @@ class ServiceForm(NetBoxModelForm): class ServiceCreateForm(ServiceForm): service_template = DynamicModelChoiceField( + label=_('Service template'), queryset=ServiceTemplate.objects.all(), required=False ) @@ -739,19 +761,21 @@ class ServiceCreateForm(ServiceForm): class L2VPNForm(TenancyForm, NetBoxModelForm): slug = SlugField() import_targets = DynamicModelMultipleChoiceField( + label=_('Import targets'), queryset=RouteTarget.objects.all(), required=False ) export_targets = DynamicModelMultipleChoiceField( + label=_('Export targets'), queryset=RouteTarget.objects.all(), required=False ) comments = CommentField() fieldsets = ( - ('L2VPN', ('name', 'slug', 'type', 'identifier', 'description', 'tags')), - ('Route Targets', ('import_targets', 'export_targets')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('L2VPN'), ('name', 'slug', 'type', 'identifier', 'description', 'tags')), + (_('Route Targets'), ('import_targets', 'export_targets')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -777,6 +801,7 @@ class L2VPNTerminationForm(NetBoxModelForm): label=_('VLAN') ) interface = DynamicModelChoiceField( + label=_('Interface'), queryset=Interface.objects.all(), required=False, selector=True @@ -815,8 +840,8 @@ class L2VPNTerminationForm(NetBoxModelForm): vlan = self.cleaned_data.get('vlan') if not (interface or vminterface or vlan): - raise ValidationError('A termination must specify an interface or VLAN.') + raise ValidationError(_('A termination must specify an interface or VLAN.')) if len([x for x in (interface, vminterface, vlan) if x]) > 1: - raise ValidationError('A termination can only have one terminating object (an interface or VLAN).') + raise ValidationError(_('A termination can only have one terminating object (an interface or VLAN).')) self.instance.assigned_object = interface or vminterface or vlan diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index 88cec405f..efa93c37c 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.db.models import Q -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices, CustomFieldVisibilityChoices from extras.forms.mixins import CustomFieldsMixin, SavedFiltersMixin @@ -28,7 +28,8 @@ class NetBoxModelForm(BootstrapMixin, CustomFieldsMixin, forms.ModelForm): fieldsets = () tags = DynamicModelMultipleChoiceField( queryset=Tag.objects.all(), - required=False + required=False, + label=_('Tags'), ) def __init__(self, *args, **kwargs): @@ -73,10 +74,12 @@ class NetBoxModelImportForm(CSVModelForm, NetBoxModelForm): Base form for creating a NetBox objects from CSV data. Used for bulk importing. """ id = forms.IntegerField( + label=_('Id'), required=False, help_text='Numeric ID of an existing object to update (if not creating a new object)' ) tags = CSVModelMultipleChoiceField( + label=_('Tags'), queryset=Tag.objects.all(), required=False, to_field_name='slug', @@ -109,10 +112,12 @@ class NetBoxModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, forms.Form): widget=forms.MultipleHiddenInput ) add_tags = DynamicModelMultipleChoiceField( + label=_('Add tags'), queryset=Tag.objects.all(), required=False ) remove_tags = DynamicModelMultipleChoiceField( + label=_('Remove tags'), queryset=Tag.objects.all(), required=False ) diff --git a/netbox/tenancy/forms/bulk_edit.py b/netbox/tenancy/forms/bulk_edit.py index 34ca35239..49866ca3e 100644 --- a/netbox/tenancy/forms/bulk_edit.py +++ b/netbox/tenancy/forms/bulk_edit.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext_lazy as _ from netbox.forms import NetBoxModelBulkEditForm from tenancy.choices import ContactPriorityChoices @@ -22,10 +23,12 @@ __all__ = ( class TenantGroupBulkEditForm(NetBoxModelBulkEditForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=TenantGroup.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -36,6 +39,7 @@ class TenantGroupBulkEditForm(NetBoxModelBulkEditForm): class TenantBulkEditForm(NetBoxModelBulkEditForm): group = DynamicModelChoiceField( + label=_('Group'), queryset=TenantGroup.objects.all(), required=False ) @@ -53,10 +57,12 @@ class TenantBulkEditForm(NetBoxModelBulkEditForm): class ContactGroupBulkEditForm(NetBoxModelBulkEditForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=ContactGroup.objects.all(), required=False ) description = forms.CharField( + label=_('Desciption'), max_length=200, required=False ) @@ -70,6 +76,7 @@ class ContactGroupBulkEditForm(NetBoxModelBulkEditForm): class ContactRoleBulkEditForm(NetBoxModelBulkEditForm): description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -83,34 +90,39 @@ class ContactRoleBulkEditForm(NetBoxModelBulkEditForm): class ContactBulkEditForm(NetBoxModelBulkEditForm): group = DynamicModelChoiceField( + label=_('Group'), queryset=ContactGroup.objects.all(), required=False ) title = forms.CharField( + label=_('Title'), max_length=100, required=False ) phone = forms.CharField( + label=_('Phone'), max_length=50, required=False ) email = forms.EmailField( + label=_('Email'), required=False ) address = forms.CharField( + label=_('Address'), max_length=200, required=False ) link = forms.URLField( + label=_('Link'), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = Contact fieldsets = ( @@ -121,14 +133,17 @@ class ContactBulkEditForm(NetBoxModelBulkEditForm): class ContactAssignmentBulkEditForm(NetBoxModelBulkEditForm): contact = DynamicModelChoiceField( + label=_('Contact'), queryset=Contact.objects.all(), required=False ) role = DynamicModelChoiceField( + label=_('Role'), queryset=ContactRole.objects.all(), required=False ) priority = forms.ChoiceField( + label=_('Priority'), choices=add_blank_choice(ContactPriorityChoices), required=False ) diff --git a/netbox/tenancy/forms/bulk_import.py b/netbox/tenancy/forms/bulk_import.py index 0aec0e28f..6a5eb05bf 100644 --- a/netbox/tenancy/forms/bulk_import.py +++ b/netbox/tenancy/forms/bulk_import.py @@ -1,5 +1,6 @@ from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ + from netbox.forms import NetBoxModelImportForm from tenancy.models import * from utilities.forms.fields import CSVContentTypeField, CSVModelChoiceField, SlugField @@ -20,6 +21,7 @@ __all__ = ( class TenantGroupImportForm(NetBoxModelImportForm): parent = CSVModelChoiceField( + label=_('Parent'), queryset=TenantGroup.objects.all(), required=False, to_field_name='name', @@ -35,6 +37,7 @@ class TenantGroupImportForm(NetBoxModelImportForm): class TenantImportForm(NetBoxModelImportForm): slug = SlugField() group = CSVModelChoiceField( + label=_('Group'), queryset=TenantGroup.objects.all(), required=False, to_field_name='name', @@ -52,6 +55,7 @@ class TenantImportForm(NetBoxModelImportForm): class ContactGroupImportForm(NetBoxModelImportForm): parent = CSVModelChoiceField( + label=_('Parent'), queryset=ContactGroup.objects.all(), required=False, to_field_name='name', @@ -74,6 +78,7 @@ class ContactRoleImportForm(NetBoxModelImportForm): class ContactImportForm(NetBoxModelImportForm): group = CSVModelChoiceField( + label=_('Group'), queryset=ContactGroup.objects.all(), required=False, to_field_name='name', diff --git a/netbox/tenancy/forms/filtersets.py b/netbox/tenancy/forms/filtersets.py index 626d26785..6ad473fa8 100644 --- a/netbox/tenancy/forms/filtersets.py +++ b/netbox/tenancy/forms/filtersets.py @@ -1,6 +1,6 @@ from django import forms from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.utils import FeatureQuery from netbox.forms import NetBoxModelFilterSetForm @@ -84,7 +84,7 @@ class ContactAssignmentFilterForm(NetBoxModelFilterSetForm): model = ContactAssignment fieldsets = ( (None, ('q', 'filter_id')), - ('Assignment', ('content_type_id', 'group_id', 'contact_id', 'role_id', 'priority')), + (_('Assignment'), ('content_type_id', 'group_id', 'contact_id', 'role_id', 'priority')), ) content_type_id = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), @@ -108,6 +108,7 @@ class ContactAssignmentFilterForm(NetBoxModelFilterSetForm): label=_('Role') ) priority = forms.MultipleChoiceField( + label=_('Priority'), choices=ContactPriorityChoices, required=False ) diff --git a/netbox/tenancy/forms/forms.py b/netbox/tenancy/forms/forms.py index 789566e94..114253e7a 100644 --- a/netbox/tenancy/forms/forms.py +++ b/netbox/tenancy/forms/forms.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from tenancy.models import * from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField @@ -13,6 +13,7 @@ __all__ = ( class TenancyForm(forms.Form): tenant_group = DynamicModelChoiceField( + label=_('Tenant group'), queryset=TenantGroup.objects.all(), required=False, null_option='None', @@ -21,6 +22,7 @@ class TenancyForm(forms.Form): } ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, query_params={ diff --git a/netbox/tenancy/forms/model_forms.py b/netbox/tenancy/forms/model_forms.py index 6d6534d40..41a202c7f 100644 --- a/netbox/tenancy/forms/model_forms.py +++ b/netbox/tenancy/forms/model_forms.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext_lazy as _ from netbox.forms import NetBoxModelForm from tenancy.models import * @@ -21,13 +22,14 @@ __all__ = ( class TenantGroupForm(NetBoxModelForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=TenantGroup.objects.all(), required=False ) slug = SlugField() fieldsets = ( - ('Tenant Group', ( + (_('Tenant Group'), ( 'parent', 'name', 'slug', 'description', 'tags', )), ) @@ -42,13 +44,14 @@ class TenantGroupForm(NetBoxModelForm): class TenantForm(NetBoxModelForm): slug = SlugField() group = DynamicModelChoiceField( + label=_('Group'), queryset=TenantGroup.objects.all(), required=False ) comments = CommentField() fieldsets = ( - ('Tenant', ('name', 'slug', 'group', 'description', 'tags')), + (_('Tenant'), ('name', 'slug', 'group', 'description', 'tags')), ) class Meta: @@ -64,13 +67,14 @@ class TenantForm(NetBoxModelForm): class ContactGroupForm(NetBoxModelForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=ContactGroup.objects.all(), required=False ) slug = SlugField() fieldsets = ( - ('Contact Group', ( + (_('Contact Group'), ( 'parent', 'name', 'slug', 'description', 'tags', )), ) @@ -84,7 +88,7 @@ class ContactRoleForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Contact Role', ( + (_('Contact Role'), ( 'name', 'slug', 'description', 'tags', )), ) @@ -96,13 +100,14 @@ class ContactRoleForm(NetBoxModelForm): class ContactForm(NetBoxModelForm): group = DynamicModelChoiceField( + label=_('Group'), queryset=ContactGroup.objects.all(), required=False ) comments = CommentField() fieldsets = ( - ('Contact', ('group', 'name', 'title', 'phone', 'email', 'address', 'link', 'description', 'tags')), + (_('Contact'), ('group', 'name', 'title', 'phone', 'email', 'address', 'link', 'description', 'tags')), ) class Meta: @@ -117,6 +122,7 @@ class ContactForm(NetBoxModelForm): class ContactAssignmentForm(BootstrapMixin, forms.ModelForm): group = DynamicModelChoiceField( + label=_('Group'), queryset=ContactGroup.objects.all(), required=False, initial_params={ @@ -124,12 +130,14 @@ class ContactAssignmentForm(BootstrapMixin, forms.ModelForm): } ) contact = DynamicModelChoiceField( + label=_('Contact'), queryset=Contact.objects.all(), query_params={ 'group_id': '$group' } ) role = DynamicModelChoiceField( + label=_('Role'), queryset=ContactRole.objects.all() ) diff --git a/netbox/users/forms/model_forms.py b/netbox/users/forms/model_forms.py index 6ca050110..1cc94b944 100644 --- a/netbox/users/forms/model_forms.py +++ b/netbox/users/forms/model_forms.py @@ -66,7 +66,6 @@ class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMe ) # List of clearable preferences pk = forms.MultipleChoiceField( - label=_('Pk'), choices=[], required=False ) diff --git a/netbox/utilities/forms/fields/array.py b/netbox/utilities/forms/fields/array.py index 6e1a40988..14f122453 100644 --- a/netbox/utilities/forms/fields/array.py +++ b/netbox/utilities/forms/fields/array.py @@ -1,5 +1,6 @@ from django import forms from django.contrib.postgres.forms import SimpleArrayField +from django.utils.translation import gettext_lazy as _ from ..utils import parse_numeric_range @@ -12,8 +13,9 @@ class NumericArrayField(SimpleArrayField): def clean(self, value): if value and not self.to_python(value): - raise forms.ValidationError(f'Invalid list ({value}). ' - f'Must be numeric and ranges must be in ascending order') + raise forms.ValidationError( + _("Invalid list ({value}). Must be numeric and ranges must be in ascending order.").format(value=value) + ) return super().clean(value) def to_python(self, value): diff --git a/netbox/utilities/forms/fields/csv.py b/netbox/utilities/forms/fields/csv.py index 5d6258193..97d772412 100644 --- a/netbox/utilities/forms/fields/csv.py +++ b/netbox/utilities/forms/fields/csv.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext_lazy as _ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.db.models import Q @@ -40,7 +41,7 @@ class CSVMultipleChoiceField(CSVChoicesMixin, forms.MultipleChoiceField): if not value: return [] if not isinstance(value, str): - raise forms.ValidationError(f"Invalid value for a multiple choice field: {value}") + raise forms.ValidationError(_("Invalid value for a multiple choice field: {value}").format(value=value)) return value.split(',') @@ -53,7 +54,7 @@ class CSVModelChoiceField(forms.ModelChoiceField): Extends Django's `ModelChoiceField` to provide additional validation for CSV values. """ default_error_messages = { - 'invalid_choice': 'Object not found: %(value)s', + 'invalid_choice': _('Object not found: %(value)s'), } def to_python(self, value): @@ -61,7 +62,7 @@ class CSVModelChoiceField(forms.ModelChoiceField): return super().to_python(value) except MultipleObjectsReturned: raise forms.ValidationError( - f'"{value}" is not a unique value for this field; multiple objects were found' + _('"{value}" is not a unique value for this field; multiple objects were found').format(value=value) ) @@ -70,7 +71,7 @@ class CSVModelMultipleChoiceField(forms.ModelMultipleChoiceField): Extends Django's `ModelMultipleChoiceField` to support comma-separated values. """ default_error_messages = { - 'invalid_choice': 'Object not found: %(value)s', + 'invalid_choice': _('Object not found: %(value)s'), } def clean(self, value): @@ -93,11 +94,11 @@ class CSVContentTypeField(CSVModelChoiceField): try: app_label, model = value.split('.') except ValueError: - raise forms.ValidationError(f'Object type must be specified as "."') + raise forms.ValidationError(_('Object type must be specified as "."')) try: return self.queryset.get(app_label=app_label, model=model) except ObjectDoesNotExist: - raise forms.ValidationError(f'Invalid object type') + raise forms.ValidationError(_('Invalid object type')) class CSVMultipleContentTypeField(forms.ModelMultipleChoiceField): diff --git a/netbox/utilities/forms/fields/expandable.py b/netbox/utilities/forms/fields/expandable.py index 781de9f76..959271a85 100644 --- a/netbox/utilities/forms/fields/expandable.py +++ b/netbox/utilities/forms/fields/expandable.py @@ -1,7 +1,7 @@ import re from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from utilities.forms.constants import * from utilities.forms.utils import expand_alphanumeric_pattern, expand_ipaddress_pattern @@ -21,10 +21,10 @@ class ExpandableNameField(forms.CharField): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not self.help_text: - self.help_text = """ - Alphanumeric ranges are supported for bulk creation. Mixed cases and types within a single range - are not supported (example: [ge,xe]-0/0/[0-9]). - """ + self.help_text = _( + "Alphanumeric ranges are supported for bulk creation. Mixed cases and types within a single range are " + "not supported (example: [ge,xe]-0/0/[0-9])." + ) def to_python(self, value): if not value: diff --git a/netbox/utilities/forms/fields/fields.py b/netbox/utilities/forms/fields/fields.py index c1e1e481c..db5e4a30d 100644 --- a/netbox/utilities/forms/fields/fields.py +++ b/netbox/utilities/forms/fields/fields.py @@ -4,7 +4,7 @@ from django import forms from django.db.models import Count from django.forms.fields import JSONField as _JSONField, InvalidJSONInput from django.templatetags.static import static -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from netaddr import AddrFormatError, EUI from utilities.forms import widgets @@ -26,14 +26,14 @@ class CommentField(forms.CharField): A textarea with support for Markdown rendering. Exists mostly just to add a standard `help_text`. """ widget = widgets.MarkdownWidget - help_text = f""" - - - Markdown syntax is supported - """ + label = _('Comments') + help_text = _( + ' ' + 'Markdown syntax is supported' + ).format(url=static('docs/reference/markdown/')) - def __init__(self, *, help_text=help_text, required=False, **kwargs): - super().__init__(help_text=help_text, required=required, **kwargs) + def __init__(self, *, label=label, help_text=help_text, required=False, **kwargs): + super().__init__(label=label, help_text=help_text, required=required, **kwargs) class SlugField(forms.SlugField): @@ -44,10 +44,11 @@ class SlugField(forms.SlugField): slug_source: Name of the form field from which the slug value will be derived """ widget = widgets.SlugWidget + label = _('Slug') help_text = _("URL-friendly unique shorthand") - def __init__(self, *, slug_source='name', help_text=help_text, **kwargs): - super().__init__(help_text=help_text, **kwargs) + def __init__(self, *, slug_source='name', label=label, help_text=help_text, **kwargs): + super().__init__(label=label, help_text=help_text, **kwargs) self.widget.attrs['slug-source'] = slug_source @@ -77,7 +78,7 @@ class TagFilterField(forms.MultipleChoiceField): ] # Choices are fetched each time the form is initialized - super().__init__(label='Tags', choices=get_choices, required=False, *args, **kwargs) + super().__init__(label=_('Tags'), choices=get_choices, required=False, *args, **kwargs) class LaxURLField(forms.URLField): @@ -113,7 +114,7 @@ class MACAddressField(forms.Field): """ widget = forms.CharField default_error_messages = { - 'invalid': 'MAC address must be in EUI-48 format', + 'invalid': _('MAC address must be in EUI-48 format'), } def to_python(self, value): diff --git a/netbox/virtualization/forms/bulk_create.py b/netbox/virtualization/forms/bulk_create.py index 0b762f38e..7153453ec 100644 --- a/netbox/virtualization/forms/bulk_create.py +++ b/netbox/virtualization/forms/bulk_create.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from utilities.forms import BootstrapMixin, form_from_model from utilities.forms.fields import ExpandableNameField diff --git a/netbox/virtualization/forms/bulk_edit.py b/netbox/virtualization/forms/bulk_edit.py index 9aa771d29..cc281a4f7 100644 --- a/netbox/virtualization/forms/bulk_edit.py +++ b/netbox/virtualization/forms/bulk_edit.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import InterfaceModeChoices from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN @@ -25,6 +25,7 @@ __all__ = ( class ClusterTypeBulkEditForm(NetBoxModelBulkEditForm): description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -38,6 +39,7 @@ class ClusterTypeBulkEditForm(NetBoxModelBulkEditForm): class ClusterGroupBulkEditForm(NetBoxModelBulkEditForm): description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -51,31 +53,38 @@ class ClusterGroupBulkEditForm(NetBoxModelBulkEditForm): class ClusterBulkEditForm(NetBoxModelBulkEditForm): type = DynamicModelChoiceField( + label=_('Type'), queryset=ClusterType.objects.all(), required=False ) group = DynamicModelChoiceField( + label=_('Group'), queryset=ClusterGroup.objects.all(), required=False ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(ClusterStatusChoices), required=False, initial='' ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False, ) site_group = DynamicModelChoiceField( + label=_('Site group'), queryset=SiteGroup.objects.all(), required=False, ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, query_params={ @@ -84,17 +93,16 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm): } ) description = forms.CharField( + label=_('Site'), max_length=200, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() model = Cluster fieldsets = ( (None, ('type', 'group', 'status', 'tenant', 'description')), - ('Site', ('region', 'site_group', 'site')), + (_('Site'), ('region', 'site_group', 'site')), ) nullable_fields = ( 'group', 'site', 'tenant', 'description', 'comments', @@ -103,15 +111,18 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm): class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(VirtualMachineStatusChoices), required=False, initial='', ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False ) cluster = DynamicModelChoiceField( + label=_('Cluster'), queryset=Cluster.objects.all(), required=False, query_params={ @@ -119,6 +130,7 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): } ) device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False, query_params={ @@ -126,6 +138,7 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): } ) role = DynamicModelChoiceField( + label=_('Role'), queryset=DeviceRole.objects.filter( vm_role=True ), @@ -135,10 +148,12 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): } ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) platform = DynamicModelChoiceField( + label=_('Platform'), queryset=Platform.objects.all(), required=False ) @@ -155,17 +170,16 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): label=_('Disk (GB)') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label=_('Comments') - ) + comments = CommentField() model = VirtualMachine fieldsets = ( (None, ('site', 'cluster', 'device', 'status', 'role', 'tenant', 'platform', 'description')), - ('Resources', ('vcpus', 'memory', 'disk')) + (_('Resources'), ('vcpus', 'memory', 'disk')) ) nullable_fields = ( 'site', 'cluster', 'device', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'description', 'comments', @@ -174,20 +188,24 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): virtual_machine = forms.ModelChoiceField( + label=_('Virtual machine'), queryset=VirtualMachine.objects.all(), required=False, disabled=True, widget=forms.HiddenInput() ) parent = DynamicModelChoiceField( + label=_('Parent'), queryset=VMInterface.objects.all(), required=False ) bridge = DynamicModelChoiceField( + label=_('Bridge'), queryset=VMInterface.objects.all(), required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=BulkEditNullBooleanSelect() ) @@ -198,10 +216,12 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): label=_('MTU') ) description = forms.CharField( + label=_('Description'), max_length=100, required=False ) mode = forms.ChoiceField( + label=_('Mode'), choices=add_blank_choice(InterfaceModeChoices), required=False ) @@ -235,8 +255,8 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): model = VMInterface fieldsets = ( (None, ('mtu', 'enabled', 'vrf', 'description')), - ('Related Interfaces', ('parent', 'bridge')), - ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), + (_('Related Interfaces'), ('parent', 'bridge')), + (_('802.1Q Switching'), ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), ) nullable_fields = ( 'parent', 'bridge', 'mtu', 'vrf', 'description', diff --git a/netbox/virtualization/forms/bulk_import.py b/netbox/virtualization/forms/bulk_import.py index 15651f2ae..19f718f03 100644 --- a/netbox/virtualization/forms/bulk_import.py +++ b/netbox/virtualization/forms/bulk_import.py @@ -1,4 +1,4 @@ -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import InterfaceModeChoices from dcim.models import Device, DeviceRole, Platform, Site @@ -36,27 +36,32 @@ class ClusterGroupImportForm(NetBoxModelImportForm): class ClusterImportForm(NetBoxModelImportForm): type = CSVModelChoiceField( + label=_('Type'), queryset=ClusterType.objects.all(), to_field_name='name', help_text=_('Type of cluster') ) group = CSVModelChoiceField( + label=_('Group'), queryset=ClusterGroup.objects.all(), to_field_name='name', required=False, help_text=_('Assigned cluster group') ) status = CSVChoiceField( + label=_('Status'), choices=ClusterStatusChoices, help_text=_('Operational status') ) site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', required=False, help_text=_('Assigned site') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), to_field_name='name', required=False, @@ -70,28 +75,33 @@ class ClusterImportForm(NetBoxModelImportForm): class VirtualMachineImportForm(NetBoxModelImportForm): status = CSVChoiceField( + label=_('Status'), choices=VirtualMachineStatusChoices, help_text=_('Operational status') ) site = CSVModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), to_field_name='name', required=False, help_text=_('Assigned site') ) cluster = CSVModelChoiceField( + label=_('Cluster'), queryset=Cluster.objects.all(), to_field_name='name', required=False, help_text=_('Assigned cluster') ) device = CSVModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), to_field_name='name', required=False, help_text=_('Assigned device within cluster') ) role = CSVModelChoiceField( + label=_('Role'), queryset=DeviceRole.objects.filter( vm_role=True ), @@ -100,12 +110,14 @@ class VirtualMachineImportForm(NetBoxModelImportForm): help_text=_('Functional role') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Assigned tenant') ) platform = CSVModelChoiceField( + label=_('Platform'), queryset=Platform.objects.all(), required=False, to_field_name='name', @@ -122,27 +134,32 @@ class VirtualMachineImportForm(NetBoxModelImportForm): class VMInterfaceImportForm(NetBoxModelImportForm): virtual_machine = CSVModelChoiceField( + label=_('Virtual machine'), queryset=VirtualMachine.objects.all(), to_field_name='name' ) parent = CSVModelChoiceField( + label=_('Parent'), queryset=VMInterface.objects.all(), required=False, to_field_name='name', help_text=_('Parent interface') ) bridge = CSVModelChoiceField( + label=_('Bridge'), queryset=VMInterface.objects.all(), required=False, to_field_name='name', help_text=_('Bridged interface') ) mode = CSVChoiceField( + label=_('Mode'), choices=InterfaceModeChoices, required=False, help_text=_('IEEE 802.1Q operational mode (for L2 interfaces)') ) vrf = CSVModelChoiceField( + label=_('VRF'), queryset=VRF.objects.all(), required=False, to_field_name='rd', diff --git a/netbox/virtualization/forms/filtersets.py b/netbox/virtualization/forms/filtersets.py index 3e228742c..cd1269645 100644 --- a/netbox/virtualization/forms/filtersets.py +++ b/netbox/virtualization/forms/filtersets.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup from extras.forms import LocalConfigContextFilterForm @@ -30,7 +30,7 @@ class ClusterGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): tag = TagFilterField(model) fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) @@ -38,10 +38,10 @@ class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi model = Cluster fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('group_id', 'type_id', 'status')), - ('Location', ('region_id', 'site_group_id', 'site_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Attributes'), ('group_id', 'type_id', 'status')), + (_('Location'), ('region_id', 'site_group_id', 'site_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) type_id = DynamicModelMultipleChoiceField( queryset=ClusterType.objects.all(), @@ -54,6 +54,7 @@ class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi label=_('Region') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=ClusterStatusChoices, required=False ) @@ -90,11 +91,11 @@ class VirtualMachineFilterForm( model = VirtualMachine fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Cluster', ('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id')), - ('Location', ('region_id', 'site_group_id', 'site_id')), - ('Attributes', ('status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'local_context_data')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Contacts', ('contact', 'contact_role', 'contact_group')), + (_('Cluster'), ('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id')), + (_('Location'), ('region_id', 'site_group_id', 'site_id')), + (_('Attributes'), ('status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'local_context_data')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Contacts'), ('contact', 'contact_role', 'contact_group')), ) cluster_group_id = DynamicModelMultipleChoiceField( queryset=ClusterGroup.objects.all(), @@ -148,6 +149,7 @@ class VirtualMachineFilterForm( label=_('Role') ) status = forms.MultipleChoiceField( + label=_('Status'), choices=VirtualMachineStatusChoices, required=False ) @@ -175,8 +177,8 @@ class VMInterfaceFilterForm(NetBoxModelFilterSetForm): model = VMInterface fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Virtual Machine', ('cluster_id', 'virtual_machine_id')), - ('Attributes', ('enabled', 'mac_address', 'vrf_id', 'l2vpn_id')), + (_('Virtual Machine'), ('cluster_id', 'virtual_machine_id')), + (_('Attributes'), ('enabled', 'mac_address', 'vrf_id', 'l2vpn_id')), ) cluster_id = DynamicModelMultipleChoiceField( queryset=Cluster.objects.all(), @@ -192,6 +194,7 @@ class VMInterfaceFilterForm(NetBoxModelFilterSetForm): label=_('Virtual machine') ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -199,12 +202,12 @@ class VMInterfaceFilterForm(NetBoxModelFilterSetForm): ) mac_address = forms.CharField( required=False, - label='MAC address' + label=_('MAC address') ) vrf_id = DynamicModelMultipleChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) l2vpn_id = DynamicModelMultipleChoiceField( queryset=L2VPN.objects.all(), diff --git a/netbox/virtualization/forms/model_forms.py b/netbox/virtualization/forms/model_forms.py index b4051dec2..0c8c98f9f 100644 --- a/netbox/virtualization/forms/model_forms.py +++ b/netbox/virtualization/forms/model_forms.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.forms.common import InterfaceCommonForm from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site, SiteGroup @@ -30,7 +30,7 @@ class ClusterTypeForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Cluster Type', ( + (_('Cluster Type'), ( 'name', 'slug', 'description', 'tags', )), ) @@ -46,7 +46,7 @@ class ClusterGroupForm(NetBoxModelForm): slug = SlugField() fieldsets = ( - ('Cluster Group', ( + (_('Cluster Group'), ( 'name', 'slug', 'description', 'tags', )), ) @@ -60,13 +60,16 @@ class ClusterGroupForm(NetBoxModelForm): class ClusterForm(TenancyForm, NetBoxModelForm): type = DynamicModelChoiceField( + label=_('Type'), queryset=ClusterType.objects.all() ) group = DynamicModelChoiceField( + label=_('Group'), queryset=ClusterGroup.objects.all(), required=False ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, selector=True @@ -74,8 +77,8 @@ class ClusterForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Cluster', ('name', 'type', 'group', 'site', 'status', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), + (_('Cluster'), ('name', 'type', 'group', 'site', 'status', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), ) class Meta: @@ -87,16 +90,19 @@ class ClusterForm(TenancyForm, NetBoxModelForm): class ClusterAddDevicesForm(BootstrapMixin, forms.Form): region = DynamicModelChoiceField( + label=_('Region'), queryset=Region.objects.all(), required=False, null_option='None' ) site_group = DynamicModelChoiceField( + label=_('Site group'), queryset=SiteGroup.objects.all(), required=False, null_option='None' ) site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False, query_params={ @@ -105,6 +111,7 @@ class ClusterAddDevicesForm(BootstrapMixin, forms.Form): } ) rack = DynamicModelChoiceField( + label=_('Rack'), queryset=Rack.objects.all(), required=False, null_option='None', @@ -113,6 +120,7 @@ class ClusterAddDevicesForm(BootstrapMixin, forms.Form): } ) devices = DynamicModelMultipleChoiceField( + label=_('Devices'), queryset=Device.objects.all(), query_params={ 'site_id': '$site', @@ -142,7 +150,7 @@ class ClusterAddDevicesForm(BootstrapMixin, forms.Form): for device in self.cleaned_data.get('devices', []): if device.site != self.cluster.site: raise ValidationError({ - 'devices': "{} belongs to a different site ({}) than the cluster ({})".format( + 'devices': _("{} belongs to a different site ({}) than the cluster ({})").format( device, device.site, self.cluster.site ) }) @@ -157,10 +165,12 @@ class ClusterRemoveDevicesForm(ConfirmationForm): class VirtualMachineForm(TenancyForm, NetBoxModelForm): site = DynamicModelChoiceField( + label=_('Site'), queryset=Site.objects.all(), required=False ) cluster = DynamicModelChoiceField( + label=_('Cluster'), queryset=Cluster.objects.all(), required=False, selector=True, @@ -169,6 +179,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): } ) device = DynamicModelChoiceField( + label=_('Device'), queryset=Device.objects.all(), required=False, query_params={ @@ -178,6 +189,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): help_text=_("Optionally pin this VM to a specific host device within the cluster") ) role = DynamicModelChoiceField( + label=_('Role'), queryset=DeviceRole.objects.all(), required=False, query_params={ @@ -185,6 +197,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): } ) platform = DynamicModelChoiceField( + label=_('Platform'), queryset=Platform.objects.all(), required=False ) @@ -195,12 +208,12 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Virtual Machine', ('name', 'role', 'status', 'description', 'tags')), - ('Site/Cluster', ('site', 'cluster', 'device')), - ('Tenancy', ('tenant_group', 'tenant')), - ('Management', ('platform', 'primary_ip4', 'primary_ip6')), - ('Resources', ('vcpus', 'memory', 'disk')), - ('Config Context', ('local_context_data',)), + (_('Virtual Machine'), ('name', 'role', 'status', 'description', 'tags')), + (_('Site/Cluster'), ('site', 'cluster', 'device')), + (_('Tenancy'), ('tenant_group', 'tenant')), + (_('Management'), ('platform', 'primary_ip4', 'primary_ip6')), + (_('Resources'), ('vcpus', 'memory', 'disk')), + (_('Config Context'), ('local_context_data',)), ) class Meta: @@ -253,6 +266,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm): virtual_machine = DynamicModelChoiceField( + label=_('Virtual machine'), queryset=VirtualMachine.objects.all(), selector=True ) @@ -302,11 +316,11 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm): ) fieldsets = ( - ('Interface', ('virtual_machine', 'name', 'description', 'tags')), - ('Addressing', ('vrf', 'mac_address')), - ('Operation', ('mtu', 'enabled')), - ('Related Interfaces', ('parent', 'bridge')), - ('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), + (_('Interface'), ('virtual_machine', 'name', 'description', 'tags')), + (_('Addressing'), ('vrf', 'mac_address')), + (_('Operation'), ('mtu', 'enabled')), + (_('Related Interfaces'), ('parent', 'bridge')), + (_('802.1Q Switching'), ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')), ) class Meta: diff --git a/netbox/virtualization/forms/object_create.py b/netbox/virtualization/forms/object_create.py index c36ce00ee..3ea374039 100644 --- a/netbox/virtualization/forms/object_create.py +++ b/netbox/virtualization/forms/object_create.py @@ -1,3 +1,4 @@ +from django.utils.translation import gettext_lazy as _ from utilities.forms.fields import ExpandableNameField from .model_forms import VMInterfaceForm @@ -7,7 +8,9 @@ __all__ = ( class VMInterfaceCreateForm(VMInterfaceForm): - name = ExpandableNameField() + name = ExpandableNameField( + label=_('Name'), + ) replication_fields = ('name',) class Meta(VMInterfaceForm.Meta): diff --git a/netbox/wireless/forms/bulk_edit.py b/netbox/wireless/forms/bulk_edit.py index 4fec0b87f..43e804345 100644 --- a/netbox/wireless/forms/bulk_edit.py +++ b/netbox/wireless/forms/bulk_edit.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import LinkStatusChoices from ipam.models import VLAN @@ -20,10 +20,12 @@ __all__ = ( class WirelessLANGroupBulkEditForm(NetBoxModelBulkEditForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=WirelessLANGroup.objects.all(), required=False ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) @@ -37,10 +39,12 @@ class WirelessLANGroupBulkEditForm(NetBoxModelBulkEditForm): class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(WirelessLANStatusChoices), required=False ) group = DynamicModelChoiceField( + label=_('Group'), queryset=WirelessLANGroup.objects.all(), required=False ) @@ -55,14 +59,17 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): label=_('SSID') ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) auth_type = forms.ChoiceField( + label=_('Authentication type'), choices=add_blank_choice(WirelessAuthTypeChoices), required=False ) auth_cipher = forms.ChoiceField( + label=_('Authentication cipher'), choices=add_blank_choice(WirelessAuthCipherChoices), required=False ) @@ -71,17 +78,16 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): label=_('Pre-shared key') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = WirelessLAN fieldsets = ( (None, ('group', 'ssid', 'status', 'vlan', 'tenant', 'description')), - ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')), + (_('Authentication'), ('auth_type', 'auth_cipher', 'auth_psk')), ) nullable_fields = ( 'ssid', 'group', 'vlan', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'comments', @@ -95,18 +101,22 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): label=_('SSID') ) status = forms.ChoiceField( + label=_('Status'), choices=add_blank_choice(LinkStatusChoices), required=False ) tenant = DynamicModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False ) auth_type = forms.ChoiceField( + label=_('Authentication type'), choices=add_blank_choice(WirelessAuthTypeChoices), required=False ) auth_cipher = forms.ChoiceField( + label=_('Authentication cipher'), choices=add_blank_choice(WirelessAuthCipherChoices), required=False ) @@ -115,17 +125,16 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): label=_('Pre-shared key') ) description = forms.CharField( + label=_('Description'), max_length=200, required=False ) - comments = CommentField( - label='Comments' - ) + comments = CommentField() model = WirelessLink fieldsets = ( (None, ('ssid', 'status', 'tenant', 'description')), - ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')) + (_('Authentication'), ('auth_type', 'auth_cipher', 'auth_psk')) ) nullable_fields = ( 'ssid', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'comments', diff --git a/netbox/wireless/forms/bulk_import.py b/netbox/wireless/forms/bulk_import.py index f29e24260..c0e2dfb54 100644 --- a/netbox/wireless/forms/bulk_import.py +++ b/netbox/wireless/forms/bulk_import.py @@ -1,4 +1,4 @@ -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import LinkStatusChoices from dcim.models import Interface @@ -18,6 +18,7 @@ __all__ = ( class WirelessLANGroupImportForm(NetBoxModelImportForm): parent = CSVModelChoiceField( + label=_('Parent'), queryset=WirelessLANGroup.objects.all(), required=False, to_field_name='name', @@ -32,33 +33,39 @@ class WirelessLANGroupImportForm(NetBoxModelImportForm): class WirelessLANImportForm(NetBoxModelImportForm): group = CSVModelChoiceField( + label=_('Group'), queryset=WirelessLANGroup.objects.all(), required=False, to_field_name='name', help_text=_('Assigned group') ) status = CSVChoiceField( + label=_('Status'), choices=WirelessLANStatusChoices, help_text='Operational status' ) vlan = CSVModelChoiceField( + label=_('VLAN'), queryset=VLAN.objects.all(), required=False, to_field_name='name', help_text=_('Bridged VLAN') ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Assigned tenant') ) auth_type = CSVChoiceField( + label=_('Authentication type'), choices=WirelessAuthTypeChoices, required=False, help_text=_('Authentication type') ) auth_cipher = CSVChoiceField( + label=_('Authentication cipher'), choices=WirelessAuthCipherChoices, required=False, help_text=_('Authentication cipher') @@ -74,27 +81,33 @@ class WirelessLANImportForm(NetBoxModelImportForm): class WirelessLinkImportForm(NetBoxModelImportForm): status = CSVChoiceField( + label=_('Status'), choices=LinkStatusChoices, help_text=_('Connection status') ) interface_a = CSVModelChoiceField( + label=_('Interface A'), queryset=Interface.objects.all() ) interface_b = CSVModelChoiceField( + label=_('Interface B'), queryset=Interface.objects.all() ) tenant = CSVModelChoiceField( + label=_('Tenant'), queryset=Tenant.objects.all(), required=False, to_field_name='name', help_text=_('Assigned tenant') ) auth_type = CSVChoiceField( + label=_('Authentication type'), choices=WirelessAuthTypeChoices, required=False, help_text=_('Authentication type') ) auth_cipher = CSVChoiceField( + label=_('Authentication cipher'), choices=WirelessAuthCipherChoices, required=False, help_text=_('Authentication cipher') diff --git a/netbox/wireless/forms/filtersets.py b/netbox/wireless/forms/filtersets.py index f281ed0db..f4c1cb523 100644 --- a/netbox/wireless/forms/filtersets.py +++ b/netbox/wireless/forms/filtersets.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.choices import LinkStatusChoices from netbox.forms import NetBoxModelFilterSetForm @@ -30,9 +30,9 @@ class WirelessLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = WirelessLAN fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('ssid', 'group_id', 'status')), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')), + (_('Attributes'), ('ssid', 'group_id', 'status')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Authentication'), ('auth_type', 'auth_cipher', 'auth_psk')), ) ssid = forms.CharField( required=False, @@ -45,18 +45,22 @@ class WirelessLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('Group') ) status = forms.ChoiceField( + label=_('Status'), required=False, choices=add_blank_choice(WirelessLANStatusChoices) ) auth_type = forms.ChoiceField( + label=_('Authentication type'), required=False, choices=add_blank_choice(WirelessAuthTypeChoices) ) auth_cipher = forms.ChoiceField( + label=_('Authentication cipher'), required=False, choices=add_blank_choice(WirelessAuthCipherChoices) ) auth_psk = forms.CharField( + label=_('Pre-shared key'), required=False ) tag = TagFilterField(model) @@ -66,27 +70,31 @@ class WirelessLinkFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): model = WirelessLink fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Attributes', ('ssid', 'status',)), - ('Tenant', ('tenant_group_id', 'tenant_id')), - ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')), + (_('Attributes'), ('ssid', 'status',)), + (_('Tenant'), ('tenant_group_id', 'tenant_id')), + (_('Authentication'), ('auth_type', 'auth_cipher', 'auth_psk')), ) ssid = forms.CharField( required=False, label=_('SSID') ) status = forms.ChoiceField( + label=_('Status'), required=False, choices=add_blank_choice(LinkStatusChoices) ) auth_type = forms.ChoiceField( + label=_('Authentication type'), required=False, choices=add_blank_choice(WirelessAuthTypeChoices) ) auth_cipher = forms.ChoiceField( + label=_('Authentication cipher'), required=False, choices=add_blank_choice(WirelessAuthCipherChoices) ) auth_psk = forms.CharField( + label=_('Pre-shared key'), required=False ) tag = TagFilterField(model) diff --git a/netbox/wireless/forms/model_forms.py b/netbox/wireless/forms/model_forms.py index 2523ff7a9..666bddaa9 100644 --- a/netbox/wireless/forms/model_forms.py +++ b/netbox/wireless/forms/model_forms.py @@ -1,5 +1,5 @@ from django.forms import PasswordInput -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim.models import Device, Interface, Location, Site from ipam.models import VLAN @@ -17,13 +17,14 @@ __all__ = ( class WirelessLANGroupForm(NetBoxModelForm): parent = DynamicModelChoiceField( + label=_('Parent'), queryset=WirelessLANGroup.objects.all(), required=False ) slug = SlugField() fieldsets = ( - ('Wireless LAN Group', ( + (_('Wireless LAN Group'), ( 'parent', 'name', 'slug', 'description', 'tags', )), ) @@ -37,6 +38,7 @@ class WirelessLANGroupForm(NetBoxModelForm): class WirelessLANForm(TenancyForm, NetBoxModelForm): group = DynamicModelChoiceField( + label=_('Group'), queryset=WirelessLANGroup.objects.all(), required=False ) @@ -49,9 +51,9 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Wireless LAN', ('ssid', 'group', 'vlan', 'status', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')), + (_('Wireless LAN'), ('ssid', 'group', 'vlan', 'status', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), + (_('Authentication'), ('auth_type', 'auth_cipher', 'auth_psk')), ) class Meta: @@ -152,11 +154,11 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Side A', ('site_a', 'location_a', 'device_a', 'interface_a')), - ('Side B', ('site_b', 'location_b', 'device_b', 'interface_b')), - ('Link', ('status', 'ssid', 'description', 'tags')), - ('Tenancy', ('tenant_group', 'tenant')), - ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')), + (_('Side A'), ('site_a', 'location_a', 'device_a', 'interface_a')), + (_('Side B'), ('site_b', 'location_b', 'device_b', 'interface_b')), + (_('Link'), ('status', 'ssid', 'description', 'tags')), + (_('Tenancy'), ('tenant_group', 'tenant')), + (_('Authentication'), ('auth_type', 'auth_cipher', 'auth_psk')), ) class Meta: